mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[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:
parent
e7fb5e7c33
commit
128ea676bf
4 changed files with 206 additions and 0 deletions
|
@ -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)
|
||||
|
|
5
rosapps/applications/cmdutils/pendmoves/CMakeLists.txt
Normal file
5
rosapps/applications/cmdutils/pendmoves/CMakeLists.txt
Normal 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)
|
196
rosapps/applications/cmdutils/pendmoves/pendmoves.c
Normal file
196
rosapps/applications/cmdutils/pendmoves/pendmoves.c
Normal 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;
|
||||
}
|
4
rosapps/applications/cmdutils/pendmoves/pendmoves.rc
Normal file
4
rosapps/applications/cmdutils/pendmoves/pendmoves.rc
Normal 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>
|
Loading…
Reference in a new issue