mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
add a not yet complete tool to dump the recycle bin databases
svn path=/trunk/; revision=18384
This commit is contained in:
parent
be1c8d7a38
commit
d49c0b4e12
2 changed files with 746 additions and 0 deletions
733
reactos/apps/utils/dumprecbin/dumprecbin.c
Normal file
733
reactos/apps/utils/dumprecbin/dumprecbin.c
Normal file
|
@ -0,0 +1,733 @@
|
|||
/*
|
||||
*
|
||||
* dumprecbin - dumps a recycle bin database
|
||||
*
|
||||
* Copyright (c) 2005 by Thomas Weidenmueller <w3seek@reactos.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* TODO: - Support for Vista recycle bins (read the DeleteInfo NTFS streams, also NT 5.x)
|
||||
* - Support for INFO databases (win95)
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include <sddl.h>
|
||||
#include <ntsecapi.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#ifndef NT_SUCCESS
|
||||
#define NT_SUCCESS(status) ((LONG)(status) >= 0)
|
||||
#endif
|
||||
|
||||
typedef struct _RECYCLE_BIN
|
||||
{
|
||||
struct _RECYCLE_BIN *Next;
|
||||
PSID Sid;
|
||||
WCHAR User[255];
|
||||
WCHAR Path[MAX_PATH + 1];
|
||||
} RECYCLE_BIN, *PRECYCLE_BIN;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ivUnknown = 0,
|
||||
ivINFO2
|
||||
} INFO_VERSION, *PINFO_VERSION;
|
||||
|
||||
typedef struct _INFO2_HEADER
|
||||
{
|
||||
DWORD Version;
|
||||
DWORD Zero1;
|
||||
DWORD Zero2;
|
||||
DWORD RecordSize;
|
||||
} INFO2_HEADER, *PINFO2_HEADER;
|
||||
|
||||
typedef struct _INFO2_RECORD
|
||||
{
|
||||
DWORD Unknown;
|
||||
CHAR AnsiFileName[MAX_PATH];
|
||||
DWORD RecordNumber;
|
||||
DWORD DriveLetter;
|
||||
FILETIME DeletionTime;
|
||||
DWORD DeletedPhysicalSize;
|
||||
WCHAR FileName[MAX_PATH - 2];
|
||||
} INFO2_RECORD, *PINFO2_RECORD;
|
||||
|
||||
static HANDLE
|
||||
OpenAndMapInfoDatabase(IN LPTSTR szFileName,
|
||||
OUT PVOID *MappingBasePtr,
|
||||
OUT PLARGE_INTEGER FileSize)
|
||||
{
|
||||
HANDLE hFile, hMapping = INVALID_HANDLE_VALUE;
|
||||
|
||||
hFile = CreateFile(szFileName,
|
||||
FILE_READ_DATA,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
|
||||
NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (GetFileSizeEx(hFile,
|
||||
FileSize) &&
|
||||
FileSize->QuadPart >= 0xF)
|
||||
{
|
||||
hMapping = CreateFileMapping(hFile,
|
||||
NULL,
|
||||
PAGE_READONLY,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
if (hMapping == NULL ||
|
||||
!(*MappingBasePtr = MapViewOfFile(hMapping,
|
||||
FILE_MAP_READ,
|
||||
0,
|
||||
0,
|
||||
0)))
|
||||
{
|
||||
if (hMapping != NULL)
|
||||
{
|
||||
CloseHandle(hMapping);
|
||||
}
|
||||
hMapping = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
return hMapping;
|
||||
}
|
||||
|
||||
static VOID
|
||||
UnmapAndCloseDatabase(IN HANDLE hMapping,
|
||||
IN PVOID MappingBasePtr)
|
||||
{
|
||||
UnmapViewOfFile(MappingBasePtr);
|
||||
CloseHandle(hMapping);
|
||||
}
|
||||
|
||||
static INFO_VERSION
|
||||
DetectDatabaseVersion(PVOID Header)
|
||||
{
|
||||
PINFO2_HEADER Info2 = (PINFO2_HEADER)Header;
|
||||
INFO_VERSION Version = ivUnknown;
|
||||
|
||||
if (Info2->Version == 5 &&
|
||||
Info2->Zero1 == 0 &&
|
||||
Info2->Zero2 == 0 &&
|
||||
Info2->RecordSize == 0x320)
|
||||
{
|
||||
Version = ivINFO2;
|
||||
}
|
||||
|
||||
return Version;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
IsValidRecycleBin(IN LPTSTR szPath)
|
||||
{
|
||||
TCHAR szFile[MAX_PATH + 1];
|
||||
TCHAR szClsId[48];
|
||||
INFO_VERSION DbVersion = ivUnknown;
|
||||
|
||||
_stprintf(szFile,
|
||||
_T("%s\\desktop.ini"),
|
||||
szPath);
|
||||
|
||||
/* check if directory contains a valid desktop.ini for the recycle bin */
|
||||
if (GetPrivateProfileString(TEXT(".ShellClassInfo"),
|
||||
TEXT("CLSID"),
|
||||
NULL,
|
||||
szClsId,
|
||||
sizeof(szClsId) / sizeof(szClsId[0]),
|
||||
szFile) &&
|
||||
!_tcsicmp(_T("{645FF040-5081-101B-9F08-00AA002F954E}"),
|
||||
szClsId))
|
||||
{
|
||||
HANDLE hDb;
|
||||
LARGE_INTEGER FileSize;
|
||||
PVOID pDbBase = NULL;
|
||||
|
||||
/* open the database and check the signature */
|
||||
_stprintf(szFile,
|
||||
_T("%s\\INFO2"),
|
||||
szPath);
|
||||
hDb = OpenAndMapInfoDatabase(szFile,
|
||||
&pDbBase,
|
||||
&FileSize);
|
||||
if (hDb != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DbVersion = DetectDatabaseVersion(pDbBase);
|
||||
UnmapAndCloseDatabase(hDb,
|
||||
pDbBase);
|
||||
}
|
||||
}
|
||||
|
||||
return DbVersion != ivUnknown;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
OpenLocalLSAPolicyHandle(IN ACCESS_MASK DesiredAccess,
|
||||
OUT PLSA_HANDLE PolicyHandle)
|
||||
{
|
||||
LSA_OBJECT_ATTRIBUTES LsaObjectAttributes = {0};
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = LsaOpenPolicy(NULL,
|
||||
&LsaObjectAttributes,
|
||||
DesiredAccess,
|
||||
PolicyHandle);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
SetLastError(LsaNtStatusToWinError(Status));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
ConvertSIDToAccountName(IN PSID Sid,
|
||||
OUT LPWSTR User)
|
||||
{
|
||||
DWORD AccountNameLen = 0;
|
||||
DWORD DomainNameLen = 0;
|
||||
SID_NAME_USE NameUse;
|
||||
DWORD Error = ERROR_SUCCESS;
|
||||
LPWSTR AccountName, DomainName;
|
||||
BOOL Ret = FALSE;
|
||||
|
||||
if (!LookupAccountSidW(NULL,
|
||||
Sid,
|
||||
NULL,
|
||||
&AccountNameLen,
|
||||
NULL,
|
||||
&DomainNameLen,
|
||||
&NameUse))
|
||||
{
|
||||
Error = GetLastError();
|
||||
if (Error == ERROR_NONE_MAPPED ||
|
||||
Error != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
/* some unexpected error occured! */
|
||||
goto ConvertSID;
|
||||
}
|
||||
}
|
||||
|
||||
AccountName = (LPWSTR)HeapAlloc(GetProcessHeap(),
|
||||
0,
|
||||
(AccountNameLen + DomainNameLen) * sizeof(WCHAR));
|
||||
if (AccountName != NULL)
|
||||
{
|
||||
LSA_HANDLE PolicyHandle;
|
||||
DomainName = AccountName + AccountNameLen;
|
||||
|
||||
if (!LookupAccountSidW(NULL,
|
||||
Sid,
|
||||
AccountName,
|
||||
&AccountNameLen,
|
||||
DomainName,
|
||||
&DomainNameLen,
|
||||
&NameUse))
|
||||
{
|
||||
goto BailFreeAccountName;
|
||||
}
|
||||
|
||||
wcscpy(User,
|
||||
AccountName);
|
||||
Ret = TRUE;
|
||||
|
||||
if (OpenLocalLSAPolicyHandle(POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
|
||||
&PolicyHandle))
|
||||
{
|
||||
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain;
|
||||
PLSA_TRANSLATED_NAME Names;
|
||||
PLSA_TRUST_INFORMATION Domain;
|
||||
PLSA_UNICODE_STRING DomainName;
|
||||
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = LsaLookupSids(PolicyHandle,
|
||||
1,
|
||||
&Sid,
|
||||
&ReferencedDomain,
|
||||
&Names);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
if (ReferencedDomain != NULL &&
|
||||
Names->DomainIndex >= 0)
|
||||
{
|
||||
Domain = &ReferencedDomain->Domains[Names->DomainIndex];
|
||||
DomainName = &Domain->Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
Domain = NULL;
|
||||
DomainName = NULL;
|
||||
}
|
||||
|
||||
switch (Names->Use)
|
||||
{
|
||||
case SidTypeAlias:
|
||||
if (Domain != NULL)
|
||||
{
|
||||
/* query the domain name for BUILTIN accounts */
|
||||
Status = LsaQueryInformationPolicy(PolicyHandle,
|
||||
PolicyAccountDomainInformation,
|
||||
(PVOID*)&PolicyAccountDomainInfo);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
DomainName = &PolicyAccountDomainInfo->DomainName;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
case SidTypeUser:
|
||||
{
|
||||
if (Domain != NULL)
|
||||
{
|
||||
WCHAR *s;
|
||||
|
||||
/* NOTE: LSA_UNICODE_STRINGs are not always NULL-terminated! */
|
||||
|
||||
wcscpy(User,
|
||||
AccountName);
|
||||
wcscat(User,
|
||||
L" (");
|
||||
s = User + wcslen(User);
|
||||
CopyMemory(s,
|
||||
DomainName->Buffer,
|
||||
DomainName->Length);
|
||||
s += DomainName->Length / sizeof(WCHAR);
|
||||
*(s++) = L'\\';
|
||||
CopyMemory(s,
|
||||
Names->Name.Buffer,
|
||||
Names->Name.Length);
|
||||
s += Names->Name.Length / sizeof(WCHAR);
|
||||
*(s++) = L')';
|
||||
*s = L'\0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SidTypeWellKnownGroup:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
_ftprintf(stderr,
|
||||
_T("Unhandled SID type: 0x%x\n"),
|
||||
Names->Use);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (PolicyAccountDomainInfo != NULL)
|
||||
{
|
||||
LsaFreeMemory(PolicyAccountDomainInfo);
|
||||
}
|
||||
|
||||
LsaFreeMemory(ReferencedDomain);
|
||||
LsaFreeMemory(Names);
|
||||
}
|
||||
|
||||
LsaClose(PolicyHandle);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
Ret = FALSE;
|
||||
goto BailFreeAccountName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BailFreeAccountName:
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
AccountName);
|
||||
goto ConvertSID;
|
||||
}
|
||||
}
|
||||
|
||||
ConvertSID:
|
||||
if (!Ret)
|
||||
{
|
||||
LPWSTR StrSid;
|
||||
Ret = ConvertSidToStringSidW(Sid,
|
||||
&StrSid);
|
||||
if (Ret)
|
||||
{
|
||||
wcscpy(User,
|
||||
StrSid);
|
||||
LocalFree((HLOCAL)StrSid);
|
||||
}
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static VOID
|
||||
FreeRecycleBinsList(IN OUT PRECYCLE_BIN *RecycleBinsListHead)
|
||||
{
|
||||
PRECYCLE_BIN CurrentBin, NextBin;
|
||||
|
||||
CurrentBin = *RecycleBinsListHead;
|
||||
while (CurrentBin != NULL)
|
||||
{
|
||||
NextBin = CurrentBin->Next;
|
||||
LocalFree((HLOCAL)CurrentBin->Sid);
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
CurrentBin);
|
||||
CurrentBin = NextBin;
|
||||
}
|
||||
|
||||
*RecycleBinsListHead = NULL;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
LocateRecycleBins(IN LPWSTR szDrive,
|
||||
OUT PRECYCLE_BIN *RecycleBinsListHead)
|
||||
{
|
||||
TCHAR szRecBinPath[MAX_PATH + 1];
|
||||
HANDLE FindResult;
|
||||
WIN32_FIND_DATA FindData;
|
||||
PRECYCLE_BIN NewBin;
|
||||
BOOL Ret = FALSE;
|
||||
|
||||
FreeRecycleBinsList(RecycleBinsListHead);
|
||||
|
||||
/*
|
||||
* search for recycle bins on volumes that support file security (NTFS)
|
||||
*/
|
||||
_stprintf(szRecBinPath,
|
||||
_T("%lS\\RECYCLER\\*"),
|
||||
szDrive);
|
||||
FindResult = FindFirstFile(szRecBinPath,
|
||||
&FindData);
|
||||
if (FindResult != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
|
||||
_tcscmp(FindData.cFileName,
|
||||
_T("..")) &&
|
||||
_tcscmp(FindData.cFileName,
|
||||
_T(".")))
|
||||
{
|
||||
PSID Sid;
|
||||
|
||||
if (ConvertStringSidToSid(FindData.cFileName,
|
||||
&Sid))
|
||||
{
|
||||
_stprintf(szRecBinPath,
|
||||
_T("%s\\RECYCLER\\%s"),
|
||||
szDrive,
|
||||
FindData.cFileName);
|
||||
if (IsValidRecycleBin(szRecBinPath))
|
||||
{
|
||||
NewBin = (PRECYCLE_BIN)HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof(RECYCLE_BIN));
|
||||
if (NewBin != NULL)
|
||||
{
|
||||
_tcscpy(NewBin->Path,
|
||||
szRecBinPath);
|
||||
|
||||
/* convert the SID to an account name */
|
||||
ConvertSIDToAccountName(Sid,
|
||||
NewBin->User);
|
||||
|
||||
/* append the recycle bin */
|
||||
*RecycleBinsListHead = NewBin;
|
||||
RecycleBinsListHead = &NewBin->Next;
|
||||
|
||||
Ret = TRUE;
|
||||
}
|
||||
else
|
||||
goto ContinueFreeSid;
|
||||
}
|
||||
else
|
||||
{
|
||||
ContinueFreeSid:
|
||||
LocalFree((HLOCAL)Sid);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(FindResult,
|
||||
&FindData));
|
||||
|
||||
FindClose(FindResult);
|
||||
}
|
||||
|
||||
/*
|
||||
* search for recycle bins on volumes that don't support file security (FAT)
|
||||
*/
|
||||
_stprintf(szRecBinPath,
|
||||
_T("%s\\Recycled"),
|
||||
szDrive);
|
||||
FindResult = FindFirstFile(szRecBinPath,
|
||||
&FindData);
|
||||
if (FindResult != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (IsValidRecycleBin(szRecBinPath))
|
||||
{
|
||||
SID_IDENTIFIER_AUTHORITY WorldSia = {SECURITY_WORLD_SID_AUTHORITY};
|
||||
PSID EveryoneSid;
|
||||
|
||||
/* create an Everyone SID */
|
||||
if (AllocateAndInitializeSid(&WorldSia,
|
||||
1,
|
||||
SECURITY_WORLD_RID,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&EveryoneSid))
|
||||
{
|
||||
NewBin = (PRECYCLE_BIN)HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof(RECYCLE_BIN));
|
||||
if (NewBin != NULL)
|
||||
{
|
||||
_tcscpy(NewBin->Path,
|
||||
szRecBinPath);
|
||||
|
||||
/* convert the SID to an account name */
|
||||
ConvertSIDToAccountName(EveryoneSid,
|
||||
NewBin->User);
|
||||
|
||||
/* append the recycle bin */
|
||||
*RecycleBinsListHead = NewBin;
|
||||
RecycleBinsListHead = &NewBin->Next;
|
||||
|
||||
Ret = TRUE;
|
||||
}
|
||||
else
|
||||
FreeSid(EveryoneSid);
|
||||
}
|
||||
}
|
||||
FindClose(FindResult);
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static VOID
|
||||
DiskFileNameFromRecord(OUT LPTSTR szShortFileName,
|
||||
IN DWORD RecordNumber,
|
||||
IN WCHAR cDriveLetter,
|
||||
IN LPWSTR szFileName)
|
||||
{
|
||||
LPWSTR FileExt;
|
||||
|
||||
FileExt = wcsrchr(szFileName,
|
||||
L'.');
|
||||
if (FileExt != NULL)
|
||||
{
|
||||
_stprintf(szShortFileName,
|
||||
_T("D%lC%d%lS"),
|
||||
cDriveLetter,
|
||||
RecordNumber,
|
||||
FileExt);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stprintf(szShortFileName,
|
||||
_T("D%lC%d"),
|
||||
cDriveLetter,
|
||||
RecordNumber);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL
|
||||
DumpRecycleBin(IN PRECYCLE_BIN RecycleBin)
|
||||
{
|
||||
WCHAR szFile[MAX_PATH + 1];
|
||||
HANDLE hDb;
|
||||
LARGE_INTEGER FileSize;
|
||||
PVOID pDbBase = NULL;
|
||||
INFO_VERSION Version = ivUnknown;
|
||||
|
||||
_tprintf(_T("Dumping recycle bin of \"%lS\":\n"),
|
||||
RecycleBin->User);
|
||||
_tprintf(_T("Directory: %lS\n\n"),
|
||||
RecycleBin->Path);
|
||||
|
||||
_stprintf(szFile,
|
||||
_T("%s\\INFO2"),
|
||||
RecycleBin->Path);
|
||||
hDb = OpenAndMapInfoDatabase(szFile,
|
||||
&pDbBase,
|
||||
&FileSize);
|
||||
if (hDb != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Version = DetectDatabaseVersion(pDbBase);
|
||||
|
||||
/* dump the INFO2 database */
|
||||
switch (Version)
|
||||
{
|
||||
case ivINFO2:
|
||||
{
|
||||
DWORD nRecords;
|
||||
PINFO2_HEADER Info2Header = (PINFO2_HEADER)pDbBase;
|
||||
PINFO2_RECORD Info2 = (PINFO2_RECORD)(Info2Header + 1);
|
||||
int i = 0;
|
||||
|
||||
nRecords = (FileSize.QuadPart - sizeof(INFO2_HEADER)) / Info2Header->RecordSize;
|
||||
|
||||
while (nRecords != 0)
|
||||
{
|
||||
/* if the first character of the AnsiFileName is zero, the record
|
||||
is considered deleted */
|
||||
if (Info2->AnsiFileName[0] != '\0')
|
||||
{
|
||||
_tprintf(_T(" [%d] Record: #%d \"%lS\"\n"),
|
||||
++i,
|
||||
Info2->RecordNumber,
|
||||
Info2->FileName);
|
||||
|
||||
DiskFileNameFromRecord(szFile,
|
||||
Info2->RecordNumber,
|
||||
(WCHAR)Info2->DriveLetter + L'a',
|
||||
Info2->FileName);
|
||||
_tprintf(_T(" Name on disk: \"%s\"\n"),
|
||||
szFile);
|
||||
_tprintf(_T(" Deleted size on disk: %d KB\n"),
|
||||
Info2->DeletedPhysicalSize / 1024);
|
||||
}
|
||||
nRecords--;
|
||||
Info2++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UnmapAndCloseDatabase(hDb,
|
||||
pDbBase);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
SelectRecycleBin(IN LPWSTR szDrive)
|
||||
{
|
||||
BOOL Ret;
|
||||
PRECYCLE_BIN RecycleBinsList = NULL;
|
||||
|
||||
Ret = LocateRecycleBins(szDrive,
|
||||
&RecycleBinsList);
|
||||
if (Ret)
|
||||
{
|
||||
if (RecycleBinsList->Next != NULL)
|
||||
{
|
||||
PRECYCLE_BIN CurrentBin = RecycleBinsList;
|
||||
int n = 0, i = 0;
|
||||
|
||||
/* if there are multiple recycle bins ask the user which one to dump */
|
||||
_tprintf(_T("There are several recycle bins on this drive. Select one:\n"));
|
||||
|
||||
while (CurrentBin != NULL)
|
||||
{
|
||||
_tprintf(_T(" [%d] %lS\n"),
|
||||
++i,
|
||||
CurrentBin->User);
|
||||
CurrentBin = CurrentBin->Next;
|
||||
n++;
|
||||
}
|
||||
|
||||
_tprintf(_T("Enter the number: "));
|
||||
DisplayPrompt:
|
||||
_tscanf(_T("%d"),
|
||||
&i);
|
||||
if (i > n || i < 1)
|
||||
{
|
||||
_tprintf(_T("Please enter a number between 1 and %d: "),
|
||||
n);
|
||||
goto DisplayPrompt;
|
||||
}
|
||||
|
||||
/* walk to the selected recycle bin */
|
||||
CurrentBin = RecycleBinsList;
|
||||
while (CurrentBin != NULL && i != 1)
|
||||
{
|
||||
CurrentBin = CurrentBin->Next;
|
||||
i--;
|
||||
}
|
||||
|
||||
/* dump it */
|
||||
Ret = DumpRecycleBin(CurrentBin);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* dump the first (and only) recycle bin */
|
||||
Ret = DumpRecycleBin(RecycleBinsList);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_ftprintf(stderr,
|
||||
_T("No recycle bins on this volume!\n"));
|
||||
}
|
||||
|
||||
FreeRecycleBinsList(&RecycleBinsList);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static VOID
|
||||
PrintHelp(VOID)
|
||||
{
|
||||
_ftprintf(stderr,
|
||||
_T("Usage: dumprecbin C:\n"));
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc,
|
||||
char *argv[])
|
||||
{
|
||||
if (argc != 2 ||
|
||||
strlen(argv[1]) != 2 || argv[1][1] != ':' ||
|
||||
toupper(argv[1][0]) < 'A' || toupper(argv[1][0]) > 'Z')
|
||||
{
|
||||
PrintHelp();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WCHAR szDrive[3];
|
||||
_stprintf(szDrive,
|
||||
_T("%lC:"),
|
||||
argv[1][0]);
|
||||
|
||||
if (!SelectRecycleBin(szDrive))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
13
reactos/apps/utils/dumprecbin/dumprecbin.xml
Normal file
13
reactos/apps/utils/dumprecbin/dumprecbin.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<module name="dumprecbin" type="win32cui" installbase="bin" installname="dumprecbin.exe">
|
||||
<include base="dumprecbin">.</include>
|
||||
<define name="__USE_W32API" />
|
||||
<define name="UNICODE" />
|
||||
<define name="_UNICODE" />
|
||||
<define name="_WIN32_IE">0x0500</define>
|
||||
<define name="_WIN32_WINNT">0x0600</define>
|
||||
<define name="WINVER">0x0600</define>
|
||||
<library>advapi32</library>
|
||||
<library>kernel32</library>
|
||||
<library>ntdll</library>
|
||||
<file>dumprecbin.c</file>
|
||||
</module>
|
Loading…
Reference in a new issue