[PENDMOVES]
[reactos.git] / rosapps / applications / cmdutils / pendmoves / pendmoves.c
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 }