[PENDMOVES]
authorPierre Schweitzer <pierre@reactos.org>
Sat, 12 Aug 2017 18:17:12 +0000 (18:17 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Sat, 12 Aug 2017 18:17:12 +0000 (18:17 +0000)
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

rosapps/applications/cmdutils/CMakeLists.txt
rosapps/applications/cmdutils/pendmoves/CMakeLists.txt [new file with mode: 0644]
rosapps/applications/cmdutils/pendmoves/pendmoves.c [new file with mode: 0644]
rosapps/applications/cmdutils/pendmoves/pendmoves.rc [new file with mode: 0644]

index 51fbfb3..5bdc331 100644 (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)
diff --git a/rosapps/applications/cmdutils/pendmoves/CMakeLists.txt b/rosapps/applications/cmdutils/pendmoves/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7541e14
--- /dev/null
@@ -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)
diff --git a/rosapps/applications/cmdutils/pendmoves/pendmoves.c b/rosapps/applications/cmdutils/pendmoves/pendmoves.c
new file mode 100644 (file)
index 0000000..c7b3be0
--- /dev/null
@@ -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;
+}
diff --git a/rosapps/applications/cmdutils/pendmoves/pendmoves.rc b/rosapps/applications/cmdutils/pendmoves/pendmoves.rc
new file mode 100644 (file)
index 0000000..d28a86e
--- /dev/null
@@ -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>