Merge to trunk head (r46631)
[reactos.git] / base / system / smss / initmv.c
1 /*
2 * PROJECT: ReactOS Session Manager
3 * LICENSE: GPL v2 or later - See COPYING in the top level directory
4 * FILE: base/system/smss/initmv.c
5 * PURPOSE: Process the file rename list.
6 * PROGRAMMERS: ReactOS Development Team
7 */
8
9 /* INCLUDES ******************************************************************/
10 #include "smss.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 /* FUNCTIONS *****************************************************************/
17
18 /*++
19 * @name SmpDeleteFile
20 *
21 * The SmpDeleteFile function deletes a specify file.
22 *
23 * @param lpFileName
24 * the name of a file which should be deleted
25 *
26 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
27 * othwerwise.
28 *
29 * @remarks
30 * This function is called by SmpMoveFilesQueryRoutine().
31 *
32 *
33 *--*/
34 NTSTATUS
35 SmpDeleteFile( IN LPCWSTR lpFileName )
36 {
37 FILE_DISPOSITION_INFORMATION FileDispInfo;
38 OBJECT_ATTRIBUTES ObjectAttributes;
39 IO_STATUS_BLOCK IoStatusBlock;
40 UNICODE_STRING FileNameU;
41 HANDLE FileHandle;
42 NTSTATUS Status;
43
44 DPRINT("SmpDeleteFile ( %S )\n", lpFileName);
45
46 if( !lpFileName )
47 return (STATUS_INVALID_PARAMETER);
48
49 RtlInitUnicodeString(&FileNameU, lpFileName);
50
51 InitializeObjectAttributes(&ObjectAttributes,
52 &FileNameU,
53 OBJ_CASE_INSENSITIVE,
54 NULL,
55 NULL);
56
57 Status = NtCreateFile (&FileHandle,
58 DELETE,
59 &ObjectAttributes,
60 &IoStatusBlock,
61 NULL,
62 FILE_ATTRIBUTE_NORMAL,
63 FILE_SHARE_READ | FILE_SHARE_WRITE,
64 FILE_OPEN,
65 FILE_SYNCHRONOUS_IO_NONALERT,
66 NULL,
67 0);
68
69 if( !NT_SUCCESS(Status) ) {
70 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
71 return (Status);
72 }
73
74 FileDispInfo.DeleteFile = TRUE;
75
76 Status = NtSetInformationFile(
77 FileHandle,
78 &IoStatusBlock,
79 &FileDispInfo,
80 sizeof(FILE_DISPOSITION_INFORMATION),
81 FileDispositionInformation );
82
83 NtClose(FileHandle);
84
85 return (Status);
86 }
87
88
89 /*++
90 * @name SmpMoveFile
91 *
92 * The SmpMoveFile function deletes a specify file.
93 *
94 * @param lpExistingFileName
95 * the name of an existing file which should be removed
96 *
97 * @param lpNewFileName
98 * a new name of an existing file.
99 *
100 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
101 * othwerwise.
102 *
103 * @remarks
104 * This function called from the SmpMoveFilesQueryRoutine function.
105 *
106 *
107 *--*/
108 NTSTATUS
109 SmpMoveFile( IN LPCWSTR lpExistingFileName,
110 IN LPCWSTR lpNewFileName
111 )
112 {
113 PFILE_RENAME_INFORMATION FileRenameInfo;
114 OBJECT_ATTRIBUTES ObjectAttributes;
115 IO_STATUS_BLOCK IoStatusBlock;
116 UNICODE_STRING ExistingFileNameU;
117 HANDLE FileHandle;
118 DWORD FileNameSize;
119 BOOLEAN ReplaceIfExists;
120 NTSTATUS Status;
121
122 if( !lpExistingFileName || !lpNewFileName )
123 return (STATUS_INVALID_PARAMETER);
124
125 DPRINT("SmpMoveFile (%S, %S)\n", lpExistingFileName, lpNewFileName);
126
127 RtlInitUnicodeString(&ExistingFileNameU, lpExistingFileName);
128
129 InitializeObjectAttributes(&ObjectAttributes,
130 &ExistingFileNameU,
131 OBJ_CASE_INSENSITIVE,
132 NULL,
133 NULL);
134
135 Status = NtCreateFile (&FileHandle,
136 FILE_ALL_ACCESS,
137 &ObjectAttributes,
138 &IoStatusBlock,
139 NULL,
140 FILE_ATTRIBUTE_NORMAL,
141 FILE_SHARE_READ | FILE_SHARE_WRITE,
142 FILE_OPEN,
143 FILE_SYNCHRONOUS_IO_NONALERT,
144 NULL,
145 0);
146
147 if( !NT_SUCCESS(Status) ) {
148 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
149 return (Status);
150 }
151
152 FileNameSize = wcslen(lpNewFileName)*sizeof(*lpNewFileName);
153 FileRenameInfo = RtlAllocateHeap(
154 RtlGetProcessHeap(),
155 HEAP_ZERO_MEMORY,
156 sizeof(FILE_RENAME_INFORMATION)+FileNameSize);
157 if( !FileRenameInfo ) {
158 DPRINT("RtlAllocateHeap failed\n");
159 NtClose(FileHandle);
160 return (STATUS_NO_MEMORY);
161 }
162
163 if( L'!' == *lpNewFileName ) {
164 lpNewFileName++;
165 FileNameSize -= sizeof(*lpNewFileName);
166 ReplaceIfExists = TRUE;
167 }
168 else {
169 ReplaceIfExists = FALSE;
170 }
171
172 FileRenameInfo->RootDirectory = NULL;
173 FileRenameInfo->ReplaceIfExists = ReplaceIfExists;
174 FileRenameInfo->FileNameLength = FileNameSize;
175 RtlCopyMemory(FileRenameInfo->FileName, lpNewFileName, FileNameSize);
176
177 Status = NtSetInformationFile(
178 FileHandle,
179 &IoStatusBlock,
180 FileRenameInfo,
181 sizeof(FILE_RENAME_INFORMATION)+FileNameSize,
182 FileRenameInformation );
183
184 RtlFreeHeap(RtlGetProcessHeap(), 0, FileRenameInfo);
185
186 /* FIXME: After the FileRenameInformation parameter will be implemented into the fs driver
187 the following code can be removed */
188 if( STATUS_NOT_IMPLEMENTED == Status )
189 {
190 HANDLE FileHandleNew;
191 UNICODE_STRING NewFileNameU;
192 FILE_BASIC_INFORMATION FileBasicInfo;
193 UCHAR *lpBuffer = NULL;
194 SIZE_T RegionSize = 0x10000;
195 LARGE_INTEGER BytesCopied;
196 BOOL EndOfFileFound;
197
198 Status = NtQueryInformationFile(
199 FileHandle,
200 &IoStatusBlock,
201 &FileBasicInfo,
202 sizeof(FILE_BASIC_INFORMATION),
203 FileBasicInformation);
204 if( !NT_SUCCESS(Status) ) {
205 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
206 NtClose(FileHandle);
207 return (Status);
208 }
209
210 RtlInitUnicodeString(&NewFileNameU, lpNewFileName);
211
212 InitializeObjectAttributes(&ObjectAttributes,
213 &NewFileNameU,
214 OBJ_CASE_INSENSITIVE,
215 NULL,
216 NULL);
217
218 Status = NtCreateFile (&FileHandleNew,
219 FILE_ALL_ACCESS,
220 &ObjectAttributes,
221 &IoStatusBlock,
222 NULL,
223 FILE_ATTRIBUTE_NORMAL,
224 FILE_SHARE_READ | FILE_SHARE_WRITE,
225 ReplaceIfExists ? FILE_OVERWRITE_IF : FILE_CREATE,
226 FILE_SYNCHRONOUS_IO_NONALERT,
227 NULL,
228 0);
229
230 if( !NT_SUCCESS(Status) ) {
231 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
232 NtClose(FileHandle);
233 return (Status);
234 }
235
236 Status = NtAllocateVirtualMemory(
237 NtCurrentProcess(),
238 (PVOID *)&lpBuffer,
239 2,
240 &RegionSize,
241 MEM_RESERVE | MEM_COMMIT,
242 PAGE_READWRITE);
243 if( !NT_SUCCESS(Status) ) {
244 DPRINT("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
245 NtClose(FileHandle);
246 SmpDeleteFile(lpNewFileName);
247 return (Status);
248 }
249 BytesCopied.QuadPart = 0;
250 EndOfFileFound = FALSE;
251 while( !EndOfFileFound
252 && NT_SUCCESS(Status) )
253 {
254 Status = NtReadFile(FileHandle,
255 NULL,
256 NULL,
257 NULL,
258 &IoStatusBlock,
259 lpBuffer,
260 RegionSize,
261 NULL,
262 NULL);
263 if( NT_SUCCESS(Status) ) {
264 Status = NtWriteFile(FileHandleNew,
265 NULL,
266 NULL,
267 NULL,
268 &IoStatusBlock,
269 lpBuffer,
270 IoStatusBlock.Information,
271 NULL,
272 NULL);
273 if( NT_SUCCESS(Status) ) {
274 BytesCopied.QuadPart += IoStatusBlock.Information;
275 }
276 else {
277 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
278 }
279 }
280 else {
281 if( STATUS_END_OF_FILE == Status ) {
282 EndOfFileFound = TRUE;
283 Status = STATUS_SUCCESS;
284 }
285 else {
286 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
287 }
288 }
289 }
290
291 NtFreeVirtualMemory(NtCurrentProcess(),
292 (PVOID *)&lpBuffer,
293 &RegionSize,
294 MEM_RELEASE);
295
296 Status = NtQueryInformationFile(
297 FileHandleNew,
298 &IoStatusBlock,
299 &FileBasicInfo,
300 sizeof(FILE_BASIC_INFORMATION),
301 FileBasicInformation);
302 if( !NT_SUCCESS(Status) ) {
303 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
304 }
305
306 Status = NtSetInformationFile(FileHandleNew,
307 &IoStatusBlock,
308 &FileBasicInfo,
309 sizeof(FILE_BASIC_INFORMATION),
310 FileBasicInformation);
311 if( !NT_SUCCESS(Status) ) {
312 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
313 }
314 NtClose(FileHandleNew);
315 NtClose(FileHandle);
316
317 SmpDeleteFile(lpExistingFileName);
318
319 return (Status);
320 }
321
322 NtClose(FileHandle);
323
324 return (Status);
325 }
326
327
328 /*++
329 * @name SmpMoveFilesQueryRoutine
330 *
331 * The SmpMoveFilesQueryRoutine function processes registry entries.
332 *
333 * @param ValueName
334 * The name of the value.
335 *
336 * @param ValueType
337 * The type of the value.
338 *
339 * @param ValueData
340 * The null-terminated data for the value.
341 *
342 * @param ValueLength
343 * The length of ValueData.
344 *
345 * @param Context
346 * NULL
347 *
348 * @param EntryContext
349 * NULL
350 *
351 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
352 * othwerwise.
353 *
354 * @remarks
355 *
356 *
357 *
358 *--*/
359 static NTSTATUS NTAPI
360 SmpMoveFilesQueryRoutine(IN PWSTR ValueName,
361 IN ULONG ValueType,
362 IN PVOID ValueData,
363 IN ULONG ValueLength,
364 IN PVOID Context,
365 IN PVOID EntryContext)
366 {
367 NTSTATUS Status;
368 static LPWSTR FistFileName = NULL;
369
370 DPRINT("SmpMoveFilesQueryRoutine() called \n");
371 DPRINT("ValueData = %S \n", (PWSTR) ValueData);
372
373 if( !FistFileName )
374 {
375 /* save a first file name */
376 FistFileName = ValueData;
377 Status = STATUS_SUCCESS;
378 }
379 else
380 {
381 if( 0 == *((LPWSTR)ValueData) ) {
382 /* delete if second file name is absent */
383 Status = SmpDeleteFile( FistFileName );
384 } else {
385 /* remove a file */
386 Status = SmpMoveFile( FistFileName, (LPCWSTR)ValueData );
387 }
388 FistFileName = NULL;
389 }
390
391 return Status;
392 }
393
394
395 /*++
396 * @name SmProcessFileRenameList
397 * @implemented
398 *
399 * The SmProcessFileRenameList function moves or deletes files thats have been added to the specify registry key for delayed moving.
400 *
401 * @param VOID
402 *
403 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
404 * othwerwise.
405 *
406 * @remarks
407 * This function reads the following registry value:
408 * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations
409 * This registry value is of type REG_MULTI_SZ. The each operation is specifed as two file names.
410 * A first name is a source file, a second name is a destination file.
411 * In the case of deleting operation a second file name must be the empty string.
412 * For exapmle:
413 * szxSrcFile\0szxDestFile\0\0 <-- the szxSrcFile file will be renamed to the szxDestFile file
414 * szxSomeFile\0\0\0 <-- the szxSomeFile file will be removed
415 * After it will be done, the registry value will be deleted.
416 *
417 *
418 *--*/
419 NTSTATUS
420 SmProcessFileRenameList( VOID )
421 {
422 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
423 NTSTATUS Status;
424
425 DPRINT("SmProcessFileRenameList() called\n");
426
427 RtlZeroMemory( &QueryTable, sizeof(QueryTable) );
428 QueryTable[0].Name = L"PendingFileRenameOperations";
429 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DELETE;
430 QueryTable[0].DefaultType = REG_NONE;
431 QueryTable[0].QueryRoutine = SmpMoveFilesQueryRoutine;
432
433 Status = RtlQueryRegistryValues(
434 RTL_REGISTRY_CONTROL,
435 L"\\Session Manager",
436 QueryTable,
437 NULL,
438 NULL);
439
440 if( !NT_SUCCESS(Status) ) {
441 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
442 }
443
444 /* FIXME: RtlQueryRegistryValues can return an error status if the PendingFileRenameOperations value
445 does not exist, in this case smss hungs, therefore we always return STATUS_SUCCESS */
446 return (STATUS_SUCCESS);
447 }
448
449 /* EOF */