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)
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)
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
;
476 TRACE("(%p, %s, %p)\n", This
, debugstr_w(pDeletedFileName
), pDeletedFile
);
478 if (s
->EnumeratorCount
!= 0)
481 pHeader
= MapViewOfFile(s
->hInfoMapped
, FILE_MAP_WRITE
, 0, 0, 0);
483 return HRESULT_FROM_WIN32(GetLastError());
485 FileSize
.u
.LowPart
= GetFileSize(s
->hInfo
, &FileSize
.u
.HighPart
);
486 if (FileSize
.u
.LowPart
== 0)
488 UnmapViewOfFile(pHeader
);
489 return HRESULT_FROM_WIN32(GetLastError());
491 dwEntries
= (DWORD
)((FileSize
.QuadPart
- sizeof(INFO2_HEADER
)) / sizeof(DELETED_FILE_RECORD
));
493 pRecord
= (DELETED_FILE_RECORD
*)(pHeader
+ 1);
494 for (i
= 0; i
< dwEntries
; i
++)
496 if (pRecord
->dwRecordUniqueId
== pDeletedFile
->dwRecordUniqueId
)
499 if (!MoveFileW(pDeletedFileName
, pDeletedFile
->FileNameW
))
501 UnmapViewOfFile(pHeader
);
502 return HRESULT_FROM_WIN32(GetLastError());
505 /* Clear last entry in the file */
506 MoveMemory(pRecord
, pRecord
+ 1, (dwEntries
- i
- 1) * sizeof(DELETED_FILE_RECORD
));
507 pLast
= pRecord
+ (dwEntries
- i
- 1);
508 ZeroMemory(pLast
, sizeof(DELETED_FILE_RECORD
));
509 UnmapViewOfFile(pHeader
);
512 CloseHandle(s
->hInfoMapped
);
513 SetFilePointer(s
->hInfo
, -(LONG
)sizeof(DELETED_FILE_RECORD
), NULL
, FILE_END
);
514 SetEndOfFile(s
->hInfo
);
515 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
517 return HRESULT_FROM_WIN32(GetLastError());
523 UnmapViewOfFile(pHeader
);
524 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
527 static HRESULT STDMETHODCALLTYPE
528 RecycleBin5_RecycleBin5_OnClosing(
529 IN IRecycleBin5
*This
,
530 IN IRecycleBinEnumList
*prbel
)
532 struct RecycleBin5
*s
= CONTAINING_RECORD(This
, struct RecycleBin5
, recycleBinImpl
);
533 TRACE("(%p, %p)\n", This
, prbel
);
534 s
->EnumeratorCount
--;
538 CONST_VTBL
struct IRecycleBin5Vtbl RecycleBin5Vtbl
=
540 RecycleBin5_RecycleBin5_QueryInterface
,
541 RecycleBin5_RecycleBin5_AddRef
,
542 RecycleBin5_RecycleBin5_Release
,
543 RecycleBin5_RecycleBin5_DeleteFile
,
544 RecycleBin5_RecycleBin5_EmptyRecycleBin
,
545 RecycleBin5_RecycleBin5_EnumObjects
,
546 RecycleBin5_RecycleBin5_Delete
,
547 RecycleBin5_RecycleBin5_Restore
,
548 RecycleBin5_RecycleBin5_OnClosing
,
554 IN PSID OwnerSid OPTIONAL
)
556 LPWSTR BufferName
= NULL
;
557 LPWSTR Separator
; /* Pointer into BufferName buffer */
558 LPWSTR FileName
; /* Pointer into BufferName buffer */
559 LPCSTR DesktopIniContents
= "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
560 INFO2_HEADER Info2Contents
[] = { { 5, 0, 0, 0x320, 0 } };
561 SIZE_T BytesToWrite
, BytesWritten
, Needed
;
562 HANDLE hFile
= INVALID_HANDLE_VALUE
;
565 Needed
= (wcslen(Folder
) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME
), wcslen(L
"desktop.ini")) + 1) * sizeof(WCHAR
);
566 BufferName
= HeapAlloc(GetProcessHeap(), 0, Needed
);
569 hr
= ERROR_NOT_ENOUGH_MEMORY
;
573 wcscpy(BufferName
, Folder
);
574 Separator
= wcsstr(&BufferName
[3], L
"\\");
576 *Separator
= UNICODE_NULL
;
577 if (!CreateDirectoryW(BufferName
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
579 hr
= HRESULT_FROM_WIN32(GetLastError());
582 SetFileAttributesW(BufferName
, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
);
586 if (!CreateDirectoryW(BufferName
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
588 hr
= HRESULT_FROM_WIN32(GetLastError());
597 /* Add ACL to allow only user/SYSTEM to open it */
598 /* FIXME: rc = SetNamedSecurityInfo(
606 if (rc != ERROR_SUCCESS)
608 hr = HRESULT_FROM_WIN32(rc);
614 wcscat(BufferName
, L
"\\");
615 FileName
= &BufferName
[wcslen(BufferName
)];
617 /* Create desktop.ini */
618 wcscpy(FileName
, L
"desktop.ini");
619 hFile
= CreateFileW(BufferName
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
, NULL
);
620 if (hFile
== INVALID_HANDLE_VALUE
)
622 hr
= HRESULT_FROM_WIN32(GetLastError());
625 BytesToWrite
= strlen(DesktopIniContents
);
626 if (!WriteFile(hFile
, DesktopIniContents
, (DWORD
)BytesToWrite
, &BytesWritten
, NULL
))
628 hr
= HRESULT_FROM_WIN32(GetLastError());
631 if (BytesWritten
!= BytesToWrite
)
637 hFile
= INVALID_HANDLE_VALUE
;
639 /* Create empty INFO2 file */
640 wcscpy(FileName
, RECYCLE_BIN_FILE_NAME
);
641 hFile
= CreateFileW(BufferName
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_HIDDEN
, NULL
);
642 if (hFile
== INVALID_HANDLE_VALUE
)
644 hr
= HRESULT_FROM_WIN32(GetLastError());
647 BytesToWrite
= sizeof(Info2Contents
);
648 if (!WriteFile(hFile
, Info2Contents
, (DWORD
)BytesToWrite
, &BytesWritten
, NULL
))
650 hr
= HRESULT_FROM_WIN32(GetLastError());
653 if (BytesWritten
== BytesToWrite
)
659 HeapFree(GetProcessHeap(), 0, BufferName
);
660 if (hFile
!= INVALID_HANDLE_VALUE
)
665 HRESULT
RecycleBin5_Constructor(IN LPCWSTR VolumePath
, OUT IUnknown
**ppUnknown
)
667 struct RecycleBin5
*s
= NULL
;
668 DWORD FileSystemFlags
;
669 LPCWSTR RecycleBinDirectory
;
670 HANDLE tokenHandle
= INVALID_HANDLE_VALUE
;
671 PTOKEN_USER TokenUserInfo
= NULL
;
672 LPWSTR StringSid
= NULL
, p
;
673 SIZE_T Needed
, DirectoryLength
;
680 /* Get information about file system */
681 if (!GetVolumeInformationW(
691 hr
= HRESULT_FROM_WIN32(GetLastError());
694 if (!(FileSystemFlags
& FILE_PERSISTENT_ACLS
))
695 RecycleBinDirectory
= RECYCLE_BIN_DIRECTORY_WITHOUT_ACL
;
698 RecycleBinDirectory
= RECYCLE_BIN_DIRECTORY_WITH_ACL
;
701 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &tokenHandle
))
703 hr
= HRESULT_FROM_WIN32(GetLastError());
706 if (GetTokenInformation(tokenHandle
, TokenUser
, NULL
, 0, &Needed
))
711 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
713 hr
= HRESULT_FROM_WIN32(GetLastError());
716 TokenUserInfo
= HeapAlloc(GetProcessHeap(), 0, Needed
);
722 if (!GetTokenInformation(tokenHandle
, TokenUser
, TokenUserInfo
, (DWORD
)Needed
, &Needed
))
724 hr
= HRESULT_FROM_WIN32(GetLastError());
727 if (!ConvertSidToStringSidW(TokenUserInfo
->User
.Sid
, &StringSid
))
729 hr
= HRESULT_FROM_WIN32(GetLastError());
734 DirectoryLength
= wcslen(VolumePath
) + wcslen(RecycleBinDirectory
) + 1;
736 DirectoryLength
+= wcslen(StringSid
) + 1;
737 DirectoryLength
+= 1 + wcslen(RECYCLE_BIN_FILE_NAME
);
738 DirectoryLength
+= wcslen(VolumePath
) + 1;
739 Needed
= (DirectoryLength
+ 1) * sizeof(WCHAR
);
741 s
= CoTaskMemAlloc(sizeof(struct RecycleBin5
) + Needed
);
747 ZeroMemory(s
, sizeof(struct RecycleBin5
));
748 s
->recycleBinImpl
.lpVtbl
= &RecycleBin5Vtbl
;
751 len
= swprintf(s
->Folder
, L
"%s%s\\%s", VolumePath
, RecycleBinDirectory
, StringSid
);
753 len
= swprintf(s
->Folder
, L
"%s%s", VolumePath
, RecycleBinDirectory
);
755 wcscpy(p
, L
"\\" RECYCLE_BIN_FILE_NAME
);
756 s
->hInfo
= CreateFileW(s
->Folder
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
757 if (s
->hInfo
== INVALID_HANDLE_VALUE
&& (GetLastError() == ERROR_PATH_NOT_FOUND
|| GetLastError() == ERROR_FILE_NOT_FOUND
))
760 hr
= RecycleBin5_Create(s
->Folder
, TokenUserInfo
? TokenUserInfo
->User
.Sid
: NULL
);
764 s
->hInfo
= CreateFileW(s
->Folder
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
766 if (s
->hInfo
== INVALID_HANDLE_VALUE
)
768 hr
= HRESULT_FROM_WIN32(GetLastError());
771 s
->hInfoMapped
= CreateFileMappingW(s
->hInfo
, NULL
, PAGE_READWRITE
| SEC_COMMIT
, 0, 0, NULL
);
774 hr
= HRESULT_FROM_WIN32(GetLastError());
778 s
->VolumePath
= p
+ 1;
779 wcscpy(s
->VolumePath
, VolumePath
);
781 *ppUnknown
= (IUnknown
*)&s
->recycleBinImpl
;
786 if (tokenHandle
!= INVALID_HANDLE_VALUE
)
787 CloseHandle(tokenHandle
);
788 HeapFree(GetProcessHeap(), 0, TokenUserInfo
);
790 LocalFree(StringSid
);
794 RecycleBin5_Destructor(s
);