Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

748 lines
25 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. fileren.c
  5. Abstract:
  6. This program is used to help make GUI Setup restartable,
  7. if setup was started in restartable mode.
  8. Author:
  9. Souren Aghajanyan (sourenag) July 2001
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include "msg.h"
  15. #include "psp.h"
  16. #define MAX_DOS_PATH_IN_NT_PATH 260
  17. #define TXT_FILE_UNICODE_SIGN 0xfeff
  18. #define SIZE_ULONG64(x, y) (((ULONGLONG)x)-((ULONGLONG)y))
  19. const PCWSTR UndoFilePath = L"\\SystemRoot\\System32\\UNDO_GUIMODE.TXT";
  20. typedef struct _SP_FILE_OPERATION {
  21. LIST_ENTRY Entry;
  22. UNICODE_STRING Name;
  23. UNICODE_STRING Value;
  24. } SP_FILE_OPERATION, *PSP_FILE_OPERATION;
  25. BOOLEAN
  26. SpRemoveFileObject_U(
  27. IN PUNICODE_STRING FileObjectPath
  28. );
  29. NTSTATUS
  30. SpSaveFileOperation(
  31. IN OUT PLIST_ENTRY ListHead,
  32. IN PCWSTR Name,
  33. IN PCWSTR Value OPTIONAL
  34. )
  35. {
  36. PSP_FILE_OPERATION p = NULL;
  37. UNICODE_STRING UnicodeName;
  38. UNICODE_STRING UnicodeValue;
  39. RtlInitUnicodeString( &UnicodeName, Name );
  40. RtlInitUnicodeString( &UnicodeValue, Value );
  41. p = (PSP_FILE_OPERATION)MALLOC(sizeof(*p) + UnicodeName.MaximumLength);
  42. if(!p){
  43. return STATUS_NO_MEMORY;
  44. }
  45. InitializeListHead(&p->Entry);
  46. p->Name.Buffer = (PWSTR)(p+1);
  47. p->Name.Length = UnicodeName.Length;
  48. p->Name.MaximumLength = UnicodeName.MaximumLength;
  49. RtlMoveMemory(p->Name.Buffer,
  50. UnicodeName.Buffer,
  51. UnicodeName.MaximumLength);
  52. p->Value.Buffer = NULL;
  53. InsertHeadList( ListHead, &p->Entry );
  54. if (p->Value.Buffer != NULL) {
  55. FREE(p->Value.Buffer);
  56. }
  57. if(ARGUMENT_PRESENT(Value)){
  58. p->Value.Buffer = (PWSTR)MALLOC(UnicodeValue.MaximumLength);
  59. if(!p->Value.Buffer){
  60. RemoveEntryList(&p->Entry);
  61. FREE(p);
  62. return STATUS_NO_MEMORY;
  63. }
  64. p->Value.Length = UnicodeValue.Length;
  65. p->Value.MaximumLength = UnicodeValue.MaximumLength;
  66. RtlMoveMemory(p->Value.Buffer,
  67. UnicodeValue.Buffer,
  68. UnicodeValue.MaximumLength);
  69. }
  70. else {
  71. RtlInitUnicodeString(&p->Value, NULL);
  72. }
  73. return STATUS_SUCCESS;
  74. }
  75. VOID
  76. SpProcessFileRenames(
  77. IN PLIST_ENTRY pFileRenameList
  78. )
  79. {
  80. NTSTATUS Status;
  81. NTSTATUS OpenStatus;
  82. PLIST_ENTRY Next;
  83. PLIST_ENTRY thisEntry;
  84. PSP_FILE_OPERATION p;
  85. OBJECT_ATTRIBUTES ObjectAttributes;
  86. IO_STATUS_BLOCK IoStatusBlock;
  87. HANDLE OldFileHandle,SetAttributesHandle;
  88. PFILE_RENAME_INFORMATION RenameInformation;
  89. FILE_INFORMATION_CLASS SetInfoClass;
  90. FILE_BASIC_INFORMATION BasicInfo;
  91. ULONG SetInfoLength;
  92. PVOID SetInfoBuffer;
  93. PWSTR s;
  94. BOOLEAN WasEnabled;
  95. UNICODE_STRING NewName;
  96. int pass;
  97. Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
  98. TRUE,
  99. FALSE,
  100. &WasEnabled);
  101. if(!NT_SUCCESS(Status)){
  102. WasEnabled = TRUE;
  103. }
  104. //
  105. // Process the list of file rename operations.
  106. //
  107. for (pass = 0 ; pass < 2 ; pass++) {
  108. thisEntry = pFileRenameList->Flink;
  109. while (thisEntry != pFileRenameList) {
  110. p = CONTAINING_RECORD(thisEntry, SP_FILE_OPERATION, Entry);
  111. thisEntry = thisEntry->Flink;
  112. DbgPrint("SPRESTRT: FileRename( [%wZ] => [%wZ] )\n", &p->Name, &p->Value);
  113. //
  114. // We left all syntax and fuctionality SMSS FileRename supports.
  115. //
  116. Status = 0;
  117. if(p->Value.Length){
  118. if (pass == 0) {
  119. //
  120. // We have target path and it means rename operation
  121. //
  122. if(p->Name.Buffer[0] == '@'){
  123. p->Name.Buffer += 1;
  124. p->Name.Length -= sizeof(WCHAR);
  125. }
  126. InitializeObjectAttributes(&ObjectAttributes,
  127. &p->Name,
  128. OBJ_CASE_INSENSITIVE,
  129. NULL,
  130. NULL);
  131. Status = NtOpenFile(&OldFileHandle,
  132. (ACCESS_MASK)DELETE | SYNCHRONIZE,
  133. &ObjectAttributes,
  134. &IoStatusBlock,
  135. FILE_SHARE_READ | FILE_SHARE_WRITE,
  136. FILE_SYNCHRONOUS_IO_NONALERT);
  137. if(NT_SUCCESS(Status)){
  138. SetInfoClass = FileRenameInformation;
  139. SetInfoLength = p->Value.Length + sizeof(*RenameInformation);
  140. s = p->Value.Buffer;
  141. if (*s == L'!' || *s == L'@') {
  142. s++;
  143. SetInfoLength -= sizeof( UNICODE_NULL );
  144. }
  145. SetInfoBuffer = MALLOC(SetInfoLength);
  146. if (SetInfoBuffer) {
  147. RenameInformation = (FILE_RENAME_INFORMATION *)SetInfoBuffer;
  148. RenameInformation->ReplaceIfExists = (BOOLEAN)(s != p->Value.Buffer);
  149. RenameInformation->RootDirectory = NULL;
  150. RenameInformation->FileNameLength = SetInfoLength - sizeof( *RenameInformation );
  151. RtlMoveMemory(RenameInformation->FileName,
  152. s,
  153. RenameInformation->FileNameLength);
  154. }
  155. else {
  156. Status = STATUS_NO_MEMORY;
  157. }
  158. if(NT_SUCCESS(Status)){
  159. Status = NtSetInformationFile(OldFileHandle,
  160. &IoStatusBlock,
  161. SetInfoBuffer,
  162. SetInfoLength,
  163. SetInfoClass);
  164. if(!NT_SUCCESS( Status ) &&
  165. Status == STATUS_OBJECT_NAME_COLLISION &&
  166. RenameInformation->ReplaceIfExists){
  167. KdPrintEx((DPFLTR_SETUP_ID,
  168. DPFLTR_WARNING_LEVEL,
  169. "\nSPRESTRT: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
  170. &p->Name,
  171. &p->Value,
  172. Status));
  173. //
  174. // A rename was attempted, but the source existing file is readonly.
  175. // this is a problem because folks that use movefileex to do delayed
  176. // renames expect this to work and can leave a machine unbootable if
  177. // the rename fails
  178. //
  179. //
  180. // Open the file for Write Attributes access
  181. //
  182. NewName.Length = p->Value.Length - sizeof(L'!');
  183. NewName.MaximumLength = p->Value.MaximumLength - sizeof(L'!');
  184. NewName.Buffer = s;
  185. InitializeObjectAttributes(&ObjectAttributes,
  186. &NewName,
  187. OBJ_CASE_INSENSITIVE,
  188. NULL,
  189. NULL);
  190. OpenStatus = NtOpenFile(&SetAttributesHandle,
  191. (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  192. &ObjectAttributes,
  193. &IoStatusBlock,
  194. FILE_SHARE_READ | FILE_SHARE_WRITE,
  195. FILE_SYNCHRONOUS_IO_NONALERT);
  196. if(NT_SUCCESS(OpenStatus)){
  197. KdPrintEx((DPFLTR_SETUP_ID,
  198. DPFLTR_INFO_LEVEL,
  199. " SPRESTRT: Open Existing Success\n"));
  200. RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
  201. BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  202. OpenStatus = NtSetInformationFile(SetAttributesHandle,
  203. &IoStatusBlock,
  204. &BasicInfo,
  205. sizeof(BasicInfo),
  206. FileBasicInformation);
  207. NtClose(SetAttributesHandle);
  208. if(NT_SUCCESS(OpenStatus)){
  209. KdPrintEx((DPFLTR_SETUP_ID,
  210. DPFLTR_INFO_LEVEL,
  211. " SPRESTRT: Set To NORMAL OK\n"));
  212. Status = NtSetInformationFile(OldFileHandle,
  213. &IoStatusBlock,
  214. SetInfoBuffer,
  215. SetInfoLength,
  216. SetInfoClass);
  217. if(NT_SUCCESS(Status)){
  218. KdPrintEx((DPFLTR_SETUP_ID,
  219. DPFLTR_INFO_LEVEL,
  220. " SPRESTRT: Re-Rename Worked OK\n"));
  221. }
  222. else {
  223. KdPrintEx((DPFLTR_SETUP_ID,
  224. DPFLTR_WARNING_LEVEL,
  225. " SPRESTRT: Re-Rename Failed - Status == %x\n",
  226. Status));
  227. }
  228. }
  229. else {
  230. KdPrintEx((DPFLTR_SETUP_ID,
  231. DPFLTR_WARNING_LEVEL,
  232. " SPRESTRT: Set To NORMAL Failed - Status == %x\n",
  233. OpenStatus));
  234. }
  235. }
  236. else {
  237. KdPrintEx((DPFLTR_SETUP_ID,
  238. DPFLTR_WARNING_LEVEL,
  239. " SPRESTRT: Open Existing file Failed - Status == %x\n",
  240. OpenStatus));
  241. }
  242. }
  243. }
  244. NtClose(OldFileHandle);
  245. }
  246. }
  247. }
  248. else if (pass == 1) {
  249. //
  250. // p->Value.Length == NULL means delete operation.
  251. //
  252. Status = SpRemoveFileObject_U(&p->Name)? STATUS_SUCCESS: STATUS_ACCESS_DENIED;
  253. }
  254. if (!NT_SUCCESS( Status )) {
  255. KdPrintEx((DPFLTR_SETUP_ID,
  256. DPFLTR_WARNING_LEVEL,
  257. "SPRESTRT: %wZ => %wZ failed - Status == %x\n",
  258. &p->Name,
  259. &p->Value,
  260. Status));
  261. } else if (pass == 1 && p->Value.Length == 0) {
  262. KdPrintEx((DPFLTR_SETUP_ID,
  263. DPFLTR_INFO_LEVEL,
  264. "SPRESTRT: %wZ (deleted)\n",
  265. &p->Name));
  266. } else if (pass == 0) {
  267. KdPrintEx((DPFLTR_SETUP_ID,
  268. DPFLTR_INFO_LEVEL,
  269. "SPRESTRT: %wZ (renamed to) %wZ\n",
  270. &p->Name,
  271. &p->Value));
  272. }
  273. if (pass == 1) {
  274. FREE(p);
  275. }
  276. }
  277. }
  278. if (!WasEnabled) {
  279. Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
  280. FALSE,
  281. FALSE,
  282. &WasEnabled);
  283. }
  284. return;
  285. }
  286. BOOLEAN
  287. SpRemoveFile(
  288. PCWSTR pFilePath
  289. )
  290. {
  291. NTSTATUS Status;
  292. HANDLE FileHandle;
  293. UNICODE_STRING UnicodeString;
  294. OBJECT_ATTRIBUTES ObjectAttributes;
  295. IO_STATUS_BLOCK IoStatusBlock;
  296. FILE_DISPOSITION_INFORMATION Disposition;
  297. FILE_BASIC_INFORMATION BasicInfo;
  298. BOOLEAN bResult = FALSE;
  299. INIT_OBJA(&ObjectAttributes, &UnicodeString, pFilePath);
  300. Status = NtOpenFile(&FileHandle,
  301. FILE_WRITE_ATTRIBUTES | DELETE,
  302. &ObjectAttributes,
  303. &IoStatusBlock,
  304. FILE_SHARE_VALID_FLAGS,
  305. FILE_OPEN_FOR_BACKUP_INTENT);
  306. if(NT_SUCCESS(Status)) {
  307. //
  308. // Change attribute to FILE_ATTRIBUTE_NORMAL.
  309. //
  310. RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
  311. BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  312. NtSetInformationFile(FileHandle,
  313. &IoStatusBlock,
  314. &BasicInfo,
  315. sizeof(BasicInfo),
  316. FileBasicInformation);
  317. //
  318. // Perform delete operation.
  319. //
  320. Disposition.DeleteFile = TRUE;
  321. Status = NtSetInformationFile(FileHandle,
  322. &IoStatusBlock,
  323. &Disposition,
  324. sizeof(Disposition),
  325. FileDispositionInformation);
  326. if(!NT_SUCCESS(Status)) {
  327. KdPrintEx((DPFLTR_SETUP_ID,
  328. DPFLTR_WARNING_LEVEL,
  329. "RestartSetup: Unable to delete %ws (%lx)\n",
  330. pFilePath, Status));
  331. }
  332. else {
  333. bResult = TRUE;
  334. }
  335. NtClose(FileHandle);
  336. }
  337. return bResult;
  338. }
  339. BOOLEAN
  340. SpRemoveDir(
  341. PWSTR pFilePath
  342. )
  343. {
  344. NTSTATUS Status;
  345. HANDLE DirectoryHandle;
  346. UNICODE_STRING UnicodeString;
  347. OBJECT_ATTRIBUTES ObjectAttributes;
  348. IO_STATUS_BLOCK IoStatusBlock;
  349. LONGLONG Buffer[2048/8];
  350. BOOLEAN FirstQuery;
  351. PFILE_DIRECTORY_INFORMATION FileInfo;
  352. ULONG LengthChars;
  353. BOOLEAN AnyErrors;
  354. ULONG indexEndOfRootPath;
  355. if(!pFilePath){
  356. ASSERT(FALSE);
  357. return FALSE;
  358. }
  359. indexEndOfRootPath = wcslen(pFilePath);
  360. ASSERT(indexEndOfRootPath);
  361. INIT_OBJA(&ObjectAttributes, &UnicodeString, pFilePath);
  362. Status = NtOpenFile(&DirectoryHandle,
  363. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  364. &ObjectAttributes,
  365. &IoStatusBlock,
  366. FILE_SHARE_READ | FILE_SHARE_WRITE,
  367. FILE_DIRECTORY_FILE |
  368. FILE_SYNCHRONOUS_IO_NONALERT |
  369. FILE_OPEN_FOR_BACKUP_INTENT
  370. );
  371. if(!NT_SUCCESS(Status)){
  372. KdPrintEx((DPFLTR_SETUP_ID,
  373. DPFLTR_WARNING_LEVEL,
  374. "RestartSetup: unable to open system32\\config for list access (%lx)\n",
  375. Status));
  376. return(FALSE);
  377. }
  378. FirstQuery = TRUE;
  379. FileInfo = (PFILE_DIRECTORY_INFORMATION)Buffer;
  380. AnyErrors = FALSE;
  381. do {
  382. Status = NtQueryDirectoryFile(DirectoryHandle,
  383. NULL, // no event to signal
  384. NULL, // no apc routine
  385. NULL, // no apc context
  386. &IoStatusBlock,
  387. Buffer,
  388. sizeof(Buffer)-sizeof(WCHAR), // leave room for terminating nul
  389. FileDirectoryInformation,
  390. TRUE, // want single entry
  391. NULL, // get 'em all
  392. FirstQuery);
  393. if(NT_SUCCESS(Status)){
  394. LengthChars = FileInfo->FileNameLength / sizeof(WCHAR);
  395. FileInfo->FileName[LengthChars] = 0;
  396. if(wcscmp(FileInfo->FileName, L".") &&
  397. wcscmp(FileInfo->FileName, L"..")){
  398. wcscat(pFilePath, L"\\");
  399. wcscat(pFilePath, FileInfo->FileName);
  400. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  401. SpRemoveDir(pFilePath);
  402. } else {
  403. SpRemoveFile(pFilePath);
  404. }
  405. pFilePath[indexEndOfRootPath] = '\0';
  406. }
  407. FirstQuery = FALSE;
  408. }
  409. } while(NT_SUCCESS(Status));
  410. //
  411. // Check for normal loop termination.
  412. //
  413. if(Status == STATUS_NO_MORE_FILES) {
  414. Status = STATUS_SUCCESS;
  415. }
  416. //
  417. // Even if we got errors, try to keep going.
  418. //
  419. if(!NT_SUCCESS(Status)) {
  420. AnyErrors = TRUE;
  421. KdPrintEx((DPFLTR_SETUP_ID,
  422. DPFLTR_WARNING_LEVEL,
  423. "RestartSetup: Status %lx enumerating files\n",
  424. Status));
  425. }
  426. NtClose(DirectoryHandle);
  427. SpRemoveFile(pFilePath);
  428. return ((BOOLEAN)!AnyErrors);
  429. }
  430. BOOLEAN
  431. SpRemoveFileObject(
  432. IN PCWSTR pFileObjectPath
  433. )
  434. {
  435. NTSTATUS Status;
  436. HANDLE FileHandle;
  437. UNICODE_STRING UnicodeString;
  438. OBJECT_ATTRIBUTES ObjectAttributes;
  439. IO_STATUS_BLOCK IoStatusBlock;
  440. FILE_BASIC_INFORMATION BasicInfo;
  441. ULONG logestNtPath;
  442. PWSTR pFilePathToDelete;
  443. BOOLEAN bResult = FALSE;
  444. INIT_OBJA(&ObjectAttributes, &UnicodeString, pFileObjectPath);
  445. Status = NtOpenFile(&FileHandle,
  446. SYNCHRONIZE | GENERIC_READ,
  447. &ObjectAttributes,
  448. &IoStatusBlock,
  449. FILE_SHARE_READ,
  450. 0);
  451. if(NT_SUCCESS(Status)){
  452. RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
  453. Status = NtQueryInformationFile(FileHandle,
  454. &IoStatusBlock,
  455. &BasicInfo,
  456. sizeof(BasicInfo),
  457. FileBasicInformation);
  458. NtClose(FileHandle);
  459. if(!NT_SUCCESS(Status)){
  460. KdPrintEx((DPFLTR_SETUP_ID,
  461. DPFLTR_WARNING_LEVEL,
  462. "RestartSetup: Unable to delete %ws (%lx)\n",
  463. pFileObjectPath, Status));
  464. return FALSE;
  465. }
  466. if(BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY){
  467. logestNtPath = RtlGetLongestNtPathLength();
  468. if(!logestNtPath){
  469. logestNtPath = MAX_DOS_PATH_IN_NT_PATH;
  470. }
  471. pFilePathToDelete = (PWSTR)MALLOC(logestNtPath * sizeof(WCHAR));
  472. if(pFilePathToDelete){
  473. wcscpy(pFilePathToDelete, pFileObjectPath);
  474. bResult = SpRemoveDir(pFilePathToDelete);
  475. FREE(pFilePathToDelete);
  476. }
  477. }
  478. else {
  479. bResult = SpRemoveFile(pFileObjectPath);
  480. }
  481. }
  482. return bResult;
  483. }
  484. BOOLEAN
  485. SpRemoveFileObject_U(
  486. IN PUNICODE_STRING FileObjectPath
  487. )
  488. {
  489. return SpRemoveFileObject(FileObjectPath->Buffer);
  490. }
  491. BOOLEAN
  492. SpReadFileRenameOperations(
  493. IN PLIST_ENTRY pFileRenameList
  494. )
  495. {
  496. OBJECT_ATTRIBUTES ObjectAttributes;
  497. IO_STATUS_BLOCK IoStatusBlock;
  498. UNICODE_STRING UnicodeString;
  499. NTSTATUS Status;
  500. HANDLE hUndoFile;
  501. WCHAR wUnicodeSign;
  502. WCHAR RenameOperationBuffer[2 * (MAX_DOS_PATH_IN_NT_PATH + 2/*"\n\r"*/)];
  503. ULONG readBytes;
  504. ULONG readActualBytes;
  505. PCWSTR pDestinationFilePath;
  506. FILE_POSITION_INFORMATION currentPosition;
  507. PWSTR pEnd;
  508. INIT_OBJA(&ObjectAttributes, &UnicodeString, UndoFilePath);
  509. Status = NtOpenFile(&hUndoFile,
  510. FILE_READ_DATA | SYNCHRONIZE,
  511. &ObjectAttributes,
  512. &IoStatusBlock,
  513. FILE_SHARE_READ,
  514. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  515. if(!NT_SUCCESS(Status)) {
  516. //
  517. // We do not have any operation to perform
  518. //
  519. return FALSE;
  520. }
  521. Status = NtReadFile(hUndoFile,
  522. NULL,
  523. NULL,
  524. NULL,
  525. &IoStatusBlock,
  526. &wUnicodeSign,
  527. sizeof(wUnicodeSign),
  528. NULL,
  529. NULL);
  530. if(NT_SUCCESS(Status) && TXT_FILE_UNICODE_SIGN == wUnicodeSign){
  531. currentPosition.CurrentByteOffset.QuadPart = sizeof(wUnicodeSign);
  532. do{
  533. readBytes = sizeof(RenameOperationBuffer) - 1;
  534. Status = NtReadFile(hUndoFile,
  535. NULL,
  536. NULL,
  537. NULL,
  538. &IoStatusBlock,
  539. RenameOperationBuffer,
  540. readBytes,
  541. NULL,
  542. NULL);
  543. if(!NT_SUCCESS(Status)){
  544. ASSERT(STATUS_END_OF_FILE == Status);
  545. break;
  546. }
  547. readActualBytes = (ULONG)IoStatusBlock.Information;
  548. RenameOperationBuffer[readActualBytes / sizeof(WCHAR)] = '\0';
  549. pEnd = wcsstr(RenameOperationBuffer, L"\r\n");
  550. if(!pEnd){
  551. break;
  552. }
  553. *pEnd = '\0';
  554. pDestinationFilePath = pEnd + 2;//wcslen(L"\r\n");
  555. pEnd = wcsstr(pDestinationFilePath, L"\r\n");
  556. if(!pEnd){
  557. if(readActualBytes < readBytes){
  558. pEnd = &RenameOperationBuffer[readActualBytes / 2];
  559. }
  560. else {
  561. //
  562. // Ether we have path which len exceed MAX_PATH,
  563. // or probably some crap.
  564. //
  565. ASSERT(FALSE);
  566. break;
  567. }
  568. }
  569. *pEnd = '\0';
  570. pEnd += 2;//wcslen(L"\r\n");
  571. SpSaveFileOperation(pFileRenameList,
  572. RenameOperationBuffer,
  573. *pDestinationFilePath? pDestinationFilePath: NULL);
  574. currentPosition.CurrentByteOffset.QuadPart += (LONGLONG)SIZE_ULONG64(pEnd, RenameOperationBuffer);
  575. Status = NtSetInformationFile(hUndoFile,
  576. &IoStatusBlock,
  577. &currentPosition,
  578. sizeof(currentPosition),
  579. FilePositionInformation);
  580. }while(NT_SUCCESS(Status));
  581. }
  582. NtClose(hUndoFile);
  583. //
  584. // Add this file to file operations list to be deleted.
  585. //
  586. SpSaveFileOperation(pFileRenameList, UndoFilePath, NULL);
  587. return TRUE;
  588. }
  589. BOOLEAN
  590. SetupDelayedFileRename(
  591. VOID
  592. )
  593. /*++
  594. Routine Description:
  595. Arguments:
  596. None.
  597. Return Value:
  598. Boolean value indicating whether we were successful.
  599. --*/
  600. {
  601. LIST_ENTRY listFileRename;
  602. KdPrint(("SetupDelayedFileRename: Start"));
  603. InitializeListHead(&listFileRename);
  604. //
  605. // Fill list of file operations
  606. //
  607. if(!SpReadFileRenameOperations(&listFileRename)){
  608. return FALSE;
  609. }
  610. //
  611. // Perform file operations
  612. //
  613. SpProcessFileRenames(&listFileRename);
  614. KdPrint(("SetupDelayedFileRename: End"));
  615. return TRUE;
  616. }