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)
9 #include "recyclebin_private.h"
17 DWORD RemovableAttributes
= FILE_ATTRIBUTE_READONLY
;
18 WIN32_FIND_DATAW FindData
;
19 HANDLE hSearch
= INVALID_HANDLE_VALUE
;
20 LPWSTR FullPath
= NULL
, pFilePart
;
25 FileAttributes
= GetFileAttributesW(FullName
);
26 if (FileAttributes
== INVALID_FILE_ATTRIBUTES
)
28 if (GetLastError() == ERROR_FILE_NOT_FOUND
)
32 if (FileAttributes
& RemovableAttributes
)
34 if (!SetFileAttributesW(FullName
, FileAttributes
& ~RemovableAttributes
))
37 if (FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
39 /* Prepare file specification */
40 dwLength
= wcslen(FullName
);
41 FullPath
= HeapAlloc(GetProcessHeap(), 0, (dwLength
+ 1 + MAX_PATH
+ 1) * sizeof(WCHAR
));
44 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
47 wcscpy(FullPath
, FullName
);
48 if (FullPath
[dwLength
- 1] != '\\')
50 FullPath
[dwLength
] = '\\';
53 pFilePart
= &FullPath
[dwLength
];
54 wcscpy(pFilePart
, L
"*");
56 /* Enumerate contents, and delete it */
57 hSearch
= FindFirstFileW(FullPath
, &FindData
);
58 if (hSearch
== INVALID_HANDLE_VALUE
)
62 if (!(FindData
.cFileName
[0] == '.' &&
63 (FindData
.cFileName
[1] == '\0' || (FindData
.cFileName
[1] == '.' && FindData
.cFileName
[2] == '\0'))))
65 wcscpy(pFilePart
, FindData
.cFileName
);
66 if (!IntDeleteRecursive(FullPath
))
73 while (FindNextFileW(hSearch
, &FindData
));
75 if (GetLastError() != ERROR_NO_MORE_FILES
)
78 /* Remove (now empty) directory */
79 if (!RemoveDirectoryW(FullName
))
84 if (!DeleteFileW(FullName
))
90 HeapFree(GetProcessHeap(), 0, FullPath
);
97 IRecycleBin5 recycleBinImpl
;
101 DWORD EnumeratorCount
;
104 WCHAR Folder
[ANY_SIZE
]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */
107 static HRESULT STDMETHODCALLTYPE
108 RecycleBin5_RecycleBin5_QueryInterface(
113 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
115 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
120 if (IsEqualIID(riid
, &IID_IUnknown
))
121 *ppvObject
= &s
->recycleBinImpl
;
122 else if (IsEqualIID(riid
, &IID_IRecycleBin
))
123 *ppvObject
= &s
->recycleBinImpl
;
124 else if (IsEqualIID(riid
, &IID_IRecycleBin5
))
125 *ppvObject
= &s
->recycleBinImpl
;
129 return E_NOINTERFACE
;
132 IUnknown_AddRef(This
);
136 static ULONG STDMETHODCALLTYPE
137 RecycleBin5_RecycleBin5_AddRef(
140 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
141 ULONG refCount
= InterlockedIncrement((PLONG
)&s
->ref
);
142 TRACE("(%p)\n", This
);
147 RecycleBin5_Destructor(
148 struct RecycleBin5
*s
)
152 if (s
->hInfo
&& s
->hInfo
!= INVALID_HANDLE_VALUE
)
153 CloseHandle(s
->hInfo
);
155 CloseHandle(s
->hInfoMapped
);
159 static ULONG STDMETHODCALLTYPE
160 RecycleBin5_RecycleBin5_Release(
163 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
166 TRACE("(%p)\n", This
);
168 refCount
= InterlockedDecrement((PLONG
)&s
->ref
);
171 RecycleBin5_Destructor(s
);
176 static HRESULT STDMETHODCALLTYPE
177 RecycleBin5_RecycleBin5_DeleteFile(
178 IN IRecycleBin5
*This
,
179 IN LPCWSTR szFileName
)
181 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
182 LPWSTR szFullName
= NULL
;
183 DWORD dwBufferLength
= 0;
186 WCHAR DeletedFileName
[MAX_PATH
];
188 HANDLE hFile
= INVALID_HANDLE_VALUE
;
189 PINFO2_HEADER pHeader
= NULL
;
190 PDELETED_FILE_RECORD pDeletedFile
;
191 ULARGE_INTEGER FileSize
;
192 DWORD dwAttributes
, dwEntries
;
193 SYSTEMTIME SystemTime
;
194 DWORD ClusterSize
, BytesPerSector
, SectorsPerCluster
;
197 TRACE("(%p, %s)\n", This
, debugstr_w(szFileName
));
199 if (s
->EnumeratorCount
!= 0)
200 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION
);
202 /* Get full file name */
205 len
= GetFullPathNameW(szFileName
, dwBufferLength
, szFullName
, &lpFilePart
);
209 CoTaskMemFree(szFullName
);
210 return HRESULT_FROM_WIN32(GetLastError());
212 else if (len
< dwBufferLength
)
215 CoTaskMemFree(szFullName
);
216 dwBufferLength
= len
;
217 szFullName
= CoTaskMemAlloc(dwBufferLength
* sizeof(WCHAR
));
219 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY
);
222 /* Check if file exists */
223 dwAttributes
= GetFileAttributesW(szFullName
);
224 if (dwAttributes
== INVALID_FILE_ATTRIBUTES
)
225 return HRESULT_FROM_WIN32(GetLastError());
227 if (dwBufferLength
< 2 || szFullName
[1] != ':')
229 /* Not a local file */
230 CoTaskMemFree(szFullName
);
231 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
234 hFile
= CreateFileW(szFullName
, 0, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
235 if (hFile
== INVALID_HANDLE_VALUE
)
237 hr
= HRESULT_FROM_WIN32(GetLastError());
241 /* Increase INFO2 file size */
242 CloseHandle(s
->hInfoMapped
);
243 SetFilePointer(s
->hInfo
, sizeof(DELETED_FILE_RECORD
), NULL
, FILE_END
);
244 SetEndOfFile(s
->hInfo
);
245 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
248 hr
= HRESULT_FROM_WIN32(GetLastError());
252 /* Open INFO2 file */
253 pHeader
= MapViewOfFile(s
->hInfoMapped
, FILE_MAP_WRITE
, 0, 0, 0);
256 hr
= HRESULT_FROM_WIN32(GetLastError());
260 /* Get number of entries */
261 FileSize
.u
.LowPart
= GetFileSize(s
->hInfo
, &FileSize
.u
.HighPart
);
262 if (FileSize
.u
.LowPart
< sizeof(INFO2_HEADER
))
264 UnmapViewOfFile(pHeader
);
265 return HRESULT_FROM_WIN32(GetLastError());
267 dwEntries
= (DWORD
)((FileSize
.QuadPart
- sizeof(INFO2_HEADER
)) / sizeof(DELETED_FILE_RECORD
)) - 1;
268 pDeletedFile
= ((PDELETED_FILE_RECORD
)(pHeader
+ 1)) + dwEntries
;
272 if (!GetFileSizeEx(hFile
, (PLARGE_INTEGER
)&FileSize
))
274 hr
= HRESULT_FROM_WIN32(GetLastError());
278 FileSize
.u
.LowPart
= GetFileSize(hFile
, &FileSize
.u
.HighPart
);
279 if (FileSize
.u
.LowPart
== INVALID_FILE_SIZE
&& GetLastError() != NO_ERROR
)
281 hr
= HRESULT_FROM_WIN32(GetLastError());
285 /* Check if file size is > 4Gb */
286 if (FileSize
.u
.HighPart
!= 0)
288 /* Yes, this recyclebin can't support this file */
289 hr
= HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED
);
292 pHeader
->dwTotalLogicalSize
+= FileSize
.u
.LowPart
;
294 /* Generate new name */
295 Extension
= wcsrchr(szFullName
, '.');
296 ZeroMemory(pDeletedFile
, sizeof(DELETED_FILE_RECORD
));
298 pDeletedFile
->dwRecordUniqueId
= 0;
301 PDELETED_FILE_RECORD pLastDeleted
= ((PDELETED_FILE_RECORD
)(pHeader
+ 1)) + dwEntries
- 1;
302 pDeletedFile
->dwRecordUniqueId
= pLastDeleted
->dwRecordUniqueId
+ 1;
304 pDeletedFile
->dwDriveNumber
= tolower(szFullName
[0]) - 'a';
305 _snwprintf(DeletedFileName
, MAX_PATH
, L
"%s\\D%c%lu%s", s
->Folder
, pDeletedFile
->dwDriveNumber
+ 'a', pDeletedFile
->dwRecordUniqueId
, Extension
);
307 /* Get cluster size */
308 if (!GetDiskFreeSpaceW(s
->VolumePath
, &SectorsPerCluster
, &BytesPerSector
, NULL
, NULL
))
310 hr
= HRESULT_FROM_WIN32(GetLastError());
313 ClusterSize
= BytesPerSector
* SectorsPerCluster
;
315 /* Get current time */
316 GetSystemTime(&SystemTime
);
317 if (!SystemTimeToFileTime(&SystemTime
, &pDeletedFile
->DeletionTime
))
319 hr
= HRESULT_FROM_WIN32(GetLastError());
322 pDeletedFile
->dwPhysicalFileSize
= ROUND_UP(FileSize
.u
.LowPart
, ClusterSize
);
325 wcscpy(pDeletedFile
->FileNameW
, szFullName
);
326 if (WideCharToMultiByte(CP_ACP
, 0, pDeletedFile
->FileNameW
, -1, pDeletedFile
->FileNameA
, MAX_PATH
, NULL
, NULL
) == 0)
328 hr
= HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
329 SetLastError(ERROR_INVALID_NAME
);
334 if (MoveFileW(szFullName
, DeletedFileName
))
337 hr
= HRESULT_FROM_WIN32(GetLastError());
341 UnmapViewOfFile(pHeader
);
342 if (hFile
!= INVALID_HANDLE_VALUE
)
344 CoTaskMemFree(szFullName
);
348 static HRESULT STDMETHODCALLTYPE
349 RecycleBin5_RecycleBin5_EmptyRecycleBin(
350 IN IRecycleBin5
*This
)
352 IRecycleBinEnumList
*prbel
;
353 IRecycleBinFile
*prbf
;
356 TRACE("(%p)\n", This
);
360 hr
= IRecycleBin5_EnumObjects(This
, &prbel
);
363 hr
= IRecycleBinEnumList_Next(prbel
, 1, &prbf
, NULL
);
364 IRecycleBinEnumList_Release(prbel
);
367 hr
= IRecycleBinFile_Delete(prbf
);
368 IRecycleBinFile_Release(prbf
);
374 static HRESULT STDMETHODCALLTYPE
375 RecycleBin5_RecycleBin5_EnumObjects(
376 IN IRecycleBin5
*This
,
377 OUT IRecycleBinEnumList
**ppEnumList
)
379 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
380 IRecycleBinEnumList
*prbel
;
384 TRACE("(%p, %p)\n", This
, ppEnumList
);
386 hr
= RecycleBin5Enum_Constructor(This
, s
->hInfo
, s
->hInfoMapped
, s
->Folder
, &pUnk
);
390 hr
= IUnknown_QueryInterface(pUnk
, &IID_IRecycleBinEnumList
, (void **)&prbel
);
393 s
->EnumeratorCount
++;
396 IUnknown_Release(pUnk
);
400 static HRESULT STDMETHODCALLTYPE
401 RecycleBin5_RecycleBin5_Delete(
402 IN IRecycleBin5
*This
,
403 IN LPCWSTR pDeletedFileName
,
404 IN DELETED_FILE_RECORD
*pDeletedFile
)
406 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
407 ULARGE_INTEGER FileSize
;
408 PINFO2_HEADER pHeader
;
409 DELETED_FILE_RECORD
*pRecord
, *pLast
;
412 TRACE("(%p, %s, %p)\n", This
, debugstr_w(pDeletedFileName
), pDeletedFile
);
414 if (s
->EnumeratorCount
!= 0)
415 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION
);
417 pHeader
= MapViewOfFile(s
->hInfoMapped
, FILE_MAP_WRITE
, 0, 0, 0);
419 return HRESULT_FROM_WIN32(GetLastError());
421 FileSize
.u
.LowPart
= GetFileSize(s
->hInfo
, &FileSize
.u
.HighPart
);
422 if (FileSize
.u
.LowPart
== 0)
424 UnmapViewOfFile(pHeader
);
425 return HRESULT_FROM_WIN32(GetLastError());
427 dwEntries
= (DWORD
)((FileSize
.QuadPart
- sizeof(INFO2_HEADER
)) / sizeof(DELETED_FILE_RECORD
));
429 pRecord
= (DELETED_FILE_RECORD
*)(pHeader
+ 1);
430 for (i
= 0; i
< dwEntries
; i
++)
432 if (pRecord
->dwRecordUniqueId
== pDeletedFile
->dwRecordUniqueId
)
435 if (!IntDeleteRecursive(pDeletedFileName
))
437 UnmapViewOfFile(pHeader
);
438 return HRESULT_FROM_WIN32(GetLastError());
441 /* Clear last entry in the file */
442 MoveMemory(pRecord
, pRecord
+ 1, (dwEntries
- i
- 1) * sizeof(DELETED_FILE_RECORD
));
443 pLast
= pRecord
+ (dwEntries
- i
- 1);
444 ZeroMemory(pLast
, sizeof(DELETED_FILE_RECORD
));
445 UnmapViewOfFile(pHeader
);
448 CloseHandle(s
->hInfoMapped
);
449 SetFilePointer(s
->hInfo
, -(LONG
)sizeof(DELETED_FILE_RECORD
), NULL
, FILE_END
);
450 SetEndOfFile(s
->hInfo
);
451 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
453 return HRESULT_FROM_WIN32(GetLastError());
458 UnmapViewOfFile(pHeader
);
459 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
462 static HRESULT STDMETHODCALLTYPE
463 RecycleBin5_RecycleBin5_Restore(
464 IN IRecycleBin5
*This
,
465 IN LPCWSTR pDeletedFileName
,
466 IN DELETED_FILE_RECORD
*pDeletedFile
)
468 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
469 ULARGE_INTEGER FileSize
;
470 PINFO2_HEADER pHeader
;
471 DELETED_FILE_RECORD
*pRecord
, *pLast
;
475 TRACE("(%p, %s, %p)\n", This
, debugstr_w(pDeletedFileName
), pDeletedFile
);
477 if (s
->EnumeratorCount
!= 0)
478 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION
);
480 pHeader
= MapViewOfFile(s
->hInfoMapped
, FILE_MAP_WRITE
, 0, 0, 0);
482 return HRESULT_FROM_WIN32(GetLastError());
484 FileSize
.u
.LowPart
= GetFileSize(s
->hInfo
, &FileSize
.u
.HighPart
);
485 if (FileSize
.u
.LowPart
== 0)
487 UnmapViewOfFile(pHeader
);
488 return HRESULT_FROM_WIN32(GetLastError());
490 dwEntries
= (DWORD
)((FileSize
.QuadPart
- sizeof(INFO2_HEADER
)) / sizeof(DELETED_FILE_RECORD
));
492 pRecord
= (DELETED_FILE_RECORD
*)(pHeader
+ 1);
493 for (i
= 0; i
< dwEntries
; i
++)
495 if (pRecord
->dwRecordUniqueId
== pDeletedFile
->dwRecordUniqueId
)
498 ZeroMemory(&op
, sizeof(op
));
500 op
.pFrom
= pDeletedFileName
;
501 op
.pTo
= pDeletedFile
->FileNameW
;
503 if (!SHFileOperationW(&op
))
505 UnmapViewOfFile(pHeader
);
506 return HRESULT_FROM_WIN32(GetLastError());
509 /* Clear last entry in the file */
510 MoveMemory(pRecord
, pRecord
+ 1, (dwEntries
- i
- 1) * sizeof(DELETED_FILE_RECORD
));
511 pLast
= pRecord
+ (dwEntries
- i
- 1);
512 ZeroMemory(pLast
, sizeof(DELETED_FILE_RECORD
));
513 UnmapViewOfFile(pHeader
);
516 CloseHandle(s
->hInfoMapped
);
517 SetFilePointer(s
->hInfo
, -(LONG
)sizeof(DELETED_FILE_RECORD
), NULL
, FILE_END
);
518 SetEndOfFile(s
->hInfo
);
519 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
521 return HRESULT_FROM_WIN32(GetLastError());
527 UnmapViewOfFile(pHeader
);
528 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
531 static HRESULT STDMETHODCALLTYPE
532 RecycleBin5_RecycleBin5_OnClosing(
533 IN IRecycleBin5
*This
,
534 IN IRecycleBinEnumList
*prbel
)
536 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
537 TRACE("(%p, %p)\n", This
, prbel
);
538 s
->EnumeratorCount
--;
542 CONST_VTBL
struct IRecycleBin5Vtbl RecycleBin5Vtbl
=
544 RecycleBin5_RecycleBin5_QueryInterface
,
545 RecycleBin5_RecycleBin5_AddRef
,
546 RecycleBin5_RecycleBin5_Release
,
547 RecycleBin5_RecycleBin5_DeleteFile
,
548 RecycleBin5_RecycleBin5_EmptyRecycleBin
,
549 RecycleBin5_RecycleBin5_EnumObjects
,
550 RecycleBin5_RecycleBin5_Delete
,
551 RecycleBin5_RecycleBin5_Restore
,
552 RecycleBin5_RecycleBin5_OnClosing
,
558 IN PSID OwnerSid OPTIONAL
)
560 LPWSTR BufferName
= NULL
;
561 LPWSTR Separator
; /* Pointer into BufferName buffer */
562 LPWSTR FileName
; /* Pointer into BufferName buffer */
563 LPCSTR DesktopIniContents
= "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
564 INFO2_HEADER Info2Contents
[] = { { 5, 0, 0, 0x320, 0 } };
565 DWORD BytesToWrite
, BytesWritten
, Needed
;
566 HANDLE hFile
= INVALID_HANDLE_VALUE
;
569 Needed
= (wcslen(Folder
) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME
), wcslen(L
"desktop.ini")) + 1) * sizeof(WCHAR
);
570 BufferName
= HeapAlloc(GetProcessHeap(), 0, Needed
);
573 hr
= ERROR_NOT_ENOUGH_MEMORY
;
577 wcscpy(BufferName
, Folder
);
578 Separator
= wcsstr(&BufferName
[3], L
"\\");
580 *Separator
= UNICODE_NULL
;
581 if (!CreateDirectoryW(BufferName
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
583 hr
= HRESULT_FROM_WIN32(GetLastError());
586 SetFileAttributesW(BufferName
, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
);
590 if (!CreateDirectoryW(BufferName
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
592 hr
= HRESULT_FROM_WIN32(GetLastError());
601 /* Add ACL to allow only user/SYSTEM to open it */
602 /* FIXME: rc = SetNamedSecurityInfo(
610 if (rc != ERROR_SUCCESS)
612 hr = HRESULT_FROM_WIN32(rc);
618 wcscat(BufferName
, L
"\\");
619 FileName
= &BufferName
[wcslen(BufferName
)];
621 /* Create desktop.ini */
622 wcscpy(FileName
, L
"desktop.ini");
623 hFile
= CreateFileW(BufferName
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
, NULL
);
624 if (hFile
== INVALID_HANDLE_VALUE
)
626 hr
= HRESULT_FROM_WIN32(GetLastError());
629 BytesToWrite
= strlen(DesktopIniContents
);
630 if (!WriteFile(hFile
, DesktopIniContents
, (DWORD
)BytesToWrite
, &BytesWritten
, NULL
))
632 hr
= HRESULT_FROM_WIN32(GetLastError());
635 if (BytesWritten
!= BytesToWrite
)
641 hFile
= INVALID_HANDLE_VALUE
;
643 /* Create empty INFO2 file */
644 wcscpy(FileName
, RECYCLE_BIN_FILE_NAME
);
645 hFile
= CreateFileW(BufferName
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_HIDDEN
, NULL
);
646 if (hFile
== INVALID_HANDLE_VALUE
)
648 hr
= HRESULT_FROM_WIN32(GetLastError());
651 BytesToWrite
= sizeof(Info2Contents
);
652 if (!WriteFile(hFile
, Info2Contents
, (DWORD
)BytesToWrite
, &BytesWritten
, NULL
))
654 hr
= HRESULT_FROM_WIN32(GetLastError());
657 if (BytesWritten
== BytesToWrite
)
663 HeapFree(GetProcessHeap(), 0, BufferName
);
664 if (hFile
!= INVALID_HANDLE_VALUE
)
669 HRESULT
RecycleBin5_Constructor(IN LPCWSTR VolumePath
, OUT IUnknown
**ppUnknown
)
671 struct RecycleBin5
*s
= NULL
;
672 DWORD FileSystemFlags
;
673 LPCWSTR RecycleBinDirectory
;
674 HANDLE tokenHandle
= INVALID_HANDLE_VALUE
;
675 PTOKEN_USER TokenUserInfo
= NULL
;
676 LPWSTR StringSid
= NULL
, p
;
677 DWORD Needed
, DirectoryLength
;
684 /* Get information about file system */
685 if (!GetVolumeInformationW(
695 hr
= HRESULT_FROM_WIN32(GetLastError());
698 if (!(FileSystemFlags
& FILE_PERSISTENT_ACLS
))
699 RecycleBinDirectory
= RECYCLE_BIN_DIRECTORY_WITHOUT_ACL
;
702 RecycleBinDirectory
= RECYCLE_BIN_DIRECTORY_WITH_ACL
;
705 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &tokenHandle
))
707 hr
= HRESULT_FROM_WIN32(GetLastError());
710 if (GetTokenInformation(tokenHandle
, TokenUser
, NULL
, 0, &Needed
))
715 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
717 hr
= HRESULT_FROM_WIN32(GetLastError());
720 TokenUserInfo
= HeapAlloc(GetProcessHeap(), 0, Needed
);
726 if (!GetTokenInformation(tokenHandle
, TokenUser
, TokenUserInfo
, (DWORD
)Needed
, &Needed
))
728 hr
= HRESULT_FROM_WIN32(GetLastError());
731 if (!ConvertSidToStringSidW(TokenUserInfo
->User
.Sid
, &StringSid
))
733 hr
= HRESULT_FROM_WIN32(GetLastError());
738 DirectoryLength
= wcslen(VolumePath
) + wcslen(RecycleBinDirectory
) + 1;
740 DirectoryLength
+= wcslen(StringSid
) + 1;
741 DirectoryLength
+= 1 + wcslen(RECYCLE_BIN_FILE_NAME
);
742 DirectoryLength
+= wcslen(VolumePath
) + 1;
743 Needed
= (DirectoryLength
+ 1) * sizeof(WCHAR
);
745 s
= CoTaskMemAlloc(sizeof(struct RecycleBin5
) + Needed
);
751 ZeroMemory(s
, sizeof(struct RecycleBin5
));
752 s
->recycleBinImpl
.lpVtbl
= &RecycleBin5Vtbl
;
755 len
= swprintf(s
->Folder
, L
"%s%s\\%s", VolumePath
, RecycleBinDirectory
, StringSid
);
757 len
= swprintf(s
->Folder
, L
"%s%s", VolumePath
, RecycleBinDirectory
);
759 wcscpy(p
, L
"\\" RECYCLE_BIN_FILE_NAME
);
760 s
->hInfo
= CreateFileW(s
->Folder
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
761 if (s
->hInfo
== INVALID_HANDLE_VALUE
&& (GetLastError() == ERROR_PATH_NOT_FOUND
|| GetLastError() == ERROR_FILE_NOT_FOUND
))
764 hr
= RecycleBin5_Create(s
->Folder
, TokenUserInfo
? TokenUserInfo
->User
.Sid
: NULL
);
768 s
->hInfo
= CreateFileW(s
->Folder
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
770 if (s
->hInfo
== INVALID_HANDLE_VALUE
)
772 hr
= HRESULT_FROM_WIN32(GetLastError());
775 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
778 hr
= HRESULT_FROM_WIN32(GetLastError());
782 s
->VolumePath
= p
+ 1;
783 wcscpy(s
->VolumePath
, VolumePath
);
785 *ppUnknown
= (IUnknown
*)&s
->recycleBinImpl
;
790 if (tokenHandle
!= INVALID_HANDLE_VALUE
)
791 CloseHandle(tokenHandle
);
792 HeapFree(GetProcessHeap(), 0, TokenUserInfo
);
794 LocalFree(StringSid
);
798 RecycleBin5_Destructor(s
);