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.

837 lines
21 KiB

  1. #include <ntos.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <ntosdef.h>
  5. #include <ntioapi.h>
  6. #include <ntstatus.h>
  7. #include <stdlib.h>
  8. #include <windef.h>
  9. #include "patchapi.h"
  10. #include "const.h"
  11. VOID NtGetParameter(IN INT iTh, IN WCHAR* strLine,
  12. OUT WCHAR* strParam, IN WCHAR cLimit);
  13. BOOL NtIsUnicodeFile(IN HANDLE hFile);
  14. BOOL NtReadLine(IN HANDLE hFile, OUT WCHAR* strLine);
  15. BOOL NtCopyThisFile(IN WCHAR* strFrom, IN WCHAR* strTo,
  16. IN BOOL blnDeleteFrom);
  17. BOOL NtPatchFile(IN WCHAR* strOldFile, IN WCHAR* strPatchFile,
  18. IN WCHAR* strNewFile);
  19. BOOL NtCreateZeroFile(IN WCHAR* strFile);
  20. BOOL NtCreateThisDirectory(IN WCHAR* strDirectory, IN WCHAR* strAttrib);
  21. BOOL NtDeleteThisDirectory(IN WCHAR* strDirectory);
  22. ///////////////////////////////////////////////////////////////////////////////
  23. //
  24. // main, the entry point for the OEMApply tool, it opens up the script file and
  25. // read it line by line. Each line tells the tool what to do.
  26. //
  27. // Parameters:
  28. //
  29. // none
  30. //
  31. // Return:
  32. //
  33. // none
  34. //
  35. ///////////////////////////////////////////////////////////////////////////////
  36. extern "C" VOID __cdecl main(VOID)
  37. {
  38. OBJECT_ATTRIBUTES myFileObject;
  39. HANDLE hScriptFile = NULL;
  40. IO_STATUS_BLOCK statusScriptFile;
  41. UNICODE_STRING strScriptFile;
  42. // initialize the filename and so on
  43. strScriptFile.Length = wcslen(APPLY_PATCH_SCRIPT) + 1;
  44. strScriptFile.MaximumLength = strScriptFile.Length;
  45. strScriptFile.Buffer = (USHORT*)APPLY_PATCH_SCRIPT;
  46. InitializeObjectAttributes(&myFileObject,
  47. &strScriptFile,
  48. OBJ_EXCLUSIVE,
  49. NULL,
  50. NULL);
  51. // open the script file, remove the file when we are done
  52. if(NtCreateFile(&hScriptFile,
  53. FILE_READ_DATA | DELETE | SYNCHRONIZE,
  54. &myFileObject,
  55. &statusScriptFile,
  56. NULL,
  57. FILE_ATTRIBUTE_NORMAL,
  58. FILE_SHARE_READ,
  59. FILE_OPEN,
  60. FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT,
  61. NULL,
  62. 0) == STATUS_SUCCESS)
  63. {
  64. // script file should be to be unicoded
  65. if(NtIsUnicodeFile(hScriptFile))
  66. {
  67. // local varibles
  68. BOOL blnReturn = TRUE;
  69. WCHAR strThisLine[SUPER_LENGTH / 2];
  70. WCHAR strAction[LANGUAGE_LENGTH];
  71. WCHAR strParam1[STRING_LENGTH];
  72. WCHAR strParam2[STRING_LENGTH];
  73. WCHAR strParam3[STRING_LENGTH];
  74. // get a line from the script file in strThisLine, strThisLine is
  75. // NULL terminated with no end of line or carriage return
  76. while(NtReadLine(hScriptFile, strThisLine))
  77. {
  78. blnReturn = TRUE;
  79. // get the first token from strThisLine, strThisLine is
  80. // not changed by NtGetParameter, all filenames are of
  81. // full path
  82. NtGetParameter(1, strThisLine, strAction, SEPARATOR[0]);
  83. switch(strAction[0])
  84. {
  85. case ACTION_C_NEW_DIRECTORY:
  86. // get directory name
  87. NtGetParameter(2, strThisLine,
  88. strParam1, SEPARATOR[0]);
  89. // get directory attributes, can be NULL
  90. NtGetParameter(3, strThisLine,
  91. strParam2, SEPARATOR[0]);
  92. blnReturn = NtCreateThisDirectory(strParam1,
  93. strParam2);
  94. break;
  95. case ACTION_C_PATCH_FILE:
  96. // get the old filename
  97. NtGetParameter(2, strThisLine,
  98. strParam1, SEPARATOR[0]);
  99. // get the patch filename
  100. NtGetParameter(3, strThisLine,
  101. strParam2, SEPARATOR[0]);
  102. // get the new filename
  103. NtGetParameter(4, strThisLine,
  104. strParam3, SEPARATOR[0]);
  105. blnReturn = NtPatchFile(strParam1,
  106. strParam2,
  107. strParam3);
  108. break;
  109. case ACTION_C_MOVE_FILE:
  110. case ACTION_C_EXCEPT_FILE:
  111. case ACTION_C_RENAME_FILE:
  112. case ACTION_C_NOT_PATCH_FILE:
  113. case ACTION_C_SAVED_FILE:
  114. // get the old filename
  115. NtGetParameter(2, strThisLine,
  116. strParam1, SEPARATOR[0]);
  117. // get the new filename
  118. NtGetParameter(3, strThisLine,
  119. strParam2, SEPARATOR[0]);
  120. // delete the old file once we are done
  121. blnReturn = NtCopyThisFile(strParam1, strParam2,
  122. TRUE);
  123. break;
  124. case ACTION_C_COPY_FILE:
  125. // get the old filename
  126. NtGetParameter(2, strThisLine,
  127. strParam1, SEPARATOR[0]);
  128. // get the new filename
  129. NtGetParameter(3, strThisLine,
  130. strParam2, SEPARATOR[0]);
  131. // do not remove the old file
  132. blnReturn = NtCopyThisFile(strParam1, strParam2,
  133. FALSE);
  134. break;
  135. case ACTION_C_NEW_ZERO_FILE:
  136. // get the filename
  137. NtGetParameter(2, strThisLine,
  138. strParam1, SEPARATOR[0]);
  139. blnReturn = NtCreateZeroFile(strParam1);
  140. break;
  141. case ACTION_C_DELETE_DIRECTORY:
  142. // get the directory name
  143. NtGetParameter(2, strThisLine,
  144. strParam1, SEPARATOR[0]);
  145. blnReturn = NtDeleteThisDirectory(strParam1);
  146. break;
  147. default:
  148. break;
  149. }
  150. if(!blnReturn)
  151. {
  152. // some thing went wrong
  153. DbgPrint("warning, A=%ls, 1=%ls, 2=%ls, 3=%ls\n", strAction, strParam1, strParam2, strParam3);
  154. }
  155. }
  156. }
  157. NtClose(hScriptFile);
  158. }
  159. }
  160. ///////////////////////////////////////////////////////////////////////////////
  161. //
  162. // NtGetParameter, essentially a wcstok function, returns the iTh token
  163. // separated by cLimit in strParam, if the token is not found,
  164. // strParam is of 0 length, strLine is unchanged
  165. //
  166. // Parameters:
  167. //
  168. // iTh, the nTh token
  169. // strLine, the line of characters that the token is taken from
  170. // strParam, the returned token
  171. // cLimit, the character the separates the tokens
  172. //
  173. // Return:
  174. //
  175. // none
  176. //
  177. ///////////////////////////////////////////////////////////////////////////////
  178. VOID NtGetParameter(IN INT iTh, IN WCHAR* strLine,
  179. OUT WCHAR* strParam, IN WCHAR cLimit)
  180. {
  181. INT iCount = 0;
  182. INT iPrevCount = 0;
  183. INT iEncounter = 0;
  184. INT iLength = 0;
  185. if(iTh > 0 && strLine && strParam)
  186. {
  187. while(strLine[iCount] != 0)
  188. {
  189. if(strLine[iCount] == cLimit)
  190. {
  191. // just like the real wcstok, ignores the first token separator
  192. if(iCount != 0)
  193. {
  194. iEncounter += 1;
  195. }
  196. if(iEncounter == iTh)
  197. {
  198. break;
  199. }
  200. iPrevCount = iCount + 1;
  201. }
  202. iCount += 1;
  203. }
  204. // two conditions for successful return
  205. // 1. the token is found
  206. // 2. reached the end of line, and this is the token we want
  207. if(iEncounter == iTh || iEncounter + 1 == iTh)
  208. {
  209. iLength = iCount - iPrevCount;
  210. wcsncpy(strParam, strLine + iPrevCount, iLength);
  211. strParam[iLength] = 0;
  212. }
  213. else
  214. {
  215. // zero out the return token if token is not found
  216. strParam[0] = 0;
  217. }
  218. }
  219. }
  220. ///////////////////////////////////////////////////////////////////////////////
  221. //
  222. // NtIsUnicodeFile, test to see if the file is unicoded by reading the first 2
  223. // bytes, should be FEFF, the file position is moved for next
  224. // read
  225. //
  226. // Parameters:
  227. //
  228. // hFile, the file handle to read from
  229. //
  230. // Return:
  231. //
  232. // TRUE if the first 2 bytes matches, FALSE otherwise
  233. //
  234. ///////////////////////////////////////////////////////////////////////////////
  235. BOOL NtIsUnicodeFile(IN HANDLE hFile)
  236. {
  237. WCHAR cFirstChar = 0;
  238. IO_STATUS_BLOCK ioBlock;
  239. // read the first 2 bytes
  240. if(NtReadFile(hFile,
  241. NULL,
  242. NULL,
  243. NULL,
  244. &ioBlock,
  245. &cFirstChar,
  246. sizeof(WCHAR),
  247. NULL,
  248. NULL) &&
  249. cFirstChar == UNICODE_HEAD)
  250. {
  251. return(TRUE);
  252. }
  253. return(FALSE);
  254. }
  255. ///////////////////////////////////////////////////////////////////////////////
  256. //
  257. // NtReadLine, reads a line from hFile, each line in hFile is expected to be
  258. // terminated by 0xD and 0xA, the line will be returned in strLine,
  259. // with 0xD and 0xA removed
  260. //
  261. // Parameters:
  262. //
  263. // hFile, the file handle to read from
  264. // strLine, the buffer to store the line
  265. //
  266. // Return:
  267. //
  268. // TRUE if the strLine contains a valid line, FALSE for end of file
  269. //
  270. ///////////////////////////////////////////////////////////////////////////////
  271. BOOL NtReadLine(IN HANDLE hFile, OUT WCHAR* strLine)
  272. {
  273. static WCHAR strBuffer[SUPER_LENGTH + 1];
  274. static LONG iLength = 0;
  275. static LONG iReadChar = 0;
  276. static LONG iOffset = 0;
  277. static LONG iThisLineLength = 0;
  278. static WCHAR strThisLine[SUPER_LENGTH / 2];
  279. static IO_STATUS_BLOCK ioBlock;
  280. if(iLength > 0)
  281. {
  282. NtGetParameter(1, strBuffer + iReadChar - iLength,
  283. strThisLine, CRETURN[0]);
  284. iThisLineLength = wcslen(strThisLine);
  285. if(iThisLineLength + 1 <= iLength)
  286. {
  287. // char 0xD is set to 0
  288. strThisLine[iThisLineLength - 1] = 0;
  289. wcscpy(strLine, strThisLine);
  290. iLength = iLength - iThisLineLength - 1;
  291. }
  292. else
  293. {
  294. wcsncpy(strLine, strThisLine, iLength);
  295. // set the last char + 1 to 0 for cat
  296. strLine[iLength] = 0;
  297. if(iLength <= 0 || strLine[iLength - 1] != ENDOFLINE[0])
  298. {
  299. NtReadFile(hFile, NULL, NULL, NULL, &ioBlock, strBuffer,
  300. SUPER_LENGTH * sizeof(WCHAR), NULL, NULL);
  301. iReadChar = ioBlock.Information / sizeof(WCHAR);
  302. NtGetParameter(1, strBuffer,
  303. strThisLine, CRETURN[0]);
  304. iThisLineLength = wcslen(strThisLine);
  305. iLength = iReadChar - iThisLineLength - 1;
  306. // char 0xD is set to 0
  307. strThisLine[iThisLineLength - 1] = 0;
  308. wcscat(strLine, strThisLine);
  309. if(strBuffer[0] == CRETURN[0])
  310. {
  311. iLength -= 1;
  312. }
  313. }
  314. else
  315. {
  316. strLine[iLength - 1] = 0;
  317. iLength = 0;
  318. }
  319. }
  320. }
  321. else
  322. {
  323. if(NtReadFile(hFile, NULL, NULL, NULL, &ioBlock, strBuffer,
  324. SUPER_LENGTH * sizeof(WCHAR), NULL, NULL) == STATUS_SUCCESS &&
  325. ioBlock.Information != 0)
  326. {
  327. iReadChar = ioBlock.Information / sizeof(WCHAR);
  328. NtGetParameter(1, strBuffer,
  329. strThisLine, CRETURN[0]);
  330. iThisLineLength = wcslen(strThisLine);
  331. iLength = iReadChar - iThisLineLength - 1;
  332. // char 0xD is set to 0
  333. strThisLine[iThisLineLength - 1] = 0;
  334. wcscpy(strLine, strThisLine);
  335. if(strBuffer[0] == CRETURN[0])
  336. {
  337. iLength -= 1;
  338. }
  339. }
  340. else
  341. {
  342. return(FALSE);
  343. }
  344. }
  345. return(TRUE);
  346. }
  347. ///////////////////////////////////////////////////////////////////////////////
  348. //
  349. // NtCopyThisFile, copies a file to another location, depending on
  350. // blnDeleteFrom, the old file can be deleted
  351. //
  352. // Parameters:
  353. //
  354. // strFrom, the old filename, full path
  355. // strTo, the new filename, full path
  356. // blnDeleteFrom, delete the old file?
  357. //
  358. // Return:
  359. //
  360. // TRUE for file copied successfully, FALSE otherwise
  361. //
  362. ///////////////////////////////////////////////////////////////////////////////
  363. BOOL NtCopyThisFile(IN WCHAR* strFrom, IN WCHAR* strTo, IN BOOL blnDeleteFrom)
  364. {
  365. BOOL blnReturn = FALSE;
  366. BYTE byteBuffer[1024];
  367. ULONG iCreateOptions = 0;
  368. ULONG iDesireAccess = 0;
  369. // set the options to delete the old file
  370. if(blnDeleteFrom)
  371. {
  372. iCreateOptions = FILE_DELETE_ON_CLOSE;
  373. iDesireAccess = DELETE;
  374. }
  375. OBJECT_ATTRIBUTES myFileReadObject;
  376. OBJECT_ATTRIBUTES myFileWriteObject;
  377. HANDLE hReadFile = NULL;
  378. HANDLE hWriteFile = NULL;
  379. IO_STATUS_BLOCK statusReadFile;
  380. IO_STATUS_BLOCK statusWriteFile;
  381. UNICODE_STRING strReadFile;
  382. UNICODE_STRING strWriteFile;
  383. IO_STATUS_BLOCK statusReadInfoFile;
  384. FILE_BASIC_INFORMATION infoReadFile;
  385. IO_STATUS_BLOCK ioReadBlock;
  386. IO_STATUS_BLOCK ioWriteBlock;
  387. strReadFile.Length = wcslen(strFrom) + 1;
  388. strReadFile.MaximumLength = strReadFile.Length;
  389. strReadFile.Buffer = strFrom;
  390. strReadFile.Length = wcslen(strTo) + 1;
  391. strReadFile.MaximumLength = strReadFile.Length;
  392. strReadFile.Buffer = strTo;
  393. InitializeObjectAttributes(&myFileReadObject,
  394. &strReadFile,
  395. OBJ_EXCLUSIVE,
  396. NULL,
  397. NULL);
  398. InitializeObjectAttributes(&myFileWriteObject,
  399. &strWriteFile,
  400. OBJ_EXCLUSIVE,
  401. NULL,
  402. NULL);
  403. // open the old file to read
  404. if(NtCreateFile(&hReadFile,
  405. FILE_READ_DATA | SYNCHRONIZE | FILE_READ_ATTRIBUTES |
  406. iDesireAccess,
  407. &myFileReadObject,
  408. &statusReadFile,
  409. NULL,
  410. FILE_ATTRIBUTE_NORMAL,
  411. FILE_SHARE_READ,
  412. FILE_OPEN,
  413. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
  414. iCreateOptions,
  415. NULL,
  416. 0) == STATUS_SUCCESS)
  417. {
  418. // get the old file's attributes
  419. if(NtQueryInformationFile(hReadFile,
  420. &statusReadInfoFile,
  421. &infoReadFile,
  422. sizeof(FILE_BASIC_INFORMATION),
  423. FileBasicInformation) == STATUS_SUCCESS)
  424. {
  425. // create the new file with old file's attributes
  426. if(NtCreateFile(&hWriteFile,
  427. FILE_WRITE_DATA | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
  428. &myFileWriteObject,
  429. &statusWriteFile,
  430. NULL,
  431. infoReadFile.FileAttributes,
  432. 0,
  433. FILE_CREATE,
  434. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  435. NULL,
  436. 0) == STATUS_SUCCESS)
  437. {
  438. blnReturn = TRUE;
  439. // read from the old file and write to the new file
  440. while(NtReadFile(hReadFile,
  441. NULL, NULL, NULL,
  442. &ioReadBlock,
  443. byteBuffer,
  444. 1024, NULL, NULL) == STATUS_SUCCESS &&
  445. ioReadBlock.Information != 0 && blnReturn)
  446. {
  447. // make sure that write is successful
  448. blnReturn = (NtWriteFile(hWriteFile,
  449. NULL, NULL, NULL,
  450. &ioWriteBlock,
  451. byteBuffer,
  452. ioReadBlock.Information,
  453. NULL, NULL) == STATUS_SUCCESS &&
  454. ioWriteBlock.Information == ioReadBlock.Information);
  455. }
  456. NtClose(hWriteFile);
  457. }
  458. }
  459. NtClose(hReadFile);
  460. }
  461. return(blnReturn);
  462. }
  463. ///////////////////////////////////////////////////////////////////////////////
  464. //
  465. // NtCreateZeroFile, creates a zero length file
  466. //
  467. // Parameters:
  468. //
  469. // strFile, the filename, full path
  470. //
  471. // Return:
  472. //
  473. // TRUE for file created successfully, FALSE otherwise
  474. //
  475. ///////////////////////////////////////////////////////////////////////////////
  476. BOOL NtCreateZeroFile(IN WCHAR* strFile)
  477. {
  478. BOOL blnReturn = FALSE;
  479. HANDLE hFile = NULL;
  480. OBJECT_ATTRIBUTES myFileObject;
  481. IO_STATUS_BLOCK statusFile;
  482. UNICODE_STRING strUniFile;
  483. strUniFile.Length = wcslen(strFile) + 1;
  484. strUniFile.MaximumLength = strUniFile.Length;
  485. strUniFile.Buffer = strFile;
  486. InitializeObjectAttributes(&myFileObject,
  487. &strUniFile,
  488. OBJ_EXCLUSIVE,
  489. NULL,
  490. NULL);
  491. if(NtCreateFile(&hFile,
  492. FILE_WRITE_DATA | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
  493. &myFileObject,
  494. &statusFile,
  495. NULL,
  496. FILE_ATTRIBUTE_NORMAL,
  497. 0,
  498. FILE_CREATE,
  499. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  500. NULL,
  501. 0) == STATUS_SUCCESS)
  502. {
  503. blnReturn = TRUE;
  504. NtClose(hFile);
  505. }
  506. return(blnReturn);
  507. }
  508. ///////////////////////////////////////////////////////////////////////////////
  509. //
  510. // NtPatchFile, create the new file from the patch file
  511. //
  512. // Parameters:
  513. //
  514. // strOldFile, the old filename, full path
  515. // strPatchFile, the patch filename, full path
  516. // strNewFile, the new filename, full path
  517. //
  518. // Return:
  519. //
  520. // TRUE for file created successfully, FALSE otherwise
  521. //
  522. ///////////////////////////////////////////////////////////////////////////////
  523. BOOL NtPatchFile(IN WCHAR* strOldFile,
  524. IN WCHAR* strPatchFile,
  525. IN WCHAR* strNewFile)
  526. {
  527. BOOL blnReturn = TRUE;
  528. blnReturn = ApplyPatchToFileW(strPatchFile,
  529. strOldFile,
  530. strNewFile,
  531. 0);
  532. return(blnReturn);
  533. }
  534. ///////////////////////////////////////////////////////////////////////////////
  535. //
  536. // NtCreateThisDirectory, create a directory
  537. //
  538. // Parameters:
  539. //
  540. // strDirectory, the name of the directory, full path
  541. // strAttrib, the attributes of the directory
  542. //
  543. // Return:
  544. //
  545. // TRUE for directory created successfully, FALSE otherwise
  546. //
  547. ///////////////////////////////////////////////////////////////////////////////
  548. BOOL NtCreateThisDirectory(IN WCHAR* strDirectory, IN WCHAR* strAttrib)
  549. {
  550. BOOL blnReturn = FALSE;
  551. HANDLE hDirectory = NULL;
  552. OBJECT_ATTRIBUTES myDirectoryObject;
  553. IO_STATUS_BLOCK statusDirectory;
  554. UNICODE_STRING strUniDirectory;
  555. strUniDirectory.Length = wcslen(strDirectory) + 1;
  556. strUniDirectory.MaximumLength = strUniDirectory.Length;
  557. strUniDirectory.Buffer = strDirectory;
  558. InitializeObjectAttributes(&myDirectoryObject,
  559. &strUniDirectory,
  560. OBJ_EXCLUSIVE,
  561. NULL,
  562. NULL);
  563. // create the directory
  564. if(NtCreateFile(&hDirectory,
  565. FILE_WRITE_DATA | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
  566. &myDirectoryObject,
  567. &statusDirectory,
  568. NULL,
  569. FILE_ATTRIBUTE_NORMAL,
  570. 0,
  571. FILE_CREATE,
  572. FILE_DIRECTORY_FILE,
  573. NULL,
  574. 0) == STATUS_SUCCESS)
  575. {
  576. blnReturn = TRUE;
  577. }
  578. if(blnReturn)
  579. {
  580. DWORD iAttrib = FILE_ATTRIBUTE_NORMAL;
  581. LARGE_INTEGER iLargeInt;
  582. FILE_BASIC_INFORMATION infoDirectory;
  583. // look through the attributes
  584. for(UINT i = 0; i < wcslen(strAttrib); i++)
  585. {
  586. switch(strAttrib[i])
  587. {
  588. case DIR_C_READONLY:
  589. iAttrib |= FILE_ATTRIBUTE_READONLY;
  590. break;
  591. case DIR_C_SYSTEM:
  592. iAttrib |= FILE_ATTRIBUTE_SYSTEM;
  593. break;
  594. case DIR_C_HIDDEN:
  595. iAttrib |= FILE_ATTRIBUTE_HIDDEN;
  596. break;
  597. case DIR_C_COMPRESSED:
  598. iAttrib |= FILE_ATTRIBUTE_COMPRESSED;
  599. break;
  600. case DIR_C_ENCRYPTED:
  601. iAttrib |= FILE_ATTRIBUTE_ENCRYPTED;
  602. break;
  603. default:
  604. break;
  605. }
  606. }
  607. NtQuerySystemTime(&iLargeInt);
  608. // set the information struct
  609. infoDirectory.CreationTime = iLargeInt;
  610. infoDirectory.LastAccessTime = iLargeInt;
  611. infoDirectory.LastWriteTime = iLargeInt;
  612. infoDirectory.ChangeTime = iLargeInt;
  613. infoDirectory.FileAttributes = iAttrib;
  614. // set the attributes
  615. blnReturn = (NtSetInformationFile(hDirectory,
  616. &statusDirectory,
  617. &infoDirectory,
  618. sizeof(FILE_BASIC_INFORMATION),
  619. FileBasicInformation) == STATUS_SUCCESS);
  620. NtClose(hDirectory);
  621. }
  622. return(blnReturn);
  623. }
  624. ///////////////////////////////////////////////////////////////////////////////
  625. //
  626. // NtDeleteThisDirectory, deletes the directory recursively
  627. //
  628. // Parameters:
  629. //
  630. // strDirectory, the name of the directory, full path
  631. // strAttrib, the attributes of the directory
  632. //
  633. // Return:
  634. //
  635. // TRUE for directory removed, FALSE otherwise
  636. //
  637. ///////////////////////////////////////////////////////////////////////////////
  638. BOOL NtDeleteThisDirectory(IN WCHAR* strDirectory)
  639. {
  640. INT length = 0;
  641. NTSTATUS result;
  642. WCHAR path[MAXPATH + 7];
  643. HANDLE hVddHeap = NULL;
  644. HANDLE hFindFile = NULL;
  645. OBJECT_ATTRIBUTES myFileObject;
  646. IO_STATUS_BLOCK IoStatusBlock;
  647. UNICODE_STRING strUniFile;
  648. PFILE_BOTH_DIR_INFORMATION DirectoryInfo = NULL;
  649. // adding the trailing '\'
  650. if((length = wcslen(strDirectory)) > MAXPATH)
  651. {
  652. return FALSE;
  653. }
  654. wcscpy(path, strDirectory);
  655. if(length)
  656. {
  657. if((path[length - 1] != '\\') AND (path[length - 1] != ':'))
  658. {
  659. wcscpy(path + length, L"\\");
  660. length++;
  661. }
  662. }
  663. strUniFile.Length = length;
  664. strUniFile.MaximumLength = strUniFile.Length;
  665. strUniFile.Buffer = strDirectory;
  666. InitializeObjectAttributes(&myFileObject,
  667. &strUniFile,
  668. OBJ_EXCLUSIVE,
  669. NULL,
  670. NULL);
  671. // allocate memory for the directory info struct used to get files from
  672. // the directory
  673. DirectoryInfo = (PFILE_BOTH_DIR_INFORMATION)RtlAllocateHeap(
  674. RtlProcessHeap(),
  675. 0,
  676. MAX_PATH * sizeof(WCHAR) +
  677. sizeof(FILE_BOTH_DIR_INFORMATION));
  678. // open the directory
  679. if(DirectoryInfo != NULL &&
  680. NtCreateFile(&hFindFile,
  681. FILE_LIST_DIRECTORY | SYNCHRONIZE | DELETE,
  682. &myFileObject,
  683. &IoStatusBlock,
  684. NULL,
  685. FILE_ATTRIBUTE_NORMAL,
  686. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  687. FILE_OPEN,
  688. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
  689. FILE_DELETE_ON_CLOSE,
  690. NULL,
  691. 0) == STATUS_SUCCESS)
  692. {
  693. // get a file
  694. result = NtQueryDirectoryFile(hFindFile,
  695. NULL,
  696. NULL,
  697. NULL,
  698. &IoStatusBlock,
  699. DirectoryInfo,
  700. (MAX_PATH * sizeof(WCHAR) +
  701. sizeof(FILE_BOTH_DIR_INFORMATION)),
  702. FileBothDirectoryInformation,
  703. TRUE,
  704. NULL,
  705. TRUE);
  706. while(result == STATUS_SUCCESS)
  707. {
  708. ULONG iLengthFull = DirectoryInfo->FileNameLength / sizeof(WCHAR);
  709. DirectoryInfo->FileName[iLengthFull] = 0;
  710. if((DirectoryInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ==
  711. FILE_ATTRIBUTE_DIRECTORY &&
  712. wcscmp(DirectoryInfo->ShortName, L"." ) != 0 &&
  713. wcscmp(DirectoryInfo->ShortName, L"..") != 0)
  714. {
  715. // the file is a directory
  716. NtDeleteThisDirectory(DirectoryInfo->FileName);
  717. }
  718. else
  719. {
  720. // the file is a file
  721. HANDLE hFindFileFile = NULL;
  722. OBJECT_ATTRIBUTES myFileFileObject;
  723. IO_STATUS_BLOCK FileIoStatusBlock;
  724. UNICODE_STRING strUniFileFile;
  725. strUniFileFile.Length = (USHORT)iLengthFull;
  726. strUniFileFile.MaximumLength = strUniFile.Length;
  727. strUniFileFile.Buffer = DirectoryInfo->FileName;
  728. InitializeObjectAttributes(&myFileFileObject,
  729. &strUniFileFile,
  730. OBJ_EXCLUSIVE,
  731. NULL,
  732. NULL);
  733. if(NtCreateFile(&hFindFileFile,
  734. SYNCHRONIZE | DELETE,
  735. &myFileFileObject,
  736. &FileIoStatusBlock,
  737. NULL,
  738. FILE_ATTRIBUTE_NORMAL,
  739. 0,
  740. FILE_OPEN,
  741. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE,
  742. NULL,
  743. 0) == STATUS_SUCCESS)
  744. {
  745. NtClose(hFindFileFile);
  746. }
  747. }
  748. result = NtQueryDirectoryFile(hFindFile,
  749. NULL,
  750. NULL,
  751. NULL,
  752. &IoStatusBlock,
  753. DirectoryInfo,
  754. (MAX_PATH * sizeof(WCHAR) +
  755. sizeof(FILE_BOTH_DIR_INFORMATION)),
  756. FileBothDirectoryInformation,
  757. TRUE,
  758. NULL,
  759. FALSE);
  760. }
  761. }
  762. if(DirectoryInfo != NULL)
  763. {
  764. // free the memory
  765. RtlFreeHeap(RtlProcessHeap(), 0, DirectoryInfo);
  766. DirectoryInfo = NULL;
  767. }
  768. // close the handle to the directory, since the directory is opened with
  769. // the delete on close option, the directory should be deleted
  770. return(NtClose(hFindFile) == STATUS_SUCCESS);
  771. }