Leaked source code of windows server 2003
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.

758 lines
26 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 270
  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. ULONG StringMaxSize
  343. )
  344. {
  345. NTSTATUS Status;
  346. HANDLE DirectoryHandle;
  347. UNICODE_STRING UnicodeString;
  348. OBJECT_ATTRIBUTES ObjectAttributes;
  349. IO_STATUS_BLOCK IoStatusBlock;
  350. LONGLONG Buffer[2048/8];
  351. BOOLEAN FirstQuery;
  352. PFILE_DIRECTORY_INFORMATION FileInfo;
  353. ULONG LengthChars;
  354. BOOLEAN AnyErrors;
  355. ULONG indexEndOfRootPath;
  356. if(!pFilePath){
  357. ASSERT(FALSE);
  358. return FALSE;
  359. }
  360. indexEndOfRootPath = wcslen(pFilePath);
  361. ASSERT(indexEndOfRootPath);
  362. INIT_OBJA(&ObjectAttributes, &UnicodeString, pFilePath);
  363. Status = NtOpenFile(&DirectoryHandle,
  364. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  365. &ObjectAttributes,
  366. &IoStatusBlock,
  367. FILE_SHARE_READ | FILE_SHARE_WRITE,
  368. FILE_DIRECTORY_FILE |
  369. FILE_SYNCHRONOUS_IO_NONALERT |
  370. FILE_OPEN_FOR_BACKUP_INTENT
  371. );
  372. if(!NT_SUCCESS(Status)){
  373. KdPrintEx((DPFLTR_SETUP_ID,
  374. DPFLTR_WARNING_LEVEL,
  375. "RestartSetup: unable to open system32\\config for list access (%lx)\n",
  376. Status));
  377. return(FALSE);
  378. }
  379. FirstQuery = TRUE;
  380. FileInfo = (PFILE_DIRECTORY_INFORMATION)Buffer;
  381. AnyErrors = FALSE;
  382. do {
  383. Status = NtQueryDirectoryFile(DirectoryHandle,
  384. NULL, // no event to signal
  385. NULL, // no apc routine
  386. NULL, // no apc context
  387. &IoStatusBlock,
  388. Buffer,
  389. sizeof(Buffer)-sizeof(WCHAR), // leave room for terminating nul
  390. FileDirectoryInformation,
  391. TRUE, // want single entry
  392. NULL, // get 'em all
  393. FirstQuery);
  394. if(NT_SUCCESS(Status)){
  395. LengthChars = FileInfo->FileNameLength / sizeof(WCHAR);
  396. FileInfo->FileName[LengthChars] = 0;
  397. if(wcscmp(FileInfo->FileName, L".") &&
  398. wcscmp(FileInfo->FileName, L"..")){
  399. if((wcslen(pFilePath) + 1/*'\\'*/ + wcslen(FileInfo->FileName)) < StringMaxSize){
  400. wcscat(pFilePath, L"\\");
  401. wcscat(pFilePath, FileInfo->FileName);
  402. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  403. SpRemoveDir(pFilePath, StringMaxSize);
  404. } else {
  405. SpRemoveFile(pFilePath);
  406. }
  407. pFilePath[indexEndOfRootPath] = '\0';
  408. }
  409. else{
  410. ASSERT(FALSE);
  411. }
  412. }
  413. FirstQuery = FALSE;
  414. }
  415. } while(NT_SUCCESS(Status));
  416. //
  417. // Check for normal loop termination.
  418. //
  419. if(Status == STATUS_NO_MORE_FILES) {
  420. Status = STATUS_SUCCESS;
  421. }
  422. //
  423. // Even if we got errors, try to keep going.
  424. //
  425. if(!NT_SUCCESS(Status)) {
  426. AnyErrors = TRUE;
  427. KdPrintEx((DPFLTR_SETUP_ID,
  428. DPFLTR_WARNING_LEVEL,
  429. "RestartSetup: Status %lx enumerating files\n",
  430. Status));
  431. }
  432. NtClose(DirectoryHandle);
  433. SpRemoveFile(pFilePath);
  434. return ((BOOLEAN)!AnyErrors);
  435. }
  436. BOOLEAN
  437. SpRemoveFileObject(
  438. IN PCWSTR pFileObjectPath
  439. )
  440. {
  441. NTSTATUS Status;
  442. HANDLE FileHandle;
  443. UNICODE_STRING UnicodeString;
  444. OBJECT_ATTRIBUTES ObjectAttributes;
  445. IO_STATUS_BLOCK IoStatusBlock;
  446. FILE_BASIC_INFORMATION BasicInfo;
  447. ULONG logestNtPath;
  448. PWSTR pFilePathToDelete;
  449. BOOLEAN bResult = FALSE;
  450. INIT_OBJA(&ObjectAttributes, &UnicodeString, pFileObjectPath);
  451. Status = NtOpenFile(&FileHandle,
  452. SYNCHRONIZE | GENERIC_READ,
  453. &ObjectAttributes,
  454. &IoStatusBlock,
  455. FILE_SHARE_READ,
  456. 0);
  457. if(NT_SUCCESS(Status)){
  458. RtlZeroMemory(&BasicInfo, sizeof(BasicInfo));
  459. Status = NtQueryInformationFile(FileHandle,
  460. &IoStatusBlock,
  461. &BasicInfo,
  462. sizeof(BasicInfo),
  463. FileBasicInformation);
  464. NtClose(FileHandle);
  465. if(!NT_SUCCESS(Status)){
  466. KdPrintEx((DPFLTR_SETUP_ID,
  467. DPFLTR_WARNING_LEVEL,
  468. "RestartSetup: Unable to delete %ws (%lx)\n",
  469. pFileObjectPath, Status));
  470. return FALSE;
  471. }
  472. if(BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY){
  473. //
  474. // We can possible have 2 * MAX_PATH as length of path
  475. //
  476. logestNtPath = 2 * MAX_DOS_PATH_IN_NT_PATH;
  477. ASSERT(wcslen(pFileObjectPath) < logestNtPath);
  478. pFilePathToDelete = (PWSTR)MALLOC(logestNtPath * sizeof(WCHAR));
  479. if(pFilePathToDelete && wcslen(pFileObjectPath) < logestNtPath){
  480. wcscpy(pFilePathToDelete, pFileObjectPath);
  481. bResult = SpRemoveDir(pFilePathToDelete, logestNtPath);
  482. FREE(pFilePathToDelete);
  483. }
  484. }
  485. else {
  486. bResult = SpRemoveFile(pFileObjectPath);
  487. }
  488. }
  489. return bResult;
  490. }
  491. BOOLEAN
  492. SpRemoveFileObject_U(
  493. IN PUNICODE_STRING FileObjectPath
  494. )
  495. {
  496. return SpRemoveFileObject(FileObjectPath->Buffer);
  497. }
  498. BOOLEAN
  499. SpReadFileRenameOperations(
  500. IN PLIST_ENTRY pFileRenameList
  501. )
  502. {
  503. OBJECT_ATTRIBUTES ObjectAttributes;
  504. IO_STATUS_BLOCK IoStatusBlock;
  505. UNICODE_STRING UnicodeString;
  506. NTSTATUS Status;
  507. HANDLE hUndoFile;
  508. WCHAR wUnicodeSign;
  509. WCHAR RenameOperationBuffer[2 * (MAX_DOS_PATH_IN_NT_PATH + 2/*"\n\r"*/)];
  510. ULONG readBytes;
  511. ULONG readActualBytes;
  512. PCWSTR pDestinationFilePath;
  513. FILE_POSITION_INFORMATION currentPosition;
  514. PWSTR pEnd;
  515. INIT_OBJA(&ObjectAttributes, &UnicodeString, UndoFilePath);
  516. Status = NtOpenFile(&hUndoFile,
  517. FILE_READ_DATA | SYNCHRONIZE,
  518. &ObjectAttributes,
  519. &IoStatusBlock,
  520. FILE_SHARE_READ,
  521. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  522. if(!NT_SUCCESS(Status)) {
  523. //
  524. // We do not have any operation to perform
  525. //
  526. return FALSE;
  527. }
  528. Status = NtReadFile(hUndoFile,
  529. NULL,
  530. NULL,
  531. NULL,
  532. &IoStatusBlock,
  533. &wUnicodeSign,
  534. sizeof(wUnicodeSign),
  535. NULL,
  536. NULL);
  537. if(NT_SUCCESS(Status) && TXT_FILE_UNICODE_SIGN == wUnicodeSign){
  538. currentPosition.CurrentByteOffset.QuadPart = sizeof(wUnicodeSign);
  539. do{
  540. readBytes = sizeof(RenameOperationBuffer) - sizeof(RenameOperationBuffer[0]);
  541. Status = NtReadFile(hUndoFile,
  542. NULL,
  543. NULL,
  544. NULL,
  545. &IoStatusBlock,
  546. RenameOperationBuffer,
  547. readBytes,
  548. NULL,
  549. NULL);
  550. if(!NT_SUCCESS(Status)){
  551. ASSERT(STATUS_END_OF_FILE == Status);
  552. break;
  553. }
  554. readActualBytes = (ULONG)IoStatusBlock.Information;
  555. RenameOperationBuffer[readActualBytes / sizeof(RenameOperationBuffer[0])] = '\0';
  556. pEnd = wcsstr(RenameOperationBuffer, L"\r\n");
  557. if(!pEnd){
  558. break;
  559. }
  560. *pEnd = '\0';
  561. pDestinationFilePath = pEnd + 2;//wcslen(L"\r\n");
  562. pEnd = wcsstr(pDestinationFilePath, L"\r\n");
  563. if(!pEnd){
  564. if(readActualBytes < readBytes){
  565. pEnd = &RenameOperationBuffer[readActualBytes / sizeof(WCHAR)];
  566. }
  567. else {
  568. //
  569. // Ether we have path which len exceed MAX_PATH,
  570. // or probably some crap.
  571. //
  572. ASSERT(FALSE);
  573. break;
  574. }
  575. }
  576. *pEnd = '\0';
  577. pEnd += 2;//wcslen(L"\r\n");
  578. SpSaveFileOperation(pFileRenameList,
  579. RenameOperationBuffer,
  580. *pDestinationFilePath? pDestinationFilePath: NULL);
  581. currentPosition.CurrentByteOffset.QuadPart += (LONGLONG)SIZE_ULONG64(pEnd, RenameOperationBuffer);
  582. Status = NtSetInformationFile(hUndoFile,
  583. &IoStatusBlock,
  584. &currentPosition,
  585. sizeof(currentPosition),
  586. FilePositionInformation);
  587. }while(NT_SUCCESS(Status));
  588. }
  589. NtClose(hUndoFile);
  590. //
  591. // Add this file to file operations list to be deleted.
  592. //
  593. SpSaveFileOperation(pFileRenameList, UndoFilePath, NULL);
  594. return TRUE;
  595. }
  596. BOOLEAN
  597. SetupDelayedFileRename(
  598. VOID
  599. )
  600. /*++
  601. Routine Description:
  602. Arguments:
  603. None.
  604. Return Value:
  605. Boolean value indicating whether we were successful.
  606. --*/
  607. {
  608. LIST_ENTRY listFileRename;
  609. KdPrint(("SetupDelayedFileRename: Start"));
  610. InitializeListHead(&listFileRename);
  611. //
  612. // Fill list of file operations
  613. //
  614. if(!SpReadFileRenameOperations(&listFileRename)){
  615. return FALSE;
  616. }
  617. //
  618. // Perform file operations
  619. //
  620. SpProcessFileRenames(&listFileRename);
  621. KdPrint(("SetupDelayedFileRename: End"));
  622. return TRUE;
  623. }