2 * PROJECT: Recycle bin management
3 * LICENSE: GPL v2 - See COPYING in the top level directory
4 * FILE: lib/recyclebin/openclose.c
5 * PURPOSE: Open/close recycle bins
6 * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
9 #include "recyclebin_private.h"
12 IntCheckDeletedFileHandle(
13 IN HANDLE hDeletedFile
)
15 if (hDeletedFile
== NULL
|| hDeletedFile
== INVALID_HANDLE_VALUE
)
18 if (((PDELETED_FILE_HANDLE
)hDeletedFile
)->magic
!= DELETEDFILE_MAGIC
)
25 IntCloseRecycleBinHandle(
26 IN PREFCOUNT_DATA pData
)
30 bin
= CONTAINING_RECORD(pData
, RECYCLE_BIN
, refCount
);
31 if (!CloseHandle(bin
->hInfo
))
34 RemoveEntryList(&bin
->ListEntry
);
35 HeapFree(GetProcessHeap(), 0, bin
);
40 IntCreateEmptyRecycleBin(
42 IN PSID OwnerSid OPTIONAL
)
44 LPWSTR BufferName
= NULL
;
45 LPWSTR Separator
; /* Pointer into BufferName buffer */
46 LPWSTR FileName
; /* Pointer into BufferName buffer */
47 LPCSTR DesktopIniContents
= "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
48 DWORD Info2Contents
[] = { 5, 0, 0, 0x320, 0 };
49 SIZE_T BytesToWrite
, BytesWritten
, Needed
;
50 HANDLE hFile
= INVALID_HANDLE_VALUE
;
53 Needed
= (wcslen(bin
->Folder
) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME
), wcslen(L
"desktop.ini")) + 1) * sizeof(WCHAR
);
54 BufferName
= HeapAlloc(GetProcessHeap(), 0, Needed
);
57 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
61 wcscpy(BufferName
, bin
->Folder
);
62 Separator
= wcsstr(&BufferName
[3], L
"\\");
64 *Separator
= UNICODE_NULL
;
65 ret
= CreateDirectoryW(BufferName
, NULL
);
66 if (!ret
&& GetLastError() != ERROR_ALREADY_EXISTS
)
68 SetFileAttributesW(BufferName
, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
);
72 ret
= CreateDirectoryW(BufferName
, NULL
);
73 if (!ret
&& GetLastError() != ERROR_ALREADY_EXISTS
)
81 /* Add ACL to allow only user/SYSTEM to open it */
82 /* FIXME: rc = SetNamedSecurityInfo(
90 if (rc != ERROR_SUCCESS)
98 wcscat(BufferName
, L
"\\");
99 FileName
= &BufferName
[wcslen(BufferName
)];
101 /* Create desktop.ini */
102 wcscpy(FileName
, L
"desktop.ini");
103 hFile
= CreateFileW(BufferName
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
, NULL
);
104 if (hFile
== INVALID_HANDLE_VALUE
)
106 BytesToWrite
= strlen(DesktopIniContents
);
107 ret
= WriteFile(hFile
, DesktopIniContents
, (DWORD
)BytesToWrite
, &BytesWritten
, NULL
);
110 if (BytesWritten
!= BytesToWrite
)
112 SetLastError(ERROR_GEN_FAILURE
);
116 hFile
= INVALID_HANDLE_VALUE
;
118 /* Create empty INFO2 file */
119 wcscpy(FileName
, RECYCLE_BIN_FILE_NAME
);
120 hFile
= CreateFileW(BufferName
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_HIDDEN
, NULL
);
121 if (hFile
== INVALID_HANDLE_VALUE
)
123 BytesToWrite
= sizeof(Info2Contents
);
124 ret
= WriteFile(hFile
, Info2Contents
, (DWORD
)BytesToWrite
, &BytesWritten
, NULL
);
127 if (BytesWritten
!= BytesToWrite
)
129 SetLastError(ERROR_GEN_FAILURE
);
137 HeapFree(GetProcessHeap(), 0, BufferName
);
140 if (hFile
!= INVALID_HANDLE_VALUE
)
147 IntReferenceRecycleBin(
148 IN WCHAR driveLetter
)
150 PLIST_ENTRY ListEntry
;
151 PRECYCLE_BIN bin
= NULL
, ret
= NULL
;
153 DWORD FileSystemFlags
;
154 LPCWSTR RecycleBinDirectory
;
155 HANDLE tokenHandle
= INVALID_HANDLE_VALUE
;
156 PTOKEN_USER TokenUserInfo
= NULL
;
157 LPWSTR StringSid
= NULL
;
158 SIZE_T Needed
, DirectoryLength
;
160 BOOL AlreadyCreated
= FALSE
;
163 static LIST_ENTRY ListHead
;
164 static BOOL ListInitialized
= FALSE
;
166 if (!ListInitialized
)
168 InitializeListHead(&ListHead
);
169 ListInitialized
= TRUE
;
172 /* Search if the recycle bin has already been opened */
173 driveLetter
= toupper(driveLetter
);
174 ListEntry
= ListHead
.Flink
;
175 while (ListEntry
!= &ListHead
)
177 bin
= CONTAINING_RECORD(ListEntry
, RECYCLE_BIN
, ListEntry
);
178 if (bin
->Folder
[0] == driveLetter
)
180 ReferenceHandle(&bin
->refCount
);
183 ListEntry
= ListEntry
->Flink
;
187 /* We need to create a new recycle bin */
189 /* Get information about file system */
190 wsprintfW(RootPath
, L
"%c:\\", driveLetter
);
191 if (!GetVolumeInformationW(
203 if (!(FileSystemFlags
& FILE_PERSISTENT_ACLS
))
204 RecycleBinDirectory
= RECYCLE_BIN_DIRECTORY_WITHOUT_ACL
;
207 RecycleBinDirectory
= RECYCLE_BIN_DIRECTORY_WITH_ACL
;
210 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &tokenHandle
))
212 if (GetTokenInformation(tokenHandle
, TokenUser
, NULL
, 0, &Needed
))
214 SetLastError(ERROR_GEN_FAILURE
);
217 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
219 TokenUserInfo
= HeapAlloc(GetProcessHeap(), 0, Needed
);
222 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
225 if (!GetTokenInformation(tokenHandle
, TokenUser
, TokenUserInfo
, (DWORD
)Needed
, &Needed
))
227 if (!ConvertSidToStringSidW(TokenUserInfo
->User
.Sid
, &StringSid
))
231 /* Create RECYCLEBIN structure */
233 DirectoryLength
= 3 + wcslen(RecycleBinDirectory
) + 1;
235 DirectoryLength
+= wcslen(StringSid
) + 1;
236 Needed
= FIELD_OFFSET(RECYCLE_BIN
, Folder
) + (2 * DirectoryLength
+ 2 + wcslen(RECYCLE_BIN_FILE_NAME
))* sizeof(WCHAR
);
237 bin
= HeapAlloc(GetProcessHeap(), 0, Needed
);
240 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
243 memset(bin
, 0, Needed
);
244 InitializeHandle(&bin
->refCount
, IntCloseRecycleBinHandle
);
245 bin
->magic
= RECYCLEBIN_MAGIC
;
246 bin
->hInfo
= INVALID_HANDLE_VALUE
;
247 bin
->InfoFile
= &bin
->Folder
[DirectoryLength
];
248 bin
->Folder
[0] = driveLetter
;
249 bin
->Folder
[1] = '\0';
250 wcscat(bin
->Folder
, L
":\\");
251 wcscat(bin
->Folder
, RecycleBinDirectory
);
254 wcscat(bin
->Folder
, L
"\\");
255 wcscat(bin
->Folder
, StringSid
);
257 wcscpy(bin
->InfoFile
, bin
->Folder
);
258 wcscat(bin
->InfoFile
, L
"\\");
259 wcscat(bin
->InfoFile
, RECYCLE_BIN_FILE_NAME
);
260 InsertTailList(&ListHead
, &bin
->ListEntry
);
263 bin
->hInfo
= CreateFileW(bin
->InfoFile
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
264 if (bin
->hInfo
== INVALID_HANDLE_VALUE
)
266 if (GetLastError() == ERROR_PATH_NOT_FOUND
|| GetLastError() == ERROR_FILE_NOT_FOUND
)
268 if (!IntCreateEmptyRecycleBin(bin
, TokenUserInfo
? TokenUserInfo
->User
.Sid
: NULL
))
270 AlreadyCreated
= TRUE
;
273 if (bin
->hInfo
== INVALID_HANDLE_VALUE
)
276 if (SetFilePointer(bin
->hInfo
, 0, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
)
278 if (!ReadFile(bin
->hInfo
, &Header
, sizeof(INFO2_HEADER
), &bytesRead
, NULL
))
280 if (bytesRead
!= sizeof(INFO2_HEADER
) && !AlreadyCreated
)
282 /* Create a new file */
283 if (!DereferenceHandle(&bin
->refCount
))
285 if (!DeleteFileW(bin
->InfoFile
))
289 switch (Header
.dwVersion
)
292 InitializeCallbacks5(&bin
->Callbacks
);
295 /* Unknown recycle bin version */
296 SetLastError(ERROR_NOT_SUPPORTED
);
303 if (tokenHandle
!= INVALID_HANDLE_VALUE
)
304 CloseHandle(tokenHandle
);
305 HeapFree(GetProcessHeap(), 0, TokenUserInfo
);
307 LocalFree(StringSid
);
310 if (bin
&& bin
->hInfo
!= INVALID_HANDLE_VALUE
)
311 DereferenceHandle(&bin
->refCount
);
312 HeapFree(GetProcessHeap(), 0, bin
);