diff --git a/rosapps/applications/cmdutils/CMakeLists.txt b/rosapps/applications/cmdutils/CMakeLists.txt index 51fbfb36bd7..5bdc3316be7 100644 --- a/rosapps/applications/cmdutils/CMakeLists.txt +++ b/rosapps/applications/cmdutils/CMakeLists.txt @@ -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 index 00000000000..7541e1480e6 --- /dev/null +++ b/rosapps/applications/cmdutils/pendmoves/CMakeLists.txt @@ -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 index 00000000000..c7b3be00965 --- /dev/null +++ b/rosapps/applications/cmdutils/pendmoves/pendmoves.c @@ -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 + */ + +#include +#include +#include + +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 index 00000000000..d28a86efe98 --- /dev/null +++ b/rosapps/applications/cmdutils/pendmoves/pendmoves.rc @@ -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