2 * PROJECT: Recycle bin management
3 * LICENSE: GPL v2 - See COPYING in the top level directory
4 * FILE: lib/recyclebin/recyclebin_v5.c
5 * PURPOSE: Deals with recycle bins of Windows 2000/XP/2003
6 * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
10 #include "recyclebin_v5.h"
13 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin
);
19 DWORD RemovableAttributes
= FILE_ATTRIBUTE_READONLY
;
20 WIN32_FIND_DATAW FindData
;
21 HANDLE hSearch
= INVALID_HANDLE_VALUE
;
22 LPWSTR FullPath
= NULL
, pFilePart
;
27 FileAttributes
= GetFileAttributesW(FullName
);
28 if (FileAttributes
== INVALID_FILE_ATTRIBUTES
)
30 if (GetLastError() == ERROR_FILE_NOT_FOUND
)
34 if (FileAttributes
& RemovableAttributes
)
36 if (!SetFileAttributesW(FullName
, FileAttributes
& ~RemovableAttributes
))
39 if (FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
41 /* Prepare file specification */
42 dwLength
= wcslen(FullName
);
43 FullPath
= HeapAlloc(GetProcessHeap(), 0, (dwLength
+ 1 + MAX_PATH
+ 1) * sizeof(WCHAR
));
46 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
49 wcscpy(FullPath
, FullName
);
50 if (FullPath
[dwLength
- 1] != '\\')
52 FullPath
[dwLength
] = '\\';
55 pFilePart
= &FullPath
[dwLength
];
56 wcscpy(pFilePart
, L
"*");
58 /* Enumerate contents, and delete it */
59 hSearch
= FindFirstFileW(FullPath
, &FindData
);
60 if (hSearch
== INVALID_HANDLE_VALUE
)
64 if (!(FindData
.cFileName
[0] == '.' &&
65 (FindData
.cFileName
[1] == '\0' || (FindData
.cFileName
[1] == '.' && FindData
.cFileName
[2] == '\0'))))
67 wcscpy(pFilePart
, FindData
.cFileName
);
68 if (!IntDeleteRecursive(FullPath
))
75 while (FindNextFileW(hSearch
, &FindData
));
77 if (GetLastError() != ERROR_NO_MORE_FILES
)
80 /* Remove (now empty) directory */
81 if (!RemoveDirectoryW(FullName
))
86 if (!DeleteFileW(FullName
))
92 HeapFree(GetProcessHeap(), 0, FullPath
);
99 IRecycleBin5 recycleBinImpl
;
103 DWORD EnumeratorCount
;
106 WCHAR Folder
[ANY_SIZE
]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */
109 static HRESULT STDMETHODCALLTYPE
110 RecycleBin5_RecycleBin5_QueryInterface(
115 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
117 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
122 if (IsEqualIID(riid
, &IID_IUnknown
))
123 *ppvObject
= &s
->recycleBinImpl
;
124 else if (IsEqualIID(riid
, &IID_IRecycleBin
))
125 *ppvObject
= &s
->recycleBinImpl
;
126 else if (IsEqualIID(riid
, &IID_IRecycleBin5
))
127 *ppvObject
= &s
->recycleBinImpl
;
131 return E_NOINTERFACE
;
134 IUnknown_AddRef(This
);
138 static ULONG STDMETHODCALLTYPE
139 RecycleBin5_RecycleBin5_AddRef(
142 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
143 ULONG refCount
= InterlockedIncrement((PLONG
)&s
->ref
);
144 TRACE("(%p)\n", This
);
149 RecycleBin5_Destructor(
150 struct RecycleBin5
*s
)
154 if (s
->hInfo
&& s
->hInfo
!= INVALID_HANDLE_VALUE
)
155 CloseHandle(s
->hInfo
);
157 CloseHandle(s
->hInfoMapped
);
161 static ULONG STDMETHODCALLTYPE
162 RecycleBin5_RecycleBin5_Release(
165 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
168 TRACE("(%p)\n", This
);
170 refCount
= InterlockedDecrement((PLONG
)&s
->ref
);
173 RecycleBin5_Destructor(s
);
178 static HRESULT STDMETHODCALLTYPE
179 RecycleBin5_RecycleBin5_DeleteFile(
180 IN IRecycleBin5
*This
,
181 IN LPCWSTR szFileName
)
183 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
184 LPWSTR szFullName
= NULL
;
185 DWORD dwBufferLength
= 0;
188 WCHAR DeletedFileName
[MAX_PATH
];
190 HANDLE hFile
= INVALID_HANDLE_VALUE
;
191 PINFO2_HEADER pHeader
= NULL
;
192 PDELETED_FILE_RECORD pDeletedFile
;
193 ULARGE_INTEGER FileSize
;
194 DWORD dwAttributes
, dwEntries
;
195 SYSTEMTIME SystemTime
;
196 DWORD ClusterSize
, BytesPerSector
, SectorsPerCluster
;
199 TRACE("(%p, %s)\n", This
, debugstr_w(szFileName
));
201 if (s
->EnumeratorCount
!= 0)
202 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION
);
204 /* Get full file name */
207 len
= GetFullPathNameW(szFileName
, dwBufferLength
, szFullName
, &lpFilePart
);
211 CoTaskMemFree(szFullName
);
212 return HRESULT_FROM_WIN32(GetLastError());
214 else if (len
< dwBufferLength
)
217 CoTaskMemFree(szFullName
);
218 dwBufferLength
= len
;
219 szFullName
= CoTaskMemAlloc(dwBufferLength
* sizeof(WCHAR
));
221 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY
);
224 /* Check if file exists */
225 dwAttributes
= GetFileAttributesW(szFullName
);
226 if (dwAttributes
== INVALID_FILE_ATTRIBUTES
)
227 return HRESULT_FROM_WIN32(GetLastError());
229 if (dwBufferLength
< 2 || szFullName
[1] != ':')
231 /* Not a local file */
232 CoTaskMemFree(szFullName
);
233 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
236 hFile
= CreateFileW(szFullName
, 0, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
237 if (hFile
== INVALID_HANDLE_VALUE
)
239 hr
= HRESULT_FROM_WIN32(GetLastError());
243 /* Increase INFO2 file size */
244 CloseHandle(s
->hInfoMapped
);
245 SetFilePointer(s
->hInfo
, sizeof(DELETED_FILE_RECORD
), NULL
, FILE_END
);
246 SetEndOfFile(s
->hInfo
);
247 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
250 hr
= HRESULT_FROM_WIN32(GetLastError());
254 /* Open INFO2 file */
255 pHeader
= MapViewOfFile(s
->hInfoMapped
, FILE_MAP_WRITE
, 0, 0, 0);
258 hr
= HRESULT_FROM_WIN32(GetLastError());
262 /* Get number of entries */
263 FileSize
.u
.LowPart
= GetFileSize(s
->hInfo
, &FileSize
.u
.HighPart
);
264 if (FileSize
.u
.LowPart
< sizeof(INFO2_HEADER
))
266 UnmapViewOfFile(pHeader
);
267 return HRESULT_FROM_WIN32(GetLastError());
269 dwEntries
= (DWORD
)((FileSize
.QuadPart
- sizeof(INFO2_HEADER
)) / sizeof(DELETED_FILE_RECORD
)) - 1;
270 pDeletedFile
= ((PDELETED_FILE_RECORD
)(pHeader
+ 1)) + dwEntries
;
274 if (!GetFileSizeEx(hFile
, (PLARGE_INTEGER
)&FileSize
))
276 hr
= HRESULT_FROM_WIN32(GetLastError());
280 FileSize
.u
.LowPart
= GetFileSize(hFile
, &FileSize
.u
.HighPart
);
281 if (FileSize
.u
.LowPart
== INVALID_FILE_SIZE
&& GetLastError() != NO_ERROR
)
283 hr
= HRESULT_FROM_WIN32(GetLastError());
287 /* Check if file size is > 4Gb */
288 if (FileSize
.u
.HighPart
!= 0)
290 /* Yes, this recyclebin can't support this file */
291 hr
= HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED
);
294 pHeader
->dwTotalLogicalSize
+= FileSize
.u
.LowPart
;
296 /* Generate new name */
297 Extension
= wcsrchr(szFullName
, '.');
298 ZeroMemory(pDeletedFile
, sizeof(DELETED_FILE_RECORD
));
300 pDeletedFile
->dwRecordUniqueId
= 0;
303 PDELETED_FILE_RECORD pLastDeleted
= ((PDELETED_FILE_RECORD
)(pHeader
+ 1)) + dwEntries
- 1;
304 pDeletedFile
->dwRecordUniqueId
= pLastDeleted
->dwRecordUniqueId
+ 1;
306 pDeletedFile
->dwDriveNumber
= tolower(szFullName
[0]) - 'a';
307 _snwprintf(DeletedFileName
, MAX_PATH
, L
"%s\\D%c%lu%s", s
->Folder
, pDeletedFile
->dwDriveNumber
+ 'a', pDeletedFile
->dwRecordUniqueId
, Extension
);
309 /* Get cluster size */
310 if (!GetDiskFreeSpaceW(s
->VolumePath
, &SectorsPerCluster
, &BytesPerSector
, NULL
, NULL
))
312 hr
= HRESULT_FROM_WIN32(GetLastError());
315 ClusterSize
= BytesPerSector
* SectorsPerCluster
;
317 /* Get current time */
318 GetSystemTime(&SystemTime
);
319 if (!SystemTimeToFileTime(&SystemTime
, &pDeletedFile
->DeletionTime
))
321 hr
= HRESULT_FROM_WIN32(GetLastError());
324 pDeletedFile
->dwPhysicalFileSize
= ROUND_UP(FileSize
.u
.LowPart
, ClusterSize
);
327 wcscpy(pDeletedFile
->FileNameW
, szFullName
);
328 if (WideCharToMultiByte(CP_ACP
, 0, pDeletedFile
->FileNameW
, -1, pDeletedFile
->FileNameA
, MAX_PATH
, NULL
, NULL
) == 0)
330 hr
= HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
331 SetLastError(ERROR_INVALID_NAME
);
336 if (MoveFileW(szFullName
, DeletedFileName
))
339 hr
= HRESULT_FROM_WIN32(GetLastError());
343 UnmapViewOfFile(pHeader
);
344 if (hFile
!= INVALID_HANDLE_VALUE
)
346 CoTaskMemFree(szFullName
);
350 static HRESULT STDMETHODCALLTYPE
351 RecycleBin5_RecycleBin5_EmptyRecycleBin(
352 IN IRecycleBin5
*This
)
354 IRecycleBinEnumList
*prbel
;
355 IRecycleBinFile
*prbf
;
358 TRACE("(%p)\n", This
);
362 hr
= IRecycleBin5_EnumObjects(This
, &prbel
);
365 hr
= IRecycleBinEnumList_Next(prbel
, 1, &prbf
, NULL
);
366 IRecycleBinEnumList_Release(prbel
);
369 hr
= IRecycleBinFile_Delete(prbf
);
370 IRecycleBinFile_Release(prbf
);
376 static HRESULT STDMETHODCALLTYPE
377 RecycleBin5_RecycleBin5_EnumObjects(
378 IN IRecycleBin5
*This
,
379 OUT IRecycleBinEnumList
**ppEnumList
)
381 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
382 IRecycleBinEnumList
*prbel
;
386 TRACE("(%p, %p)\n", This
, ppEnumList
);
388 hr
= RecycleBin5Enum_Constructor(This
, s
->hInfo
, s
->hInfoMapped
, s
->Folder
, &pUnk
);
392 hr
= IUnknown_QueryInterface(pUnk
, &IID_IRecycleBinEnumList
, (void **)&prbel
);
395 s
->EnumeratorCount
++;
398 IUnknown_Release(pUnk
);
402 static HRESULT STDMETHODCALLTYPE
403 RecycleBin5_RecycleBin5_Delete(
404 IN IRecycleBin5
*This
,
405 IN LPCWSTR pDeletedFileName
,
406 IN DELETED_FILE_RECORD
*pDeletedFile
)
408 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
409 ULARGE_INTEGER FileSize
;
410 PINFO2_HEADER pHeader
;
411 DELETED_FILE_RECORD
*pRecord
, *pLast
;
414 TRACE("(%p, %s, %p)\n", This
, debugstr_w(pDeletedFileName
), pDeletedFile
);
416 if (s
->EnumeratorCount
!= 0)
417 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION
);
419 pHeader
= MapViewOfFile(s
->hInfoMapped
, FILE_MAP_WRITE
, 0, 0, 0);
421 return HRESULT_FROM_WIN32(GetLastError());
423 FileSize
.u
.LowPart
= GetFileSize(s
->hInfo
, &FileSize
.u
.HighPart
);
424 if (FileSize
.u
.LowPart
== 0)
426 UnmapViewOfFile(pHeader
);
427 return HRESULT_FROM_WIN32(GetLastError());
429 dwEntries
= (DWORD
)((FileSize
.QuadPart
- sizeof(INFO2_HEADER
)) / sizeof(DELETED_FILE_RECORD
));
431 pRecord
= (DELETED_FILE_RECORD
*)(pHeader
+ 1);
432 for (i
= 0; i
< dwEntries
; i
++)
434 if (pRecord
->dwRecordUniqueId
== pDeletedFile
->dwRecordUniqueId
)
437 if (!IntDeleteRecursive(pDeletedFileName
))
439 UnmapViewOfFile(pHeader
);
440 return HRESULT_FROM_WIN32(GetLastError());
443 /* Clear last entry in the file */
444 MoveMemory(pRecord
, pRecord
+ 1, (dwEntries
- i
- 1) * sizeof(DELETED_FILE_RECORD
));
445 pLast
= pRecord
+ (dwEntries
- i
- 1);
446 ZeroMemory(pLast
, sizeof(DELETED_FILE_RECORD
));
447 UnmapViewOfFile(pHeader
);
450 CloseHandle(s
->hInfoMapped
);
451 SetFilePointer(s
->hInfo
, -(LONG
)sizeof(DELETED_FILE_RECORD
), NULL
, FILE_END
);
452 SetEndOfFile(s
->hInfo
);
453 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
455 return HRESULT_FROM_WIN32(GetLastError());
460 UnmapViewOfFile(pHeader
);
461 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
464 static HRESULT STDMETHODCALLTYPE
465 RecycleBin5_RecycleBin5_Restore(
466 IN IRecycleBin5
*This
,
467 IN LPCWSTR pDeletedFileName
,
468 IN DELETED_FILE_RECORD
*pDeletedFile
)
470 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
471 ULARGE_INTEGER FileSize
;
472 PINFO2_HEADER pHeader
;
473 DELETED_FILE_RECORD
*pRecord
, *pLast
;
477 TRACE("(%p, %s, %p)\n", This
, debugstr_w(pDeletedFileName
), pDeletedFile
);
479 if (s
->EnumeratorCount
!= 0)
480 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION
);
482 pHeader
= MapViewOfFile(s
->hInfoMapped
, FILE_MAP_WRITE
, 0, 0, 0);
484 return HRESULT_FROM_WIN32(GetLastError());
486 FileSize
.u
.LowPart
= GetFileSize(s
->hInfo
, &FileSize
.u
.HighPart
);
487 if (FileSize
.u
.LowPart
== 0)
489 UnmapViewOfFile(pHeader
);
490 return HRESULT_FROM_WIN32(GetLastError());
492 dwEntries
= (DWORD
)((FileSize
.QuadPart
- sizeof(INFO2_HEADER
)) / sizeof(DELETED_FILE_RECORD
));
494 pRecord
= (DELETED_FILE_RECORD
*)(pHeader
+ 1);
495 for (i
= 0; i
< dwEntries
; i
++)
497 if (pRecord
->dwRecordUniqueId
== pDeletedFile
->dwRecordUniqueId
)
500 ZeroMemory(&op
, sizeof(op
));
502 op
.pFrom
= pDeletedFileName
;
503 op
.pTo
= pDeletedFile
->FileNameW
;
505 if (!SHFileOperationW(&op
))
507 UnmapViewOfFile(pHeader
);
508 return HRESULT_FROM_WIN32(GetLastError());
511 /* Clear last entry in the file */
512 MoveMemory(pRecord
, pRecord
+ 1, (dwEntries
- i
- 1) * sizeof(DELETED_FILE_RECORD
));
513 pLast
= pRecord
+ (dwEntries
- i
- 1);
514 ZeroMemory(pLast
, sizeof(DELETED_FILE_RECORD
));
515 UnmapViewOfFile(pHeader
);
518 CloseHandle(s
->hInfoMapped
);
519 SetFilePointer(s
->hInfo
, -(LONG
)sizeof(DELETED_FILE_RECORD
), NULL
, FILE_END
);
520 SetEndOfFile(s
->hInfo
);
521 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
523 return HRESULT_FROM_WIN32(GetLastError());
529 UnmapViewOfFile(pHeader
);
530 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
533 static HRESULT STDMETHODCALLTYPE
534 RecycleBin5_RecycleBin5_OnClosing(
535 IN IRecycleBin5
*This
,
536 IN IRecycleBinEnumList
*prbel
)
538 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
539 TRACE("(%p, %p)\n", This
, prbel
);
540 s
->EnumeratorCount
--;
544 CONST_VTBL
struct IRecycleBin5Vtbl RecycleBin5Vtbl
=
546 RecycleBin5_RecycleBin5_QueryInterface
,
547 RecycleBin5_RecycleBin5_AddRef
,
548 RecycleBin5_RecycleBin5_Release
,
549 RecycleBin5_RecycleBin5_DeleteFile
,
550 RecycleBin5_RecycleBin5_EmptyRecycleBin
,
551 RecycleBin5_RecycleBin5_EnumObjects
,
552 RecycleBin5_RecycleBin5_Delete
,
553 RecycleBin5_RecycleBin5_Restore
,
554 RecycleBin5_RecycleBin5_OnClosing
,
560 IN PSID OwnerSid OPTIONAL
)
562 LPWSTR BufferName
= NULL
;
563 LPWSTR Separator
; /* Pointer into BufferName buffer */
564 LPWSTR FileName
; /* Pointer into BufferName buffer */
565 LPCSTR DesktopIniContents
= "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
566 INFO2_HEADER Info2Contents
[] = { { 5, 0, 0, 0x320, 0 } };
567 DWORD BytesToWrite
, BytesWritten
, Needed
;
568 HANDLE hFile
= INVALID_HANDLE_VALUE
;
571 Needed
= (wcslen(Folder
) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME
), wcslen(L
"desktop.ini")) + 1) * sizeof(WCHAR
);
572 BufferName
= HeapAlloc(GetProcessHeap(), 0, Needed
);
575 hr
= ERROR_NOT_ENOUGH_MEMORY
;
579 wcscpy(BufferName
, Folder
);
580 Separator
= wcsstr(&BufferName
[3], L
"\\");
582 *Separator
= UNICODE_NULL
;
583 if (!CreateDirectoryW(BufferName
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
585 hr
= HRESULT_FROM_WIN32(GetLastError());
588 SetFileAttributesW(BufferName
, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
);
592 if (!CreateDirectoryW(BufferName
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
594 hr
= HRESULT_FROM_WIN32(GetLastError());
603 /* Add ACL to allow only user/SYSTEM to open it */
604 /* FIXME: rc = SetNamedSecurityInfo(
612 if (rc != ERROR_SUCCESS)
614 hr = HRESULT_FROM_WIN32(rc);
620 wcscat(BufferName
, L
"\\");
621 FileName
= &BufferName
[wcslen(BufferName
)];
623 /* Create desktop.ini */
624 wcscpy(FileName
, L
"desktop.ini");
625 hFile
= CreateFileW(BufferName
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
, NULL
);
626 if (hFile
== INVALID_HANDLE_VALUE
)
628 hr
= HRESULT_FROM_WIN32(GetLastError());
631 BytesToWrite
= strlen(DesktopIniContents
);
632 if (!WriteFile(hFile
, DesktopIniContents
, (DWORD
)BytesToWrite
, &BytesWritten
, NULL
))
634 hr
= HRESULT_FROM_WIN32(GetLastError());
637 if (BytesWritten
!= BytesToWrite
)
643 hFile
= INVALID_HANDLE_VALUE
;
645 /* Create empty INFO2 file */
646 wcscpy(FileName
, RECYCLE_BIN_FILE_NAME
);
647 hFile
= CreateFileW(BufferName
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_HIDDEN
, NULL
);
648 if (hFile
== INVALID_HANDLE_VALUE
)
650 hr
= HRESULT_FROM_WIN32(GetLastError());
653 BytesToWrite
= sizeof(Info2Contents
);
654 if (!WriteFile(hFile
, Info2Contents
, (DWORD
)BytesToWrite
, &BytesWritten
, NULL
))
656 hr
= HRESULT_FROM_WIN32(GetLastError());
659 if (BytesWritten
== BytesToWrite
)
665 HeapFree(GetProcessHeap(), 0, BufferName
);
666 if (hFile
!= INVALID_HANDLE_VALUE
)
671 HRESULT
RecycleBin5_Constructor(IN LPCWSTR VolumePath
, OUT IUnknown
**ppUnknown
)
673 struct RecycleBin5
*s
= NULL
;
674 DWORD FileSystemFlags
;
675 LPCWSTR RecycleBinDirectory
;
676 HANDLE tokenHandle
= INVALID_HANDLE_VALUE
;
677 PTOKEN_USER TokenUserInfo
= NULL
;
678 LPWSTR StringSid
= NULL
, p
;
679 DWORD Needed
, DirectoryLength
;
686 /* Get information about file system */
687 if (!GetVolumeInformationW(
697 hr
= HRESULT_FROM_WIN32(GetLastError());
700 if (!(FileSystemFlags
& FILE_PERSISTENT_ACLS
))
701 RecycleBinDirectory
= RECYCLE_BIN_DIRECTORY_WITHOUT_ACL
;
704 RecycleBinDirectory
= RECYCLE_BIN_DIRECTORY_WITH_ACL
;
707 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &tokenHandle
))
709 hr
= HRESULT_FROM_WIN32(GetLastError());
712 if (GetTokenInformation(tokenHandle
, TokenUser
, NULL
, 0, &Needed
))
717 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
719 hr
= HRESULT_FROM_WIN32(GetLastError());
722 TokenUserInfo
= HeapAlloc(GetProcessHeap(), 0, Needed
);
728 if (!GetTokenInformation(tokenHandle
, TokenUser
, TokenUserInfo
, (DWORD
)Needed
, &Needed
))
730 hr
= HRESULT_FROM_WIN32(GetLastError());
733 if (!ConvertSidToStringSidW(TokenUserInfo
->User
.Sid
, &StringSid
))
735 hr
= HRESULT_FROM_WIN32(GetLastError());
740 DirectoryLength
= wcslen(VolumePath
) + wcslen(RecycleBinDirectory
) + 1;
742 DirectoryLength
+= wcslen(StringSid
) + 1;
743 DirectoryLength
+= 1 + wcslen(RECYCLE_BIN_FILE_NAME
);
744 DirectoryLength
+= wcslen(VolumePath
) + 1;
745 Needed
= (DirectoryLength
+ 1) * sizeof(WCHAR
);
747 s
= CoTaskMemAlloc(sizeof(struct RecycleBin5
) + Needed
);
753 ZeroMemory(s
, sizeof(struct RecycleBin5
));
754 s
->recycleBinImpl
.lpVtbl
= &RecycleBin5Vtbl
;
757 len
= swprintf(s
->Folder
, L
"%s%s\\%s", VolumePath
, RecycleBinDirectory
, StringSid
);
759 len
= swprintf(s
->Folder
, L
"%s%s", VolumePath
, RecycleBinDirectory
);
761 wcscpy(p
, L
"\\" RECYCLE_BIN_FILE_NAME
);
762 s
->hInfo
= CreateFileW(s
->Folder
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
763 if (s
->hInfo
== INVALID_HANDLE_VALUE
&& (GetLastError() == ERROR_PATH_NOT_FOUND
|| GetLastError() == ERROR_FILE_NOT_FOUND
))
766 hr
= RecycleBin5_Create(s
->Folder
, TokenUserInfo
? TokenUserInfo
->User
.Sid
: NULL
);
770 s
->hInfo
= CreateFileW(s
->Folder
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
772 if (s
->hInfo
== INVALID_HANDLE_VALUE
)
774 hr
= HRESULT_FROM_WIN32(GetLastError());
777 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
780 hr
= HRESULT_FROM_WIN32(GetLastError());
784 s
->VolumePath
= p
+ 1;
785 wcscpy(s
->VolumePath
, VolumePath
);
787 *ppUnknown
= (IUnknown
*)&s
->recycleBinImpl
;
792 if (tokenHandle
!= INVALID_HANDLE_VALUE
)
793 CloseHandle(tokenHandle
);
794 HeapFree(GetProcessHeap(), 0, TokenUserInfo
);
796 LocalFree(StringSid
);
800 RecycleBin5_Destructor(s
);