mirror of
https://github.com/reactos/reactos.git
synced 2024-08-19 18:02:55 +00:00
197 lines
5.5 KiB
C
197 lines
5.5 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS pending moves operations Information tool
|
|
* FILE: cmdutils/pendmoves/pendmoves.c
|
|
* PURPOSE: Query information from registry about pending moves
|
|
* PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <stdio.h>
|
|
|
|
static
|
|
TCHAR *
|
|
BeautifyPath(TCHAR * Path, DWORD * Len)
|
|
{
|
|
DWORD LocalLen = *Len;
|
|
|
|
/* If there's a ! marking that existing file can be overwritten,
|
|
* drop it
|
|
*/
|
|
if (LocalLen > 1)
|
|
{
|
|
if (Path[0] == _T('!'))
|
|
{
|
|
++Path;
|
|
--LocalLen;
|
|
}
|
|
}
|
|
|
|
/* Remove namespace if prefixed */
|
|
if (LocalLen > 4)
|
|
{
|
|
if (Path[0] == _T('\\') && Path[1] == _T('?') &&
|
|
Path[2] == _T('?') && Path[3] == _T('\\'))
|
|
{
|
|
Path += 4;
|
|
LocalLen -= 4;
|
|
}
|
|
}
|
|
|
|
/* Return modified string + len */
|
|
*Len = LocalLen;
|
|
return Path;
|
|
}
|
|
|
|
static
|
|
DWORD
|
|
DisplayPendingOps(TCHAR * Value, DWORD Len)
|
|
{
|
|
DWORD Chars, i, j, Count, SrcLen, TgtLen;
|
|
TCHAR * SrcFile, * Target, * Current;
|
|
|
|
/* Compute the amount of chars
|
|
* NULL char isn't relaible EOF (MULTI_SZ)
|
|
*/
|
|
Chars = Len / sizeof(TCHAR);
|
|
|
|
i = 0;
|
|
Count = 0;
|
|
Current = Value;
|
|
/* Browse the whole string */
|
|
while (i < Chars)
|
|
{
|
|
/* Jump to the next NULL (end of source) */
|
|
for (j = i; j < Chars && Value[j] != 0; ++j);
|
|
/* Get len & clean path */
|
|
SrcLen = _tcslen(Current);
|
|
SrcFile = BeautifyPath(Current, &SrcLen);
|
|
/* Source file is null - likely the end of the MULTI_SZ, quit */
|
|
if (SrcLen == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* Remember position, jump to the begin of the target */
|
|
i = j;
|
|
++i;
|
|
/* Update position in MULTI_SZ */
|
|
Current = Value + i;
|
|
|
|
/* Jump to the next NULL (end of target) */
|
|
for (j = i; j < Chars && Value[j] != 0; ++j);
|
|
/* Get len & clean path */
|
|
TgtLen = _tcslen(Current);
|
|
Target = BeautifyPath(Current, &TgtLen);
|
|
/* Remember position, jump to the begin of the next source */
|
|
i = j;
|
|
++i;
|
|
Current = Value + i;
|
|
|
|
/* Display source */
|
|
_ftprintf(stdout, _T("Source: %s\n"), SrcFile);
|
|
/* If is accessible? Warn if not */
|
|
if (GetFileAttributes(SrcFile) == INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
_ftprintf(stdout, _T("\t *** Source file lookup error: %d\n"), GetLastError());
|
|
}
|
|
/* And display target - if empty, it's for deletion, mark as it */
|
|
_ftprintf(stdout, _T("Target: %s\n\n"), (_tcslen(Target) != 0 ? Target: _T("DELETE")));
|
|
|
|
/* Remember position and number of entries */
|
|
Current = Value + i;
|
|
++Count;
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
_tmain(int argc, const TCHAR *argv[])
|
|
{
|
|
HKEY hKey;
|
|
LONG Ret;
|
|
DWORD MaxLen, Len, Count, Type;
|
|
PVOID Buffer;
|
|
FILETIME LastModified;
|
|
TCHAR RegistryPath[] = _T("System\\CurrentControlSet\\Control\\Session Manager");
|
|
|
|
/* Open the SMSS registry key */
|
|
Ret = RegOpenKey(HKEY_LOCAL_MACHINE, RegistryPath, &hKey);
|
|
if (Ret != ERROR_SUCCESS)
|
|
{
|
|
_ftprintf(stderr, _T("Failed opening the registry key '%s' (%lx)\n"), RegistryPath, Ret);
|
|
return 1;
|
|
}
|
|
|
|
/* Get last modified date + buffer length we need to allocate */
|
|
Ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &MaxLen, NULL, &LastModified);
|
|
if (Ret != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hKey);
|
|
_ftprintf(stderr, _T("Failed querying information for '%s' (%lx)\n"), RegistryPath, Ret);
|
|
return 1;
|
|
}
|
|
|
|
/* No value, so no operations */
|
|
if (MaxLen == 0)
|
|
{
|
|
RegCloseKey(hKey);
|
|
_ftprintf(stdout, _T("No pending file rename operations registered.\n\n"));
|
|
return 0;
|
|
}
|
|
|
|
/* Allocate memory */
|
|
Buffer = HeapAlloc(GetProcessHeap(), 0, MaxLen);
|
|
if (Buffer == NULL)
|
|
{
|
|
RegCloseKey(hKey);
|
|
_ftprintf(stderr, _T("Failed allocating %d bytes\n"), MaxLen);
|
|
return 1;
|
|
}
|
|
|
|
/* Start with PendingFileRenameOperations */
|
|
Count = 0;
|
|
Len = MaxLen;
|
|
Ret = RegQueryValueEx(hKey, _T("PendingFileRenameOperations"), NULL, &Type, Buffer, &Len);
|
|
if (Ret == ERROR_SUCCESS && Type == REG_MULTI_SZ)
|
|
{
|
|
Count += DisplayPendingOps(Buffer, Len);
|
|
}
|
|
|
|
/* Continue with PendingFileRenameOperations2 - used if PendingFileRenameOperations is too big */
|
|
Len = MaxLen;
|
|
Ret = RegQueryValueEx(hKey, _T("PendingFileRenameOperations2"), NULL, &Type, Buffer, &Len);
|
|
if (Ret == ERROR_SUCCESS && Type == REG_MULTI_SZ)
|
|
{
|
|
Count += DisplayPendingOps(Buffer, Len);
|
|
}
|
|
|
|
/* Release everything */
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
RegCloseKey(hKey);
|
|
|
|
/* If we found entries, display modification date */
|
|
if (Count != 0)
|
|
{
|
|
FILETIME LocalTime;
|
|
SYSTEMTIME SysTime;
|
|
|
|
/* Convert our UTC time to local time, and then to system time to allow easy display */
|
|
if (FileTimeToLocalFileTime(&LastModified, &LocalTime) && FileTimeToSystemTime(&LocalTime, &SysTime))
|
|
{
|
|
_ftprintf(stdout, _T("Time of last update to pending moves key: %02d/%02d/%04d %02d:%02d\n\n"),
|
|
SysTime.wDay, SysTime.wMonth, SysTime.wYear, SysTime.wHour, SysTime.wMinute);
|
|
}
|
|
}
|
|
/* No operations found */
|
|
else
|
|
{
|
|
_ftprintf(stdout, _T("No pending file rename operations registered.\n\n"));
|
|
}
|
|
|
|
return 0;
|
|
}
|