[PENDMOVES]

Open source the PendMoves utility from Sysinternals that allow easy display of renaming/deleting operations queued for next reboot.
See: https://docs.microsoft.com/en-us/sysinternals/downloads/pendmoves

svn path=/trunk/; revision=75528
This commit is contained in:
Pierre Schweitzer 2017-08-12 18:17:12 +00:00
parent e7fb5e7c33
commit 128ea676bf
4 changed files with 206 additions and 0 deletions

View file

@ -3,6 +3,7 @@ add_subdirectory(arping)
add_subdirectory(cat)
add_subdirectory(gflags)
add_subdirectory(ntfsinfo)
add_subdirectory(pendmoves)
add_subdirectory(tee)
add_subdirectory(touch)
add_subdirectory(uptime)

View file

@ -0,0 +1,5 @@
list(APPEND SOURCE pendmoves.c pendmoves.rc)
add_executable(pendmoves ${SOURCE})
set_module_type(pendmoves win32cui UNICODE)
add_importlibs(pendmoves msvcrt advapi32 kernel32 ntdll)
add_cd_file(TARGET pendmoves DESTINATION reactos/system32 FOR all)

View file

@ -0,0 +1,196 @@
/*
* 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;
}

View file

@ -0,0 +1,4 @@
#define REACTOS_STR_FILE_DESCRIPTION "Pending Move Operations Information\0"
#define REACTOS_STR_INTERNAL_NAME "pendmoves\0"
#define REACTOS_STR_ORIGINAL_FILENAME "pendmoves.exe\0"
#include <reactos/version.rc>