ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

recyclebin_v5.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:     Recycle bin management
00003  * LICENSE:     GPL v2 - See COPYING in the top level directory
00004  * FILE:        lib/recyclebin/recyclebin_v5.c
00005  * PURPOSE:     Deals with recycle bins of Windows 2000/XP/2003
00006  * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
00007  */
00008 
00009 #define COBJMACROS
00010 #include "recyclebin_v5.h"
00011 #include <stdio.h>
00012 
00013 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
00014 
00015 static BOOL
00016 IntDeleteRecursive(
00017     IN LPCWSTR FullName)
00018 {
00019     DWORD RemovableAttributes = FILE_ATTRIBUTE_READONLY;
00020     WIN32_FIND_DATAW FindData;
00021     HANDLE hSearch = INVALID_HANDLE_VALUE;
00022     LPWSTR FullPath = NULL, pFilePart;
00023     DWORD FileAttributes;
00024     SIZE_T dwLength;
00025     BOOL ret = FALSE;
00026 
00027     FileAttributes = GetFileAttributesW(FullName);
00028     if (FileAttributes == INVALID_FILE_ATTRIBUTES)
00029     {
00030         if (GetLastError() == ERROR_FILE_NOT_FOUND)
00031             ret = TRUE;
00032         goto cleanup;
00033     }
00034     if (FileAttributes & RemovableAttributes)
00035     {
00036         if (!SetFileAttributesW(FullName, FileAttributes & ~RemovableAttributes))
00037             goto cleanup;
00038     }
00039     if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
00040     {
00041         /* Prepare file specification */
00042         dwLength = wcslen(FullName);
00043         FullPath = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1 + MAX_PATH + 1) * sizeof(WCHAR));
00044         if (!FullPath)
00045         {
00046             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00047             goto cleanup;
00048         }
00049         wcscpy(FullPath, FullName);
00050         if (FullPath[dwLength - 1] != '\\')
00051         {
00052             FullPath[dwLength] = '\\';
00053             dwLength++;
00054         }
00055         pFilePart = &FullPath[dwLength];
00056         wcscpy(pFilePart, L"*");
00057 
00058         /* Enumerate contents, and delete it */
00059         hSearch = FindFirstFileW(FullPath, &FindData);
00060         if (hSearch == INVALID_HANDLE_VALUE)
00061             goto cleanup;
00062         do
00063         {
00064             if (!(FindData.cFileName[0] == '.' &&
00065                 (FindData.cFileName[1] == '\0' || (FindData.cFileName[1] == '.' && FindData.cFileName[2] == '\0'))))
00066             {
00067                 wcscpy(pFilePart, FindData.cFileName);
00068                 if (!IntDeleteRecursive(FullPath))
00069                 {
00070                     FindClose(hSearch);
00071                     goto cleanup;
00072                 }
00073             }
00074         }
00075         while (FindNextFileW(hSearch, &FindData));
00076         FindClose(hSearch);
00077         if (GetLastError() != ERROR_NO_MORE_FILES)
00078             goto cleanup;
00079 
00080         /* Remove (now empty) directory */
00081         if (!RemoveDirectoryW(FullName))
00082             goto cleanup;
00083     }
00084     else
00085     {
00086         if (!DeleteFileW(FullName))
00087             goto cleanup;
00088     }
00089     ret = TRUE;
00090 
00091 cleanup:
00092     HeapFree(GetProcessHeap(), 0, FullPath);
00093     return ret;
00094 }
00095 
00096 struct RecycleBin5
00097 {
00098     ULONG ref;
00099     IRecycleBin5 recycleBinImpl;
00100     HANDLE hInfo;
00101     HANDLE hInfoMapped;
00102 
00103     DWORD EnumeratorCount;
00104 
00105     LPWSTR VolumePath;
00106     WCHAR Folder[ANY_SIZE]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */
00107 };
00108 
00109 static HRESULT STDMETHODCALLTYPE
00110 RecycleBin5_RecycleBin5_QueryInterface(
00111     IRecycleBin5 *This,
00112     REFIID riid,
00113     void **ppvObject)
00114 {
00115     struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
00116 
00117     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
00118 
00119     if (!ppvObject)
00120         return E_POINTER;
00121 
00122     if (IsEqualIID(riid, &IID_IUnknown))
00123         *ppvObject = &s->recycleBinImpl;
00124     else if (IsEqualIID(riid, &IID_IRecycleBin))
00125         *ppvObject = &s->recycleBinImpl;
00126     else if (IsEqualIID(riid, &IID_IRecycleBin5))
00127         *ppvObject = &s->recycleBinImpl;
00128     else
00129     {
00130         *ppvObject = NULL;
00131         return E_NOINTERFACE;
00132     }
00133 
00134     IUnknown_AddRef(This);
00135     return S_OK;
00136 }
00137 
00138 static ULONG STDMETHODCALLTYPE
00139 RecycleBin5_RecycleBin5_AddRef(
00140     IRecycleBin5 *This)
00141 {
00142     struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
00143     ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
00144     TRACE("(%p)\n", This);
00145     return refCount;
00146 }
00147 
00148 static VOID
00149 RecycleBin5_Destructor(
00150     struct RecycleBin5 *s)
00151 {
00152     TRACE("(%p)\n", s);
00153 
00154     if (s->hInfo && s->hInfo != INVALID_HANDLE_VALUE)
00155         CloseHandle(s->hInfo);
00156     if (s->hInfoMapped)
00157         CloseHandle(s->hInfoMapped);
00158     CoTaskMemFree(s);
00159 }
00160 
00161 static ULONG STDMETHODCALLTYPE
00162 RecycleBin5_RecycleBin5_Release(
00163     IRecycleBin5 *This)
00164 {
00165     struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
00166     ULONG refCount;
00167 
00168     TRACE("(%p)\n", This);
00169 
00170     refCount = InterlockedDecrement((PLONG)&s->ref);
00171 
00172     if (refCount == 0)
00173         RecycleBin5_Destructor(s);
00174 
00175     return refCount;
00176 }
00177 
00178 static HRESULT STDMETHODCALLTYPE
00179 RecycleBin5_RecycleBin5_DeleteFile(
00180     IN IRecycleBin5 *This,
00181     IN LPCWSTR szFileName)
00182 {
00183     struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
00184     LPWSTR szFullName = NULL;
00185     DWORD dwBufferLength = 0;
00186     LPWSTR lpFilePart;
00187     LPCWSTR Extension;
00188     WCHAR DeletedFileName[MAX_PATH];
00189     DWORD len;
00190     HANDLE hFile = INVALID_HANDLE_VALUE;
00191     PINFO2_HEADER pHeader = NULL;
00192     PDELETED_FILE_RECORD pDeletedFile;
00193     ULARGE_INTEGER FileSize;
00194     DWORD dwAttributes, dwEntries;
00195     SYSTEMTIME SystemTime;
00196     DWORD ClusterSize, BytesPerSector, SectorsPerCluster;
00197     HRESULT hr;
00198 
00199     TRACE("(%p, %s)\n", This, debugstr_w(szFileName));
00200 
00201     if (s->EnumeratorCount != 0)
00202         return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
00203 
00204     /* Get full file name */
00205     while (TRUE)
00206     {
00207         len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, &lpFilePart);
00208         if (len == 0)
00209         {
00210             if (szFullName)
00211                 CoTaskMemFree(szFullName);
00212             return HRESULT_FROM_WIN32(GetLastError());
00213         }
00214         else if (len < dwBufferLength)
00215             break;
00216         if (szFullName)
00217             CoTaskMemFree(szFullName);
00218         dwBufferLength = len;
00219         szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
00220         if (!szFullName)
00221             return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
00222     }
00223 
00224     /* Check if file exists */
00225     dwAttributes = GetFileAttributesW(szFullName);
00226     if (dwAttributes == INVALID_FILE_ATTRIBUTES)
00227         return HRESULT_FROM_WIN32(GetLastError());
00228 
00229     if (dwBufferLength < 2 || szFullName[1] != ':')
00230     {
00231         /* Not a local file */
00232         CoTaskMemFree(szFullName);
00233         return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
00234     }
00235 
00236     hFile = CreateFileW(szFullName, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
00237     if (hFile == INVALID_HANDLE_VALUE)
00238     {
00239         hr = HRESULT_FROM_WIN32(GetLastError());
00240         goto cleanup;
00241     }
00242 
00243     /* Increase INFO2 file size */
00244     CloseHandle(s->hInfoMapped);
00245     SetFilePointer(s->hInfo, sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
00246     SetEndOfFile(s->hInfo);
00247     s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
00248     if (!s->hInfoMapped)
00249     {
00250         hr = HRESULT_FROM_WIN32(GetLastError());
00251         goto cleanup;
00252     }
00253 
00254     /* Open INFO2 file */
00255     pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
00256     if (!pHeader)
00257     {
00258         hr = HRESULT_FROM_WIN32(GetLastError());
00259         goto cleanup;
00260     }
00261 
00262     /* Get number of entries */
00263     FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
00264     if (FileSize.u.LowPart < sizeof(INFO2_HEADER))
00265     {
00266         UnmapViewOfFile(pHeader);
00267         return HRESULT_FROM_WIN32(GetLastError());
00268     }
00269     dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)) - 1;
00270     pDeletedFile = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries;
00271 
00272     /* Get file size */
00273 #if 0
00274     if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&FileSize))
00275     {
00276         hr = HRESULT_FROM_WIN32(GetLastError());
00277         goto cleanup;
00278     }
00279 #else
00280     FileSize.u.LowPart = GetFileSize(hFile, &FileSize.u.HighPart);
00281     if (FileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
00282     {
00283         hr = HRESULT_FROM_WIN32(GetLastError());
00284         goto cleanup;
00285     }
00286 #endif
00287     /* Check if file size is > 4Gb */
00288     if (FileSize.u.HighPart != 0)
00289     {
00290         /* Yes, this recyclebin can't support this file */
00291         hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
00292         goto cleanup;
00293     }
00294     pHeader->dwTotalLogicalSize += FileSize.u.LowPart;
00295 
00296     /* Generate new name */
00297     Extension = wcsrchr(szFullName, '.');
00298     ZeroMemory(pDeletedFile, sizeof(DELETED_FILE_RECORD));
00299     if (dwEntries == 0)
00300         pDeletedFile->dwRecordUniqueId = 0;
00301     else
00302     {
00303         PDELETED_FILE_RECORD pLastDeleted = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries - 1;
00304         pDeletedFile->dwRecordUniqueId = pLastDeleted->dwRecordUniqueId + 1;
00305     }
00306     pDeletedFile->dwDriveNumber = tolower(szFullName[0]) - 'a';
00307     _snwprintf(DeletedFileName, MAX_PATH, L"%s\\D%c%lu%s", s->Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension);
00308 
00309     /* Get cluster size */
00310     if (!GetDiskFreeSpaceW(s->VolumePath, &SectorsPerCluster, &BytesPerSector, NULL, NULL))
00311     {
00312         hr = HRESULT_FROM_WIN32(GetLastError());
00313         goto cleanup;
00314     }
00315     ClusterSize = BytesPerSector * SectorsPerCluster;
00316 
00317     /* Get current time */
00318     GetSystemTime(&SystemTime);
00319     if (!SystemTimeToFileTime(&SystemTime, &pDeletedFile->DeletionTime))
00320     {
00321         hr = HRESULT_FROM_WIN32(GetLastError());
00322         goto cleanup;
00323     }
00324     pDeletedFile->dwPhysicalFileSize = ROUND_UP(FileSize.u.LowPart, ClusterSize);
00325 
00326     /* Set name */
00327     wcscpy(pDeletedFile->FileNameW, szFullName);
00328     if (WideCharToMultiByte(CP_ACP, 0, pDeletedFile->FileNameW, -1, pDeletedFile->FileNameA, MAX_PATH, NULL, NULL) == 0)
00329     {
00330         hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
00331         SetLastError(ERROR_INVALID_NAME);
00332         goto cleanup;
00333     }
00334 
00335     /* Move file */
00336     if (MoveFileW(szFullName, DeletedFileName))
00337         hr = S_OK;
00338     else
00339         hr = HRESULT_FROM_WIN32(GetLastError());
00340 
00341 cleanup:
00342     if (pHeader)
00343         UnmapViewOfFile(pHeader);
00344     if (hFile != INVALID_HANDLE_VALUE)
00345         CloseHandle(hFile);
00346     CoTaskMemFree(szFullName);
00347     return hr;
00348 }
00349 
00350 static HRESULT STDMETHODCALLTYPE
00351 RecycleBin5_RecycleBin5_EmptyRecycleBin(
00352     IN IRecycleBin5 *This)
00353 {
00354     IRecycleBinEnumList *prbel;
00355     IRecycleBinFile *prbf;
00356     HRESULT hr;
00357 
00358     TRACE("(%p)\n", This);
00359 
00360     while (TRUE)
00361     {
00362         hr = IRecycleBin5_EnumObjects(This, &prbel);
00363         if (!SUCCEEDED(hr))
00364             return hr;
00365         hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
00366         IRecycleBinEnumList_Release(prbel);
00367         if (hr == S_FALSE)
00368             return S_OK;
00369         hr = IRecycleBinFile_Delete(prbf);
00370         IRecycleBinFile_Release(prbf);
00371         if (!SUCCEEDED(hr))
00372             return hr;
00373     }
00374 }
00375 
00376 static HRESULT STDMETHODCALLTYPE
00377 RecycleBin5_RecycleBin5_EnumObjects(
00378     IN IRecycleBin5 *This,
00379     OUT IRecycleBinEnumList **ppEnumList)
00380 {
00381     struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
00382     IRecycleBinEnumList *prbel;
00383     HRESULT hr;
00384     IUnknown *pUnk;
00385 
00386     TRACE("(%p, %p)\n", This, ppEnumList);
00387 
00388     hr = RecycleBin5Enum_Constructor(This, s->hInfo, s->hInfoMapped, s->Folder, &pUnk);
00389     if (!SUCCEEDED(hr))
00390         return hr;
00391 
00392     hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBinEnumList, (void **)&prbel);
00393     if (SUCCEEDED(hr))
00394     {
00395         s->EnumeratorCount++;
00396         *ppEnumList = prbel;
00397     }
00398     IUnknown_Release(pUnk);
00399     return hr;
00400 }
00401 
00402 static HRESULT STDMETHODCALLTYPE
00403 RecycleBin5_RecycleBin5_Delete(
00404     IN IRecycleBin5 *This,
00405     IN LPCWSTR pDeletedFileName,
00406     IN DELETED_FILE_RECORD *pDeletedFile)
00407 {
00408     struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
00409     ULARGE_INTEGER FileSize;
00410     PINFO2_HEADER pHeader;
00411     DELETED_FILE_RECORD *pRecord, *pLast;
00412     DWORD dwEntries, i;
00413 
00414     TRACE("(%p, %s, %p)\n", This, debugstr_w(pDeletedFileName), pDeletedFile);
00415 
00416     if (s->EnumeratorCount != 0)
00417         return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
00418 
00419     pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
00420     if (!pHeader)
00421         return HRESULT_FROM_WIN32(GetLastError());
00422 
00423     FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
00424     if (FileSize.u.LowPart == 0)
00425     {
00426         UnmapViewOfFile(pHeader);
00427         return HRESULT_FROM_WIN32(GetLastError());
00428     }
00429     dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
00430 
00431     pRecord = (DELETED_FILE_RECORD *)(pHeader + 1);
00432     for (i = 0; i < dwEntries; i++)
00433     {
00434         if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId)
00435         {
00436             /* Delete file */
00437             if (!IntDeleteRecursive(pDeletedFileName))
00438             {
00439                 UnmapViewOfFile(pHeader);
00440                 return HRESULT_FROM_WIN32(GetLastError());
00441             }
00442 
00443             /* Clear last entry in the file */
00444             MoveMemory(pRecord, pRecord + 1, (dwEntries - i - 1) * sizeof(DELETED_FILE_RECORD));
00445             pLast = pRecord + (dwEntries - i - 1);
00446             ZeroMemory(pLast, sizeof(DELETED_FILE_RECORD));
00447             UnmapViewOfFile(pHeader);
00448 
00449             /* Resize file */
00450             CloseHandle(s->hInfoMapped);
00451             SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
00452             SetEndOfFile(s->hInfo);
00453             s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
00454             if (!s->hInfoMapped)
00455                 return HRESULT_FROM_WIN32(GetLastError());
00456             return S_OK;
00457         }
00458         pRecord++;
00459     }
00460     UnmapViewOfFile(pHeader);
00461     return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
00462 }
00463 
00464 static HRESULT STDMETHODCALLTYPE
00465 RecycleBin5_RecycleBin5_Restore(
00466     IN IRecycleBin5 *This,
00467     IN LPCWSTR pDeletedFileName,
00468     IN DELETED_FILE_RECORD *pDeletedFile)
00469 {
00470     struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
00471     ULARGE_INTEGER FileSize;
00472     PINFO2_HEADER pHeader;
00473     DELETED_FILE_RECORD *pRecord, *pLast;
00474     DWORD dwEntries, i;
00475     SHFILEOPSTRUCTW op;
00476 
00477     TRACE("(%p, %s, %p)\n", This, debugstr_w(pDeletedFileName), pDeletedFile);
00478 
00479     if (s->EnumeratorCount != 0)
00480         return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
00481 
00482     pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
00483     if (!pHeader)
00484         return HRESULT_FROM_WIN32(GetLastError());
00485 
00486     FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
00487     if (FileSize.u.LowPart == 0)
00488     {
00489         UnmapViewOfFile(pHeader);
00490         return HRESULT_FROM_WIN32(GetLastError());
00491     }
00492     dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
00493 
00494     pRecord = (DELETED_FILE_RECORD *)(pHeader + 1);
00495     for (i = 0; i < dwEntries; i++)
00496     {
00497         if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId)
00498         {
00499             /* Restore file */
00500             ZeroMemory(&op, sizeof(op));
00501             op.wFunc = FO_COPY;
00502             op.pFrom = pDeletedFileName;
00503             op.pTo = pDeletedFile->FileNameW;
00504 
00505             if (!SHFileOperationW(&op))
00506             {
00507                 UnmapViewOfFile(pHeader);
00508                 return HRESULT_FROM_WIN32(GetLastError());
00509             }
00510 
00511             /* Clear last entry in the file */
00512             MoveMemory(pRecord, pRecord + 1, (dwEntries - i - 1) * sizeof(DELETED_FILE_RECORD));
00513             pLast = pRecord + (dwEntries - i - 1);
00514             ZeroMemory(pLast, sizeof(DELETED_FILE_RECORD));
00515             UnmapViewOfFile(pHeader);
00516 
00517             /* Resize file */
00518             CloseHandle(s->hInfoMapped);
00519             SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
00520             SetEndOfFile(s->hInfo);
00521             s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
00522             if (!s->hInfoMapped)
00523                 return HRESULT_FROM_WIN32(GetLastError());
00524             return S_OK;
00525         }
00526         pRecord++;
00527     }
00528 
00529     UnmapViewOfFile(pHeader);
00530     return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
00531 }
00532 
00533 static HRESULT STDMETHODCALLTYPE
00534 RecycleBin5_RecycleBin5_OnClosing(
00535     IN IRecycleBin5 *This,
00536     IN IRecycleBinEnumList *prbel)
00537 {
00538     struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
00539     TRACE("(%p, %p)\n", This, prbel);
00540     s->EnumeratorCount--;
00541     return S_OK;
00542 }
00543 
00544 CONST_VTBL struct IRecycleBin5Vtbl RecycleBin5Vtbl =
00545 {
00546     RecycleBin5_RecycleBin5_QueryInterface,
00547     RecycleBin5_RecycleBin5_AddRef,
00548     RecycleBin5_RecycleBin5_Release,
00549     RecycleBin5_RecycleBin5_DeleteFile,
00550     RecycleBin5_RecycleBin5_EmptyRecycleBin,
00551     RecycleBin5_RecycleBin5_EnumObjects,
00552     RecycleBin5_RecycleBin5_Delete,
00553     RecycleBin5_RecycleBin5_Restore,
00554     RecycleBin5_RecycleBin5_OnClosing,
00555 };
00556 
00557 static HRESULT
00558 RecycleBin5_Create(
00559     IN LPCWSTR Folder,
00560     IN PSID OwnerSid OPTIONAL)
00561 {
00562     LPWSTR BufferName = NULL;
00563     LPWSTR Separator; /* Pointer into BufferName buffer */
00564     LPWSTR FileName; /* Pointer into BufferName buffer */
00565     LPCSTR DesktopIniContents = "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
00566     INFO2_HEADER Info2Contents[] = { { 5, 0, 0, 0x320, 0 } };
00567     DWORD BytesToWrite, BytesWritten, Needed;
00568     HANDLE hFile = INVALID_HANDLE_VALUE;
00569     HRESULT hr;
00570 
00571     Needed = (wcslen(Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR);
00572     BufferName = HeapAlloc(GetProcessHeap(), 0, Needed);
00573     if (!BufferName)
00574     {
00575         hr = ERROR_NOT_ENOUGH_MEMORY;
00576         goto cleanup;
00577     }
00578 
00579     wcscpy(BufferName, Folder);
00580     Separator = wcsstr(&BufferName[3], L"\\");
00581     if (Separator)
00582         *Separator = UNICODE_NULL;
00583     if (!CreateDirectoryW(BufferName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
00584     {
00585         hr = HRESULT_FROM_WIN32(GetLastError());
00586         goto cleanup;
00587     }
00588     SetFileAttributesW(BufferName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
00589     if (Separator)
00590     {
00591         *Separator = L'\\';
00592         if (!CreateDirectoryW(BufferName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
00593         {
00594             hr = HRESULT_FROM_WIN32(GetLastError());
00595             goto cleanup;
00596         }
00597     }
00598 
00599     if (OwnerSid)
00600     {
00601         //DWORD rc;
00602 
00603         /* Add ACL to allow only user/SYSTEM to open it */
00604         /* FIXME: rc = SetNamedSecurityInfo(
00605             BufferName,
00606             SE_FILE_OBJECT,
00607             ???,
00608             OwnerSid,
00609             NULL,
00610             ???,
00611             ???);
00612         if (rc != ERROR_SUCCESS)
00613         {
00614             hr = HRESULT_FROM_WIN32(rc);
00615             goto cleanup;
00616         }
00617         */
00618     }
00619 
00620     wcscat(BufferName, L"\\");
00621     FileName = &BufferName[wcslen(BufferName)];
00622 
00623     /* Create desktop.ini */
00624     wcscpy(FileName, L"desktop.ini");
00625     hFile = CreateFileW(BufferName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL);
00626     if (hFile == INVALID_HANDLE_VALUE)
00627     {
00628         hr = HRESULT_FROM_WIN32(GetLastError());
00629         goto cleanup;
00630     }
00631     BytesToWrite = strlen(DesktopIniContents);
00632     if (!WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten, NULL))
00633     {
00634         hr = HRESULT_FROM_WIN32(GetLastError());
00635         goto cleanup;
00636     }
00637     if (BytesWritten != BytesToWrite)
00638     {
00639         hr = E_FAIL;
00640         goto cleanup;
00641     }
00642     CloseHandle(hFile);
00643     hFile = INVALID_HANDLE_VALUE;
00644 
00645     /* Create empty INFO2 file */
00646     wcscpy(FileName, RECYCLE_BIN_FILE_NAME);
00647     hFile = CreateFileW(BufferName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
00648     if (hFile == INVALID_HANDLE_VALUE)
00649     {
00650         hr = HRESULT_FROM_WIN32(GetLastError());
00651         goto cleanup;
00652     }
00653     BytesToWrite = sizeof(Info2Contents);
00654     if (!WriteFile(hFile, Info2Contents, (DWORD)BytesToWrite, &BytesWritten, NULL))
00655     {
00656         hr = HRESULT_FROM_WIN32(GetLastError());
00657         goto cleanup;
00658     }
00659     if (BytesWritten == BytesToWrite)
00660         hr = S_OK;
00661     else
00662         hr = E_FAIL;
00663 
00664 cleanup:
00665     HeapFree(GetProcessHeap(), 0, BufferName);
00666     if (hFile != INVALID_HANDLE_VALUE)
00667         CloseHandle(hFile);
00668     return hr;
00669 }
00670 
00671 HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown)
00672 {
00673     struct RecycleBin5 *s = NULL;
00674     DWORD FileSystemFlags;
00675     LPCWSTR RecycleBinDirectory;
00676     HANDLE tokenHandle = INVALID_HANDLE_VALUE;
00677     PTOKEN_USER TokenUserInfo = NULL;
00678     LPWSTR StringSid = NULL, p;
00679     DWORD Needed, DirectoryLength;
00680     INT len;
00681     HRESULT hr;
00682 
00683     if (!ppUnknown)
00684         return E_POINTER;
00685 
00686     /* Get information about file system */
00687     if (!GetVolumeInformationW(
00688         VolumePath,
00689         NULL,
00690         0,
00691         NULL,
00692         NULL,
00693         &FileSystemFlags,
00694         NULL,
00695         0))
00696     {
00697         hr = HRESULT_FROM_WIN32(GetLastError());
00698         goto cleanup;
00699     }
00700     if (!(FileSystemFlags & FILE_PERSISTENT_ACLS))
00701         RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL;
00702     else
00703     {
00704         RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL;
00705 
00706         /* Get user SID */
00707         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle))
00708         {
00709             hr = HRESULT_FROM_WIN32(GetLastError());
00710             goto cleanup;
00711         }
00712         if (GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &Needed))
00713         {
00714             hr = E_FAIL;
00715             goto cleanup;
00716         }
00717         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
00718         {
00719             hr = HRESULT_FROM_WIN32(GetLastError());
00720             goto cleanup;
00721         }
00722         TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed);
00723         if (!TokenUserInfo)
00724         {
00725             hr = E_OUTOFMEMORY;
00726             goto cleanup;
00727         }
00728         if (!GetTokenInformation(tokenHandle, TokenUser, TokenUserInfo, (DWORD)Needed, &Needed))
00729         {
00730             hr = HRESULT_FROM_WIN32(GetLastError());
00731             goto cleanup;
00732         }
00733         if (!ConvertSidToStringSidW(TokenUserInfo->User.Sid, &StringSid))
00734         {
00735             hr = HRESULT_FROM_WIN32(GetLastError());
00736             goto cleanup;
00737         }
00738     }
00739 
00740     DirectoryLength = wcslen(VolumePath) + wcslen(RecycleBinDirectory) + 1;
00741     if (StringSid)
00742         DirectoryLength += wcslen(StringSid) + 1;
00743     DirectoryLength += 1 + wcslen(RECYCLE_BIN_FILE_NAME);
00744     DirectoryLength += wcslen(VolumePath) + 1;
00745     Needed = (DirectoryLength + 1) * sizeof(WCHAR);
00746 
00747     s = CoTaskMemAlloc(sizeof(struct RecycleBin5) + Needed);
00748     if (!s)
00749     {
00750         hr = E_OUTOFMEMORY;
00751         goto cleanup;
00752     }
00753     ZeroMemory(s, sizeof(struct RecycleBin5));
00754     s->recycleBinImpl.lpVtbl = &RecycleBin5Vtbl;
00755     s->ref = 1;
00756     if (StringSid)
00757         len = swprintf(s->Folder, L"%s%s\\%s", VolumePath, RecycleBinDirectory, StringSid);
00758     else
00759         len = swprintf(s->Folder, L"%s%s", VolumePath, RecycleBinDirectory);
00760     p = &s->Folder[len];
00761     wcscpy(p, L"\\" RECYCLE_BIN_FILE_NAME);
00762     s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
00763     if (s->hInfo == INVALID_HANDLE_VALUE && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND))
00764     {
00765         *p = UNICODE_NULL;
00766         hr = RecycleBin5_Create(s->Folder, TokenUserInfo ? TokenUserInfo->User.Sid : NULL);
00767         *p = L'\\';
00768         if (!SUCCEEDED(hr))
00769             goto cleanup;
00770         s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
00771     }
00772     if (s->hInfo == INVALID_HANDLE_VALUE)
00773     {
00774         hr = HRESULT_FROM_WIN32(GetLastError());
00775         goto cleanup;
00776     }
00777     s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
00778     if (!s->hInfoMapped)
00779     {
00780         hr = HRESULT_FROM_WIN32(GetLastError());
00781         goto cleanup;
00782     }
00783     *p = UNICODE_NULL;
00784     s->VolumePath = p + 1;
00785     wcscpy(s->VolumePath, VolumePath);
00786 
00787     *ppUnknown = (IUnknown *)&s->recycleBinImpl;
00788 
00789     hr = S_OK;
00790 
00791 cleanup:
00792     if (tokenHandle != INVALID_HANDLE_VALUE)
00793         CloseHandle(tokenHandle);
00794     HeapFree(GetProcessHeap(), 0, TokenUserInfo);
00795     if (StringSid)
00796         LocalFree(StringSid);
00797     if (!SUCCEEDED(hr))
00798     {
00799         if (s)
00800             RecycleBin5_Destructor(s);
00801     }
00802     return hr;
00803 }

Generated on Sun May 27 2012 04:36:16 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.