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.

4744 lines
123 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. file.c
  5. Abstract:
  6. General file-related functions.
  7. Author:
  8. Mike Condra 16-Aug-1996
  9. Revision History:
  10. calinn 23-Sep-1998 Additional options to file enum
  11. jimschm 05-Feb-1998 File enumeration code
  12. jimschm 30-Sep-1997 WriteFileString routines
  13. --*/
  14. #include "pch.h"
  15. //
  16. // Function accepts paths within the limit of our stack variable size
  17. //
  18. BOOL
  19. IsPathLengthOkA (
  20. IN PCSTR FileSpec
  21. )
  22. {
  23. return SizeOfStringA(FileSpec) < MAX_MBCHAR_PATH;
  24. }
  25. BOOL
  26. IsPathLengthOkW (
  27. IN PCWSTR FileSpec
  28. )
  29. {
  30. return SizeOfStringW(FileSpec) < (MAX_WCHAR_PATH * sizeof (WCHAR));
  31. }
  32. BOOL
  33. IsPathOnFixedDriveA (
  34. IN PCSTR FileSpec OPTIONAL
  35. )
  36. {
  37. static CHAR root[] = "?:\\";
  38. UINT type;
  39. static BOOL lastResult;
  40. if (!FileSpec) {
  41. return FALSE;
  42. }
  43. if (!FileSpec[0]) {
  44. return FALSE;
  45. }
  46. if (FileSpec[1] != ':' || FileSpec[2] != '\\') {
  47. return FALSE;
  48. }
  49. if (root[0] == FileSpec[0]) {
  50. return lastResult;
  51. }
  52. root[0] = FileSpec[0];
  53. type = GetDriveTypeA (root);
  54. if (type != DRIVE_FIXED && type != DRIVE_REMOTE) {
  55. DEBUGMSGA_IF ((
  56. type != DRIVE_REMOVABLE && type != DRIVE_NO_ROOT_DIR,
  57. DBG_VERBOSE,
  58. "Path %s is on unexpected drive type %u",
  59. FileSpec,
  60. type
  61. ));
  62. lastResult = FALSE;
  63. } else {
  64. lastResult = TRUE;
  65. }
  66. return lastResult;
  67. }
  68. BOOL
  69. IsPathOnFixedDriveW (
  70. IN PCWSTR FileSpec OPTIONAL
  71. )
  72. {
  73. static WCHAR root[] = L"?:\\";
  74. UINT type;
  75. static BOOL lastResult;
  76. PCWSTR p;
  77. if (!FileSpec) {
  78. return FALSE;
  79. }
  80. p = FileSpec;
  81. if (p[0] == L'\\' && p[1] == L'\\' && p[2] == L'?' && p[3] == L'\\') {
  82. p += 4;
  83. }
  84. MYASSERT (ISNT());
  85. if (!p[0]) {
  86. return FALSE;
  87. }
  88. if (p[1] != L':' || p[2] != L'\\') {
  89. return FALSE;
  90. }
  91. if (root[0] == p[0]) {
  92. return lastResult;
  93. }
  94. root[0] = p[0];
  95. type = GetDriveTypeW (root);
  96. if (type != DRIVE_FIXED && type != DRIVE_REMOTE) {
  97. DEBUGMSGW_IF ((
  98. type != DRIVE_REMOVABLE && type != DRIVE_NO_ROOT_DIR,
  99. DBG_VERBOSE,
  100. "Path %s is on unexpected drive type %u",
  101. FileSpec,
  102. type
  103. ));
  104. lastResult = FALSE;
  105. } else {
  106. lastResult = TRUE;
  107. }
  108. return lastResult;
  109. }
  110. BOOL
  111. CopyFileSpecToLongA (
  112. IN PCSTR FullFileSpecIn,
  113. OUT PSTR OutPath
  114. )
  115. {
  116. CHAR fullFileSpec[MAX_MBCHAR_PATH];
  117. WIN32_FIND_DATAA findData;
  118. HANDLE findHandle;
  119. PSTR end;
  120. PSTR currentIn;
  121. PSTR currentOut;
  122. PSTR outEnd;
  123. PSTR maxOutPath = OutPath + MAX_PATH - 1;
  124. BOOL result = FALSE;
  125. UINT oldMode;
  126. BOOL forceCopy = FALSE;
  127. oldMode = SetErrorMode (SEM_FAILCRITICALERRORS);
  128. __try {
  129. //
  130. // Limit length
  131. //
  132. if (!IsPathLengthOkA (FullFileSpecIn)) {
  133. DEBUGMSGA ((DBG_ERROR, "Inbound file spec is too long: %s", FullFileSpecIn));
  134. __leave;
  135. }
  136. //
  137. // If path is on removable media, don't touch the disk
  138. //
  139. if (!IsPathOnFixedDriveA (FullFileSpecIn)) {
  140. forceCopy = TRUE;
  141. __leave;
  142. }
  143. //
  144. // Make a copy of the file spec so we can truncate it at the wacks
  145. //
  146. StringCopyA (fullFileSpec, FullFileSpecIn);
  147. //
  148. // Begin building the path
  149. //
  150. OutPath[0] = fullFileSpec[0];
  151. OutPath[1] = fullFileSpec[1];
  152. OutPath[2] = fullFileSpec[2];
  153. OutPath[3] = 0;
  154. currentIn = fullFileSpec + 3;
  155. currentOut = OutPath + 3;
  156. for (;;) {
  157. end = _mbschr (currentIn, '\\');
  158. if (end == (currentIn + 1)) {
  159. currentIn++;
  160. continue;
  161. }
  162. if (end) {
  163. *end = 0;
  164. }
  165. findHandle = FindFirstFileA (fullFileSpec, &findData);
  166. if (findHandle != INVALID_HANDLE_VALUE) {
  167. FindClose (findHandle);
  168. //
  169. // Copy long file name obtained from FindFirstFile
  170. //
  171. outEnd = currentOut + TcharCountA (findData.cFileName);
  172. if (outEnd > maxOutPath) {
  173. #ifdef DEBUG
  174. *currentOut = 0;
  175. DEBUGMSGA ((
  176. DBG_WARNING,
  177. "Path %s too long to append to %s",
  178. findData.cFileName,
  179. OutPath
  180. ));
  181. #endif
  182. __leave;
  183. }
  184. StringCopyA (currentOut, findData.cFileName);
  185. currentOut = outEnd;
  186. } else {
  187. //
  188. // Copy the rest of the path since it doesn't exist
  189. //
  190. if (end) {
  191. *end = '\\';
  192. }
  193. outEnd = currentOut + TcharCountA (currentIn);
  194. if (outEnd > maxOutPath) {
  195. #ifdef DEBUG
  196. DEBUGMSGA ((
  197. DBG_WARNING,
  198. "Path %s too long to append to %s",
  199. currentIn,
  200. OutPath
  201. ));
  202. #endif
  203. __leave;
  204. }
  205. StringCopyA (currentOut, currentIn);
  206. break; // done with path
  207. }
  208. if (!end) {
  209. MYASSERT (*currentOut == 0);
  210. break; // done with path
  211. }
  212. *currentOut++ = '\\';
  213. *currentOut = 0;
  214. *end = '\\';
  215. currentIn = end + 1;
  216. }
  217. result = TRUE;
  218. }
  219. __finally {
  220. SetErrorMode (oldMode);
  221. }
  222. if (forceCopy) {
  223. StringCopyA (OutPath, FullFileSpecIn);
  224. return TRUE;
  225. }
  226. if (!result) {
  227. StringCopyTcharCountA (OutPath, FullFileSpecIn, MAX_PATH);
  228. }
  229. return result;
  230. }
  231. BOOL
  232. CopyFileSpecToLongW (
  233. IN PCWSTR FullFileSpecIn,
  234. OUT PWSTR OutPath
  235. )
  236. {
  237. WCHAR fullFileSpec[MAX_WCHAR_PATH];
  238. WIN32_FIND_DATAW findData;
  239. HANDLE findHandle;
  240. PWSTR end;
  241. PWSTR currentIn;
  242. PWSTR currentOut;
  243. PWSTR outEnd;
  244. PWSTR maxOutPath = OutPath + MAX_PATH - 1;
  245. BOOL result = FALSE;
  246. UINT oldMode;
  247. BOOL forceCopy = FALSE;
  248. MYASSERT (ISNT());
  249. oldMode = SetErrorMode (SEM_FAILCRITICALERRORS);
  250. __try {
  251. //
  252. // Limit length
  253. //
  254. if (!IsPathLengthOkW (FullFileSpecIn)) {
  255. DEBUGMSGW ((DBG_ERROR, "Inbound file spec is too long: %s", FullFileSpecIn));
  256. __leave;
  257. }
  258. //
  259. // If path is on removable media, don't touch the disk
  260. //
  261. if (!IsPathOnFixedDriveW (FullFileSpecIn)) {
  262. forceCopy = TRUE;
  263. __leave;
  264. }
  265. //
  266. // Make a copy of the file spec so we can truncate it at the wacks
  267. //
  268. StringCopyW (fullFileSpec, FullFileSpecIn);
  269. //
  270. // Begin building the path
  271. //
  272. OutPath[0] = fullFileSpec[0];
  273. OutPath[1] = fullFileSpec[1];
  274. OutPath[2] = fullFileSpec[2];
  275. OutPath[3] = 0;
  276. currentIn = fullFileSpec + 3;
  277. currentOut = OutPath + 3;
  278. for (;;) {
  279. end = wcschr (currentIn, L'\\');
  280. if (end == (currentIn + 1)) {
  281. currentIn++;
  282. continue;
  283. }
  284. if (end) {
  285. *end = 0;
  286. }
  287. findHandle = FindFirstFileW (fullFileSpec, &findData);
  288. if (findHandle != INVALID_HANDLE_VALUE) {
  289. FindClose (findHandle);
  290. //
  291. // Copy long file name obtained from FindFirstFile
  292. //
  293. outEnd = currentOut + TcharCountW (findData.cFileName);
  294. if (outEnd > maxOutPath) {
  295. DEBUGMSGW ((
  296. DBG_WARNING,
  297. "Path %s too long to append to %s",
  298. findData.cFileName,
  299. OutPath
  300. ));
  301. __leave;
  302. }
  303. StringCopyW (currentOut, findData.cFileName);
  304. currentOut = outEnd;
  305. } else {
  306. //
  307. // Copy the rest of the path since it doesn't exist
  308. //
  309. if (end) {
  310. *end = L'\\';
  311. }
  312. outEnd = currentOut + TcharCountW (currentIn);
  313. if (outEnd > maxOutPath) {
  314. DEBUGMSGW ((
  315. DBG_WARNING,
  316. "Path %s too long to append to %s",
  317. currentIn,
  318. OutPath
  319. ));
  320. __leave;
  321. }
  322. StringCopyW (currentOut, currentIn);
  323. break; // done with path
  324. }
  325. if (!end) {
  326. MYASSERT (*currentOut == 0);
  327. break; // done with path
  328. }
  329. *currentOut++ = L'\\';
  330. *currentOut = 0;
  331. *end = L'\\';
  332. currentIn = end + 1;
  333. }
  334. result = TRUE;
  335. }
  336. __finally {
  337. SetErrorMode (oldMode);
  338. }
  339. if (forceCopy) {
  340. StringCopyW (OutPath, FullFileSpecIn);
  341. return TRUE;
  342. }
  343. if (!result) {
  344. StringCopyTcharCountW (OutPath, FullFileSpecIn, MAX_PATH);
  345. }
  346. return result;
  347. }
  348. BOOL
  349. DoesFileExistExA(
  350. IN PCSTR FileName,
  351. OUT PWIN32_FIND_DATAA FindData OPTIONAL
  352. )
  353. /*++
  354. Routine Description:
  355. Determine if a file exists and is accessible.
  356. Errormode is set (and then restored) so the user will not see
  357. any pop-ups.
  358. Arguments:
  359. FileName - supplies full path of file to check for existance.
  360. FindData - if specified, receives find data for the file.
  361. Return Value:
  362. TRUE if the file exists and is accessible.
  363. FALSE if not. GetLastError() returns extended error info.
  364. --*/
  365. {
  366. WIN32_FIND_DATAA ourFindData;
  367. HANDLE FindHandle;
  368. UINT OldMode;
  369. DWORD Error;
  370. if (!FindData) {
  371. return GetFileAttributesA (FileName) != 0xffffffff;
  372. }
  373. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  374. FindHandle = FindFirstFileA(FileName, &ourFindData);
  375. if (FindHandle == INVALID_HANDLE_VALUE) {
  376. Error = GetLastError();
  377. } else {
  378. FindClose(FindHandle);
  379. *FindData = ourFindData;
  380. Error = NO_ERROR;
  381. }
  382. SetErrorMode(OldMode);
  383. SetLastError(Error);
  384. return (Error == NO_ERROR);
  385. }
  386. BOOL
  387. DoesFileExistExW (
  388. IN PCWSTR FileName,
  389. OUT PWIN32_FIND_DATAW FindData OPTIONAL
  390. )
  391. /*++
  392. Routine Description:
  393. Determine if a file exists and is accessible.
  394. Errormode is set (and then restored) so the user will not see
  395. any pop-ups.
  396. Arguments:
  397. FileName - supplies full path of file to check for existance.
  398. FindData - if specified, receives find data for the file.
  399. Return Value:
  400. TRUE if the file exists and is accessible.
  401. FALSE if not. GetLastError() returns extended error info.
  402. --*/
  403. {
  404. WIN32_FIND_DATAW ourFindData;
  405. HANDLE FindHandle;
  406. UINT OldMode;
  407. DWORD Error = NO_ERROR;
  408. UINT length;
  409. BOOL result = FALSE;
  410. PCWSTR longFileName = NULL;
  411. __try {
  412. if (FileName[0] != TEXT('\\')) {
  413. length = TcharCountW (FileName);
  414. if (length >= MAX_PATH) {
  415. longFileName = JoinPathsW (L"\\\\?", FileName);
  416. MYASSERT (longFileName);
  417. FileName = longFileName;
  418. }
  419. }
  420. if (!FindData) {
  421. result = (GetLongPathAttributesW (FileName) != 0xffffffff);
  422. __leave;
  423. }
  424. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  425. FindHandle = FindFirstFileW(FileName,&ourFindData);
  426. if (FindHandle == INVALID_HANDLE_VALUE) {
  427. Error = GetLastError();
  428. } else {
  429. FindClose(FindHandle);
  430. *FindData = ourFindData;
  431. }
  432. SetErrorMode(OldMode);
  433. SetLastError(Error);
  434. result = (Error == NO_ERROR);
  435. }
  436. __finally {
  437. if (longFileName) {
  438. FreePathStringW (longFileName);
  439. }
  440. }
  441. return result;
  442. }
  443. DWORD
  444. MakeSurePathExistsA(
  445. IN PCSTR FullFileSpec,
  446. IN BOOL PathOnly
  447. )
  448. {
  449. CHAR Buffer[MAX_MBCHAR_PATH];
  450. PCHAR p,q;
  451. BOOL Done;
  452. BOOL isUnc;
  453. DWORD d;
  454. WIN32_FIND_DATAA FindData;
  455. isUnc = (FullFileSpec[0] == '\\') && (FullFileSpec[1] == '\\');
  456. //
  457. // Locate and strip off the final component
  458. //
  459. _mbssafecpy(Buffer,FullFileSpec,sizeof(Buffer));
  460. p = _mbsrchr(Buffer, '\\');
  461. if (p) {
  462. if (!PathOnly) {
  463. *p = 0;
  464. }
  465. //
  466. // If it's a drive root, nothing to do.
  467. //
  468. if(Buffer[0] && (Buffer[1] == ':') && !Buffer[2]) {
  469. return(NO_ERROR);
  470. }
  471. } else {
  472. //
  473. // Just a relative filename, nothing to do.
  474. //
  475. return(NO_ERROR);
  476. }
  477. //
  478. // If it already exists do nothing.
  479. //
  480. if (DoesFileExistExA (Buffer,&FindData)) {
  481. return NO_ERROR;
  482. }
  483. p = Buffer;
  484. //
  485. // Compensate for drive spec.
  486. //
  487. if(p[0] && (p[1] == ':')) {
  488. p += 2;
  489. }
  490. //
  491. // Compensate for UNC paths.
  492. //
  493. if (isUnc) {
  494. //
  495. // Skip the initial wack wack before machine name.
  496. //
  497. p += 2;
  498. //
  499. // Skip to the share.
  500. //
  501. p = _mbschr(p, '\\');
  502. if (p==NULL) {
  503. return ERROR_BAD_PATHNAME;
  504. }
  505. //
  506. // Skip past the share.
  507. //
  508. p = _mbschr(p, '\\');
  509. if (p==NULL) {
  510. return ERROR_BAD_PATHNAME;
  511. }
  512. }
  513. Done = FALSE;
  514. do {
  515. //
  516. // Skip path sep char.
  517. //
  518. while(*p == '\\') {
  519. p++;
  520. }
  521. //
  522. // Locate next path sep char or terminating nul.
  523. //
  524. if(q = _mbschr(p, '\\')) {
  525. *q = 0;
  526. } else {
  527. q = GetEndOfStringA(p);
  528. Done = TRUE;
  529. }
  530. //
  531. // Create this portion of the path.
  532. //
  533. if(!CreateDirectoryA(Buffer,NULL)) {
  534. d = GetLastError();
  535. if(d != ERROR_ALREADY_EXISTS) {
  536. return(d);
  537. }
  538. }
  539. if(!Done) {
  540. *q = '\\';
  541. p = q+1;
  542. }
  543. } while(!Done);
  544. return(NO_ERROR);
  545. }
  546. VOID
  547. DestPathCopyW (
  548. OUT PWSTR DestPath,
  549. IN PCWSTR SrcPath
  550. )
  551. {
  552. PCWSTR p;
  553. PWSTR q;
  554. PCWSTR end;
  555. PCWSTR maxStart;
  556. UINT len;
  557. UINT count;
  558. len = TcharCountW (SrcPath);
  559. if (len < MAX_PATH) {
  560. StringCopyW (DestPath, SrcPath);
  561. return;
  562. }
  563. //
  564. // Path is too long -- try to truncate it
  565. //
  566. wsprintfW (DestPath, L"%c:\\Long", SrcPath[0]);
  567. CreateDirectoryW (DestPath, NULL);
  568. p = SrcPath;
  569. end = SrcPath + len;
  570. maxStart = end - 220;
  571. while (p < end) {
  572. if (*p == '\\') {
  573. if (p >= maxStart) {
  574. break;
  575. }
  576. }
  577. p++;
  578. }
  579. if (p == end) {
  580. p = maxStart;
  581. }
  582. MYASSERT (TcharCountW (p) <= 220);
  583. StringCopyW (AppendWackW (DestPath), p);
  584. q = (PWSTR) GetEndOfStringW (DestPath);
  585. //
  586. // Verify there is no collision
  587. //
  588. for (count = 1 ; count < 1000000 ; count++) {
  589. if (GetFileAttributesW (DestPath) == INVALID_ATTRIBUTES) {
  590. break;
  591. }
  592. wsprintfW (q, L" (%u)", count);
  593. }
  594. }
  595. DWORD
  596. MakeSurePathExistsW(
  597. IN LPCWSTR FullFileSpec,
  598. IN BOOL PathOnly
  599. )
  600. {
  601. PWSTR buffer;
  602. WCHAR *p, *q;
  603. BOOL Done;
  604. DWORD d;
  605. WIN32_FIND_DATAW FindData;
  606. DWORD result = NO_ERROR;
  607. if (FullFileSpec[0] != L'\\') {
  608. if (TcharCountW (FullFileSpec) >= MAX_PATH) {
  609. if (PathOnly || ((wcsrchr (FullFileSpec, L'\\') - FullFileSpec) >= MAX_PATH)) {
  610. LOGW ((LOG_ERROR, "Can't create path %s because it is too long", FullFileSpec));
  611. return ERROR_FILENAME_EXCED_RANGE;
  612. }
  613. }
  614. }
  615. //
  616. // Locate and strip off the final component
  617. //
  618. buffer = DuplicatePathStringW (FullFileSpec, 0);
  619. __try {
  620. p = wcsrchr(buffer, L'\\');
  621. if (p) {
  622. if (!PathOnly) {
  623. *p = 0;
  624. }
  625. } else {
  626. //
  627. // Just a relative filename, nothing to do.
  628. //
  629. __leave;
  630. }
  631. //
  632. // If it already exists do nothing.
  633. //
  634. if (DoesFileExistExW (buffer, &FindData)) {
  635. result = ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? NO_ERROR : ERROR_DIRECTORY);
  636. __leave;
  637. }
  638. p = buffer;
  639. //
  640. // Compensate for drive spec.
  641. //
  642. if (p[0] == L'\\' && p[1] == L'\\' && p[2] == L'?' && p[3] == L'\\') {
  643. p += 4;
  644. }
  645. if (p[0] && (p[1] == L':')) {
  646. p += 2;
  647. }
  648. if ((p[0] == 0) || (p[0] == L'\\' && p[1] == 0)) {
  649. //
  650. // Root -- leave
  651. //
  652. __leave;
  653. }
  654. Done = FALSE;
  655. do {
  656. //
  657. // Skip path sep char.
  658. //
  659. while(*p == L'\\') {
  660. p++;
  661. }
  662. //
  663. // Locate next path sep char or terminating nul.
  664. //
  665. q = wcschr(p, L'\\');
  666. if(q) {
  667. *q = 0;
  668. } else {
  669. q = GetEndOfStringW (p);
  670. Done = TRUE;
  671. }
  672. //
  673. // Create this portion of the path.
  674. //
  675. if(!CreateDirectoryW(buffer,NULL)) {
  676. d = GetLastError();
  677. if(d != ERROR_ALREADY_EXISTS) {
  678. result = d;
  679. __leave;
  680. }
  681. }
  682. if(!Done) {
  683. *q = L'\\';
  684. p = q+1;
  685. }
  686. } while(!Done);
  687. }
  688. __finally {
  689. FreePathStringW (buffer);
  690. }
  691. return result;
  692. }
  693. //
  694. // ...PACKFILE HANDLING...
  695. //
  696. #define PACKFILE_BUFFERSIZE 2048
  697. BOOL
  698. pFillEnumStructureA (
  699. IN PPACKFILEENUMA Enum
  700. )
  701. {
  702. BOOL rSuccess = TRUE;
  703. DWORD numBytesRead;
  704. HANDLE savedHandle;
  705. MYASSERT(Enum && Enum -> Handle != INVALID_HANDLE_VALUE && Enum -> Handle != NULL);
  706. //
  707. // Save this away.. The read below blows it away.
  708. //
  709. savedHandle = Enum -> Handle;
  710. //
  711. // Read the header information from the current position in the file.
  712. //
  713. rSuccess = ReadFile(
  714. Enum -> Handle,
  715. Enum,
  716. sizeof(PACKFILEENUMA),
  717. &numBytesRead,
  718. NULL
  719. );
  720. //
  721. // Restore the handle member.
  722. //
  723. Enum -> Handle = savedHandle;
  724. return rSuccess && numBytesRead == sizeof(PACKFILEENUMA);
  725. }
  726. BOOL
  727. PackedFile_ExtractFileUsingEnumA (
  728. IN PPACKFILEENUMA Enum,
  729. IN LPCSTR FileName OPTIONAL
  730. )
  731. {
  732. BOOL rSuccess = TRUE;
  733. HANDLE newFileHandle;
  734. LONGLONG numberOfBytesToExtract;
  735. LONGLONG numberOfBytesExtracted;
  736. DWORD numberOfBytesToRead;
  737. DWORD numberOfBytesRead;
  738. BYTE buffer[PACKFILE_BUFFERSIZE];
  739. DWORD fileHigh;
  740. DWORD fileLow;
  741. MYASSERT(Enum && Enum -> Handle != INVALID_HANDLE_VALUE && Enum -> Handle != NULL);
  742. //
  743. // First, attempt to create the new file. If FileName was not specified, we'll use the
  744. // Identifier name in the enum struct.
  745. //
  746. if (!FileName) {
  747. FileName = Enum -> Identifier;
  748. }
  749. newFileHandle = CreateFileA (
  750. FileName,
  751. GENERIC_WRITE,
  752. 0, // No sharing.
  753. NULL, // No inheritance.
  754. CREATE_ALWAYS,
  755. FILE_ATTRIBUTE_NORMAL,
  756. NULL // No template file.
  757. );
  758. if (newFileHandle == INVALID_HANDLE_VALUE) {
  759. rSuccess = FALSE;
  760. DEBUGMSG((DBG_ERROR,"PackedFile_ExtractFromEnum: Could not open file %s. FileName"));
  761. }
  762. else {
  763. //
  764. // File was successfully opened. Extract the data starting from the current file position
  765. //
  766. //
  767. // Create a LONGLONG value out of the size of the file.
  768. //
  769. numberOfBytesToExtract = ((LONGLONG)Enum -> SizeHigh) << 32 | ((LONGLONG) Enum -> SizeLow);
  770. numberOfBytesExtracted = 0;
  771. do {
  772. //
  773. // Figure out how much to read from the file.
  774. //
  775. if (numberOfBytesToExtract - numberOfBytesExtracted > PACKFILE_BUFFERSIZE) {
  776. numberOfBytesToRead = PACKFILE_BUFFERSIZE;
  777. }
  778. else {
  779. numberOfBytesToRead = (DWORD) (numberOfBytesToExtract - numberOfBytesExtracted);
  780. }
  781. if (!ReadFile(
  782. Enum -> Handle,
  783. buffer,
  784. numberOfBytesToRead,
  785. &numberOfBytesRead,
  786. NULL
  787. ) ||
  788. !WriteFile(
  789. newFileHandle,
  790. buffer,
  791. numberOfBytesRead,
  792. &numberOfBytesRead,
  793. NULL
  794. )) {
  795. numberOfBytesExtracted += (LONGLONG) numberOfBytesRead;
  796. break;
  797. }
  798. //
  799. // Update the count of bytes extracted.
  800. //
  801. numberOfBytesExtracted += (LONGLONG) numberOfBytesRead;
  802. } while (numberOfBytesExtracted < numberOfBytesToExtract);
  803. //
  804. // Close the handle to the new file we created.
  805. //
  806. CloseHandle(newFileHandle);
  807. //
  808. // Reset the file pointer.
  809. //
  810. fileHigh = (DWORD) (numberOfBytesExtracted >> 32);
  811. fileLow = (DWORD) (numberOfBytesExtracted & 0xffffffff);
  812. SetFilePointer(Enum -> Handle,fileLow,&fileHigh,FILE_CURRENT);
  813. if (numberOfBytesExtracted != numberOfBytesToExtract) {
  814. rSuccess = FALSE;
  815. DEBUGMSG((DBG_ERROR,"PackedFile_ExtractFromEnum: Could not extract file."));
  816. }
  817. }
  818. return rSuccess;
  819. }
  820. VOID
  821. PackedFile_AbortEnum (
  822. IN OUT PPACKFILEENUMA Enum
  823. )
  824. {
  825. MYASSERT(Enum -> Handle != INVALID_HANDLE_VALUE && Enum -> Handle != NULL);
  826. //
  827. // Nothing to do except close the handle.
  828. //
  829. CloseHandle(Enum -> Handle);
  830. }
  831. BOOL
  832. PackedFile_EnumNextA (
  833. IN PPACKFILEENUMA Enum
  834. )
  835. {
  836. BOOL rSuccess = TRUE;
  837. MYASSERT(Enum && Enum -> Handle != INVALID_HANDLE_VALUE && Enum -> Handle != NULL);
  838. //
  839. // Move the file pointer ahead by the size contained in the current enum structure.
  840. //
  841. if (SetFilePointer(Enum -> Handle,Enum -> SizeLow,&Enum -> SizeHigh,FILE_CURRENT) == 0xffffffff &&
  842. GetLastError() != NO_ERROR) {
  843. rSuccess = FALSE;
  844. }
  845. else {
  846. //
  847. // Fill in the enum structure with the fresh data.
  848. //
  849. rSuccess = pFillEnumStructureA(Enum);
  850. }
  851. if (!rSuccess) {
  852. PackedFile_AbortEnum(Enum);
  853. }
  854. return rSuccess;
  855. }
  856. BOOL
  857. PackedFile_EnumFirstA (
  858. IN LPCSTR PackFile,
  859. OUT PPACKFILEENUMA Enum
  860. )
  861. {
  862. BOOL rSuccess = FALSE;
  863. MYASSERT(Enum && PackFile);
  864. //
  865. // Clean out the Enum structure.
  866. //
  867. ZeroMemory(Enum,sizeof(PACKFILEENUMA));
  868. //
  869. // Open a handle to the PackFile.
  870. //
  871. Enum -> Handle = CreateFileA (
  872. PackFile,
  873. GENERIC_READ,
  874. FILE_SHARE_READ,
  875. NULL, // No inheritance.
  876. OPEN_ALWAYS,
  877. FILE_ATTRIBUTE_NORMAL,
  878. NULL // No template file.
  879. );
  880. //
  881. // If that succeeds, trust EnumNext to handle the dirty work.
  882. //
  883. if (Enum -> Handle != INVALID_HANDLE_VALUE) {
  884. rSuccess = pFillEnumStructureA(Enum);
  885. }
  886. return rSuccess;
  887. }
  888. BOOL
  889. PackedFile_ExtractFileA (
  890. IN LPCSTR PackFile,
  891. IN LPCSTR FileIdentifier,
  892. IN LPCSTR FileName OPTIONAL
  893. )
  894. {
  895. PACKFILEENUMA e;
  896. BOOL rSuccess = FALSE;
  897. MYASSERT(PackFile && FileIdentifier);
  898. if (PackedFile_EnumFirstA(PackFile,&e)) {
  899. do {
  900. if (StringIMatchA (e.Identifier,FileIdentifier)) {
  901. //
  902. // We found the one they were looking for..
  903. //
  904. rSuccess = PackedFile_ExtractFileUsingEnumA(&e,FileName);
  905. PackedFile_AbortEnum(&e);
  906. break;
  907. }
  908. } while (PackedFile_EnumNextA(&e));
  909. }
  910. return rSuccess;
  911. }
  912. BOOL
  913. PackedFile_AddFileA (
  914. IN LPCSTR PackFile,
  915. IN LPCSTR NewFile,
  916. IN LPCSTR Identifier OPTIONAL
  917. )
  918. {
  919. HANDLE packFileHandle = INVALID_HANDLE_VALUE;
  920. HANDLE newFileHandle = INVALID_HANDLE_VALUE;
  921. BOOL rSuccess = TRUE;
  922. PACKFILEENUMA fileHeader;
  923. DWORD numBytes;
  924. BYTE buffer[PACKFILE_BUFFERSIZE];
  925. //
  926. // Now, attempt to open the new file.
  927. //
  928. newFileHandle = CreateFileA (
  929. NewFile,
  930. GENERIC_READ,
  931. 0,
  932. NULL,
  933. OPEN_EXISTING,
  934. FILE_ATTRIBUTE_NORMAL,
  935. NULL
  936. );
  937. if (newFileHandle == INVALID_HANDLE_VALUE) {
  938. DEBUGMSG((DBG_ERROR,"PackedFile_AddFile could not open %s and therefore cannot add it.",NewFile));
  939. return FALSE;
  940. }
  941. //
  942. // Open or create the packfile. If it does not already exist, then it will be created.
  943. //
  944. packFileHandle = CreateFileA (
  945. PackFile,
  946. GENERIC_READ | GENERIC_WRITE,
  947. 0, // No sharing.
  948. NULL, // No inheritance.
  949. OPEN_ALWAYS,
  950. FILE_ATTRIBUTE_NORMAL,
  951. NULL // No template file.
  952. );
  953. if (packFileHandle == INVALID_HANDLE_VALUE) {
  954. rSuccess = FALSE;
  955. DEBUGMSG((DBG_ERROR,"PackedFile_AddFile Could not open or create the packed file %s.",PackFile));
  956. } else {
  957. //
  958. // Both files have been successfully opened. Add the new file to the packfile.
  959. //
  960. //
  961. // First, we need to set the file pointer to the end of the packed file.
  962. //
  963. SetFilePointer(packFileHandle,0,NULL,FILE_END);
  964. //
  965. // Ok, Fill in a header structure for this file. It is a simple header. All it contains
  966. // is the Identifier (or the file path if Identifier is NULL) and the size of the file.
  967. // There is another parameter (Handle) in the structure, but this is only used
  968. // for enumeration purposes and is always NULL when written into the file.
  969. //
  970. if (!Identifier) {
  971. Identifier = NewFile;
  972. }
  973. fileHeader.Handle = NULL; // This member is only used in enumeration.
  974. _mbssafecpy(fileHeader.Identifier,Identifier,MAX_MBCHAR_PATH);
  975. fileHeader.SizeLow = GetFileSize(newFileHandle,&fileHeader.SizeHigh);
  976. if (fileHeader.SizeLow == 0xffffffff && GetLastError() != NO_ERROR) {
  977. rSuccess = FALSE;
  978. DEBUGMSG((DBG_ERROR,"PackedFile_AddFile Could not get the file size for %s.",NewFile));
  979. }
  980. else {
  981. //
  982. // Now, write the header into the packed file.
  983. //
  984. if (!WriteFile(
  985. packFileHandle,
  986. &fileHeader,
  987. sizeof(PACKFILEENUMA),
  988. &numBytes,
  989. NULL // Not overlapped.
  990. )) {
  991. DEBUGMSG((DBG_ERROR,"PackedFile_AddFile Could not write a file header to the pack file %s.",PackFile));
  992. rSuccess = FALSE;
  993. }
  994. else {
  995. //
  996. // At this point, all that is left to do is to write the bits from the packed file into
  997. // the packed file.
  998. //
  999. do {
  1000. if (!ReadFile(
  1001. newFileHandle,
  1002. buffer,
  1003. PACKFILE_BUFFERSIZE,
  1004. &numBytes,
  1005. NULL
  1006. ) ||
  1007. !WriteFile(
  1008. packFileHandle,
  1009. buffer,
  1010. numBytes,
  1011. &numBytes,
  1012. NULL
  1013. )) {
  1014. rSuccess = FALSE;
  1015. DEBUGMSG((DBG_ERROR,"PackedFile_AddFile encountered an error writing the file %s to the packed file %s.",NewFile,PackFile));
  1016. break;
  1017. }
  1018. } while (numBytes == PACKFILE_BUFFERSIZE);
  1019. }
  1020. }
  1021. //
  1022. // Close the handles to both files. We are done with them.
  1023. //
  1024. CloseHandle(packFileHandle);
  1025. }
  1026. CloseHandle(newFileHandle);
  1027. return rSuccess;
  1028. }
  1029. //
  1030. // The W versions of these files are unimplemented.
  1031. //
  1032. BOOL
  1033. PackedFile_AddFileW (
  1034. IN LPCSTR PackFile,
  1035. IN LPCSTR NewFile,
  1036. IN LPCSTR Identifier OPTIONAL
  1037. )
  1038. {
  1039. return FALSE;
  1040. }
  1041. BOOL
  1042. PackedFile_ExtractFileW (
  1043. IN LPCSTR PackFile,
  1044. IN LPCSTR FileIdentifier,
  1045. IN LPCSTR FileName OPTIONAL
  1046. )
  1047. {
  1048. return FALSE;
  1049. }
  1050. BOOL
  1051. PackedFile_EnumFirstW (
  1052. IN LPCSTR PackFile,
  1053. OUT PPACKFILEENUMA Enum
  1054. )
  1055. {
  1056. return FALSE;
  1057. }
  1058. BOOL
  1059. PackedFile_EnumNextW (
  1060. IN PPACKFILEENUMA Enum
  1061. )
  1062. {
  1063. return FALSE;
  1064. }
  1065. BOOL
  1066. PackedFile_ExtractFileUsingEnumW (
  1067. IN PPACKFILEENUMA Enum,
  1068. IN LPCSTR FileName OPTIONAL
  1069. )
  1070. {
  1071. return FALSE;
  1072. }
  1073. BOOL
  1074. WriteFileStringA (
  1075. IN HANDLE File,
  1076. IN PCSTR String
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. Writes a DBCS string to the specified file.
  1081. Arguments:
  1082. File - Specifies the file handle that was opened with write access.
  1083. String - Specifies the nul-terminated string to write to the file.
  1084. Return Value:
  1085. TRUE if successful, FALSE if an error occurred. Call GetLastError
  1086. for error condition.
  1087. --*/
  1088. {
  1089. DWORD DontCare;
  1090. return WriteFile (File, String, ByteCountA (String), &DontCare, NULL);
  1091. }
  1092. BOOL
  1093. WriteFileStringW (
  1094. IN HANDLE File,
  1095. IN PCWSTR String
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. Converts a UNICODE string to DBCS, then Writes it to the specified file.
  1100. Arguments:
  1101. File - Specifies the file handle that was opened with write access.
  1102. String - Specifies the UNICODE nul-terminated string to convert and
  1103. write to the file.
  1104. Return Value:
  1105. TRUE if successful, FALSE if an error occurred. Call GetLastError for
  1106. error condition.
  1107. --*/
  1108. {
  1109. DWORD DontCare;
  1110. PCSTR AnsiVersion;
  1111. BOOL b;
  1112. AnsiVersion = ConvertWtoA (String);
  1113. if (!AnsiVersion) {
  1114. return FALSE;
  1115. }
  1116. b = WriteFile (File, AnsiVersion, ByteCountA (AnsiVersion), &DontCare, NULL);
  1117. FreeConvertedStr (AnsiVersion);
  1118. return b;
  1119. }
  1120. /*++
  1121. Routine Description:
  1122. pFindShortNameA is a helper function for OurGetLongPathName. It
  1123. obtains the short file name, if it exists, using FindFirstFile.
  1124. Arguments:
  1125. WhatToFind - Specifies the short or long name of a file to locate
  1126. Buffer - Receives the matching file name
  1127. Return Value:
  1128. TRUE if the file was found and Buffer was updated, or FALSE if the
  1129. file was not found and Buffer was not updated.
  1130. --*/
  1131. BOOL
  1132. pFindShortNameA (
  1133. IN PCSTR WhatToFind,
  1134. OUT PSTR Buffer,
  1135. OUT INT *BufferSizeInBytes
  1136. )
  1137. {
  1138. WIN32_FIND_DATAA fd;
  1139. HANDLE hFind;
  1140. hFind = FindFirstFileA (WhatToFind, &fd);
  1141. if (hFind == INVALID_HANDLE_VALUE) {
  1142. return FALSE;
  1143. }
  1144. FindClose (hFind);
  1145. *BufferSizeInBytes -= ByteCountA (fd.cFileName);
  1146. if (*BufferSizeInBytes >= sizeof (CHAR)) {
  1147. StringCopyA (Buffer, fd.cFileName);
  1148. }
  1149. return TRUE;
  1150. }
  1151. BOOL
  1152. pFindShortNameW (
  1153. IN PCWSTR WhatToFind,
  1154. OUT PWSTR Buffer,
  1155. OUT INT *BufferSizeInBytes
  1156. )
  1157. {
  1158. WIN32_FIND_DATAA fdA;
  1159. WIN32_FIND_DATAW fdW;
  1160. PCWSTR UnicodeVersion;
  1161. PCSTR AnsiVersion;
  1162. HANDLE hFind;
  1163. if (ISNT ()) {
  1164. hFind = FindFirstFileW (WhatToFind, &fdW);
  1165. if (hFind == INVALID_HANDLE_VALUE) {
  1166. return FALSE;
  1167. }
  1168. FindClose (hFind);
  1169. } else {
  1170. AnsiVersion = ConvertWtoA (WhatToFind);
  1171. hFind = FindFirstFileA (AnsiVersion, &fdA);
  1172. FreeConvertedStr (AnsiVersion);
  1173. if (hFind == INVALID_HANDLE_VALUE) {
  1174. return FALSE;
  1175. }
  1176. FindClose (hFind);
  1177. fdW.dwFileAttributes = fdA.dwFileAttributes;
  1178. fdW.ftCreationTime = fdA.ftCreationTime;
  1179. fdW.ftLastAccessTime = fdA.ftLastAccessTime;
  1180. fdW.ftLastWriteTime = fdA.ftLastWriteTime;
  1181. fdW.nFileSizeHigh = fdA.nFileSizeHigh;
  1182. fdW.nFileSizeLow = fdA.nFileSizeLow;
  1183. fdW.dwReserved0 = fdA.dwReserved0;
  1184. fdW.dwReserved1 = fdA.dwReserved1;
  1185. UnicodeVersion = ConvertAtoW (fdA.cFileName);
  1186. StringCopyTcharCountW (fdW.cFileName, UnicodeVersion, MAX_PATH);
  1187. FreeConvertedStr (UnicodeVersion);
  1188. UnicodeVersion = ConvertAtoW (fdA.cAlternateFileName);
  1189. StringCopyTcharCountW (fdW.cAlternateFileName, UnicodeVersion, 14);
  1190. FreeConvertedStr (UnicodeVersion);
  1191. }
  1192. *BufferSizeInBytes -= ByteCountW (fdW.cFileName);
  1193. if (*BufferSizeInBytes >= sizeof (WCHAR)) {
  1194. StringCopyW (Buffer, fdW.cFileName);
  1195. }
  1196. return TRUE;
  1197. }
  1198. /*++
  1199. Routine Description:
  1200. OurGetLongPathName locates the long name for a file. It first locates the
  1201. full path if a path is not explicitly provided, and then uses FindFirstFile
  1202. to get the long file name. NOTE: This is exactly what the Win32 function
  1203. GetLongPathName does, but unfortunately the Win32 API is not available on Win95.
  1204. This routine resolves each piece of a short path name using recursion.
  1205. Arguments:
  1206. ShortPath - Specifies the file name or full file path to locate
  1207. Buffer - Receives the full file path. This buffer must be big enough to
  1208. handle the maximum file name size.
  1209. Return Value:
  1210. TRUE if the file is found and Buffer contains the long name, or FALSE
  1211. if the file is not found and Buffer is not modified.
  1212. --*/
  1213. BOOL
  1214. OurGetLongPathNameA (
  1215. IN PCSTR ShortPath,
  1216. OUT PSTR Buffer,
  1217. IN INT BufferSizeInBytes
  1218. )
  1219. {
  1220. CHAR FullPath[MAX_MBCHAR_PATH];
  1221. PCSTR SanitizedPath;
  1222. PSTR FilePart;
  1223. PSTR BufferEnd;
  1224. PSTR p, p2;
  1225. MBCHAR c;
  1226. BOOL result = TRUE;
  1227. MYASSERT (BufferSizeInBytes >= MAX_MBCHAR_PATH);
  1228. if (ShortPath[0] == 0) {
  1229. return FALSE;
  1230. }
  1231. __try {
  1232. SanitizedPath = SanitizePathA (ShortPath);
  1233. if (!SanitizedPath) {
  1234. SanitizedPath = DuplicatePathStringA (ShortPath, 0);
  1235. }
  1236. if (!_mbschr (SanitizedPath, '\\')) {
  1237. if (!SearchPathA (NULL, SanitizedPath, NULL, sizeof (FullPath), FullPath, &FilePart)) {
  1238. result = FALSE;
  1239. __leave;
  1240. }
  1241. } else {
  1242. GetFullPathNameA (SanitizedPath, sizeof (FullPath), FullPath, &FilePart);
  1243. }
  1244. //
  1245. // Convert short paths to long paths
  1246. //
  1247. p = FullPath;
  1248. if (!IsPathOnFixedDriveA (FullPath)) {
  1249. _mbssafecpy (Buffer, FullPath, BufferSizeInBytes);
  1250. __leave;
  1251. }
  1252. p += 3;
  1253. // Copy drive letter to buffer
  1254. StringCopyABA (Buffer, FullPath, p);
  1255. BufferEnd = GetEndOfStringA (Buffer);
  1256. BufferSizeInBytes -= p - FullPath;
  1257. // Convert each portion of the path
  1258. do {
  1259. // Locate end of this file or dir
  1260. p2 = _mbschr (p, '\\');
  1261. if (!p2) {
  1262. p = GetEndOfStringA (p);
  1263. } else {
  1264. p = p2;
  1265. }
  1266. // Look up file
  1267. c = *p;
  1268. *p = 0;
  1269. if (!pFindShortNameA (FullPath, BufferEnd, &BufferSizeInBytes)) {
  1270. DEBUGMSG ((DBG_VERBOSE, "OurGetLongPathNameA: %s does not exist", FullPath));
  1271. result = FALSE;
  1272. __leave;
  1273. }
  1274. *p = (CHAR)c;
  1275. // Move on to next part of path
  1276. if (*p) {
  1277. p = _mbsinc (p);
  1278. if (BufferSizeInBytes >= sizeof (CHAR) * 2) {
  1279. BufferEnd = _mbsappend (BufferEnd, "\\");
  1280. BufferSizeInBytes -= sizeof (CHAR);
  1281. }
  1282. }
  1283. } while (*p);
  1284. }
  1285. __finally {
  1286. FreePathStringA (SanitizedPath);
  1287. }
  1288. return result;
  1289. }
  1290. DWORD
  1291. OurGetShortPathNameW (
  1292. IN PCWSTR LongPath,
  1293. OUT PWSTR ShortPath,
  1294. IN DWORD CharSize
  1295. )
  1296. {
  1297. PCSTR LongPathA;
  1298. PSTR ShortPathA;
  1299. PCWSTR ShortPathW;
  1300. DWORD result;
  1301. if (ISNT()) {
  1302. return GetShortPathNameW (LongPath, ShortPath, CharSize);
  1303. } else {
  1304. LongPathA = ConvertWtoA (LongPath);
  1305. if (!IsPathOnFixedDriveA (LongPathA)) {
  1306. StringCopyTcharCountW (ShortPath, LongPath, CharSize);
  1307. FreeConvertedStr (LongPathA);
  1308. return TcharCountW (ShortPath);
  1309. }
  1310. ShortPathA = AllocPathStringA (CharSize);
  1311. result = GetShortPathNameA (LongPathA, ShortPathA, CharSize);
  1312. if (result) {
  1313. ShortPathW = ConvertAtoW (ShortPathA);
  1314. StringCopyTcharCountW (ShortPath, ShortPathW, CharSize);
  1315. FreeConvertedStr (ShortPathW);
  1316. } else {
  1317. StringCopyTcharCountW (ShortPath, LongPath, CharSize);
  1318. }
  1319. FreePathStringA (ShortPathA);
  1320. FreeConvertedStr (LongPathA);
  1321. return result;
  1322. }
  1323. }
  1324. DWORD
  1325. OurGetFullPathNameW (
  1326. PCWSTR FileName,
  1327. DWORD CharSize,
  1328. PWSTR FullPath,
  1329. PWSTR *FilePtr
  1330. )
  1331. {
  1332. PCSTR FileNameA;
  1333. PSTR FullPathA;
  1334. PSTR FilePtrA;
  1335. PCWSTR FullPathW;
  1336. DWORD result;
  1337. DWORD err;
  1338. if (ISNT()) {
  1339. return GetFullPathNameW (FileName, CharSize, FullPath, FilePtr);
  1340. } else {
  1341. FileNameA = ConvertWtoA (FileName);
  1342. FullPathA = AllocPathStringA (CharSize);
  1343. result = GetFullPathNameA (FileNameA, CharSize, FullPathA, &FilePtrA);
  1344. FullPathW = ConvertAtoW (FullPathA);
  1345. StringCopyTcharCountW (FullPath, FullPathW, CharSize);
  1346. err = GetLastError ();
  1347. *FilePtr = (PWSTR)GetFileNameFromPathW (FullPath);
  1348. FreeConvertedStr (FullPathW);
  1349. FreePathStringA (FullPathA);
  1350. FreeConvertedStr (FileNameA);
  1351. return result;
  1352. }
  1353. }
  1354. BOOL
  1355. OurGetLongPathNameW (
  1356. IN PCWSTR ShortPath,
  1357. OUT PWSTR Buffer,
  1358. IN INT BufferSizeInChars
  1359. )
  1360. {
  1361. WCHAR FullPath[MAX_WCHAR_PATH];
  1362. PWSTR FilePart;
  1363. PWSTR BufferEnd;
  1364. PWSTR p, p2;
  1365. WCHAR c;
  1366. INT BufferSizeInBytes;
  1367. MYASSERT (BufferSizeInChars >= MAX_WCHAR_PATH);
  1368. if (ShortPath[0] == 0) {
  1369. return FALSE;
  1370. }
  1371. BufferSizeInBytes = BufferSizeInChars * sizeof (WCHAR);
  1372. if (!wcschr (ShortPath, L'\\')) {
  1373. if (!SearchPathW (NULL, ShortPath, NULL, MAX_WCHAR_PATH, FullPath, &FilePart)) {
  1374. return FALSE;
  1375. }
  1376. } else {
  1377. if (OurGetFullPathNameW (ShortPath, MAX_WCHAR_PATH, FullPath, &FilePart) == 0) {
  1378. return FALSE;
  1379. }
  1380. }
  1381. //
  1382. // Convert short paths to long paths
  1383. //
  1384. p = FullPath;
  1385. if (!IsPathOnFixedDriveW (FullPath)) {
  1386. StringCopyTcharCountW (Buffer, FullPath, BufferSizeInChars);
  1387. return TRUE;
  1388. }
  1389. p += 3;
  1390. // Copy drive letter to buffer
  1391. StringCopyABW (Buffer, FullPath, p);
  1392. BufferEnd = GetEndOfStringW (Buffer);
  1393. BufferSizeInBytes -= sizeof (WCHAR) * 3;
  1394. // Convert each portion of the path
  1395. do {
  1396. // Locate end of this file or dir
  1397. p2 = wcschr (p, L'\\');
  1398. if (!p2) {
  1399. p = GetEndOfStringW (p);
  1400. } else {
  1401. p = p2;
  1402. }
  1403. // Look up file
  1404. c = *p;
  1405. *p = 0;
  1406. if (!pFindShortNameW (FullPath, BufferEnd, &BufferSizeInBytes)) {
  1407. DEBUGMSG ((DBG_VERBOSE, "OurGetLongPathNameW: %ls does not exist", FullPath));
  1408. return FALSE;
  1409. }
  1410. *p = c;
  1411. // Move on to next part of path
  1412. if (*p) {
  1413. p++;
  1414. if (BufferSizeInBytes >= sizeof (WCHAR) * 2) {
  1415. BufferEnd = _wcsappend (BufferEnd, L"\\");
  1416. BufferSizeInBytes -= sizeof (WCHAR);
  1417. }
  1418. }
  1419. } while (*p);
  1420. return TRUE;
  1421. }
  1422. #ifdef DEBUG
  1423. UINT g_FileEnumResourcesInUse;
  1424. #endif
  1425. VOID
  1426. pTrackedFindClose (
  1427. HANDLE FindHandle
  1428. )
  1429. {
  1430. #ifdef DEBUG
  1431. g_FileEnumResourcesInUse--;
  1432. #endif
  1433. FindClose (FindHandle);
  1434. }
  1435. BOOL
  1436. EnumFirstFileInTreeExA (
  1437. OUT PTREE_ENUMA EnumPtr,
  1438. IN PCSTR RootPath,
  1439. IN PCSTR FilePattern, OPTIONAL
  1440. IN BOOL EnumDirsFirst,
  1441. IN BOOL EnumDepthFirst,
  1442. IN INT MaxLevel
  1443. )
  1444. /*++
  1445. Routine Description:
  1446. EnumFirstFileInTree begins an enumeration of a directory tree. The
  1447. caller supplies an uninitialized enum structure, a directory path to
  1448. enumerate, and an optional file pattern. On return, the caller
  1449. receives all files and directories that match the pattern.
  1450. If a file pattern is supplied, directories that do not match the
  1451. file pattern are enumerated anyway.
  1452. Arguments:
  1453. EnumPtr - Receives the enumerated file or directory
  1454. RootPath - Specifies the full path of the directory to enumerate
  1455. FilePattern - Specifies a pattern of files to limit the search to
  1456. EnumDirsFirst - Specifies TRUE if the directories should be enumerated
  1457. before the files, or FALSE if the directories should
  1458. be enumerated after the files.
  1459. Return Value:
  1460. TRUE if a file or directory was enumerated, or FALSE if enumeration is complete
  1461. or an error occurred. (Use GetLastError to determine the result.)
  1462. --*/
  1463. {
  1464. ZeroMemory (EnumPtr, sizeof (TREE_ENUMA));
  1465. EnumPtr->State = TREE_ENUM_INIT;
  1466. _mbssafecpy (EnumPtr->RootPath, RootPath, MAX_MBCHAR_PATH);
  1467. if (FilePattern) {
  1468. _mbssafecpy (EnumPtr->FilePattern, FilePattern, MAX_MBCHAR_PATH);
  1469. } else {
  1470. StringCopyA (EnumPtr->FilePattern, "*.*");
  1471. }
  1472. EnumPtr->EnumDirsFirst = EnumDirsFirst;
  1473. EnumPtr->EnumDepthFirst = EnumDepthFirst;
  1474. EnumPtr->Level = 1;
  1475. EnumPtr->MaxLevel = MaxLevel;
  1476. return EnumNextFileInTreeA (EnumPtr);
  1477. }
  1478. BOOL
  1479. EnumFirstFileInTreeExW (
  1480. OUT PTREE_ENUMW EnumPtr,
  1481. IN PCWSTR RootPath,
  1482. IN PCWSTR FilePattern, OPTIONAL
  1483. IN BOOL EnumDirsFirst,
  1484. IN BOOL EnumDepthFirst,
  1485. IN INT MaxLevel
  1486. )
  1487. {
  1488. ZeroMemory (EnumPtr, sizeof (TREE_ENUMW));
  1489. EnumPtr->State = TREE_ENUM_INIT;
  1490. _wcssafecpy (EnumPtr->RootPath, RootPath, MAX_PATH);
  1491. if (FilePattern) {
  1492. _wcssafecpy (EnumPtr->FilePattern, FilePattern, MAX_PATH);
  1493. } else {
  1494. StringCopyW (EnumPtr->FilePattern, L"*.*");
  1495. }
  1496. EnumPtr->EnumDirsFirst = EnumDirsFirst;
  1497. EnumPtr->EnumDepthFirst = EnumDepthFirst;
  1498. EnumPtr->Level = 1;
  1499. EnumPtr->MaxLevel = MaxLevel;
  1500. return EnumNextFileInTreeW (EnumPtr);
  1501. }
  1502. BOOL
  1503. EnumNextFileInTreeA (
  1504. IN OUT PTREE_ENUMA EnumPtr
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. EnumNextFileInTree continues an enumeration of a directory tree,
  1509. returning the files that match the pattern specified in EnumFirstFileInTree,
  1510. and also returning all directories.
  1511. Arguments:
  1512. EnumPtr - Specifies the enumeration in progress, receives the enumerated file
  1513. or directory
  1514. Return Value:
  1515. TRUE if a file or directory was enumerated, or FALSE if enumeration is complete
  1516. or an error occurred. (Use GetLastError to determine the result.)
  1517. --*/
  1518. {
  1519. PSTR p;
  1520. for (;;) {
  1521. switch (EnumPtr->State) {
  1522. case TREE_ENUM_INIT:
  1523. //
  1524. // Get rid of wack at the end of root path, if it exists
  1525. //
  1526. p = GetEndOfStringA (EnumPtr->RootPath);
  1527. p = _mbsdec2 (EnumPtr->RootPath, p);
  1528. if (!p) {
  1529. DEBUGMSGA ((DBG_ERROR, "Path spec %s is incomplete", EnumPtr->RootPath));
  1530. EnumPtr->State = TREE_ENUM_FAILED;
  1531. break;
  1532. }
  1533. if (_mbsnextc (p) == '\\') {
  1534. *p = 0;
  1535. }
  1536. //
  1537. // Initialize enumeration structure
  1538. //
  1539. EnumPtr->FilePatternSize = SizeOfStringA (EnumPtr->FilePattern);
  1540. StringCopyA (EnumPtr->FileBuffer, EnumPtr->RootPath);
  1541. EnumPtr->EndOfFileBuffer = GetEndOfStringA (EnumPtr->FileBuffer);
  1542. StringCopyA (EnumPtr->Pattern, EnumPtr->RootPath);
  1543. EnumPtr->EndOfPattern = GetEndOfStringA (EnumPtr->Pattern);
  1544. EnumPtr->FullPath = EnumPtr->FileBuffer;
  1545. EnumPtr->RootPathSize = ByteCountA (EnumPtr->RootPath);
  1546. //
  1547. // Allocate first find data sturct
  1548. //
  1549. EnumPtr->Current = (PFIND_DATAA) GrowBuffer (
  1550. &EnumPtr->FindDataArray,
  1551. sizeof (FIND_DATAA)
  1552. );
  1553. if (!EnumPtr->Current) {
  1554. EnumPtr->State = TREE_ENUM_FAILED;
  1555. break;
  1556. }
  1557. #ifdef DEBUG
  1558. g_FileEnumResourcesInUse++; // account for grow buffer
  1559. #endif
  1560. EnumPtr->State = TREE_ENUM_BEGIN;
  1561. break;
  1562. case TREE_ENUM_BEGIN:
  1563. //
  1564. // Initialize current find data struct
  1565. //
  1566. EnumPtr->Current->SavedEndOfFileBuffer = EnumPtr->EndOfFileBuffer;
  1567. EnumPtr->Current->SavedEndOfPattern = EnumPtr->EndOfPattern;
  1568. //
  1569. // Limit the length of the pattern string
  1570. //
  1571. if ((EnumPtr->EndOfPattern - EnumPtr->Pattern) +
  1572. EnumPtr->FilePatternSize >= MAX_MBCHAR_PATH
  1573. ) {
  1574. LOGA ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->Pattern, EnumPtr->FilePattern));
  1575. EnumPtr->State = TREE_ENUM_POP;
  1576. break;
  1577. }
  1578. //
  1579. // Enuemrate the files or directories
  1580. //
  1581. if (EnumPtr->EnumDirsFirst) {
  1582. EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
  1583. } else {
  1584. EnumPtr->State = TREE_ENUM_FILES_BEGIN;
  1585. }
  1586. break;
  1587. case TREE_ENUM_FILES_BEGIN:
  1588. //
  1589. // Begin enumeration of files
  1590. //
  1591. StringCopyA (EnumPtr->EndOfPattern, "\\");
  1592. StringCopyA (EnumPtr->EndOfPattern + 1, EnumPtr->FilePattern);
  1593. EnumPtr->Current->FindHandle = FindFirstFileA (
  1594. EnumPtr->Pattern,
  1595. &EnumPtr->Current->FindData
  1596. );
  1597. if (EnumPtr->Current->FindHandle == INVALID_HANDLE_VALUE) {
  1598. if (EnumPtr->EnumDirsFirst) {
  1599. EnumPtr->State = TREE_ENUM_POP;
  1600. } else {
  1601. EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
  1602. }
  1603. } else {
  1604. #ifdef DEBUG
  1605. g_FileEnumResourcesInUse++; // account for creation of find handle
  1606. #endif
  1607. //
  1608. // Skip directories
  1609. //
  1610. if (EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1611. EnumPtr->State = TREE_ENUM_FILES_NEXT;
  1612. } else {
  1613. EnumPtr->State = TREE_ENUM_RETURN_ITEM;
  1614. }
  1615. }
  1616. break;
  1617. case TREE_ENUM_RETURN_ITEM:
  1618. //
  1619. // Update pointers to current item
  1620. //
  1621. EnumPtr->FindData = &EnumPtr->Current->FindData;
  1622. EnumPtr->Name = EnumPtr->FindData->cFileName;
  1623. EnumPtr->Directory = (EnumPtr->FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  1624. //
  1625. // Limit the length of the resulting full path
  1626. //
  1627. if ((EnumPtr->EndOfFileBuffer - EnumPtr->FileBuffer) +
  1628. SizeOfStringA (EnumPtr->Name) >= MAX_MBCHAR_PATH
  1629. ) {
  1630. LOGA ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->FileBuffer, EnumPtr->Name));
  1631. if (EnumPtr->Directory) {
  1632. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1633. } else {
  1634. EnumPtr->State = TREE_ENUM_FILES_NEXT;
  1635. }
  1636. break;
  1637. }
  1638. //
  1639. // Generate the full path
  1640. //
  1641. StringCopyA (EnumPtr->EndOfFileBuffer, "\\");
  1642. StringCopyA (EnumPtr->EndOfFileBuffer + 1, EnumPtr->Name);
  1643. if (EnumPtr->Directory) {
  1644. if ((EnumPtr->MaxLevel == FILE_ENUM_ALL_LEVELS) ||
  1645. (EnumPtr->Level < EnumPtr->MaxLevel)
  1646. ) {
  1647. if (EnumPtr->EnumDepthFirst) {
  1648. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1649. }
  1650. else {
  1651. EnumPtr->State = TREE_ENUM_PUSH;
  1652. }
  1653. }
  1654. else {
  1655. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1656. }
  1657. } else {
  1658. EnumPtr->State = TREE_ENUM_FILES_NEXT;
  1659. }
  1660. EnumPtr->SubPath = (PCSTR) ((PBYTE) EnumPtr->FileBuffer + EnumPtr->RootPathSize);
  1661. if (*EnumPtr->SubPath) {
  1662. EnumPtr->SubPath++;
  1663. }
  1664. return TRUE;
  1665. case TREE_ENUM_FILES_NEXT:
  1666. if (FindNextFileA (EnumPtr->Current->FindHandle, &EnumPtr->Current->FindData)) {
  1667. //
  1668. // Return files only
  1669. //
  1670. if (!(EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1671. EnumPtr->State = TREE_ENUM_RETURN_ITEM;
  1672. }
  1673. } else {
  1674. if (!EnumPtr->EnumDirsFirst) {
  1675. pTrackedFindClose (EnumPtr->Current->FindHandle);
  1676. EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
  1677. } else {
  1678. EnumPtr->State = TREE_ENUM_POP;
  1679. }
  1680. }
  1681. break;
  1682. case TREE_ENUM_DIRS_FILTER:
  1683. if (!(EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1684. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1685. } else if (StringMatchA (EnumPtr->Current->FindData.cFileName, ".") ||
  1686. StringMatchA (EnumPtr->Current->FindData.cFileName, "..")
  1687. ) {
  1688. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1689. } else {
  1690. if (EnumPtr->EnumDepthFirst) {
  1691. EnumPtr->State = TREE_ENUM_PUSH;
  1692. }
  1693. else {
  1694. EnumPtr->State = TREE_ENUM_RETURN_ITEM;
  1695. }
  1696. }
  1697. break;
  1698. case TREE_ENUM_DIRS_BEGIN:
  1699. //
  1700. // Begin enumeration of directories
  1701. //
  1702. StringCopyA (EnumPtr->EndOfPattern, "\\");
  1703. StringCopyA (EnumPtr->EndOfPattern + 1, "*.*");
  1704. EnumPtr->Current->FindHandle = FindFirstFileA (
  1705. EnumPtr->Pattern,
  1706. &EnumPtr->Current->FindData
  1707. );
  1708. if (EnumPtr->Current->FindHandle == INVALID_HANDLE_VALUE) {
  1709. EnumPtr->State = TREE_ENUM_POP;
  1710. } else {
  1711. #ifdef DEBUG
  1712. g_FileEnumResourcesInUse++; // account for creation of find handle
  1713. #endif
  1714. EnumPtr->State = TREE_ENUM_DIRS_FILTER;
  1715. }
  1716. break;
  1717. case TREE_ENUM_DIRS_NEXT:
  1718. if (FindNextFileA (EnumPtr->Current->FindHandle, &EnumPtr->Current->FindData)) {
  1719. //
  1720. // Return directories only, then recurse into directory
  1721. //
  1722. EnumPtr->State = TREE_ENUM_DIRS_FILTER;
  1723. } else {
  1724. //
  1725. // Directory enumeration complete.
  1726. //
  1727. if (EnumPtr->EnumDirsFirst) {
  1728. pTrackedFindClose (EnumPtr->Current->FindHandle);
  1729. EnumPtr->State = TREE_ENUM_FILES_BEGIN;
  1730. } else {
  1731. EnumPtr->State = TREE_ENUM_POP;
  1732. }
  1733. }
  1734. break;
  1735. case TREE_ENUM_PUSH:
  1736. //
  1737. // Limit the length of the resulting full path
  1738. //
  1739. if ((EnumPtr->EndOfFileBuffer - EnumPtr->FileBuffer) +
  1740. SizeOfStringA (EnumPtr->Current->FindData.cFileName) >= MAX_MBCHAR_PATH
  1741. ) {
  1742. LOGA ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->FileBuffer, EnumPtr->Name));
  1743. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1744. break;
  1745. }
  1746. //
  1747. // Tack on directory name to strings and recalcuate end pointers
  1748. //
  1749. StringCopyA (EnumPtr->EndOfPattern + 1, EnumPtr->Current->FindData.cFileName);
  1750. StringCopyA (EnumPtr->EndOfFileBuffer, "\\");
  1751. StringCopyA (EnumPtr->EndOfFileBuffer + 1, EnumPtr->Current->FindData.cFileName);
  1752. EnumPtr->EndOfPattern = GetEndOfStringA (EnumPtr->EndOfPattern);
  1753. EnumPtr->EndOfFileBuffer = GetEndOfStringA (EnumPtr->EndOfFileBuffer);
  1754. //
  1755. // Allocate another find data struct
  1756. //
  1757. EnumPtr->Current = (PFIND_DATAA) GrowBuffer (
  1758. &EnumPtr->FindDataArray,
  1759. sizeof (FIND_DATAA)
  1760. );
  1761. if (!EnumPtr->Current) {
  1762. EnumPtr->State = TREE_ENUM_FAILED;
  1763. break;
  1764. }
  1765. EnumPtr->Level++;
  1766. EnumPtr->State = TREE_ENUM_BEGIN;
  1767. break;
  1768. case TREE_ENUM_POP:
  1769. //
  1770. // Free the current resources
  1771. //
  1772. pTrackedFindClose (EnumPtr->Current->FindHandle);
  1773. EnumPtr->Level--;
  1774. //
  1775. // Get the previous find data struct
  1776. //
  1777. MYASSERT (EnumPtr->FindDataArray.End >= sizeof (FIND_DATAA));
  1778. EnumPtr->FindDataArray.End -= sizeof (FIND_DATAA);
  1779. if (!EnumPtr->FindDataArray.End) {
  1780. EnumPtr->State = TREE_ENUM_DONE;
  1781. break;
  1782. }
  1783. EnumPtr->Current = (PFIND_DATAA) (EnumPtr->FindDataArray.Buf +
  1784. (EnumPtr->FindDataArray.End - sizeof (FIND_DATAA)));
  1785. //
  1786. // Restore the settings of the parent directory
  1787. //
  1788. EnumPtr->EndOfPattern = EnumPtr->Current->SavedEndOfPattern;
  1789. EnumPtr->EndOfFileBuffer = EnumPtr->Current->SavedEndOfFileBuffer;
  1790. if (EnumPtr->EnumDepthFirst) {
  1791. EnumPtr->State = TREE_ENUM_RETURN_ITEM;
  1792. }
  1793. else {
  1794. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1795. }
  1796. break;
  1797. case TREE_ENUM_DONE:
  1798. AbortEnumFileInTreeA (EnumPtr);
  1799. SetLastError (ERROR_SUCCESS);
  1800. return FALSE;
  1801. case TREE_ENUM_FAILED:
  1802. PushError();
  1803. AbortEnumFileInTreeA (EnumPtr);
  1804. PopError();
  1805. return FALSE;
  1806. case TREE_ENUM_CLEANED_UP:
  1807. return FALSE;
  1808. }
  1809. }
  1810. }
  1811. BOOL
  1812. EnumNextFileInTreeW (
  1813. IN OUT PTREE_ENUMW EnumPtr
  1814. )
  1815. {
  1816. PWSTR p;
  1817. for (;;) {
  1818. switch (EnumPtr->State) {
  1819. case TREE_ENUM_INIT:
  1820. //
  1821. // Get rid of wack at the end of root path, if it exists
  1822. //
  1823. p = GetEndOfStringW (EnumPtr->RootPath);
  1824. p = _wcsdec2 (EnumPtr->RootPath, p);
  1825. if (!p) {
  1826. DEBUGMSG ((DBG_ERROR, "Path spec %ls is incomplete", EnumPtr->RootPath));
  1827. EnumPtr->State = TREE_ENUM_FAILED;
  1828. break;
  1829. }
  1830. if (*p == L'\\') {
  1831. *p = 0;
  1832. }
  1833. //
  1834. // Initialize enumeration structure
  1835. //
  1836. EnumPtr->FilePatternSize = SizeOfStringW (EnumPtr->FilePattern);
  1837. StringCopyW (EnumPtr->FileBuffer, EnumPtr->RootPath);
  1838. EnumPtr->EndOfFileBuffer = GetEndOfStringW (EnumPtr->FileBuffer);
  1839. StringCopyW (EnumPtr->Pattern, EnumPtr->RootPath);
  1840. EnumPtr->EndOfPattern = GetEndOfStringW (EnumPtr->Pattern);
  1841. EnumPtr->FullPath = EnumPtr->FileBuffer;
  1842. EnumPtr->RootPathSize = ByteCountW (EnumPtr->RootPath);
  1843. //
  1844. // Allocate first find data sturct
  1845. //
  1846. EnumPtr->Current = (PFIND_DATAW) GrowBuffer (
  1847. &EnumPtr->FindDataArray,
  1848. sizeof (FIND_DATAW)
  1849. );
  1850. if (!EnumPtr->Current) {
  1851. EnumPtr->State = TREE_ENUM_FAILED;
  1852. break;
  1853. }
  1854. #ifdef DEBUG
  1855. g_FileEnumResourcesInUse++; // account for grow buffer
  1856. #endif
  1857. EnumPtr->State = TREE_ENUM_BEGIN;
  1858. break;
  1859. case TREE_ENUM_BEGIN:
  1860. //
  1861. // Initialize current find data struct
  1862. //
  1863. EnumPtr->Current->SavedEndOfFileBuffer = EnumPtr->EndOfFileBuffer;
  1864. EnumPtr->Current->SavedEndOfPattern = EnumPtr->EndOfPattern;
  1865. //
  1866. // Limit the length of the pattern string
  1867. //
  1868. if (((PBYTE) EnumPtr->EndOfPattern - (PBYTE) EnumPtr->Pattern) +
  1869. EnumPtr->FilePatternSize >= (MAX_PATH * 2 * sizeof (WCHAR))
  1870. ) {
  1871. LOGW ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->Pattern, EnumPtr->FilePattern));
  1872. EnumPtr->State = TREE_ENUM_POP;
  1873. break;
  1874. }
  1875. //
  1876. // Enuemrate the files or directories
  1877. //
  1878. if (EnumPtr->EnumDirsFirst) {
  1879. EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
  1880. } else {
  1881. EnumPtr->State = TREE_ENUM_FILES_BEGIN;
  1882. }
  1883. break;
  1884. case TREE_ENUM_FILES_BEGIN:
  1885. //
  1886. // Begin enumeration of files
  1887. //
  1888. StringCopyW (EnumPtr->EndOfPattern, L"\\");
  1889. StringCopyW (EnumPtr->EndOfPattern + 1, EnumPtr->FilePattern);
  1890. EnumPtr->Current->FindHandle = FindFirstFileW (
  1891. EnumPtr->Pattern,
  1892. &EnumPtr->Current->FindData
  1893. );
  1894. if (EnumPtr->Current->FindHandle == INVALID_HANDLE_VALUE) {
  1895. if (EnumPtr->EnumDirsFirst) {
  1896. EnumPtr->State = TREE_ENUM_POP;
  1897. } else {
  1898. EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
  1899. }
  1900. } else {
  1901. #ifdef DEBUG
  1902. g_FileEnumResourcesInUse++; // account for creation of find handle
  1903. #endif
  1904. //
  1905. // Skip directories
  1906. //
  1907. if (EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1908. EnumPtr->State = TREE_ENUM_FILES_NEXT;
  1909. } else {
  1910. EnumPtr->State = TREE_ENUM_RETURN_ITEM;
  1911. }
  1912. }
  1913. break;
  1914. case TREE_ENUM_RETURN_ITEM:
  1915. //
  1916. // Update pointers to current item
  1917. //
  1918. EnumPtr->FindData = &EnumPtr->Current->FindData;
  1919. EnumPtr->Name = EnumPtr->FindData->cFileName;
  1920. EnumPtr->Directory = (EnumPtr->FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  1921. //
  1922. // Limit the length of the resulting full path
  1923. //
  1924. if (((PBYTE) EnumPtr->EndOfFileBuffer - (PBYTE) EnumPtr->FileBuffer) +
  1925. SizeOfStringW (EnumPtr->Name) >= (MAX_PATH * 2 * sizeof (WCHAR))
  1926. ) {
  1927. LOGW ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->FileBuffer, EnumPtr->Name));
  1928. if (EnumPtr->Directory) {
  1929. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1930. } else {
  1931. EnumPtr->State = TREE_ENUM_FILES_NEXT;
  1932. }
  1933. break;
  1934. }
  1935. //
  1936. // Generate the full path
  1937. //
  1938. StringCopyW (EnumPtr->EndOfFileBuffer, L"\\");
  1939. StringCopyW (EnumPtr->EndOfFileBuffer + 1, EnumPtr->Name);
  1940. if (EnumPtr->Directory) {
  1941. if ((EnumPtr->MaxLevel == FILE_ENUM_ALL_LEVELS) ||
  1942. (EnumPtr->Level < EnumPtr->MaxLevel)
  1943. ) {
  1944. if (EnumPtr->EnumDepthFirst) {
  1945. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1946. }
  1947. else {
  1948. EnumPtr->State = TREE_ENUM_PUSH;
  1949. }
  1950. }
  1951. else {
  1952. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1953. }
  1954. } else {
  1955. EnumPtr->State = TREE_ENUM_FILES_NEXT;
  1956. }
  1957. EnumPtr->SubPath = (PCWSTR) ((PBYTE) EnumPtr->FileBuffer + EnumPtr->RootPathSize);
  1958. if (*EnumPtr->SubPath) {
  1959. EnumPtr->SubPath++;
  1960. }
  1961. return TRUE;
  1962. case TREE_ENUM_FILES_NEXT:
  1963. if (FindNextFileW (EnumPtr->Current->FindHandle, &EnumPtr->Current->FindData)) {
  1964. //
  1965. // Return files only
  1966. //
  1967. if (!(EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1968. EnumPtr->State = TREE_ENUM_RETURN_ITEM;
  1969. }
  1970. } else {
  1971. if (!EnumPtr->EnumDirsFirst) {
  1972. pTrackedFindClose (EnumPtr->Current->FindHandle);
  1973. EnumPtr->State = TREE_ENUM_DIRS_BEGIN;
  1974. } else {
  1975. EnumPtr->State = TREE_ENUM_POP;
  1976. }
  1977. }
  1978. break;
  1979. case TREE_ENUM_DIRS_FILTER:
  1980. if (!(EnumPtr->Current->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1981. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1982. } else if (StringMatchW (EnumPtr->Current->FindData.cFileName, L".") ||
  1983. StringMatchW (EnumPtr->Current->FindData.cFileName, L"..")
  1984. ) {
  1985. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  1986. } else {
  1987. if (EnumPtr->EnumDepthFirst) {
  1988. EnumPtr->State = TREE_ENUM_PUSH;
  1989. }
  1990. else {
  1991. EnumPtr->State = TREE_ENUM_RETURN_ITEM;
  1992. }
  1993. }
  1994. break;
  1995. case TREE_ENUM_DIRS_BEGIN:
  1996. //
  1997. // Begin enumeration of directories
  1998. //
  1999. StringCopyW (EnumPtr->EndOfPattern, L"\\*.*");
  2000. EnumPtr->Current->FindHandle = FindFirstFileW (
  2001. EnumPtr->Pattern,
  2002. &EnumPtr->Current->FindData
  2003. );
  2004. if (EnumPtr->Current->FindHandle == INVALID_HANDLE_VALUE) {
  2005. EnumPtr->State = TREE_ENUM_POP;
  2006. } else {
  2007. #ifdef DEBUG
  2008. g_FileEnumResourcesInUse++; // account for creation of find handle
  2009. #endif
  2010. EnumPtr->State = TREE_ENUM_DIRS_FILTER;
  2011. }
  2012. break;
  2013. case TREE_ENUM_DIRS_NEXT:
  2014. if (FindNextFileW (EnumPtr->Current->FindHandle, &EnumPtr->Current->FindData)) {
  2015. //
  2016. // Return directories only, then recurse into directory
  2017. //
  2018. EnumPtr->State = TREE_ENUM_DIRS_FILTER;
  2019. } else {
  2020. //
  2021. // Directory enumeration complete.
  2022. //
  2023. if (EnumPtr->EnumDirsFirst) {
  2024. pTrackedFindClose (EnumPtr->Current->FindHandle);
  2025. EnumPtr->State = TREE_ENUM_FILES_BEGIN;
  2026. } else {
  2027. EnumPtr->State = TREE_ENUM_POP;
  2028. }
  2029. }
  2030. break;
  2031. case TREE_ENUM_PUSH:
  2032. //
  2033. // Limit the length of the resulting full path
  2034. //
  2035. if (((PBYTE) EnumPtr->EndOfFileBuffer - (PBYTE) EnumPtr->FileBuffer) +
  2036. SizeOfStringW (EnumPtr->Current->FindData.cFileName) >= (MAX_PATH * 2 * sizeof (WCHAR))
  2037. ) {
  2038. LOGW ((LOG_ERROR, "Path %s\\%s is too long", EnumPtr->FileBuffer, EnumPtr->Name));
  2039. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  2040. break;
  2041. }
  2042. //
  2043. // Tack on directory name to strings and recalcuate end pointers
  2044. //
  2045. StringCopyW (EnumPtr->EndOfPattern + 1, EnumPtr->Current->FindData.cFileName);
  2046. StringCopyW (EnumPtr->EndOfFileBuffer, L"\\");
  2047. StringCopyW (EnumPtr->EndOfFileBuffer + 1, EnumPtr->Current->FindData.cFileName);
  2048. EnumPtr->EndOfPattern = GetEndOfStringW (EnumPtr->EndOfPattern);
  2049. EnumPtr->EndOfFileBuffer = GetEndOfStringW (EnumPtr->EndOfFileBuffer);
  2050. //
  2051. // Allocate another find data struct
  2052. //
  2053. EnumPtr->Current = (PFIND_DATAW) GrowBuffer (
  2054. &EnumPtr->FindDataArray,
  2055. sizeof (FIND_DATAW)
  2056. );
  2057. if (!EnumPtr->Current) {
  2058. EnumPtr->State = TREE_ENUM_FAILED;
  2059. break;
  2060. }
  2061. EnumPtr->Level++;
  2062. EnumPtr->State = TREE_ENUM_BEGIN;
  2063. break;
  2064. case TREE_ENUM_POP:
  2065. //
  2066. // Free the current resources
  2067. //
  2068. pTrackedFindClose (EnumPtr->Current->FindHandle);
  2069. EnumPtr->Level--;
  2070. //
  2071. // Get the previous find data struct
  2072. //
  2073. MYASSERT (EnumPtr->FindDataArray.End >= sizeof (FIND_DATAW));
  2074. EnumPtr->FindDataArray.End -= sizeof (FIND_DATAW);
  2075. if (!EnumPtr->FindDataArray.End) {
  2076. EnumPtr->State = TREE_ENUM_DONE;
  2077. break;
  2078. }
  2079. EnumPtr->Current = (PFIND_DATAW) (EnumPtr->FindDataArray.Buf +
  2080. (EnumPtr->FindDataArray.End - sizeof (FIND_DATAW)));
  2081. //
  2082. // Restore the settings of the parent directory
  2083. //
  2084. EnumPtr->EndOfPattern = EnumPtr->Current->SavedEndOfPattern;
  2085. EnumPtr->EndOfFileBuffer = EnumPtr->Current->SavedEndOfFileBuffer;
  2086. if (EnumPtr->EnumDepthFirst) {
  2087. EnumPtr->State = TREE_ENUM_RETURN_ITEM;
  2088. }
  2089. else {
  2090. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  2091. }
  2092. break;
  2093. case TREE_ENUM_DONE:
  2094. AbortEnumFileInTreeW (EnumPtr);
  2095. SetLastError (ERROR_SUCCESS);
  2096. return FALSE;
  2097. case TREE_ENUM_FAILED:
  2098. PushError();
  2099. AbortEnumFileInTreeW (EnumPtr);
  2100. PopError();
  2101. return FALSE;
  2102. case TREE_ENUM_CLEANED_UP:
  2103. return FALSE;
  2104. }
  2105. }
  2106. }
  2107. VOID
  2108. AbortEnumFileInTreeA (
  2109. IN OUT PTREE_ENUMA EnumPtr
  2110. )
  2111. /*++
  2112. Routine Description:
  2113. AbortEnumFileInTree cleans up all resources used by an enumeration started
  2114. by EnumFirstFileInTree. This routine must be called if file enumeration
  2115. will not be completed by calling EnumNextFileInTree until it returns FALSE.
  2116. If EnumNextFileInTree returns FALSE, it is unnecessary to call this
  2117. function.
  2118. Arguments:
  2119. EnumPtr - Specifies the enumeration in progress, receives the enumerated file
  2120. or directory
  2121. Return Value:
  2122. none
  2123. --*/
  2124. {
  2125. UINT Pos;
  2126. PGROWBUFFER g;
  2127. PFIND_DATAA Current;
  2128. if (EnumPtr->State == TREE_ENUM_CLEANED_UP) {
  2129. return;
  2130. }
  2131. //
  2132. // Close any currently open handles
  2133. //
  2134. g = &EnumPtr->FindDataArray;
  2135. for (Pos = 0 ; Pos < g->End ; Pos += sizeof (FIND_DATAA)) {
  2136. Current = (PFIND_DATAA) (g->Buf + Pos);
  2137. pTrackedFindClose (Current->FindHandle);
  2138. }
  2139. FreeGrowBuffer (&EnumPtr->FindDataArray);
  2140. #ifdef DEBUG
  2141. g_FileEnumResourcesInUse--;
  2142. #endif
  2143. EnumPtr->State = TREE_ENUM_CLEANED_UP;
  2144. }
  2145. VOID
  2146. AbortEnumFileInTreeW (
  2147. IN OUT PTREE_ENUMW EnumPtr
  2148. )
  2149. {
  2150. UINT Pos;
  2151. PGROWBUFFER g;
  2152. PFIND_DATAW Current;
  2153. if (EnumPtr->State == TREE_ENUM_CLEANED_UP) {
  2154. return;
  2155. }
  2156. //
  2157. // Close any currently open handles
  2158. //
  2159. g = &EnumPtr->FindDataArray;
  2160. for (Pos = 0 ; Pos < g->End ; Pos += sizeof (FIND_DATAW)) {
  2161. Current = (PFIND_DATAW) (g->Buf + Pos);
  2162. pTrackedFindClose (Current->FindHandle);
  2163. }
  2164. FreeGrowBuffer (&EnumPtr->FindDataArray);
  2165. #ifdef DEBUG
  2166. g_FileEnumResourcesInUse--;
  2167. #endif
  2168. EnumPtr->State = TREE_ENUM_CLEANED_UP;
  2169. }
  2170. VOID
  2171. AbortEnumCurrentDirA (
  2172. IN OUT PTREE_ENUMA EnumPtr
  2173. )
  2174. {
  2175. if (EnumPtr->State == TREE_ENUM_PUSH) {
  2176. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  2177. }
  2178. }
  2179. VOID
  2180. AbortEnumCurrentDirW (
  2181. IN OUT PTREE_ENUMW EnumPtr
  2182. )
  2183. {
  2184. if (EnumPtr->State == TREE_ENUM_PUSH) {
  2185. EnumPtr->State = TREE_ENUM_DIRS_NEXT;
  2186. }
  2187. }
  2188. BOOL
  2189. EnumFirstFileA (
  2190. OUT PFILE_ENUMA EnumPtr,
  2191. IN PCSTR RootPath,
  2192. IN PCSTR FilePattern OPTIONAL
  2193. )
  2194. {
  2195. ZeroMemory (EnumPtr, sizeof (FILE_ENUMA));
  2196. EnumPtr->FileName = EnumPtr->fd.cFileName;
  2197. EnumPtr->FullPath = EnumPtr->RootPath;
  2198. StringCopyA (EnumPtr->RootPath, RootPath);
  2199. EnumPtr->EndOfRoot = AppendWackA (EnumPtr->RootPath);
  2200. StringCopyA (EnumPtr->EndOfRoot, FilePattern ? FilePattern : "*.*");
  2201. EnumPtr->Handle = FindFirstFileA (EnumPtr->RootPath, &EnumPtr->fd);
  2202. if (EnumPtr->Handle != INVALID_HANDLE_VALUE) {
  2203. if (StringMatchA (EnumPtr->FileName, ".") ||
  2204. StringMatchA (EnumPtr->FileName, "..")
  2205. ) {
  2206. return EnumNextFileA (EnumPtr);
  2207. }
  2208. StringCopyA (EnumPtr->EndOfRoot, EnumPtr->FileName);
  2209. EnumPtr->Directory = EnumPtr->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
  2210. return TRUE;
  2211. }
  2212. return FALSE;
  2213. }
  2214. BOOL
  2215. EnumFirstFileW (
  2216. OUT PFILE_ENUMW EnumPtr,
  2217. IN PCWSTR RootPath,
  2218. IN PCWSTR FilePattern OPTIONAL
  2219. )
  2220. {
  2221. ZeroMemory (EnumPtr, sizeof (FILE_ENUMW));
  2222. EnumPtr->FileName = EnumPtr->fd.cFileName;
  2223. EnumPtr->FullPath = EnumPtr->RootPath;
  2224. StringCopyW (EnumPtr->RootPath, RootPath);
  2225. EnumPtr->EndOfRoot = AppendWackW (EnumPtr->RootPath);
  2226. StringCopyW (EnumPtr->EndOfRoot, FilePattern ? FilePattern : L"*.*");
  2227. EnumPtr->Handle = FindFirstFileW (EnumPtr->RootPath, &EnumPtr->fd);
  2228. if (EnumPtr->Handle != INVALID_HANDLE_VALUE) {
  2229. if (StringMatchW (EnumPtr->FileName, L".") ||
  2230. StringMatchW (EnumPtr->FileName, L"..")
  2231. ) {
  2232. return EnumNextFileW (EnumPtr);
  2233. }
  2234. StringCopyW (EnumPtr->EndOfRoot, EnumPtr->FileName);
  2235. EnumPtr->Directory = EnumPtr->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
  2236. return TRUE;
  2237. }
  2238. return FALSE;
  2239. }
  2240. BOOL
  2241. EnumNextFileA (
  2242. IN OUT PFILE_ENUMA EnumPtr
  2243. )
  2244. {
  2245. do {
  2246. if (!FindNextFileA (EnumPtr->Handle, &EnumPtr->fd)) {
  2247. AbortFileEnumA (EnumPtr);
  2248. return FALSE;
  2249. }
  2250. } while (StringMatchA (EnumPtr->FileName, ".") ||
  2251. StringMatchA (EnumPtr->FileName, "..")
  2252. );
  2253. StringCopyA (EnumPtr->EndOfRoot, EnumPtr->FileName);
  2254. EnumPtr->Directory = EnumPtr->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
  2255. return TRUE;
  2256. }
  2257. BOOL
  2258. EnumNextFileW (
  2259. IN OUT PFILE_ENUMW EnumPtr
  2260. )
  2261. {
  2262. do {
  2263. if (!FindNextFileW (EnumPtr->Handle, &EnumPtr->fd)) {
  2264. AbortFileEnumW (EnumPtr);
  2265. return FALSE;
  2266. }
  2267. } while (StringMatchW (EnumPtr->FileName, L".") ||
  2268. StringMatchW (EnumPtr->FileName, L"..")
  2269. );
  2270. if (!FindNextFileW (EnumPtr->Handle, &EnumPtr->fd)) {
  2271. AbortFileEnumW (EnumPtr);
  2272. return FALSE;
  2273. }
  2274. StringCopyW (EnumPtr->EndOfRoot, EnumPtr->FileName);
  2275. EnumPtr->Directory = EnumPtr->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
  2276. return TRUE;
  2277. }
  2278. VOID
  2279. AbortFileEnumA (
  2280. IN OUT PFILE_ENUMA EnumPtr
  2281. )
  2282. {
  2283. if (EnumPtr->Handle && EnumPtr->Handle != INVALID_HANDLE_VALUE) {
  2284. FindClose (EnumPtr->Handle);
  2285. ZeroMemory (EnumPtr, sizeof (FILE_ENUMA));
  2286. }
  2287. }
  2288. VOID
  2289. AbortFileEnumW (
  2290. IN OUT PFILE_ENUMW EnumPtr
  2291. )
  2292. {
  2293. if (EnumPtr->Handle && EnumPtr->Handle != INVALID_HANDLE_VALUE) {
  2294. FindClose (EnumPtr->Handle);
  2295. ZeroMemory (EnumPtr, sizeof (FILE_ENUMW));
  2296. }
  2297. }
  2298. /*++
  2299. Routine Description:
  2300. MapFileIntoMemoryA and MapFileIntoMemoryW map a file into memory. It does that
  2301. by opening the file, creating a mapping object and mapping opened file into
  2302. created mapping object. It returnes the address where the file is mapped and
  2303. also sets FileHandle and MapHandle variables to be used in order to unmap the
  2304. file when work is done.
  2305. Arguments:
  2306. FileName - the name of the file to be mapped into memory
  2307. FileHandle - will end keeping the file handle if the file was opened successfully
  2308. MapHandle - will end keeping the mapping object handle if this object was created successfully
  2309. Return Value:
  2310. NULL if function fails, a valid memory address if successfull
  2311. Comments:
  2312. If the return value is NULL you should call UnmapFile to release all allocated resources
  2313. --*/
  2314. PVOID
  2315. MapFileIntoMemoryExA (
  2316. IN PCSTR FileName,
  2317. OUT PHANDLE FileHandle,
  2318. OUT PHANDLE MapHandle,
  2319. IN BOOL WriteAccess
  2320. )
  2321. {
  2322. PVOID fileImage = NULL;
  2323. //verify function parameters
  2324. if ((FileHandle == NULL) || (MapHandle == NULL)) {
  2325. return NULL;
  2326. }
  2327. //first thing. Try to open the file, read-only
  2328. *FileHandle = CreateFileA (
  2329. FileName,
  2330. WriteAccess?GENERIC_READ|GENERIC_WRITE:GENERIC_READ,
  2331. FILE_SHARE_READ,
  2332. NULL,
  2333. OPEN_EXISTING,
  2334. FILE_ATTRIBUTE_NORMAL,
  2335. NULL
  2336. );
  2337. if (*FileHandle == INVALID_HANDLE_VALUE) {
  2338. return NULL;
  2339. }
  2340. //now try to create a mapping object, read-only
  2341. *MapHandle = CreateFileMappingA (*FileHandle, NULL, WriteAccess?PAGE_READWRITE:PAGE_READONLY, 0, 0, NULL);
  2342. if (*MapHandle == NULL) {
  2343. return NULL;
  2344. }
  2345. //one more thing to do: map view of file
  2346. fileImage = MapViewOfFile (*MapHandle, WriteAccess?FILE_MAP_WRITE:FILE_MAP_READ, 0, 0, 0);
  2347. return fileImage;
  2348. }
  2349. PVOID
  2350. MapFileIntoMemoryExW (
  2351. IN PCWSTR FileName,
  2352. OUT PHANDLE FileHandle,
  2353. OUT PHANDLE MapHandle,
  2354. IN BOOL WriteAccess
  2355. )
  2356. {
  2357. PVOID fileImage = NULL;
  2358. //verify function parameters
  2359. if ((FileHandle == NULL) || (MapHandle == NULL)) {
  2360. return NULL;
  2361. }
  2362. //first thing. Try to open the file, read-only
  2363. *FileHandle = CreateFileW (
  2364. FileName,
  2365. WriteAccess?GENERIC_READ|GENERIC_WRITE:GENERIC_READ,
  2366. FILE_SHARE_READ,
  2367. NULL,
  2368. OPEN_EXISTING,
  2369. FILE_ATTRIBUTE_NORMAL,
  2370. NULL
  2371. );
  2372. if (*FileHandle == INVALID_HANDLE_VALUE) {
  2373. return NULL;
  2374. }
  2375. //now try to create a mapping object, read-only
  2376. *MapHandle = CreateFileMappingW (*FileHandle, NULL, WriteAccess?PAGE_READWRITE:PAGE_READONLY, 0, 0, NULL);
  2377. if (*MapHandle == NULL) {
  2378. return NULL;
  2379. }
  2380. //one more thing to do: map view of file
  2381. fileImage = MapViewOfFile (*MapHandle, WriteAccess?FILE_MAP_WRITE:FILE_MAP_READ, 0, 0, 0);
  2382. return fileImage;
  2383. }
  2384. /*++
  2385. Routine Description:
  2386. UnmapFile is used to release all resources allocated by MapFileIntoMemory.
  2387. Arguments:
  2388. FileImage - image of the mapped file as returned by MapFileIntoMemory
  2389. MapHandle - handle of the mapping object as returned by MapFileIntoMemory
  2390. FileHandle - handle of the file as returned by MapFileIntoMemory
  2391. Return Value:
  2392. TRUE if successfull, FALSE if not
  2393. --*/
  2394. BOOL
  2395. UnmapFile (
  2396. IN PVOID FileImage,
  2397. IN HANDLE MapHandle,
  2398. IN HANDLE FileHandle
  2399. )
  2400. {
  2401. BOOL result = TRUE;
  2402. //if FileImage is a valid pointer then try to unmap file
  2403. if (FileImage != NULL) {
  2404. if (UnmapViewOfFile (FileImage) == 0) {
  2405. result = FALSE;
  2406. }
  2407. }
  2408. //if mapping object is valid then try to delete it
  2409. if (MapHandle != NULL) {
  2410. if (CloseHandle (MapHandle) == 0) {
  2411. result = FALSE;
  2412. }
  2413. }
  2414. //if file handle is valid then try to close the file
  2415. if (FileHandle != INVALID_HANDLE_VALUE) {
  2416. if (CloseHandle (FileHandle) == 0) {
  2417. result = FALSE;
  2418. }
  2419. }
  2420. return result;
  2421. }
  2422. BOOL
  2423. RemoveCompleteDirectoryA (
  2424. IN PCSTR Dir
  2425. )
  2426. {
  2427. TREE_ENUMA e;
  2428. BOOL b = TRUE;
  2429. CHAR CurDir[MAX_MBCHAR_PATH];
  2430. CHAR NewDir[MAX_MBCHAR_PATH];
  2431. LONG rc = ERROR_SUCCESS;
  2432. DWORD Attribs;
  2433. Attribs = GetFileAttributesA (Dir);
  2434. if (Attribs == INVALID_ATTRIBUTES) {
  2435. return TRUE;
  2436. }
  2437. if (!(Attribs & FILE_ATTRIBUTE_DIRECTORY)) {
  2438. SetFileAttributesA (Dir, FILE_ATTRIBUTE_NORMAL);
  2439. return DeleteFileA (Dir);
  2440. }
  2441. GetCurrentDirectoryA (MAX_MBCHAR_PATH, CurDir);
  2442. SetCurrentDirectoryA (Dir);
  2443. GetCurrentDirectoryA (MAX_MBCHAR_PATH, NewDir);
  2444. if (EnumFirstFileInTreeA (&e, NewDir, NULL, FALSE)) {
  2445. do {
  2446. if (!e.Directory) {
  2447. SetFileAttributesA (e.FullPath, FILE_ATTRIBUTE_NORMAL);
  2448. if (!DeleteFileA (e.FullPath)) {
  2449. DEBUGMSGA ((DBG_ERROR, "Can't delete %s", e.FullPath));
  2450. if (b) {
  2451. b = FALSE;
  2452. rc = GetLastError();
  2453. }
  2454. }
  2455. }
  2456. } while (EnumNextFileInTreeA (&e));
  2457. }
  2458. if (EnumFirstFileInTreeExA (&e, NewDir, NULL, TRUE, TRUE, FILE_ENUM_ALL_LEVELS)) {
  2459. do {
  2460. if (e.Directory) {
  2461. SetFileAttributesA (e.FullPath, FILE_ATTRIBUTE_NORMAL);
  2462. if (!RemoveDirectoryA (e.FullPath)) {
  2463. DEBUGMSGA ((DBG_ERROR, "Can't remove %s", e.FullPath));
  2464. if (b) {
  2465. b = FALSE;
  2466. rc = GetLastError();
  2467. }
  2468. }
  2469. }
  2470. } while (EnumNextFileInTreeA (&e));
  2471. }
  2472. if (b) {
  2473. SetFileAttributesA (NewDir, FILE_ATTRIBUTE_NORMAL);
  2474. SetCurrentDirectoryA ("..");
  2475. b = RemoveDirectoryA (NewDir);
  2476. }
  2477. if (!b && rc == ERROR_SUCCESS) {
  2478. rc = GetLastError();
  2479. }
  2480. SetCurrentDirectoryA (CurDir);
  2481. SetLastError (rc);
  2482. return b;
  2483. }
  2484. BOOL
  2485. RemoveCompleteDirectoryW (
  2486. IN PCWSTR Dir
  2487. )
  2488. {
  2489. TREE_ENUMW e;
  2490. BOOL b = TRUE;
  2491. WCHAR CurDir[MAX_WCHAR_PATH];
  2492. WCHAR NewDir[MAX_WCHAR_PATH];
  2493. LONG rc = ERROR_SUCCESS;
  2494. DWORD Attribs;
  2495. Attribs = GetLongPathAttributesW (Dir);
  2496. if (Attribs == INVALID_ATTRIBUTES) {
  2497. return TRUE;
  2498. }
  2499. if (!(Attribs & FILE_ATTRIBUTE_DIRECTORY)) {
  2500. SetLongPathAttributesW (Dir, FILE_ATTRIBUTE_NORMAL);
  2501. return DeleteLongPathW (Dir);
  2502. }
  2503. GetCurrentDirectoryW (MAX_WCHAR_PATH, CurDir);
  2504. SetCurrentDirectoryW (Dir);
  2505. GetCurrentDirectoryW (MAX_WCHAR_PATH, NewDir);
  2506. if (EnumFirstFileInTreeW (&e, NewDir, NULL, FALSE)) {
  2507. do {
  2508. if (!e.Directory) {
  2509. SetLongPathAttributesW (e.FullPath, FILE_ATTRIBUTE_NORMAL);
  2510. if (!DeleteLongPathW (e.FullPath)) {
  2511. DEBUGMSGW ((DBG_ERROR, "Can't delete %s", e.FullPath));
  2512. if (b) {
  2513. b = FALSE;
  2514. rc = GetLastError();
  2515. }
  2516. }
  2517. }
  2518. } while (EnumNextFileInTreeW (&e));
  2519. }
  2520. if (EnumFirstFileInTreeExW (&e, NewDir, NULL, TRUE, TRUE, FILE_ENUM_ALL_LEVELS)) {
  2521. do {
  2522. if (e.Directory) {
  2523. SetLongPathAttributesW (e.FullPath, FILE_ATTRIBUTE_NORMAL);
  2524. if (!RemoveDirectoryW (e.FullPath)) {
  2525. DEBUGMSGW ((DBG_ERROR, "Can't remove %s", e.FullPath));
  2526. if (b) {
  2527. b = FALSE;
  2528. rc = GetLastError();
  2529. }
  2530. }
  2531. }
  2532. } while (EnumNextFileInTreeW (&e));
  2533. }
  2534. if (b) {
  2535. SetLongPathAttributesW (NewDir, FILE_ATTRIBUTE_NORMAL);
  2536. SetCurrentDirectoryW (L"..");
  2537. b = RemoveDirectoryW (NewDir);
  2538. }
  2539. if (!b && rc == ERROR_SUCCESS) {
  2540. rc = GetLastError();
  2541. }
  2542. SetCurrentDirectoryW (CurDir);
  2543. SetLastError (rc);
  2544. return b;
  2545. }
  2546. PCMDLINEA
  2547. ParseCmdLineA (
  2548. IN PCSTR CmdLine,
  2549. IN OUT PGROWBUFFER Buffer
  2550. )
  2551. {
  2552. GROWBUFFER SpacePtrs = GROWBUF_INIT;
  2553. PCSTR p;
  2554. PSTR q;
  2555. INT Count;
  2556. INT i;
  2557. INT j;
  2558. PSTR *Array;
  2559. PCSTR Start;
  2560. CHAR OldChar = 0;
  2561. GROWBUFFER StringBuf = GROWBUF_INIT;
  2562. PBYTE CopyBuf;
  2563. PCMDLINEA CmdLineTable;
  2564. PCMDLINEARGA CmdLineArg;
  2565. UINT Base;
  2566. CHAR Path[MAX_MBCHAR_PATH];
  2567. CHAR UnquotedPath[MAX_MBCHAR_PATH];
  2568. CHAR FixedFileName[MAX_MBCHAR_PATH];
  2569. PCSTR FullPath = NULL;
  2570. DWORD Attribs = INVALID_ATTRIBUTES;
  2571. PSTR CmdLineCopy;
  2572. BOOL Quoted;
  2573. UINT OriginalArgOffset = 0;
  2574. UINT CleanedUpArgOffset = 0;
  2575. BOOL GoodFileFound = FALSE;
  2576. PSTR DontCare;
  2577. CHAR FirstArgPath[MAX_MBCHAR_PATH];
  2578. PSTR EndOfFirstArg;
  2579. BOOL QuoteMode = FALSE;
  2580. PSTR End;
  2581. CmdLineCopy = DuplicateTextA (CmdLine);
  2582. //
  2583. // Build an array of places to break the string
  2584. //
  2585. for (p = CmdLineCopy ; *p ; p = _mbsinc (p)) {
  2586. if (_mbsnextc (p) == '\"') {
  2587. QuoteMode = !QuoteMode;
  2588. } else if (!QuoteMode && (_mbsnextc (p) == ' ' || _mbsnextc (p) == '=')) {
  2589. //
  2590. // Remove excess spaces
  2591. //
  2592. q = (PSTR) p + 1;
  2593. while (_mbsnextc (q) == ' ') {
  2594. q++;
  2595. }
  2596. if (q > p + 1) {
  2597. MoveMemory ((PBYTE) p + sizeof (CHAR), q, SizeOfStringA (q));
  2598. }
  2599. GrowBufAppendDword (&SpacePtrs, (DWORD) p);
  2600. }
  2601. }
  2602. //
  2603. // Prepare the CMDLINE struct
  2604. //
  2605. CmdLineTable = (PCMDLINEA) GrowBuffer (Buffer, sizeof (CMDLINEA));
  2606. MYASSERT (CmdLineTable);
  2607. //
  2608. // NOTE: We store string offsets, then at the end resolve them
  2609. // to pointers later.
  2610. //
  2611. CmdLineTable->CmdLine = (PCSTR) StringBuf.End;
  2612. MultiSzAppendA (&StringBuf, CmdLine);
  2613. CmdLineTable->ArgCount = 0;
  2614. //
  2615. // Now test every combination, emulating CreateProcess
  2616. //
  2617. Count = SpacePtrs.End / sizeof (DWORD);
  2618. Array = (PSTR *) SpacePtrs.Buf;
  2619. i = -1;
  2620. EndOfFirstArg = NULL;
  2621. while (i < Count) {
  2622. GoodFileFound = FALSE;
  2623. Quoted = FALSE;
  2624. if (i >= 0) {
  2625. Start = Array[i] + 1;
  2626. } else {
  2627. Start = CmdLineCopy;
  2628. }
  2629. //
  2630. // Check for a full path at Start
  2631. //
  2632. if (_mbsnextc (Start) != '/') {
  2633. for (j = i + 1 ; j <= Count && !GoodFileFound ; j++) {
  2634. if (j < Count) {
  2635. OldChar = *Array[j];
  2636. *Array[j] = 0;
  2637. }
  2638. FullPath = Start;
  2639. //
  2640. // Remove quotes; continue in the loop if it has no terminating quotes
  2641. //
  2642. Quoted = FALSE;
  2643. if (_mbsnextc (Start) == '\"') {
  2644. StringCopyByteCountA (UnquotedPath, Start + 1, sizeof (UnquotedPath));
  2645. q = _mbschr (UnquotedPath, '\"');
  2646. if (q) {
  2647. *q = 0;
  2648. FullPath = UnquotedPath;
  2649. Quoted = TRUE;
  2650. } else {
  2651. FullPath = NULL;
  2652. }
  2653. }
  2654. if (FullPath && *FullPath) {
  2655. //
  2656. // Look in file system for the path
  2657. //
  2658. Attribs = GetFileAttributesA (FullPath);
  2659. if (Attribs == INVALID_ATTRIBUTES && EndOfFirstArg) {
  2660. //
  2661. // Try prefixing the path with the first arg's path.
  2662. //
  2663. StringCopyByteCountA (
  2664. EndOfFirstArg,
  2665. FullPath,
  2666. sizeof (FirstArgPath) - ((PBYTE) EndOfFirstArg - (PBYTE) FirstArgPath)
  2667. );
  2668. FullPath = FirstArgPath;
  2669. Attribs = GetFileAttributesA (FullPath);
  2670. }
  2671. if (Attribs == INVALID_ATTRIBUTES && i < 0) {
  2672. //
  2673. // Try appending .exe, then testing again. This
  2674. // emulates what CreateProcess does.
  2675. //
  2676. StringCopyByteCountA (
  2677. FixedFileName,
  2678. FullPath,
  2679. sizeof (FixedFileName) - sizeof (".exe")
  2680. );
  2681. q = GetEndOfStringA (FixedFileName);
  2682. q = _mbsdec (FixedFileName, q);
  2683. MYASSERT (q);
  2684. if (_mbsnextc (q) != '.') {
  2685. q = _mbsinc (q);
  2686. }
  2687. StringCopyA (q, ".exe");
  2688. FullPath = FixedFileName;
  2689. Attribs = GetFileAttributesA (FullPath);
  2690. }
  2691. if (Attribs != INVALID_ATTRIBUTES) {
  2692. //
  2693. // Full file path found. Test its file status, then
  2694. // move on if there are no important operations on it.
  2695. //
  2696. OriginalArgOffset = StringBuf.End;
  2697. MultiSzAppendA (&StringBuf, Start);
  2698. if (!StringMatchA (Start, FullPath)) {
  2699. CleanedUpArgOffset = StringBuf.End;
  2700. MultiSzAppendA (&StringBuf, FullPath);
  2701. } else {
  2702. CleanedUpArgOffset = OriginalArgOffset;
  2703. }
  2704. i = j;
  2705. GoodFileFound = TRUE;
  2706. }
  2707. }
  2708. if (j < Count) {
  2709. *Array[j] = OldChar;
  2710. }
  2711. }
  2712. if (!GoodFileFound) {
  2713. //
  2714. // If a wack is in the path, then we could have a relative path, an arg, or
  2715. // a full path to a non-existent file.
  2716. //
  2717. if (_mbschr (Start, '\\')) {
  2718. #ifdef DEBUG
  2719. j = i + 1;
  2720. if (j < Count) {
  2721. OldChar = *Array[j];
  2722. *Array[j] = 0;
  2723. }
  2724. DEBUGMSGA ((
  2725. DBG_VERBOSE,
  2726. "%s is a non-existent path spec, a relative path, or an arg",
  2727. Start
  2728. ));
  2729. if (j < Count) {
  2730. *Array[j] = OldChar;
  2731. }
  2732. #endif
  2733. } else {
  2734. //
  2735. // The string at Start did not contain a full path; try using
  2736. // SearchPath.
  2737. //
  2738. for (j = i + 1 ; j <= Count && !GoodFileFound ; j++) {
  2739. if (j < Count) {
  2740. OldChar = *Array[j];
  2741. *Array[j] = 0;
  2742. }
  2743. FullPath = Start;
  2744. //
  2745. // Remove quotes; continue in the loop if it has no terminating quotes
  2746. //
  2747. Quoted = FALSE;
  2748. if (_mbsnextc (Start) == '\"') {
  2749. StringCopyByteCountA (UnquotedPath, Start + 1, sizeof (UnquotedPath));
  2750. q = _mbschr (UnquotedPath, '\"');
  2751. if (q) {
  2752. *q = 0;
  2753. FullPath = UnquotedPath;
  2754. Quoted = TRUE;
  2755. } else {
  2756. FullPath = NULL;
  2757. }
  2758. }
  2759. if (FullPath && *FullPath) {
  2760. if (SearchPathA (
  2761. NULL,
  2762. FullPath,
  2763. NULL,
  2764. sizeof (Path) / sizeof (Path[0]),
  2765. Path,
  2766. &DontCare
  2767. )) {
  2768. FullPath = Path;
  2769. } else if (i < 0) {
  2770. //
  2771. // Try appending .exe and searching the path again
  2772. //
  2773. StringCopyByteCountA (
  2774. FixedFileName,
  2775. FullPath,
  2776. sizeof (FixedFileName) - sizeof (".exe")
  2777. );
  2778. q = GetEndOfStringA (FixedFileName);
  2779. q = _mbsdec (FixedFileName, q);
  2780. MYASSERT (q);
  2781. if (_mbsnextc (q) != '.') {
  2782. q = _mbsinc (q);
  2783. }
  2784. StringCopyA (q, ".exe");
  2785. if (SearchPathA (
  2786. NULL,
  2787. FixedFileName,
  2788. NULL,
  2789. sizeof (Path) / sizeof (Path[0]),
  2790. Path,
  2791. &DontCare
  2792. )) {
  2793. FullPath = Path;
  2794. } else {
  2795. FullPath = NULL;
  2796. }
  2797. } else {
  2798. FullPath = NULL;
  2799. }
  2800. }
  2801. if (FullPath && *FullPath) {
  2802. Attribs = GetFileAttributesA (FullPath);
  2803. MYASSERT (Attribs != INVALID_ATTRIBUTES);
  2804. OriginalArgOffset = StringBuf.End;
  2805. MultiSzAppendA (&StringBuf, Start);
  2806. if (!StringMatchA (Start, FullPath)) {
  2807. CleanedUpArgOffset = StringBuf.End;
  2808. MultiSzAppendA (&StringBuf, FullPath);
  2809. } else {
  2810. CleanedUpArgOffset = OriginalArgOffset;
  2811. }
  2812. i = j;
  2813. GoodFileFound = TRUE;
  2814. }
  2815. if (j < Count) {
  2816. *Array[j] = OldChar;
  2817. }
  2818. }
  2819. }
  2820. }
  2821. }
  2822. CmdLineTable->ArgCount += 1;
  2823. CmdLineArg = (PCMDLINEARGA) GrowBuffer (Buffer, sizeof (CMDLINEARGA));
  2824. MYASSERT (CmdLineArg);
  2825. if (GoodFileFound) {
  2826. //
  2827. // We have a good full file spec in FullPath, its attributes
  2828. // are in Attribs, and i has been moved to the space beyond
  2829. // the path. We now add a table entry.
  2830. //
  2831. CmdLineArg->OriginalArg = (PCSTR) OriginalArgOffset;
  2832. CmdLineArg->CleanedUpArg = (PCSTR) CleanedUpArgOffset;
  2833. CmdLineArg->Attributes = Attribs;
  2834. CmdLineArg->Quoted = Quoted;
  2835. if (!EndOfFirstArg) {
  2836. StringCopyByteCountA (FirstArgPath, (PCSTR) (StringBuf.Buf + (UINT) CmdLineArg->CleanedUpArg), sizeof (FirstArgPath));
  2837. q = (PSTR) GetFileNameFromPathA (FirstArgPath);
  2838. if (q) {
  2839. q = _mbsdec (FirstArgPath, q);
  2840. if (q) {
  2841. *q = 0;
  2842. }
  2843. }
  2844. EndOfFirstArg = AppendWackA (FirstArgPath);
  2845. }
  2846. } else {
  2847. //
  2848. // We do not have a good file spec; we must have a non-file
  2849. // argument. Put it in the table, and advance to the next
  2850. // arg.
  2851. //
  2852. j = i + 1;
  2853. if (j <= Count) {
  2854. if (j < Count) {
  2855. OldChar = *Array[j];
  2856. *Array[j] = 0;
  2857. }
  2858. CmdLineArg->OriginalArg = (PCSTR) StringBuf.End;
  2859. MultiSzAppendA (&StringBuf, Start);
  2860. Quoted = FALSE;
  2861. if (_mbschr (Start, '\"')) {
  2862. p = Start;
  2863. q = UnquotedPath;
  2864. End = (PSTR) ((PBYTE) UnquotedPath + sizeof (UnquotedPath) - sizeof (CHAR));
  2865. while (*p && q < End) {
  2866. if (IsLeadByte (*p)) {
  2867. *q++ = *p++;
  2868. *q++ = *p++;
  2869. } else {
  2870. if (*p == '\"') {
  2871. p++;
  2872. } else {
  2873. *q++ = *p++;
  2874. }
  2875. }
  2876. }
  2877. *q = 0;
  2878. CmdLineArg->CleanedUpArg = (PCSTR) StringBuf.End;
  2879. MultiSzAppendA (&StringBuf, UnquotedPath);
  2880. Quoted = TRUE;
  2881. } else {
  2882. CmdLineArg->CleanedUpArg = CmdLineArg->OriginalArg;
  2883. }
  2884. CmdLineArg->Attributes = INVALID_ATTRIBUTES;
  2885. CmdLineArg->Quoted = Quoted;
  2886. if (j < Count) {
  2887. *Array[j] = OldChar;
  2888. }
  2889. i = j;
  2890. }
  2891. }
  2892. }
  2893. //
  2894. // We now have a command line table; transfer StringBuf to Buffer, then
  2895. // convert all offsets into pointers.
  2896. //
  2897. MYASSERT (StringBuf.End);
  2898. CopyBuf = GrowBuffer (Buffer, StringBuf.End);
  2899. MYASSERT (CopyBuf);
  2900. Base = (UINT) CopyBuf;
  2901. CopyMemory (CopyBuf, StringBuf.Buf, StringBuf.End);
  2902. CmdLineTable->CmdLine = (PCSTR) ((PBYTE) CmdLineTable->CmdLine + Base);
  2903. CmdLineArg = &CmdLineTable->Args[0];
  2904. for (i = 0 ; i < (INT) CmdLineTable->ArgCount ; i++) {
  2905. CmdLineArg->OriginalArg = (PCSTR) ((PBYTE) CmdLineArg->OriginalArg + Base);
  2906. CmdLineArg->CleanedUpArg = (PCSTR) ((PBYTE) CmdLineArg->CleanedUpArg + Base);
  2907. CmdLineArg++;
  2908. }
  2909. FreeGrowBuffer (&StringBuf);
  2910. FreeGrowBuffer (&SpacePtrs);
  2911. return (PCMDLINEA) Buffer->Buf;
  2912. }
  2913. PCMDLINEW
  2914. ParseCmdLineW (
  2915. IN PCWSTR CmdLine,
  2916. IN OUT PGROWBUFFER Buffer
  2917. )
  2918. {
  2919. GROWBUFFER SpacePtrs = GROWBUF_INIT;
  2920. PCWSTR p;
  2921. PWSTR q;
  2922. INT Count;
  2923. INT i;
  2924. INT j;
  2925. PWSTR *Array;
  2926. PCWSTR Start;
  2927. WCHAR OldChar = 0;
  2928. GROWBUFFER StringBuf = GROWBUF_INIT;
  2929. PBYTE CopyBuf;
  2930. PCMDLINEW CmdLineTable;
  2931. PCMDLINEARGW CmdLineArg;
  2932. UINT Base;
  2933. WCHAR Path[MAX_WCHAR_PATH];
  2934. WCHAR UnquotedPath[MAX_WCHAR_PATH];
  2935. WCHAR FixedFileName[MAX_WCHAR_PATH];
  2936. PCWSTR FullPath = NULL;
  2937. DWORD Attribs = INVALID_ATTRIBUTES;
  2938. PWSTR CmdLineCopy;
  2939. BOOL Quoted;
  2940. UINT OriginalArgOffset = 0;
  2941. UINT CleanedUpArgOffset = 0;
  2942. BOOL GoodFileFound = FALSE;
  2943. PWSTR DontCare;
  2944. WCHAR FirstArgPath[MAX_MBCHAR_PATH];
  2945. PWSTR EndOfFirstArg;
  2946. BOOL QuoteMode = FALSE;
  2947. PWSTR End;
  2948. CmdLineCopy = DuplicateTextW (CmdLine);
  2949. //
  2950. // Build an array of places to break the string
  2951. //
  2952. for (p = CmdLineCopy ; *p ; p++) {
  2953. if (*p == L'\"') {
  2954. QuoteMode = !QuoteMode;
  2955. } else if (!QuoteMode && (*p == L' ' || *p == L'=')) {
  2956. //
  2957. // Remove excess spaces
  2958. //
  2959. q = (PWSTR) p + 1;
  2960. while (*q == L' ') {
  2961. q++;
  2962. }
  2963. if (q > p + 1) {
  2964. MoveMemory ((PBYTE) p + sizeof (WCHAR), q, SizeOfStringW (q));
  2965. }
  2966. GrowBufAppendDword (&SpacePtrs, (DWORD) p);
  2967. }
  2968. }
  2969. //
  2970. // Prepare the CMDLINE struct
  2971. //
  2972. CmdLineTable = (PCMDLINEW) GrowBuffer (Buffer, sizeof (CMDLINEW));
  2973. MYASSERT (CmdLineTable);
  2974. //
  2975. // NOTE: We store string offsets, then at the end resolve them
  2976. // to pointers later.
  2977. //
  2978. CmdLineTable->CmdLine = (PCWSTR) StringBuf.End;
  2979. MultiSzAppendW (&StringBuf, CmdLine);
  2980. CmdLineTable->ArgCount = 0;
  2981. //
  2982. // Now test every combination, emulating CreateProcess
  2983. //
  2984. Count = SpacePtrs.End / sizeof (DWORD);
  2985. Array = (PWSTR *) SpacePtrs.Buf;
  2986. i = -1;
  2987. EndOfFirstArg = NULL;
  2988. while (i < Count) {
  2989. GoodFileFound = FALSE;
  2990. Quoted = FALSE;
  2991. if (i >= 0) {
  2992. Start = Array[i] + 1;
  2993. } else {
  2994. Start = CmdLineCopy;
  2995. }
  2996. //
  2997. // Check for a full path at Start
  2998. //
  2999. if (*Start != L'/') {
  3000. for (j = i + 1 ; j <= Count && !GoodFileFound ; j++) {
  3001. if (j < Count) {
  3002. OldChar = *Array[j];
  3003. *Array[j] = 0;
  3004. }
  3005. FullPath = Start;
  3006. //
  3007. // Remove quotes; continue in the loop if it has no terminating quotes
  3008. //
  3009. Quoted = FALSE;
  3010. if (*Start == L'\"') {
  3011. StringCopyByteCountW (UnquotedPath, Start + 1, sizeof (UnquotedPath));
  3012. q = wcschr (UnquotedPath, L'\"');
  3013. if (q) {
  3014. *q = 0;
  3015. FullPath = UnquotedPath;
  3016. Quoted = TRUE;
  3017. } else {
  3018. FullPath = NULL;
  3019. }
  3020. }
  3021. if (FullPath && *FullPath) {
  3022. //
  3023. // Look in file system for the path
  3024. //
  3025. Attribs = GetLongPathAttributesW (FullPath);
  3026. if (Attribs == INVALID_ATTRIBUTES && EndOfFirstArg) {
  3027. //
  3028. // Try prefixing the path with the first arg's path.
  3029. //
  3030. StringCopyByteCountW (
  3031. EndOfFirstArg,
  3032. FullPath,
  3033. sizeof (FirstArgPath) - ((PBYTE) EndOfFirstArg - (PBYTE) FirstArgPath)
  3034. );
  3035. FullPath = FirstArgPath;
  3036. Attribs = GetLongPathAttributesW (FullPath);
  3037. }
  3038. if (Attribs == INVALID_ATTRIBUTES && i < 0) {
  3039. //
  3040. // Try appending .exe, then testing again. This
  3041. // emulates what CreateProcess does.
  3042. //
  3043. StringCopyByteCountW (
  3044. FixedFileName,
  3045. FullPath,
  3046. sizeof (FixedFileName) - sizeof (L".exe")
  3047. );
  3048. q = GetEndOfStringW (FixedFileName);
  3049. q--;
  3050. MYASSERT (q >= FixedFileName);
  3051. if (*q != L'.') {
  3052. q++;
  3053. }
  3054. StringCopyW (q, L".exe");
  3055. FullPath = FixedFileName;
  3056. Attribs = GetLongPathAttributesW (FullPath);
  3057. }
  3058. if (Attribs != INVALID_ATTRIBUTES) {
  3059. //
  3060. // Full file path found. Test its file status, then
  3061. // move on if there are no important operations on it.
  3062. //
  3063. OriginalArgOffset = StringBuf.End;
  3064. MultiSzAppendW (&StringBuf, Start);
  3065. if (!StringMatchW (Start, FullPath)) {
  3066. CleanedUpArgOffset = StringBuf.End;
  3067. MultiSzAppendW (&StringBuf, FullPath);
  3068. } else {
  3069. CleanedUpArgOffset = OriginalArgOffset;
  3070. }
  3071. i = j;
  3072. GoodFileFound = TRUE;
  3073. }
  3074. }
  3075. if (j < Count) {
  3076. *Array[j] = OldChar;
  3077. }
  3078. }
  3079. if (!GoodFileFound) {
  3080. //
  3081. // If a wack is in the path, then we could have a relative path, an arg, or
  3082. // a full path to a non-existent file.
  3083. //
  3084. if (wcschr (Start, L'\\')) {
  3085. #ifdef DEBUG
  3086. j = i + 1;
  3087. if (j < Count) {
  3088. OldChar = *Array[j];
  3089. *Array[j] = 0;
  3090. }
  3091. DEBUGMSGW ((
  3092. DBG_VERBOSE,
  3093. "%s is a non-existent path spec, a relative path, or an arg",
  3094. Start
  3095. ));
  3096. if (j < Count) {
  3097. *Array[j] = OldChar;
  3098. }
  3099. #endif
  3100. } else {
  3101. //
  3102. // The string at Start did not contain a full path; try using
  3103. // SearchPath.
  3104. //
  3105. for (j = i + 1 ; j <= Count && !GoodFileFound ; j++) {
  3106. if (j < Count) {
  3107. OldChar = *Array[j];
  3108. *Array[j] = 0;
  3109. }
  3110. FullPath = Start;
  3111. //
  3112. // Remove quotes; continue in the loop if it has no terminating quotes
  3113. //
  3114. Quoted = FALSE;
  3115. if (*Start == L'\"') {
  3116. StringCopyByteCountW (UnquotedPath, Start + 1, sizeof (UnquotedPath));
  3117. q = wcschr (UnquotedPath, L'\"');
  3118. if (q) {
  3119. *q = 0;
  3120. FullPath = UnquotedPath;
  3121. Quoted = TRUE;
  3122. } else {
  3123. FullPath = NULL;
  3124. }
  3125. }
  3126. if (FullPath && *FullPath) {
  3127. if (SearchPathW (
  3128. NULL,
  3129. FullPath,
  3130. NULL,
  3131. sizeof (Path) / sizeof (Path[0]),
  3132. Path,
  3133. &DontCare
  3134. )) {
  3135. FullPath = Path;
  3136. } else if (i < 0) {
  3137. //
  3138. // Try appending .exe and searching the path again
  3139. //
  3140. StringCopyByteCountW (
  3141. FixedFileName,
  3142. FullPath,
  3143. sizeof (FixedFileName) - sizeof (L".exe")
  3144. );
  3145. q = GetEndOfStringW (FixedFileName);
  3146. q--;
  3147. MYASSERT (q >= FixedFileName);
  3148. if (*q != L'.') {
  3149. q++;
  3150. }
  3151. StringCopyW (q, L".exe");
  3152. if (SearchPathW (
  3153. NULL,
  3154. FixedFileName,
  3155. NULL,
  3156. sizeof (Path) / sizeof (Path[0]),
  3157. Path,
  3158. &DontCare
  3159. )) {
  3160. FullPath = Path;
  3161. } else {
  3162. FullPath = NULL;
  3163. }
  3164. } else {
  3165. FullPath = NULL;
  3166. }
  3167. }
  3168. if (FullPath && *FullPath) {
  3169. Attribs = GetLongPathAttributesW (FullPath);
  3170. MYASSERT (Attribs != INVALID_ATTRIBUTES);
  3171. OriginalArgOffset = StringBuf.End;
  3172. MultiSzAppendW (&StringBuf, Start);
  3173. if (!StringMatchW (Start, FullPath)) {
  3174. CleanedUpArgOffset = StringBuf.End;
  3175. MultiSzAppendW (&StringBuf, FullPath);
  3176. } else {
  3177. CleanedUpArgOffset = OriginalArgOffset;
  3178. }
  3179. i = j;
  3180. GoodFileFound = TRUE;
  3181. }
  3182. if (j < Count) {
  3183. *Array[j] = OldChar;
  3184. }
  3185. }
  3186. }
  3187. }
  3188. }
  3189. CmdLineTable->ArgCount += 1;
  3190. CmdLineArg = (PCMDLINEARGW) GrowBuffer (Buffer, sizeof (CMDLINEARGW));
  3191. MYASSERT (CmdLineArg);
  3192. if (GoodFileFound) {
  3193. //
  3194. // We have a good full file spec in FullPath, its attributes
  3195. // are in Attribs, and i has been moved to the space beyond
  3196. // the path. We now add a table entry.
  3197. //
  3198. CmdLineArg->OriginalArg = (PCWSTR) OriginalArgOffset;
  3199. CmdLineArg->CleanedUpArg = (PCWSTR) CleanedUpArgOffset;
  3200. CmdLineArg->Attributes = Attribs;
  3201. CmdLineArg->Quoted = Quoted;
  3202. if (!EndOfFirstArg) {
  3203. StringCopyByteCountW (FirstArgPath, (PCWSTR) (StringBuf.Buf + (UINT) CmdLineArg->CleanedUpArg), sizeof (FirstArgPath));
  3204. q = (PWSTR) GetFileNameFromPathW (FirstArgPath);
  3205. if (q) {
  3206. q--;
  3207. if (q >= FirstArgPath) {
  3208. *q = 0;
  3209. }
  3210. }
  3211. EndOfFirstArg = AppendWackW (FirstArgPath);
  3212. }
  3213. } else {
  3214. //
  3215. // We do not have a good file spec; we must have a non-file
  3216. // argument. Put it in the table, and advance to the next
  3217. // arg.
  3218. //
  3219. j = i + 1;
  3220. if (j <= Count) {
  3221. if (j < Count) {
  3222. OldChar = *Array[j];
  3223. *Array[j] = 0;
  3224. }
  3225. CmdLineArg->OriginalArg = (PCWSTR) StringBuf.End;
  3226. MultiSzAppendW (&StringBuf, Start);
  3227. Quoted = FALSE;
  3228. if (wcschr (Start, '\"')) {
  3229. p = Start;
  3230. q = UnquotedPath;
  3231. End = (PWSTR) ((PBYTE) UnquotedPath + sizeof (UnquotedPath) - sizeof (WCHAR));
  3232. while (*p && q < End) {
  3233. if (*p == L'\"') {
  3234. p++;
  3235. } else {
  3236. *q++ = *p++;
  3237. }
  3238. }
  3239. *q = 0;
  3240. CmdLineArg->CleanedUpArg = (PCWSTR) StringBuf.End;
  3241. MultiSzAppendW (&StringBuf, UnquotedPath);
  3242. Quoted = TRUE;
  3243. } else {
  3244. CmdLineArg->CleanedUpArg = CmdLineArg->OriginalArg;
  3245. }
  3246. CmdLineArg->Attributes = INVALID_ATTRIBUTES;
  3247. CmdLineArg->Quoted = Quoted;
  3248. if (j < Count) {
  3249. *Array[j] = OldChar;
  3250. }
  3251. i = j;
  3252. }
  3253. }
  3254. }
  3255. //
  3256. // We now have a command line table; transfer StringBuf to Buffer, then
  3257. // convert all offsets into pointers.
  3258. //
  3259. MYASSERT (StringBuf.End);
  3260. CopyBuf = GrowBuffer (Buffer, StringBuf.End);
  3261. MYASSERT (CopyBuf);
  3262. Base = (UINT) CopyBuf;
  3263. CopyMemory (CopyBuf, StringBuf.Buf, StringBuf.End);
  3264. CmdLineTable->CmdLine = (PCWSTR) ((PBYTE) CmdLineTable->CmdLine + Base);
  3265. CmdLineArg = &CmdLineTable->Args[0];
  3266. for (i = 0 ; i < (INT) CmdLineTable->ArgCount ; i++) {
  3267. CmdLineArg->OriginalArg = (PCWSTR) ((PBYTE) CmdLineArg->OriginalArg + Base);
  3268. CmdLineArg->CleanedUpArg = (PCWSTR) ((PBYTE) CmdLineArg->CleanedUpArg + Base);
  3269. CmdLineArg++;
  3270. }
  3271. FreeGrowBuffer (&StringBuf);
  3272. FreeGrowBuffer (&SpacePtrs);
  3273. return (PCMDLINEW) Buffer->Buf;
  3274. }
  3275. BOOL
  3276. GetFileSizeFromFilePathA(
  3277. IN PCSTR FilePath,
  3278. OUT ULARGE_INTEGER * FileSize
  3279. )
  3280. {
  3281. WIN32_FILE_ATTRIBUTE_DATA fileDataAttributes;
  3282. if(!FilePath || !FileSize){
  3283. MYASSERT(FALSE);
  3284. return FALSE;
  3285. }
  3286. if (!IsPathOnFixedDriveA (FilePath)) {
  3287. FileSize->QuadPart = 0;
  3288. MYASSERT(FALSE);
  3289. return FALSE;
  3290. }
  3291. if(!GetFileAttributesExA(FilePath, GetFileExInfoStandard, &fileDataAttributes) ||
  3292. fileDataAttributes.dwFileAttributes == INVALID_ATTRIBUTES ||
  3293. (fileDataAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
  3294. MYASSERT(FALSE);
  3295. return FALSE;
  3296. }
  3297. FileSize->LowPart = fileDataAttributes.nFileSizeLow;
  3298. FileSize->HighPart = fileDataAttributes.nFileSizeHigh;
  3299. return TRUE;
  3300. }
  3301. BOOL
  3302. GetFileSizeFromFilePathW(
  3303. IN PCWSTR FilePath,
  3304. OUT ULARGE_INTEGER * FileSize
  3305. )
  3306. {
  3307. WIN32_FILE_ATTRIBUTE_DATA fileDataAttributes;
  3308. if(!FilePath || !FileSize){
  3309. MYASSERT(FALSE);
  3310. return FALSE;
  3311. }
  3312. if (!IsPathOnFixedDriveW (FilePath)) {
  3313. FileSize->QuadPart = 0;
  3314. MYASSERT(FALSE);
  3315. return FALSE;
  3316. }
  3317. if(!GetFileAttributesExW(FilePath, GetFileExInfoStandard, &fileDataAttributes) ||
  3318. fileDataAttributes.dwFileAttributes == INVALID_ATTRIBUTES ||
  3319. (fileDataAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
  3320. MYASSERT(FALSE);
  3321. return FALSE;
  3322. }
  3323. FileSize->LowPart = fileDataAttributes.nFileSizeLow;
  3324. FileSize->HighPart = fileDataAttributes.nFileSizeHigh;
  3325. return TRUE;
  3326. }
  3327. VOID
  3328. InitializeDriveLetterStructureA (
  3329. OUT PDRIVELETTERSA DriveLetters
  3330. )
  3331. {
  3332. BYTE bitPosition;
  3333. DWORD maxBitPosition = NUMDRIVELETTERS;
  3334. CHAR rootPath[] = "?:\\";
  3335. BOOL driveExists;
  3336. UINT type;
  3337. //
  3338. // GetLogicalDrives returns a bitmask of all of the drive letters
  3339. // in use on the system. (i.e. bit position 0 is turned on if there is
  3340. // an 'A' drive, 1 is turned on if there is a 'B' drive, etc.
  3341. // This loop will use this bitmask to fill in the global drive
  3342. // letters structure with information about what drive letters
  3343. // are available and what there drive types are.
  3344. //
  3345. for (bitPosition = 0; bitPosition < maxBitPosition; bitPosition++) {
  3346. //
  3347. // Initialize this drive
  3348. //
  3349. DriveLetters->ExistsOnSystem[bitPosition] = FALSE;
  3350. DriveLetters->Type[bitPosition] = 0;
  3351. DriveLetters->IdentifierString[bitPosition][0] = 0;
  3352. rootPath[0] = 'A' + bitPosition;
  3353. DriveLetters->Letter[bitPosition] = rootPath[0];
  3354. //
  3355. // Determine if there is a drive in this spot.
  3356. //
  3357. driveExists = GetLogicalDrives() & (1 << bitPosition);
  3358. if (driveExists) {
  3359. //
  3360. // There is. Now, see if it is one that we care about.
  3361. //
  3362. type = GetDriveTypeA(rootPath);
  3363. if (type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM) {
  3364. //
  3365. // This is a drive that we are interested in.
  3366. //
  3367. DriveLetters->ExistsOnSystem[bitPosition] = TRUE;
  3368. DriveLetters->Type[bitPosition] = type;
  3369. //
  3370. // Identifier String is not filled in this function.
  3371. //
  3372. }
  3373. }
  3374. }
  3375. }
  3376. VOID
  3377. InitializeDriveLetterStructureW (
  3378. OUT PDRIVELETTERSW DriveLetters
  3379. )
  3380. {
  3381. BYTE bitPosition;
  3382. DWORD maxBitPosition = NUMDRIVELETTERS;
  3383. WCHAR rootPath[] = L"?:\\";
  3384. BOOL driveExists;
  3385. UINT type;
  3386. //
  3387. // GetLogicalDrives returns a bitmask of all of the drive letters
  3388. // in use on the system. (i.e. bit position 0 is turned on if there is
  3389. // an 'A' drive, 1 is turned on if there is a 'B' drive, etc.
  3390. // This loop will use this bitmask to fill in the global drive
  3391. // letters structure with information about what drive letters
  3392. // are available and what there drive types are.
  3393. //
  3394. for (bitPosition = 0; bitPosition < maxBitPosition; bitPosition++) {
  3395. //
  3396. // Initialize this drive
  3397. //
  3398. DriveLetters->ExistsOnSystem[bitPosition] = FALSE;
  3399. DriveLetters->Type[bitPosition] = 0;
  3400. DriveLetters->IdentifierString[bitPosition][0] = 0;
  3401. rootPath[0] = L'A' + bitPosition;
  3402. DriveLetters->Letter[bitPosition] = rootPath[0];
  3403. //
  3404. // Determine if there is a drive in this spot.
  3405. //
  3406. driveExists = GetLogicalDrives() & (1 << bitPosition);
  3407. if (driveExists) {
  3408. //
  3409. // There is. Now, see if it is one that we care about.
  3410. //
  3411. type = GetDriveTypeW(rootPath);
  3412. if (type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM) {
  3413. //
  3414. // This is a drive that we are interested in.
  3415. //
  3416. DriveLetters->ExistsOnSystem[bitPosition] = TRUE;
  3417. DriveLetters->Type[bitPosition] = type;
  3418. //
  3419. // Identifier String is not filled in this function.
  3420. //
  3421. }
  3422. }
  3423. }
  3424. }
  3425. typedef BOOL (WINAPI * GETDISKFREESPACEEXA)(
  3426. PCSTR lpDirectoryName, // directory name
  3427. PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
  3428. PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
  3429. PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
  3430. );
  3431. typedef BOOL (WINAPI * GETDISKFREESPACEEXW)(
  3432. PCWSTR lpDirectoryName, // directory name
  3433. PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
  3434. PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
  3435. PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
  3436. );
  3437. BOOL
  3438. GetDiskFreeSpaceNewA(
  3439. IN PCSTR DriveName,
  3440. OUT DWORD * OutSectorsPerCluster,
  3441. OUT DWORD * OutBytesPerSector,
  3442. OUT ULARGE_INTEGER * OutNumberOfFreeClusters,
  3443. OUT ULARGE_INTEGER * OutTotalNumberOfClusters
  3444. )
  3445. /*++
  3446. Routine Description:
  3447. On Win9x GetDiskFreeSpace never return free/total space more than 2048MB.
  3448. GetDiskFreeSpaceNew use GetDiskFreeSpaceEx to calculate real number of free/total clusters.
  3449. Has same declaration as GetDiskFreeSpaceA.
  3450. Arguments:
  3451. DriveName - supplies directory name
  3452. OutSectorsPerCluster - receive number of sectors per cluster
  3453. OutBytesPerSector - receive number of bytes per sector
  3454. OutNumberOfFreeClusters - receive number of free clusters
  3455. OutTotalNumberOfClusters - receive number of total clusters
  3456. Return Value:
  3457. TRUE if the function succeeds.
  3458. If the function fails, the return value is FALSE. To get extended error information, call GetLastError
  3459. --*/
  3460. {
  3461. ULARGE_INTEGER TotalNumberOfFreeBytes = {0, 0};
  3462. ULARGE_INTEGER TotalNumberOfBytes = {0, 0};
  3463. ULARGE_INTEGER DonotCare;
  3464. HMODULE hKernel32;
  3465. GETDISKFREESPACEEXA pGetDiskFreeSpaceExA;
  3466. ULARGE_INTEGER NumberOfFreeClusters = {0, 0};
  3467. ULARGE_INTEGER TotalNumberOfClusters = {0, 0};
  3468. DWORD SectorsPerCluster;
  3469. DWORD BytesPerSector;
  3470. if(!GetDiskFreeSpaceA(DriveName,
  3471. &SectorsPerCluster,
  3472. &BytesPerSector,
  3473. &NumberOfFreeClusters.LowPart,
  3474. &TotalNumberOfClusters.LowPart)){
  3475. DEBUGMSG((DBG_ERROR,"GetDiskFreeSpaceNewA: GetDiskFreeSpaceA failed on drive %s", DriveName));
  3476. return FALSE;
  3477. }
  3478. hKernel32 = LoadLibraryA("kernel32.dll");
  3479. pGetDiskFreeSpaceExA = (GETDISKFREESPACEEXA)GetProcAddress(hKernel32, "GetDiskFreeSpaceExA");
  3480. if(pGetDiskFreeSpaceExA &&
  3481. pGetDiskFreeSpaceExA(DriveName, &DonotCare, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)){
  3482. NumberOfFreeClusters.QuadPart = TotalNumberOfFreeBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
  3483. TotalNumberOfClusters.QuadPart = TotalNumberOfBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
  3484. }
  3485. else{
  3486. DEBUGMSG((DBG_WARNING,
  3487. pGetDiskFreeSpaceExA?
  3488. "GetDiskFreeSpaceNewA: GetDiskFreeSpaceExA is failed":
  3489. "GetDiskFreeSpaceNewA: GetDiskFreeSpaceExA function is not in kernel32.dll"));
  3490. }
  3491. FreeLibrary(hKernel32);
  3492. if(OutSectorsPerCluster){
  3493. *OutSectorsPerCluster = SectorsPerCluster;
  3494. }
  3495. if(OutBytesPerSector){
  3496. *OutBytesPerSector = BytesPerSector;
  3497. }
  3498. if(OutNumberOfFreeClusters){
  3499. OutNumberOfFreeClusters->QuadPart = NumberOfFreeClusters.QuadPart;
  3500. }
  3501. if(OutTotalNumberOfClusters){
  3502. OutTotalNumberOfClusters->QuadPart = TotalNumberOfClusters.QuadPart;
  3503. }
  3504. DEBUGMSG((DBG_VERBOSE,
  3505. "GetDiskFreeSpaceNewA: \n\t"
  3506. "SectorsPerCluster = %d\n\t"
  3507. "BytesPerSector = %d\n\t"
  3508. "NumberOfFreeClusters = %I64u\n\t"
  3509. "TotalNumberOfClusters = %I64u",
  3510. SectorsPerCluster,
  3511. BytesPerSector,
  3512. NumberOfFreeClusters.QuadPart,
  3513. TotalNumberOfClusters.QuadPart));
  3514. return TRUE;
  3515. }
  3516. BOOL
  3517. GetDiskFreeSpaceNewW(
  3518. IN PCWSTR DriveName,
  3519. OUT DWORD * OutSectorsPerCluster,
  3520. OUT DWORD * OutBytesPerSector,
  3521. OUT ULARGE_INTEGER * OutNumberOfFreeClusters,
  3522. OUT ULARGE_INTEGER * OutTotalNumberOfClusters
  3523. )
  3524. /*++
  3525. Routine Description:
  3526. Correct NumberOfFreeClusters and TotalNumberOfClusters out parameters
  3527. with using GetDiskFreeSpace and GetDiskFreeSpaceEx
  3528. Arguments:
  3529. DriveName - supplies directory name
  3530. OutSectorsPerCluster - receive number of sectors per cluster
  3531. OutBytesPerSector - receive number of bytes per sector
  3532. OutNumberOfFreeClusters - receive number of free clusters
  3533. OutTotalNumberOfClusters - receive number of total clusters
  3534. Return Value:
  3535. TRUE if the function succeeds.
  3536. If the function fails, the return value is FALSE. To get extended error information, call GetLastError
  3537. --*/
  3538. {
  3539. ULARGE_INTEGER TotalNumberOfFreeBytes = {0, 0};
  3540. ULARGE_INTEGER TotalNumberOfBytes = {0, 0};
  3541. ULARGE_INTEGER DonotCare;
  3542. HMODULE hKernel32;
  3543. GETDISKFREESPACEEXW pGetDiskFreeSpaceExW;
  3544. ULARGE_INTEGER NumberOfFreeClusters = {0, 0};
  3545. ULARGE_INTEGER TotalNumberOfClusters = {0, 0};
  3546. DWORD SectorsPerCluster;
  3547. DWORD BytesPerSector;
  3548. if(!GetDiskFreeSpaceW(DriveName,
  3549. &SectorsPerCluster,
  3550. &BytesPerSector,
  3551. &NumberOfFreeClusters.LowPart,
  3552. &TotalNumberOfClusters.LowPart)){
  3553. DEBUGMSG((DBG_ERROR,"GetDiskFreeSpaceNewW: GetDiskFreeSpaceW failed on drive %s", DriveName));
  3554. return FALSE;
  3555. }
  3556. hKernel32 = LoadLibraryA("kernel32.dll");
  3557. pGetDiskFreeSpaceExW = (GETDISKFREESPACEEXW)GetProcAddress(hKernel32, "GetDiskFreeSpaceExW");
  3558. if(pGetDiskFreeSpaceExW &&
  3559. pGetDiskFreeSpaceExW(DriveName, &DonotCare, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)){
  3560. NumberOfFreeClusters.QuadPart = TotalNumberOfFreeBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
  3561. TotalNumberOfClusters.QuadPart = TotalNumberOfBytes.QuadPart / (SectorsPerCluster * BytesPerSector);
  3562. }
  3563. else{
  3564. DEBUGMSG((DBG_WARNING,
  3565. pGetDiskFreeSpaceExW?
  3566. "GetDiskFreeSpaceNewW: GetDiskFreeSpaceExW is failed":
  3567. "GetDiskFreeSpaceNewW: GetDiskFreeSpaceExW function is not in kernel32.dll"));
  3568. }
  3569. FreeLibrary(hKernel32);
  3570. if(OutSectorsPerCluster){
  3571. *OutSectorsPerCluster = SectorsPerCluster;
  3572. }
  3573. if(OutBytesPerSector){
  3574. *OutBytesPerSector = BytesPerSector;
  3575. }
  3576. if(OutNumberOfFreeClusters){
  3577. OutNumberOfFreeClusters->QuadPart = NumberOfFreeClusters.QuadPart;
  3578. }
  3579. if(OutTotalNumberOfClusters){
  3580. OutTotalNumberOfClusters->QuadPart = TotalNumberOfClusters.QuadPart;
  3581. }
  3582. DEBUGMSG((DBG_VERBOSE,
  3583. "GetDiskFreeSpaceNewW: \n\t"
  3584. "SectorsPerCluster = %d\n\t"
  3585. "BytesPerSector = %d\n\t"
  3586. "NumberOfFreeClusters = %I64u\n\t"
  3587. "TotalNumberOfClusters = %I64u",
  3588. SectorsPerCluster,
  3589. BytesPerSector,
  3590. NumberOfFreeClusters.QuadPart,
  3591. TotalNumberOfClusters.QuadPart));
  3592. return TRUE;
  3593. }
  3594. DWORD
  3595. QuietGetFileAttributesA (
  3596. IN PCSTR FilePath
  3597. )
  3598. {
  3599. if (!IsPathOnFixedDriveA (FilePath)) {
  3600. return INVALID_ATTRIBUTES;
  3601. }
  3602. return GetFileAttributesA (FilePath);
  3603. }
  3604. DWORD
  3605. QuietGetFileAttributesW (
  3606. IN PCWSTR FilePath
  3607. )
  3608. {
  3609. MYASSERT (ISNT());
  3610. if (!IsPathOnFixedDriveW (FilePath)) {
  3611. return INVALID_ATTRIBUTES;
  3612. }
  3613. return GetLongPathAttributesW (FilePath);
  3614. }
  3615. DWORD
  3616. MakeSureLongPathExistsW (
  3617. IN PCWSTR Path,
  3618. IN BOOL PathOnly
  3619. )
  3620. {
  3621. PCWSTR tmp;
  3622. DWORD result;
  3623. if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
  3624. result = MakeSurePathExistsW (Path, PathOnly);
  3625. } else {
  3626. tmp = JoinPathsW (L"\\\\?", Path);
  3627. result = MakeSurePathExistsW (tmp, PathOnly);
  3628. FreePathStringW (tmp);
  3629. }
  3630. return result;
  3631. }
  3632. DWORD
  3633. SetLongPathAttributesW (
  3634. IN PCWSTR Path,
  3635. IN DWORD Attributes
  3636. )
  3637. {
  3638. PCWSTR tmp;
  3639. DWORD result;
  3640. if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
  3641. result = SetFileAttributesW (Path, Attributes);
  3642. } else {
  3643. tmp = JoinPathsW (L"\\\\?", Path);
  3644. result = SetFileAttributesW (tmp, Attributes);
  3645. FreePathStringW (tmp);
  3646. }
  3647. return result;
  3648. }
  3649. DWORD
  3650. GetLongPathAttributesW (
  3651. IN PCWSTR Path
  3652. )
  3653. {
  3654. PCWSTR tmp;
  3655. DWORD result;
  3656. if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
  3657. result = GetFileAttributesW (Path);
  3658. } else {
  3659. tmp = JoinPathsW (L"\\\\?", Path);
  3660. result = GetFileAttributesW (tmp);
  3661. FreePathStringW (tmp);
  3662. }
  3663. return result;
  3664. }
  3665. BOOL
  3666. DeleteLongPathW (
  3667. IN PCWSTR Path
  3668. )
  3669. {
  3670. PCWSTR tmp;
  3671. BOOL result;
  3672. if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
  3673. result = DeleteFileW (Path);
  3674. } else {
  3675. tmp = JoinPathsW (L"\\\\?", Path);
  3676. result = DeleteFileW (tmp);
  3677. FreePathStringW (tmp);
  3678. }
  3679. return result;
  3680. }
  3681. BOOL
  3682. RemoveLongDirectoryPathW (
  3683. IN PCWSTR Path
  3684. )
  3685. {
  3686. PCWSTR tmp;
  3687. BOOL result;
  3688. if (Path[0] == L'\\' || TcharCountW (Path) < MAX_PATH) {
  3689. result = RemoveDirectoryW (Path);
  3690. } else {
  3691. tmp = JoinPathsW (L"\\\\?", Path);
  3692. result = RemoveDirectoryW (tmp);
  3693. FreePathStringW (tmp);
  3694. }
  3695. return result;
  3696. }