1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS pending moves operations Information tool 4 * FILE: cmdutils/pendmoves/pendmoves.c 5 * PURPOSE: Query information from registry about pending moves 6 * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org> 7 */ 8 9 #include <windows.h> 10 #include <tchar.h> 11 #include <stdio.h> 12 13 static 14 TCHAR * 15 BeautifyPath(TCHAR * Path, DWORD * Len) 16 { 17 DWORD LocalLen = *Len; 18 19 /* If there's a ! marking that existing file can be overwritten, 20 * drop it 21 */ 22 if (LocalLen > 1) 23 { 24 if (Path[0] == _T('!')) 25 { 26 ++Path; 27 --LocalLen; 28 } 29 } 30 31 /* Remove namespace if prefixed */ 32 if (LocalLen > 4) 33 { 34 if (Path[0] == _T('\\') && Path[1] == _T('?') && 35 Path[2] == _T('?') && Path[3] == _T('\\')) 36 { 37 Path += 4; 38 LocalLen -= 4; 39 } 40 } 41 42 /* Return modified string + len */ 43 *Len = LocalLen; 44 return Path; 45 } 46 47 static 48 DWORD 49 DisplayPendingOps(TCHAR * Value, DWORD Len) 50 { 51 DWORD Chars, i, j, Count, SrcLen, TgtLen; 52 TCHAR * SrcFile, * Target, * Current; 53 54 /* Compute the amount of chars 55 * NULL char isn't relaible EOF (MULTI_SZ) 56 */ 57 Chars = Len / sizeof(TCHAR); 58 59 i = 0; 60 Count = 0; 61 Current = Value; 62 /* Browse the whole string */ 63 while (i < Chars) 64 { 65 /* Jump to the next NULL (end of source) */ 66 for (j = i; j < Chars && Value[j] != 0; ++j); 67 /* Get len & clean path */ 68 SrcLen = _tcslen(Current); 69 SrcFile = BeautifyPath(Current, &SrcLen); 70 /* Source file is null - likely the end of the MULTI_SZ, quit */ 71 if (SrcLen == 0) 72 { 73 break; 74 } 75 76 /* Remember position, jump to the begin of the target */ 77 i = j; 78 ++i; 79 /* Update position in MULTI_SZ */ 80 Current = Value + i; 81 82 /* Jump to the next NULL (end of target) */ 83 for (j = i; j < Chars && Value[j] != 0; ++j); 84 /* Get len & clean path */ 85 TgtLen = _tcslen(Current); 86 Target = BeautifyPath(Current, &TgtLen); 87 /* Remember position, jump to the begin of the next source */ 88 i = j; 89 ++i; 90 Current = Value + i; 91 92 /* Display source */ 93 _ftprintf(stdout, _T("Source: %s\n"), SrcFile); 94 /* If is accessible? Warn if not */ 95 if (GetFileAttributes(SrcFile) == INVALID_FILE_ATTRIBUTES) 96 { 97 _ftprintf(stdout, _T("\t *** Source file lookup error: %d\n"), GetLastError()); 98 } 99 /* And display target - if empty, it's for deletion, mark as it */ 100 _ftprintf(stdout, _T("Target: %s\n\n"), (_tcslen(Target) != 0 ? Target: _T("DELETE"))); 101 102 /* Remember position and number of entries */ 103 Current = Value + i; 104 ++Count; 105 } 106 107 return Count; 108 } 109 110 int 111 __cdecl 112 _tmain(int argc, const TCHAR *argv[]) 113 { 114 HKEY hKey; 115 LONG Ret; 116 DWORD MaxLen, Len, Count, Type; 117 PVOID Buffer; 118 FILETIME LastModified; 119 TCHAR RegistryPath[] = _T("System\\CurrentControlSet\\Control\\Session Manager"); 120 121 /* Open the SMSS registry key */ 122 Ret = RegOpenKey(HKEY_LOCAL_MACHINE, RegistryPath, &hKey); 123 if (Ret != ERROR_SUCCESS) 124 { 125 _ftprintf(stderr, _T("Failed opening the registry key '%s' (%lx)\n"), RegistryPath, Ret); 126 return 1; 127 } 128 129 /* Get last modified date + buffer length we need to allocate */ 130 Ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &MaxLen, NULL, &LastModified); 131 if (Ret != ERROR_SUCCESS) 132 { 133 RegCloseKey(hKey); 134 _ftprintf(stderr, _T("Failed querying information for '%s' (%lx)\n"), RegistryPath, Ret); 135 return 1; 136 } 137 138 /* No value, so no operations */ 139 if (MaxLen == 0) 140 { 141 RegCloseKey(hKey); 142 _ftprintf(stdout, _T("No pending file rename operations registered.\n\n")); 143 return 0; 144 } 145 146 /* Allocate memory */ 147 Buffer = HeapAlloc(GetProcessHeap(), 0, MaxLen); 148 if (Buffer == NULL) 149 { 150 RegCloseKey(hKey); 151 _ftprintf(stderr, _T("Failed allocating %d bytes\n"), MaxLen); 152 return 1; 153 } 154 155 /* Start with PendingFileRenameOperations */ 156 Count = 0; 157 Len = MaxLen; 158 Ret = RegQueryValueEx(hKey, _T("PendingFileRenameOperations"), NULL, &Type, Buffer, &Len); 159 if (Ret == ERROR_SUCCESS && Type == REG_MULTI_SZ) 160 { 161 Count += DisplayPendingOps(Buffer, Len); 162 } 163 164 /* Continue with PendingFileRenameOperations2 - used if PendingFileRenameOperations is too big */ 165 Len = MaxLen; 166 Ret = RegQueryValueEx(hKey, _T("PendingFileRenameOperations2"), NULL, &Type, Buffer, &Len); 167 if (Ret == ERROR_SUCCESS && Type == REG_MULTI_SZ) 168 { 169 Count += DisplayPendingOps(Buffer, Len); 170 } 171 172 /* Release everything */ 173 HeapFree(GetProcessHeap(), 0, Buffer); 174 RegCloseKey(hKey); 175 176 /* If we found entries, display modification date */ 177 if (Count != 0) 178 { 179 FILETIME LocalTime; 180 SYSTEMTIME SysTime; 181 182 /* Convert our UTC time to local time, and then to system time to allow easy display */ 183 if (FileTimeToLocalFileTime(&LastModified, &LocalTime) && FileTimeToSystemTime(&LocalTime, &SysTime)) 184 { 185 _ftprintf(stdout, _T("Time of last update to pending moves key: %02d/%02d/%04d %02d:%02d\n\n"), 186 SysTime.wDay, SysTime.wMonth, SysTime.wYear, SysTime.wHour, SysTime.wMinute); 187 } 188 } 189 /* No operations found */ 190 else 191 { 192 _ftprintf(stdout, _T("No pending file rename operations registered.\n\n")); 193 } 194 195 return 0; 196 } 197