Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2556 lines
69 KiB

  1. /* demsrch.c - SVC handlers for calls to search files
  2. *
  3. * demFindFirst
  4. * demFindNext
  5. * demFindFirstFCB
  6. * demFindNextFCB
  7. *
  8. * Modification History:
  9. *
  10. * Sudeepb 06-Apr-1991 Created
  11. *
  12. */
  13. #include "dem.h"
  14. #include "demmsg.h"
  15. #include "winbasep.h"
  16. #include <vdm.h>
  17. #include <softpc.h>
  18. #include <mvdm.h>
  19. #include <memory.h>
  20. #include <nt_vdd.h>
  21. #include "dpmtbls.h"
  22. extern BOOL IsFirstCall;
  23. // Defined in host\src\nt_devs.c
  24. VOID nt_devices_block_or_terminate(VOID);
  25. /*
  26. * Internal globals, function prototypes
  27. */
  28. #define FINDFILE_DEVICE (HANDLE)0xffffffff
  29. typedef struct _PSP_FILEFINDLIST {
  30. LIST_ENTRY PspFFindEntry; // Next psp
  31. LIST_ENTRY FFindHeadList; // File Find list for this psp
  32. ULONG usPsp; // PSP id
  33. } PSP_FFINDLIST, *PPSP_FFINDLIST;
  34. typedef struct _FFINDDOSDATA {
  35. ULONG FileIndex;
  36. ULONG FileNameLength;
  37. WCHAR FileName[MAXIMUM_FILENAME_LENGTH + 1];
  38. FILETIME ftLastWriteTime;
  39. DWORD dwFileSizeLow;
  40. UCHAR uchFileAttributes;
  41. CHAR cFileName[14];
  42. } FFINDDOSDATA, *PFFINDDOSDATA;
  43. typedef struct _FILEFINDLIST {
  44. LIST_ENTRY FFindEntry;
  45. ULONG FFindId;
  46. NTSTATUS LastQueryStatus;
  47. LARGE_INTEGER FindFileTics;
  48. HANDLE DirectoryHandle;
  49. PVOID FindBufferBase;
  50. PVOID FindBufferNext;
  51. ULONG FindBufferLength;
  52. FFINDDOSDATA DosData;
  53. USHORT usSrchAttr;
  54. BOOLEAN SupportReset;
  55. UNICODE_STRING PathName;
  56. UNICODE_STRING FileName;
  57. BOOL SearchOnCD;
  58. }FFINDLIST, *PFFINDLIST;
  59. LIST_ENTRY PspFFindHeadList= {&PspFFindHeadList, &PspFFindHeadList};
  60. #define FFINDID_BASE 0x80000000
  61. ULONG NextFFindId = FFINDID_BASE;
  62. BOOLEAN FFindIdWrap = FALSE;
  63. #define MAX_DIRECTORYHANDLE 64
  64. #define MAX_FINDBUFFER 128
  65. ULONG NumDirectoryHandle = 0;
  66. ULONG NumFindBuffer=0;
  67. LARGE_INTEGER FindFileTics = {0,0};
  68. LARGE_INTEGER NextFindFileTics = {0,0};
  69. char szStartDotStar[]="????????.???";
  70. PFFINDLIST
  71. SearchFile(
  72. PWCHAR pwcFile,
  73. USHORT SearchAttr,
  74. PFFINDLIST pFFindEntry,
  75. PFFINDDOSDATA pFFindDDOut
  76. );
  77. NTSTATUS
  78. FileFindNext(
  79. PFFINDDOSDATA pFFindDD,
  80. PFFINDLIST pFFindEntry
  81. );
  82. NTSTATUS
  83. FileFindLast(
  84. PFFINDLIST pFFindEntry
  85. );
  86. VOID
  87. FileFindClose(
  88. PFFINDLIST pFFindEntry
  89. );
  90. NTSTATUS
  91. FileFindOpen(
  92. PWCHAR pwcFile,
  93. PFFINDLIST pFFindEntry,
  94. ULONG BufferSize
  95. );
  96. NTSTATUS
  97. FileFindReset(
  98. PFFINDLIST pFFindEntry
  99. );
  100. HANDLE
  101. FileFindFirstDevice(
  102. PWCHAR FileName,
  103. PFILE_BOTH_DIR_INFORMATION DirectoryInfo
  104. );
  105. void
  106. CloseOldestFileFindBuffer(
  107. void
  108. );
  109. BOOL
  110. CopyDirInfoToDosData(
  111. PFFINDDOSDATA pFFindDD,
  112. PFILE_BOTH_DIR_INFORMATION DirectoryInfo,
  113. USHORT SearchAttr
  114. );
  115. BOOL
  116. DemOemToUni(
  117. PUNICODE_STRING pUnicode,
  118. LPSTR lpstr
  119. );
  120. VOID
  121. FillFcbVolume(
  122. PSRCHBUF pSrchBuf,
  123. CHAR *pFileName,
  124. USHORT SearchAttr
  125. );
  126. BOOL
  127. FillDtaVolume(
  128. CHAR *pFileName,
  129. PSRCHDTA pDta,
  130. USHORT SearchAttr
  131. );
  132. BOOL
  133. MatchVolLabel(
  134. CHAR * pVolLabel,
  135. CHAR * pBaseName
  136. );
  137. VOID
  138. NtVolumeNameToDosVolumeName(
  139. CHAR * pDosName,
  140. CHAR * pNtName
  141. );
  142. VOID
  143. FillFCBSrchBuf(
  144. PFFINDDOSDATA pFFindDD,
  145. PSRCHBUF pSrchBuf,
  146. BOOL IsOnCD
  147. );
  148. VOID
  149. FillSrchDta(
  150. PFFINDDOSDATA pFFindDD,
  151. PSRCHDTA pDta,
  152. BOOL IsOnCD
  153. );
  154. PFFINDLIST
  155. AddFFindEntry(
  156. PWCHAR pwcFile,
  157. PFFINDLIST pFFindEntrySrc
  158. );
  159. PPSP_FFINDLIST
  160. GetPspFFindList(
  161. USHORT CurrPsp
  162. );
  163. PFFINDLIST
  164. GetFFindEntryByFindId(
  165. ULONG NextFFindId
  166. );
  167. VOID
  168. FreeFFindEntry(
  169. PFFINDLIST pFFindEntry
  170. );
  171. VOID
  172. FreeFFindList(
  173. PLIST_ENTRY pFFindHeadList
  174. );
  175. /* demFindFirst - Path-Style Find First File
  176. *
  177. * Entry - Client (DS:DX) - File Path with wildcard
  178. * Client (CX) - Search Attributes
  179. *
  180. * Exit - Success
  181. * Client (CF) = 0
  182. * DTA updated
  183. *
  184. * Failure
  185. * Client (CF) = 1
  186. * Client (AX) = Error Code
  187. *
  188. * NOTES
  189. * Search Rules: Ignore Read_only and Archive bits.
  190. * If CX == ATTR_NORMAL Search only for normal files
  191. * If CX == ATTR_HIDDEN Search Hidden or normal files
  192. * If CX == ATTR_SYSTEM Search System or normal files
  193. * If CX == ATTR_DIRECTORY Search directory or normal files
  194. * If CX == ATTR_VOLUME_ID Search Volume_ID
  195. * if CX == -1 return everytiing you find
  196. *
  197. * Limitations - 21-Sep-1992 Jonle
  198. * cannot return label from a UNC name,just like dos.
  199. * Apps which keep many find handles open can cause
  200. * serious trouble, we must rewrite so that we can
  201. * close the handles
  202. *
  203. */
  204. VOID demFindFirst (VOID)
  205. {
  206. DWORD dwRet;
  207. PVOID pDta;
  208. #ifdef DBCS /* demFindFirst() for CSNW */
  209. CHAR achPath[MAX_PATH];
  210. #endif /* DBCS */
  211. LPSTR lpFile = (LPSTR) GetVDMAddr (getDS(),getDX());
  212. pDta = (PVOID) GetVDMAddr (*((PUSHORT)pulDTALocation + 1),
  213. *((PUSHORT)pulDTALocation));
  214. #ifdef DBCS /* demFindFirst() for CSNW */
  215. /*
  216. * convert Netware path to Dos path
  217. */
  218. ConvNwPathToDosPath(achPath,lpFile, sizeof(achPath));
  219. lpFile = achPath;
  220. #endif /* DBCS */
  221. dwRet = demFileFindFirst (pDta, lpFile, getCX());
  222. if (dwRet == -1) {
  223. dwRet = GetLastError();
  224. demClientError(INVALID_HANDLE_VALUE, *lpFile);
  225. return;
  226. }
  227. if (dwRet != 0) {
  228. setAX((USHORT) dwRet);
  229. setCF (1);
  230. } else {
  231. setCF (0);
  232. }
  233. return;
  234. }
  235. DWORD demFileFindFirst (
  236. PVOID pvDTA,
  237. LPSTR lpFile,
  238. USHORT SearchAttr)
  239. {
  240. PSRCHDTA pDta = (PSRCHDTA)pvDTA;
  241. PFFINDLIST pFFindEntry;
  242. FFINDDOSDATA FFindDD;
  243. UNICODE_STRING FileUni;
  244. WCHAR wcFile[MAX_PATH + sizeof(WCHAR)];
  245. BOOL IsOnCD;
  246. #if DBG
  247. if (SIZEOF_DOSSRCHDTA != sizeof(SRCHDTA)) {
  248. sprintf(demDebugBuffer,
  249. "demsrch: FFirst SIZEOF_DOSSRCHDTA %ld != sizeof(SRCHDTA) %ld\n",
  250. SIZEOF_DOSSRCHDTA,
  251. sizeof(SRCHDTA));
  252. OutputDebugStringOem(demDebugBuffer);
  253. }
  254. if (fShowSVCMsg & DEMFILIO){
  255. sprintf(demDebugBuffer,"demsrch: FindFirst<%s>\n", lpFile);
  256. OutputDebugStringOem(demDebugBuffer);
  257. }
  258. #endif
  259. STOREDWORD(pDta->FFindId,0);
  260. STOREDWORD(pDta->pFFindEntry,0);
  261. FileUni.Buffer = wcFile;
  262. FileUni.MaximumLength = sizeof(wcFile);
  263. DemOemToUni(&FileUni, lpFile);
  264. IsOnCD = IsCdRomFile(lpFile);
  265. //
  266. // Do volume label first.
  267. //
  268. if (SearchAttr & ATTR_VOLUME_ID) {
  269. if (FillDtaVolume(lpFile, pDta, SearchAttr)) {
  270. // got vol label match
  271. // do look ahead before returning
  272. if (SearchAttr != ATTR_VOLUME_ID) {
  273. pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, NULL);
  274. if (pFFindEntry) {
  275. pFFindEntry->SearchOnCD = IsOnCD;
  276. STOREDWORD(pDta->pFFindEntry,pFFindEntry);
  277. STOREDWORD(pDta->FFindId,pFFindEntry->FFindId);
  278. }
  279. }
  280. return 0;
  281. }
  282. // no vol match, if asking for more than vol label
  283. // fall thru to file search code, otherwise ret error
  284. else if (SearchAttr == ATTR_VOLUME_ID) {
  285. return GetLastError();
  286. }
  287. }
  288. //
  289. // Search the dir
  290. //
  291. pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, &FFindDD);
  292. if (!FFindDD.cFileName[0]) {
  293. // search.asm in doskrnl never returns ERROR_FILE_NOT_FOUND
  294. // only ERROR_PATH_NOT_FOUND, ERROR_NO_MORE_FILES
  295. DWORD dw;
  296. dw = GetLastError();
  297. if (dw == ERROR_FILE_NOT_FOUND) {
  298. SetLastError(ERROR_NO_MORE_FILES);
  299. }
  300. else if (dw == ERROR_BAD_PATHNAME || dw == ERROR_DIRECTORY ) {
  301. SetLastError(ERROR_PATH_NOT_FOUND);
  302. }
  303. return (DWORD)-1;
  304. }
  305. FillSrchDta(&FFindDD, pDta, IsOnCD);
  306. if (pFFindEntry) {
  307. pFFindEntry->SearchOnCD = IsOnCD;
  308. STOREDWORD(pDta->pFFindEntry,pFFindEntry);
  309. STOREDWORD(pDta->FFindId,pFFindEntry->FFindId);
  310. }
  311. return 0;
  312. }
  313. /*
  314. * DemOemToUni
  315. *
  316. * returns TRUE\FALSE for success, sets last error if fail
  317. *
  318. */
  319. BOOL DemOemToUni(PUNICODE_STRING pUnicode, LPSTR lpstr)
  320. {
  321. NTSTATUS Status;
  322. OEM_STRING OemString;
  323. RtlInitString(&OemString,lpstr);
  324. Status = RtlOemStringToUnicodeString(pUnicode,&OemString,FALSE);
  325. if (!NT_SUCCESS(Status)) {
  326. if (Status == STATUS_BUFFER_OVERFLOW) {
  327. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  328. }
  329. else {
  330. SetLastError(RtlNtStatusToDosError(Status));
  331. }
  332. return FALSE;
  333. }
  334. *(PWCHAR)((PUCHAR)pUnicode->Buffer + pUnicode->Length) = UNICODE_NULL;
  335. return TRUE;
  336. }
  337. /* demFindNext - Path-Style Find Next File
  338. *
  339. * Entry - None
  340. *
  341. * Exit - Success
  342. * Client (CF) = 0
  343. * DTA updated
  344. *
  345. * Failure
  346. * Client (CF) = 1
  347. * Client (AX) = Error Code
  348. */
  349. VOID demFindNext (VOID)
  350. {
  351. DWORD dwRet;
  352. PVOID pDta;
  353. pDta = (PVOID) GetVDMAddr(*((PUSHORT)pulDTALocation + 1),
  354. *((PUSHORT)pulDTALocation));
  355. dwRet = demFileFindNext (pDta);
  356. if (dwRet != 0) {
  357. setAX((USHORT) dwRet);
  358. setCF (1);
  359. return;
  360. }
  361. setCF (0);
  362. return;
  363. }
  364. DWORD demFileFindNext (
  365. PVOID pvDta)
  366. {
  367. PSRCHDTA pDta = (PSRCHDTA)pvDta;
  368. USHORT SearchAttr;
  369. PFFINDLIST pFFindEntry;
  370. FFINDDOSDATA FFindDD;
  371. BOOL IsOnCD;
  372. pFFindEntry = GetFFindEntryByFindId(FETCHDWORD(pDta->FFindId));
  373. if (!pFFindEntry ||
  374. FETCHDWORD(pDta->pFFindEntry) != (DWORD)pFFindEntry )
  375. {
  376. STOREDWORD(pDta->FFindId,0);
  377. STOREDWORD(pDta->pFFindEntry,0);
  378. // DOS has only one error (no_more_files) for all causes.
  379. return(ERROR_NO_MORE_FILES);
  380. }
  381. #if DBG
  382. if (fShowSVCMsg & DEMFILIO) {
  383. sprintf(demDebugBuffer, "demFileFindNext<%ws>\n", pFFindEntry->PathName.Buffer);
  384. OutputDebugStringOem(demDebugBuffer);
  385. }
  386. #endif
  387. SearchAttr = pFFindEntry->usSrchAttr;
  388. IsOnCD = pFFindEntry->SearchOnCD;
  389. //
  390. // Search the dir
  391. //
  392. pFFindEntry = SearchFile(NULL,
  393. SearchAttr,
  394. pFFindEntry,
  395. &FFindDD
  396. );
  397. if (!FFindDD.cFileName[0]) {
  398. STOREDWORD(pDta->FFindId,0);
  399. STOREDWORD(pDta->pFFindEntry,0);
  400. return GetLastError();
  401. }
  402. FillSrchDta(&FFindDD, pDta, IsOnCD);
  403. if (!pFFindEntry) {
  404. STOREDWORD(pDta->FFindId,0);
  405. STOREDWORD(pDta->pFFindEntry,0);
  406. }
  407. return 0;
  408. }
  409. /* demFindFirstFCB - FCB based Find First file
  410. *
  411. * Entry - Client (DS:SI) - SRCHBUF where the information will be returned
  412. * Client (ES:DI) - Full path file name with possibly wild cards
  413. * Client (Al) - 0 if not an extended FCB
  414. * Client (DL) - Search Attributes
  415. *
  416. * Exit - Success
  417. * Client (CF) = 0
  418. * SRCHBUF is filled in
  419. *
  420. * Failure
  421. * Client (AL) = -1
  422. *
  423. * NOTES
  424. * Search Rules: Ignore Read_only and Archive bits.
  425. * If DL == ATTR_NORMAL Search only for normal files
  426. * If DL == ATTR_HIDDEN Search Hidden or normal files
  427. * If DL == ATTR_SYSTEM Search System or normal files
  428. * If DL == ATTR_DIRECTORY Search directory or normal files
  429. * If DL == ATTR_VOLUME_ID Search only Volume_ID
  430. * if DL == -1 return everytiing you find
  431. */
  432. VOID demFindFirstFCB (VOID)
  433. {
  434. LPSTR lpFile;
  435. USHORT SearchAttr;
  436. PSRCHBUF pFCBSrchBuf;
  437. PDIRENT pDirEnt;
  438. PFFINDLIST pFFindEntry;
  439. FFINDDOSDATA FFindDD;
  440. UNICODE_STRING FileUni;
  441. WCHAR wcFile[MAX_PATH];
  442. BOOL IsOnCD;
  443. lpFile = (LPSTR) GetVDMAddr (getES(),getDI());
  444. #if DBG
  445. if (fShowSVCMsg & DEMFILIO) {
  446. sprintf(demDebugBuffer, "demFindFirstFCB<%s>\n", lpFile);
  447. OutputDebugStringOem(demDebugBuffer);
  448. }
  449. #endif
  450. pFCBSrchBuf = (PSRCHBUF) GetVDMAddr (getDS(),getSI());
  451. pDirEnt = &pFCBSrchBuf->DirEnt;
  452. STOREDWORD(pDirEnt->pFFindEntry,0);
  453. STOREDWORD(pDirEnt->FFindId,0);
  454. if (getDL() == ATTR_VOLUME_ID) {
  455. FillFcbVolume(pFCBSrchBuf,lpFile, ATTR_VOLUME_ID);
  456. return;
  457. }
  458. FileUni.Buffer = wcFile;
  459. FileUni.MaximumLength = sizeof(wcFile);
  460. if (!DemOemToUni(&FileUni ,lpFile)) {
  461. setCF(1);
  462. return;
  463. }
  464. SearchAttr = getAL() ? getDL() : 0;
  465. pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, &FFindDD);
  466. if (!FFindDD.cFileName[0]){
  467. demClientError(INVALID_HANDLE_VALUE, *lpFile);
  468. return;
  469. }
  470. IsOnCD = IsCdRomFile(lpFile);
  471. FillFCBSrchBuf(&FFindDD, pFCBSrchBuf, IsOnCD);
  472. if (pFFindEntry) {
  473. pFFindEntry->SearchOnCD = IsOnCD;
  474. STOREDWORD(pDirEnt->pFFindEntry,pFFindEntry);
  475. STOREDWORD(pDirEnt->FFindId,pFFindEntry->FFindId);
  476. }
  477. setCF(0);
  478. return;
  479. }
  480. /* demFindNextFCB - FCB based Find Next file
  481. *
  482. * Entry - Client (DS:SI) - SRCHBUF where the information will be returned
  483. * Client (Al) - 0 if not an extended FCB
  484. * Client (DL) - Search Attributes
  485. *
  486. * Exit - Success
  487. * Client (CF) = 0
  488. * SRCHBUF is filled in
  489. *
  490. * Failure
  491. * Client (AL) = -1
  492. *
  493. * NOTES
  494. * Search Rules: Ignore Read_only and Archive bits.
  495. * If DL == ATTR_NORMAL Search only for normal files
  496. * If DL == ATTR_HIDDEN Search Hidden or normal files
  497. * If DL == ATTR_SYSTEM Search System or normal files
  498. * If DL == ATTR_DIRECTORY Search directory or normal files
  499. * If DL == ATTR_VOLUME_ID Search only Volume_ID
  500. */
  501. VOID demFindNextFCB (VOID)
  502. {
  503. USHORT SearchAttr;
  504. PSRCHBUF pSrchBuf;
  505. PDIRENT pDirEnt;
  506. PFFINDLIST pFFindEntry;
  507. FFINDDOSDATA FFindDD;
  508. BOOL IsOnCD;
  509. pSrchBuf = (PSRCHBUF) GetVDMAddr (getDS(),getSI());
  510. pDirEnt = &pSrchBuf->DirEnt;
  511. pFFindEntry = GetFFindEntryByFindId(FETCHDWORD(pDirEnt->FFindId));
  512. if (!pFFindEntry ||
  513. FETCHDWORD(pDirEnt->pFFindEntry) != (DWORD)pFFindEntry ||
  514. getDL() == ATTR_VOLUME_ID )
  515. {
  516. if (pFFindEntry &&
  517. FETCHDWORD(pDirEnt->pFFindEntry) != (DWORD)pFFindEntry)
  518. {
  519. FreeFFindEntry(pFFindEntry);
  520. }
  521. STOREDWORD(pDirEnt->pFFindEntry,0);
  522. STOREDWORD(pDirEnt->FFindId,0);
  523. // DOS has only one error (no_more_files) for all causes.
  524. setAX(ERROR_NO_MORE_FILES);
  525. setCF(1);
  526. return;
  527. }
  528. #if DBG
  529. if (fShowSVCMsg & DEMFILIO) {
  530. sprintf(demDebugBuffer, "demFindNextFCB<%ws>\n", pFFindEntry->PathName.Buffer);
  531. OutputDebugStringOem(demDebugBuffer);
  532. }
  533. #endif
  534. SearchAttr = getAL() ? getDL() : 0;
  535. IsOnCD = pFFindEntry->SearchOnCD;
  536. //
  537. // Search the dir
  538. //
  539. pFFindEntry = SearchFile(NULL,
  540. SearchAttr,
  541. pFFindEntry,
  542. &FFindDD
  543. );
  544. if (!FFindDD.cFileName[0]) {
  545. STOREDWORD(pDirEnt->pFFindEntry,0);
  546. STOREDWORD(pDirEnt->FFindId,0);
  547. setAX((USHORT) GetLastError());
  548. setCF(1);
  549. return;
  550. }
  551. FillFCBSrchBuf(&FFindDD, pSrchBuf,IsOnCD);
  552. if (!pFFindEntry) {
  553. STOREDWORD(pDirEnt->FFindId,0);
  554. STOREDWORD(pDirEnt->pFFindEntry,0);
  555. }
  556. setCF(0);
  557. return;
  558. }
  559. /* demTerminatePDB - PDB Terminate Notification
  560. *
  561. * Entry - Client (BX) - Terminating PDB
  562. *
  563. * Exit - None
  564. *
  565. */
  566. VOID demTerminatePDB (VOID)
  567. {
  568. PPSP_FFINDLIST pPspFFindEntry;
  569. USHORT PSP;
  570. PSP = getBX ();
  571. if(!IsFirstCall) {
  572. nt_devices_block_or_terminate();
  573. VDDTerminateUserHook(PSP);
  574. }
  575. /* let host knows a process is terminating */
  576. HostTerminatePDB(PSP);
  577. pPspFFindEntry = GetPspFFindList(PSP);
  578. if (!pPspFFindEntry)
  579. return;
  580. if (!IsListEmpty(&pPspFFindEntry->FFindHeadList)) {
  581. FreeFFindList( &pPspFFindEntry->FFindHeadList);
  582. }
  583. RemoveEntryList(&pPspFFindEntry->PspFFindEntry);
  584. free(pPspFFindEntry);
  585. return;
  586. }
  587. /* SearchFile - Common routine for FIND_FRST and FIND_NEXT
  588. *
  589. * Entry -
  590. * PCHAR pwcFile file name to search for
  591. * USHORT SearchAttr file attributes to match
  592. * PFFINDLIST pFFindEntry, current list entry
  593. * if new search FFindId is expected to be zero
  594. * PFFINDDOSDATA pFFindDDOut, filled with the next file in search
  595. *
  596. * Exit - if no more files pFFindDDOut is filled with zeros
  597. * returns PFFINDLIST if buffered entries exist, else NULL
  598. */
  599. PFFINDLIST
  600. SearchFile(
  601. PWCHAR pwcFile,
  602. USHORT SearchAttr,
  603. PFFINDLIST pFFindEntry,
  604. PFFINDDOSDATA pFFindDDOut)
  605. {
  606. NTSTATUS Status;
  607. ULONG BufferSize;
  608. FFINDLIST FFindEntry;
  609. PFFINDLIST pFFEntry = NULL;
  610. SearchAttr &= ~(ATTR_READ_ONLY | ATTR_ARCHIVE | ATTR_DEVICE);
  611. Status = STATUS_NO_MORE_FILES;
  612. if (pFFindDDOut) {
  613. memset(pFFindDDOut, 0, sizeof(FFINDDOSDATA));
  614. }
  615. try {
  616. if (pFFindEntry) {
  617. pFFEntry = pFFindEntry;
  618. Status = pFFindEntry->LastQueryStatus;
  619. if (pFFindDDOut) {
  620. *pFFindDDOut = pFFEntry->DosData;
  621. pFFEntry->DosData.cFileName[0] = '\0';
  622. }
  623. else {
  624. return pFFEntry;
  625. }
  626. if (pFFEntry->FindBufferNext || pFFEntry->DirectoryHandle) {
  627. NTSTATUS st;
  628. st = FileFindNext(&pFFEntry->DosData,
  629. pFFEntry
  630. );
  631. if (NT_SUCCESS(st)) {
  632. return pFFEntry;
  633. }
  634. if (pFFEntry->DirectoryHandle) {
  635. Status = st;
  636. }
  637. }
  638. //
  639. // Check Last Known Status before retrying
  640. //
  641. if (!NT_SUCCESS(Status)) {
  642. return NULL;
  643. }
  644. //
  645. // Reopen the FileFind Handle with a large buffer size
  646. //
  647. Status = FileFindOpen(NULL,
  648. pFFEntry,
  649. 4096
  650. );
  651. if (!NT_SUCCESS(Status)) {
  652. return NULL;
  653. }
  654. //
  655. // reset the search to the last known search pos
  656. //
  657. Status = FileFindReset(pFFEntry);
  658. if (!NT_SUCCESS(Status)) {
  659. return NULL;
  660. }
  661. }
  662. else {
  663. pFFEntry = &FFindEntry;
  664. memset(pFFEntry, 0, sizeof(FFINDLIST));
  665. pFFEntry->SupportReset = TRUE;
  666. pFFEntry->usSrchAttr = SearchAttr;
  667. Status = FileFindOpen(pwcFile,
  668. pFFEntry,
  669. 1024
  670. );
  671. if (!NT_SUCCESS(Status)) {
  672. return NULL;
  673. }
  674. //
  675. // Fill up pFFindDDOut
  676. //
  677. if (pFFindDDOut) {
  678. Status = FileFindNext(pFFindDDOut, pFFEntry);
  679. if (!NT_SUCCESS(Status)) {
  680. return NULL;
  681. }
  682. }
  683. }
  684. //
  685. // Fill up pFFEntry->DosData
  686. //
  687. Status = FileFindNext(&pFFEntry->DosData, pFFEntry);
  688. if (!NT_SUCCESS(Status)) {
  689. return NULL;
  690. }
  691. //
  692. // if findfirst, fill in the static entries, and add the find entry
  693. //
  694. if (!pFFindEntry) {
  695. pFFEntry->FFindId = NextFFindId++;
  696. if (NextFFindId == 0xffffffff) {
  697. NextFFindId = FFINDID_BASE;
  698. FFindIdWrap = TRUE;
  699. }
  700. if (FFindIdWrap) {
  701. pFFindEntry = GetFFindEntryByFindId(NextFFindId);
  702. if (pFFindEntry) {
  703. FreeFFindEntry(pFFindEntry);
  704. pFFindEntry = NULL;
  705. }
  706. }
  707. pFFEntry = AddFFindEntry(pwcFile, pFFEntry);
  708. if (!pFFEntry) {
  709. pFFEntry = &FFindEntry;
  710. pFFEntry->DosData.cFileName[0] = '\0';
  711. Status = STATUS_NO_MEMORY;
  712. return NULL;
  713. }
  714. }
  715. //
  716. // Try to fill one more entry. If the NtQuery for this search
  717. // is complete we can set the LastQueryStatus, and close dir handles.
  718. //
  719. Status = FileFindLast(pFFEntry);
  720. }
  721. finally {
  722. if (pFFEntry) {
  723. pFFEntry->LastQueryStatus = Status;
  724. //
  725. // if nothing is buffered, cleanup look aheads
  726. //
  727. if (!pFFEntry->DosData.cFileName[0] ||
  728. pFFEntry->DirectoryHandle == FINDFILE_DEVICE)
  729. {
  730. if (pFFEntry == &FFindEntry) {
  731. FileFindClose(pFFEntry);
  732. RtlFreeUnicodeString(&pFFEntry->FileName);
  733. RtlFreeUnicodeString(&pFFEntry->PathName);
  734. }
  735. else {
  736. FreeFFindEntry(pFFEntry);
  737. }
  738. SetLastError(RtlNtStatusToDosError(Status));
  739. pFFEntry = NULL;
  740. }
  741. }
  742. if (pFFEntry) {
  743. if (pFFEntry->DirectoryHandle) {
  744. if (!pFFindEntry || !NT_SUCCESS(pFFEntry->LastQueryStatus)) {
  745. NumDirectoryHandle--;
  746. NtClose(pFFEntry->DirectoryHandle);
  747. pFFEntry->DirectoryHandle = 0;
  748. }
  749. }
  750. if (NumFindBuffer > MAX_FINDBUFFER ||
  751. NumDirectoryHandle > MAX_DIRECTORYHANDLE)
  752. {
  753. CloseOldestFileFindBuffer();
  754. }
  755. //
  756. // Set HeartBeat timer to close find buffers, directory handle
  757. // Tics = 8(min) * 60(sec/min) * 18(tic/sec)
  758. //
  759. pFFEntry->FindFileTics.QuadPart = 8640 + FindFileTics.QuadPart;
  760. if (!FindFileTics.QuadPart) {
  761. NextFindFileTics.QuadPart = pFFEntry->FindFileTics.QuadPart;
  762. }
  763. }
  764. }
  765. return pFFEntry;
  766. }
  767. NTSTATUS
  768. FileFindOpen(
  769. PWCHAR pwcFile,
  770. PFFINDLIST pFFindEntry,
  771. ULONG BufferSize
  772. )
  773. {
  774. NTSTATUS Status;
  775. BOOLEAN bStatus;
  776. BOOLEAN bReturnSingleEntry;
  777. PWCHAR pwc;
  778. OBJECT_ATTRIBUTES Obja;
  779. PUNICODE_STRING FileName;
  780. PUNICODE_STRING PathName;
  781. IO_STATUS_BLOCK IoStatusBlock;
  782. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  783. Status = STATUS_SUCCESS;
  784. PathName = &pFFindEntry->PathName;
  785. FileName = &pFFindEntry->FileName;
  786. try {
  787. if (pFFindEntry->DirectoryHandle == FINDFILE_DEVICE) {
  788. Status = STATUS_NO_MORE_FILES;
  789. goto FFOFinallyExit;
  790. }
  791. if (BufferSize <= sizeof(FILE_BOTH_DIR_INFORMATION) +
  792. MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR))
  793. {
  794. Status = STATUS_BUFFER_TOO_SMALL;
  795. goto FFOFinallyExit;
  796. }
  797. if (pwcFile) {
  798. bStatus = RtlDosPathNameToNtPathName_U(pwcFile,
  799. PathName,
  800. &pwc,
  801. NULL
  802. );
  803. if (!bStatus ) {
  804. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  805. goto FFOFinallyExit;
  806. }
  807. //
  808. // Copy out the PathName, FileName
  809. //
  810. if (pwc) {
  811. bStatus = RtlCreateUnicodeString(FileName,
  812. pwc
  813. );
  814. if (!bStatus) {
  815. Status = STATUS_NO_MEMORY;
  816. goto FFOFinallyExit;
  817. }
  818. PathName->Length = (USHORT)((ULONG)pwc - (ULONG)PathName->Buffer);
  819. if (PathName->Buffer[(PathName->Length>>1)-2] != (WCHAR)':' ) {
  820. PathName->Length -= sizeof(UNICODE_NULL);
  821. }
  822. }
  823. else {
  824. FileName->Length = 0;
  825. FileName->MaximumLength = 0;
  826. }
  827. bReturnSingleEntry = FALSE;
  828. }
  829. else {
  830. bReturnSingleEntry = pFFindEntry->SupportReset;
  831. }
  832. //
  833. // Prepare Find Buffer for NtQueryDirectory
  834. //
  835. if (BufferSize != pFFindEntry->FindBufferLength) {
  836. if (pFFindEntry->FindBufferBase) {
  837. RtlFreeHeap(RtlProcessHeap(), 0, pFFindEntry->FindBufferBase);
  838. }
  839. else {
  840. NumFindBuffer++;
  841. }
  842. pFFindEntry->FindBufferBase = RtlAllocateHeap(RtlProcessHeap(),
  843. 0,
  844. BufferSize
  845. );
  846. if (!pFFindEntry->FindBufferBase) {
  847. Status = STATUS_NO_MEMORY;
  848. goto FFOFinallyExit;
  849. }
  850. }
  851. pFFindEntry->FindBufferNext = NULL;
  852. pFFindEntry->FindBufferLength = BufferSize;
  853. DirectoryInfo = pFFindEntry->FindBufferBase;
  854. //
  855. // Open the directory for list access
  856. //
  857. if (!pFFindEntry->DirectoryHandle) {
  858. InitializeObjectAttributes(
  859. &Obja,
  860. PathName,
  861. OBJ_CASE_INSENSITIVE,
  862. NULL,
  863. NULL
  864. );
  865. Status = NtOpenFile(
  866. &pFFindEntry->DirectoryHandle,
  867. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  868. &Obja,
  869. &IoStatusBlock,
  870. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  871. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  872. );
  873. if (!NT_SUCCESS(Status)) {
  874. if (pwcFile) {
  875. pFFindEntry->DirectoryHandle = FileFindFirstDevice(pwcFile,
  876. DirectoryInfo
  877. );
  878. }
  879. else {
  880. pFFindEntry->DirectoryHandle = NULL;
  881. }
  882. if (pFFindEntry->DirectoryHandle) {
  883. Status = STATUS_SUCCESS;
  884. goto FFOFinallyExit;
  885. }
  886. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  887. Status == STATUS_OBJECT_TYPE_MISMATCH )
  888. {
  889. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  890. }
  891. goto FFOFinallyExit;
  892. }
  893. NumDirectoryHandle++;
  894. }
  895. //
  896. // Prepare the filename for NtQueryDirectory
  897. //
  898. if (pwcFile) {
  899. WCHAR wchCurr, wchPrev;
  900. int Len = FileName->Length/sizeof(WCHAR);
  901. //
  902. // If there is no file part, but we are not looking at a device exit
  903. //
  904. if (!Len) {
  905. //
  906. // At this point, pwcFile has been parsed to PathName and FileName. If PathName
  907. // does not exist, the NtOpen() above will have failed and we will not be here.
  908. // PathName is formatted to \??\c:\xxx\yyy\zzz
  909. // DOS had this "feature" that if you looked for something like c:\foobar\, you'd
  910. // get PATH_NOT_FOUND, but if you looked for c:\ or \ you'd get NO_MORE_FILES,
  911. // so we special case this here. If the caller is only looking for c:\ or \
  912. // PathName will be \??\c:\ If the caller is looking for ANY other string,
  913. // the PathName string will be longer than strlen("\??\c:\") because the text of
  914. // any dir will be added to the end. That's why a simple check of the string len
  915. // works at this time.
  916. //
  917. if ( PathName->Length > (sizeof( L"\\??\\c:\\")-sizeof(WCHAR)) ) {
  918. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  919. }
  920. else {
  921. Status = STATUS_NO_MORE_FILES;
  922. }
  923. goto FFOFinallyExit;
  924. }
  925. //
  926. // ntio expects the following transmogrifications:
  927. //
  928. // - Change all ? to DOS_QM
  929. // - Change all . followed by ? or * to DOS_DOT
  930. // - Change all * followed by a . into DOS_STAR
  931. //
  932. // However, the doskrnl and wow32 have expanded '*'s to '?'s
  933. // so the * rules can be ignored.
  934. //
  935. pwc = FileName->Buffer;
  936. wchPrev = 0;
  937. while (Len--) {
  938. wchCurr = *pwc;
  939. if (wchCurr == L'?') {
  940. if (wchPrev == L'.') {
  941. *(pwc - 1) = DOS_DOT;
  942. }
  943. *pwc = DOS_QM;
  944. }
  945. wchPrev = wchCurr;
  946. pwc++;
  947. }
  948. }
  949. #if DBG
  950. if (fShowSVCMsg & DEMFILIO) {
  951. sprintf(demDebugBuffer,
  952. "FFOpen %x %ws (%ws)\n",
  953. pFFindEntry->DirectoryHandle,
  954. FileName->Buffer,
  955. pwcFile
  956. );
  957. OutputDebugStringOem(demDebugBuffer);
  958. }
  959. #endif
  960. //
  961. // Do an initial query to fill the buffers, and verify everything is ok
  962. //
  963. Status = DPM_NtQueryDirectoryFile(
  964. pFFindEntry->DirectoryHandle,
  965. NULL,
  966. NULL,
  967. NULL,
  968. &IoStatusBlock,
  969. DirectoryInfo,
  970. BufferSize,
  971. FileBothDirectoryInformation,
  972. bReturnSingleEntry,
  973. FileName,
  974. FALSE
  975. );
  976. FFOFinallyExit:;
  977. }
  978. finally {
  979. if (!NT_SUCCESS(Status)) {
  980. #if DBG
  981. if ((fShowSVCMsg & DEMFILIO) && !NT_SUCCESS(Status)) {
  982. sprintf(demDebugBuffer, "FFOpen Status %x\n", Status);
  983. OutputDebugStringOem(demDebugBuffer);
  984. }
  985. #endif
  986. FileFindClose(pFFindEntry);
  987. RtlFreeUnicodeString(PathName);
  988. PathName->Buffer = NULL;
  989. RtlFreeUnicodeString(FileName);
  990. FileName->Buffer = NULL;
  991. }
  992. else {
  993. pFFindEntry->FindBufferNext = pFFindEntry->FindBufferBase;
  994. }
  995. }
  996. return Status;
  997. }
  998. /*
  999. * Closes a FileFindHandle
  1000. */
  1001. VOID
  1002. FileFindClose(
  1003. PFFINDLIST pFFindEntry
  1004. )
  1005. {
  1006. NTSTATUS Status;
  1007. HANDLE DirectoryHandle;
  1008. DirectoryHandle = pFFindEntry->DirectoryHandle;
  1009. if (DirectoryHandle &&
  1010. DirectoryHandle != FINDFILE_DEVICE)
  1011. {
  1012. NtClose(DirectoryHandle);
  1013. --NumDirectoryHandle;
  1014. }
  1015. pFFindEntry->DirectoryHandle = 0;
  1016. if (pFFindEntry->FindBufferBase) {
  1017. RtlFreeHeap(RtlProcessHeap(), 0, pFFindEntry->FindBufferBase);
  1018. --NumFindBuffer;
  1019. }
  1020. pFFindEntry->FindBufferBase = NULL;
  1021. pFFindEntry->FindBufferNext = NULL;
  1022. pFFindEntry->FindBufferLength = 0;
  1023. pFFindEntry->FindFileTics.QuadPart = 0;
  1024. if (!NumDirectoryHandle && !NumFindBuffer) {
  1025. FindFileTics.QuadPart = 0;
  1026. NextFindFileTics.QuadPart = 0;
  1027. }
  1028. }
  1029. /*
  1030. * FileFindReset
  1031. *
  1032. * Resets search pos according to FileName, FileIndex.
  1033. * The FindBuffers will point to the next file in the search
  1034. * order. Assumes that the remembered search pos, has not been
  1035. * reached yet for the current search.
  1036. *
  1037. */
  1038. NTSTATUS
  1039. FileFindReset(
  1040. PFFINDLIST pFFindEntry
  1041. )
  1042. {
  1043. NTSTATUS Status;
  1044. IO_STATUS_BLOCK IoStatusBlock;
  1045. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  1046. UNICODE_STRING LastFileName;
  1047. UNICODE_STRING CurrFileName;
  1048. BOOLEAN bSlowReset;
  1049. if (pFFindEntry->DirectoryHandle == FINDFILE_DEVICE) {
  1050. return STATUS_NO_MORE_FILES;
  1051. }
  1052. Status = STATUS_UNSUCCESSFUL;
  1053. LastFileName.Length = (USHORT)pFFindEntry->DosData.FileNameLength;
  1054. LastFileName.MaximumLength = (USHORT)pFFindEntry->DosData.FileNameLength;
  1055. LastFileName.Buffer = pFFindEntry->DosData.FileName;
  1056. RtlInitUnicodeString(&CurrFileName, L".");
  1057. if (!RtlCompareUnicodeString(&LastFileName, &CurrFileName, TRUE)) {
  1058. bSlowReset = TRUE;
  1059. }
  1060. else {
  1061. RtlInitUnicodeString(&CurrFileName, L"..");
  1062. if (!RtlCompareUnicodeString(&LastFileName, &CurrFileName, TRUE)) {
  1063. bSlowReset = TRUE;
  1064. }
  1065. else {
  1066. bSlowReset = FALSE;
  1067. }
  1068. }
  1069. //
  1070. // if the last file name, wasn't Dots and the volume supports reset
  1071. // functionality call nt file sysetm to do the reset.
  1072. //
  1073. if (!bSlowReset && pFFindEntry->SupportReset) {
  1074. VDMQUERYDIRINFO VdmQueryDirInfo;
  1075. UNICODE_STRING UnicodeString;
  1076. DirectoryInfo = (PFILE_BOTH_DIR_INFORMATION) pFFindEntry->FindBufferBase;
  1077. VdmQueryDirInfo.FileHandle = pFFindEntry->DirectoryHandle;
  1078. VdmQueryDirInfo.FileInformation = DirectoryInfo;
  1079. VdmQueryDirInfo.Length = pFFindEntry->FindBufferLength;
  1080. VdmQueryDirInfo.FileIndex = pFFindEntry->DosData.FileIndex;
  1081. UnicodeString.Length = (USHORT)pFFindEntry->DosData.FileNameLength;
  1082. UnicodeString.MaximumLength = UnicodeString.Length;
  1083. UnicodeString.Buffer = pFFindEntry->DosData.FileName;
  1084. VdmQueryDirInfo.FileName = &UnicodeString;
  1085. Status = DPM_NtVdmControl(VdmQueryDir, &VdmQueryDirInfo);
  1086. if (NT_SUCCESS(Status) ||
  1087. Status == STATUS_NO_MORE_FILES || Status == STATUS_NO_SUCH_FILE)
  1088. {
  1089. return Status;
  1090. }
  1091. pFFindEntry->SupportReset = FALSE;
  1092. }
  1093. //
  1094. // Reset the slow way by comparing FileName directly.
  1095. //
  1096. // WARNING: if the "remembered" File has been deleted we will
  1097. // fail, is there something else we can do ?
  1098. //
  1099. Status = STATUS_NO_MORE_FILES;
  1100. while (TRUE) {
  1101. //
  1102. // If there is no data in the find file buffer, call NtQueryDir
  1103. //
  1104. DirectoryInfo = pFFindEntry->FindBufferNext;
  1105. if (!DirectoryInfo) {
  1106. DirectoryInfo = pFFindEntry->FindBufferBase;
  1107. Status = DPM_NtQueryDirectoryFile(
  1108. pFFindEntry->DirectoryHandle,
  1109. NULL, // no event
  1110. NULL, // no apcRoutine
  1111. NULL, // no apcContext
  1112. &IoStatusBlock,
  1113. DirectoryInfo,
  1114. pFFindEntry->FindBufferLength,
  1115. FileBothDirectoryInformation,
  1116. FALSE, // single entry
  1117. NULL, // no file name
  1118. FALSE
  1119. );
  1120. if (!NT_SUCCESS(Status)) {
  1121. #if DBG
  1122. if (fShowSVCMsg & DEMFILIO) {
  1123. sprintf(demDebugBuffer, "FFReset Status %x\n", Status);
  1124. OutputDebugStringOem(demDebugBuffer);
  1125. }
  1126. #endif
  1127. return Status;
  1128. }
  1129. }
  1130. if ( DirectoryInfo->NextEntryOffset ) {
  1131. pFFindEntry->FindBufferNext = (PVOID)((ULONG)DirectoryInfo +
  1132. DirectoryInfo->NextEntryOffset);
  1133. }
  1134. else {
  1135. pFFindEntry->FindBufferNext = NULL;
  1136. }
  1137. if (DirectoryInfo->FileIndex == pFFindEntry->DosData.FileIndex) {
  1138. CurrFileName.Length = (USHORT)DirectoryInfo->FileNameLength;
  1139. CurrFileName.MaximumLength = (USHORT)DirectoryInfo->FileNameLength;
  1140. CurrFileName.Buffer = DirectoryInfo->FileName;
  1141. if (!RtlCompareUnicodeString(&LastFileName, &CurrFileName, TRUE)) {
  1142. return STATUS_SUCCESS;
  1143. }
  1144. }
  1145. }
  1146. return Status;
  1147. }
  1148. /*
  1149. * FileFindLast - Attempts to fill the FindFile buffer completely.
  1150. *
  1151. *
  1152. * PFFINDLIST pFFindEntry -
  1153. *
  1154. * Returns - Status of NtQueryDir operation if invoked, otherwise
  1155. * STATUS_SUCCESS.
  1156. *
  1157. */
  1158. NTSTATUS
  1159. FileFindLast(
  1160. PFFINDLIST pFFindEntry
  1161. )
  1162. {
  1163. NTSTATUS Status;
  1164. IO_STATUS_BLOCK IoStatusBlock;
  1165. PFILE_BOTH_DIR_INFORMATION DirInfo, LastDirInfo;
  1166. LONG BytesLeft;
  1167. if (pFFindEntry->DirectoryHandle == FINDFILE_DEVICE) {
  1168. return STATUS_NO_MORE_FILES;
  1169. }
  1170. if (pFFindEntry->FindBufferNext) {
  1171. ULONG BytesOffset;
  1172. BytesOffset = (ULONG)pFFindEntry->FindBufferNext -
  1173. (ULONG)pFFindEntry->FindBufferBase;
  1174. if (BytesOffset) {
  1175. RtlMoveMemory(pFFindEntry->FindBufferBase,
  1176. pFFindEntry->FindBufferNext,
  1177. pFFindEntry->FindBufferLength - BytesOffset
  1178. );
  1179. }
  1180. pFFindEntry->FindBufferNext = pFFindEntry->FindBufferBase;
  1181. DirInfo = pFFindEntry->FindBufferBase;
  1182. while (DirInfo->NextEntryOffset) {
  1183. DirInfo = (PVOID)((ULONG)DirInfo + DirInfo->NextEntryOffset);
  1184. }
  1185. LastDirInfo = DirInfo;
  1186. DirInfo = (PVOID)&DirInfo->FileName[DirInfo->FileNameLength>>1];
  1187. DirInfo = (PVOID) (((ULONG) DirInfo + sizeof(LONGLONG) - 1) &
  1188. ~(sizeof(LONGLONG) - 1));
  1189. BytesLeft = pFFindEntry->FindBufferLength -
  1190. ((ULONG)DirInfo - (ULONG)pFFindEntry->FindBufferBase);
  1191. }
  1192. else {
  1193. DirInfo = pFFindEntry->FindBufferBase;
  1194. LastDirInfo = NULL;
  1195. BytesLeft = pFFindEntry->FindBufferLength;
  1196. }
  1197. // the size of the dirinfo structure including the name must be a longlong.
  1198. while (BytesLeft > sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(LONGLONG) + MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)) {
  1199. Status = DPM_NtQueryDirectoryFile(
  1200. pFFindEntry->DirectoryHandle,
  1201. NULL, // no event
  1202. NULL, // no apcRoutine
  1203. NULL, // no apcContext
  1204. &IoStatusBlock,
  1205. DirInfo,
  1206. BytesLeft,
  1207. FileBothDirectoryInformation,
  1208. FALSE, // single entry ?
  1209. NULL, // no file name
  1210. FALSE
  1211. );
  1212. if (Status == STATUS_NO_MORE_FILES || Status == STATUS_NO_SUCH_FILE) {
  1213. #if DBG
  1214. if ((fShowSVCMsg & DEMFILIO)) {
  1215. sprintf(demDebugBuffer, "FFLast Status %x\n", Status);
  1216. OutputDebugStringOem(demDebugBuffer);
  1217. }
  1218. #endif
  1219. return Status;
  1220. }
  1221. if (!NT_SUCCESS(Status)) {
  1222. break;
  1223. }
  1224. if (LastDirInfo) {
  1225. LastDirInfo->NextEntryOffset =(ULONG)DirInfo - (ULONG)LastDirInfo;
  1226. }
  1227. else {
  1228. pFFindEntry->FindBufferNext = pFFindEntry->FindBufferBase;
  1229. }
  1230. while (DirInfo->NextEntryOffset) {
  1231. DirInfo = (PVOID)((ULONG)DirInfo + DirInfo->NextEntryOffset);
  1232. }
  1233. LastDirInfo = DirInfo;
  1234. DirInfo = (PVOID)&DirInfo->FileName[DirInfo->FileNameLength>>1];
  1235. DirInfo = (PVOID) (((ULONG) DirInfo + sizeof(LONGLONG) - 1) &
  1236. ~(sizeof(LONGLONG) - 1));
  1237. BytesLeft = pFFindEntry->FindBufferLength -
  1238. ((ULONG)DirInfo - (ULONG)pFFindEntry->FindBufferBase);
  1239. }
  1240. return STATUS_SUCCESS;
  1241. }
  1242. /*
  1243. * FileFindNext - retrieves the next file in the current search order,
  1244. *
  1245. * PFFINDDOSDATA pFFindDD
  1246. * Receives File info returned by the nt FileSystem
  1247. *
  1248. * PFFINDLIST pFFindEntry -
  1249. * Contains the DirectoryInfo (FileName,FileIndex) necessary to reset a
  1250. * search pos. For operations other than QDIR_RESET_SCAN, this is ignored.
  1251. *
  1252. * Returns -
  1253. * If Got a DirectoryInformation Entry, STATUS_SUCCESS
  1254. * If no Open Directory handle and is unknown if there are more files
  1255. * returns STATUS_IN`VALID_HANDLE
  1256. *
  1257. */
  1258. NTSTATUS
  1259. FileFindNext(
  1260. PFFINDDOSDATA pFFindDD,
  1261. PFFINDLIST pFFindEntry
  1262. )
  1263. {
  1264. NTSTATUS Status;
  1265. IO_STATUS_BLOCK IoStatusBlock;
  1266. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  1267. if (pFFindEntry->DirectoryHandle == FINDFILE_DEVICE) {
  1268. return STATUS_NO_MORE_FILES;
  1269. }
  1270. Status = STATUS_UNSUCCESSFUL;
  1271. do {
  1272. //
  1273. // If there is no data in the find file buffer, call NtQueryDir
  1274. //
  1275. DirectoryInfo = pFFindEntry->FindBufferNext;
  1276. if (!DirectoryInfo) {
  1277. if (!pFFindEntry->DirectoryHandle) {
  1278. return STATUS_INVALID_HANDLE;
  1279. }
  1280. DirectoryInfo = pFFindEntry->FindBufferBase;
  1281. Status = DPM_NtQueryDirectoryFile(
  1282. pFFindEntry->DirectoryHandle,
  1283. NULL, // no event
  1284. NULL, // no apcRoutine
  1285. NULL, // no apcContext
  1286. &IoStatusBlock,
  1287. DirectoryInfo,
  1288. pFFindEntry->FindBufferLength,
  1289. FileBothDirectoryInformation,
  1290. FALSE, // single entry ?
  1291. NULL, // no file name
  1292. FALSE
  1293. );
  1294. if (!NT_SUCCESS(Status)) {
  1295. #if DBG
  1296. if (fShowSVCMsg & DEMFILIO) {
  1297. sprintf(demDebugBuffer, "FFNext Status %x\n", Status);
  1298. OutputDebugStringOem(demDebugBuffer);
  1299. }
  1300. #endif
  1301. return Status;
  1302. }
  1303. }
  1304. if ( DirectoryInfo->NextEntryOffset ) {
  1305. pFFindEntry->FindBufferNext = (PVOID)((ULONG)DirectoryInfo +
  1306. DirectoryInfo->NextEntryOffset);
  1307. }
  1308. else {
  1309. pFFindEntry->FindBufferNext = NULL;
  1310. }
  1311. } while (!CopyDirInfoToDosData(pFFindDD,
  1312. DirectoryInfo,
  1313. pFFindEntry->usSrchAttr
  1314. ));
  1315. return STATUS_SUCCESS;
  1316. }
  1317. /*
  1318. * CopyDirInfoToDosData
  1319. *
  1320. */
  1321. BOOL
  1322. CopyDirInfoToDosData(
  1323. PFFINDDOSDATA pFFindDD,
  1324. PFILE_BOTH_DIR_INFORMATION DirInfo,
  1325. USHORT SearchAttr
  1326. )
  1327. {
  1328. NTSTATUS Status;
  1329. OEM_STRING OemString;
  1330. UNICODE_STRING UnicodeString;
  1331. DWORD dwAttr;
  1332. BOOLEAN SpacesInName = FALSE;
  1333. BOOLEAN NameValid8Dot3;
  1334. //
  1335. // match the attributes
  1336. // See DOS5.0 sources (dir2.asm, MatchAttributes)
  1337. // ignores READONLY and ARCHIVE bits
  1338. //
  1339. if (FILE_ATTRIBUTE_NORMAL == DirInfo->FileAttributes) {
  1340. DirInfo->FileAttributes = 0;
  1341. }
  1342. else {
  1343. DirInfo->FileAttributes &= DOS_ATTR_MASK;
  1344. }
  1345. dwAttr = DirInfo->FileAttributes;
  1346. dwAttr &= ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY);
  1347. if (((~(ULONG)SearchAttr) & dwAttr) & ATTR_ALL)
  1348. return FALSE;
  1349. //
  1350. // set up the destination oem string buffer
  1351. //
  1352. OemString.Buffer = pFFindDD->cFileName;
  1353. OemString.MaximumLength = 14;
  1354. //
  1355. // see if the name is legal fat
  1356. //
  1357. UnicodeString.Buffer = DirInfo->FileName;
  1358. UnicodeString.Length = (USHORT)DirInfo->FileNameLength;
  1359. UnicodeString.MaximumLength = (USHORT)DirInfo->FileNameLength;
  1360. NameValid8Dot3 = RtlIsNameLegalDOS8Dot3( &UnicodeString,
  1361. &OemString,
  1362. &SpacesInName );
  1363. //
  1364. // if failed (incompatible codepage or illegal FAT name),
  1365. // use the short name
  1366. //
  1367. if (!NameValid8Dot3 ||
  1368. (SpacesInName && (DirInfo->ShortName[0] != UNICODE_NULL))) {
  1369. if (DirInfo->ShortName[0] == UNICODE_NULL) {
  1370. pFFindDD->cFileName[0] = '\0';
  1371. return FALSE;
  1372. }
  1373. UnicodeString.Buffer = DirInfo->ShortName;
  1374. UnicodeString.Length = (USHORT)DirInfo->ShortNameLength;
  1375. UnicodeString.MaximumLength = (USHORT)DirInfo->ShortNameLength;
  1376. if (!NT_SUCCESS(RtlUpcaseUnicodeStringToCountedOemString(&OemString, &UnicodeString, FALSE))) {
  1377. pFFindDD->cFileName[0] = '\0';
  1378. return FALSE;
  1379. }
  1380. }
  1381. OemString.Buffer[OemString.Length] = '\0';
  1382. // fill in time, size and attributes
  1383. //
  1384. // bjm-11/10/97 - for directories, FAT does not update lastwritten time
  1385. // when things actually happen in the directory. NTFS does. This causes
  1386. // a problem for Encore 3.0 (when running on NTFS) which, at install time,
  1387. // gets the lastwritten time for it's directory, then compares it, at app
  1388. // run time, to the "current" last written time and will bail (with a "Not
  1389. // correctly installed" message) if they're different. So, 16 bit apps
  1390. // (which can only reasonably expect FAT info), should only get creation
  1391. // time for this file if it's a directory.
  1392. //
  1393. // VadimB: 11/20/98 -- this hold true ONLY for apps running on NTFS and
  1394. // not FAT -- since older FAT partitions are then given an incorrect
  1395. // creation time
  1396. if (FILE_ATTRIBUTE_DIRECTORY & DirInfo->FileAttributes) {
  1397. pFFindDD->ftLastWriteTime = *(LPFILETIME)&DirInfo->CreationTime;
  1398. }
  1399. else {
  1400. pFFindDD->ftLastWriteTime = *(LPFILETIME)&DirInfo->LastWriteTime;
  1401. }
  1402. pFFindDD->dwFileSizeLow = DirInfo->EndOfFile.LowPart;
  1403. pFFindDD->uchFileAttributes = (UCHAR)DirInfo->FileAttributes;
  1404. // Save File Name, Index for restarting searches
  1405. pFFindDD->FileIndex = DirInfo->FileIndex;
  1406. pFFindDD->FileNameLength = DirInfo->FileNameLength;
  1407. RtlCopyMemory(pFFindDD->FileName,
  1408. DirInfo->FileName,
  1409. DirInfo->FileNameLength
  1410. );
  1411. pFFindDD->FileName[DirInfo->FileNameLength >> 1] = UNICODE_NULL;
  1412. return TRUE;
  1413. }
  1414. HANDLE
  1415. FileFindFirstDevice(
  1416. PWCHAR FileName,
  1417. PFILE_BOTH_DIR_INFORMATION DirectoryInfo
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. Determines if the FileName is a device, and copies out the
  1422. device name found if it is.
  1423. Arguments:
  1424. FileName - Supplies the device name of the file to find.
  1425. pQueryDirInfo - On a successful find, this parameter returns information
  1426. about the located file.
  1427. Return Value:
  1428. --*/
  1429. {
  1430. ULONG DeviceNameData;
  1431. PWSTR DeviceName;
  1432. DeviceNameData = RtlIsDosDeviceName_U(FileName);
  1433. if (DeviceNameData) {
  1434. RtlZeroMemory(DirectoryInfo, sizeof(FILE_BOTH_DIR_INFORMATION));
  1435. DirectoryInfo->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
  1436. DeviceName = (PWSTR)((ULONG)FileName + (DeviceNameData >> 16));
  1437. DeviceNameData &= 0xffff;
  1438. DirectoryInfo->FileNameLength = DeviceNameData;
  1439. DirectoryInfo->ShortNameLength = (CCHAR)DeviceNameData;
  1440. RtlCopyMemory(DirectoryInfo->FileName,
  1441. DeviceName,
  1442. DeviceNameData
  1443. );
  1444. RtlCopyMemory(DirectoryInfo->ShortName,
  1445. DeviceName,
  1446. DeviceNameData
  1447. );
  1448. return FINDFILE_DEVICE;
  1449. }
  1450. return NULL;
  1451. }
  1452. /* FillFcbVolume - fill Volume info in the FCB
  1453. *
  1454. * Entry - pSrchBuf FCB Search buffer to be filled in
  1455. * FileName File Name (interesting part is the drive letter)
  1456. *
  1457. * Exit - SUCCESS
  1458. * Client (CF) - 0
  1459. * pSrchBuf is filled with volume info
  1460. *
  1461. * FAILURE
  1462. * Client (CF) - 1
  1463. * Client (AX) = Error Code
  1464. */
  1465. VOID
  1466. FillFcbVolume(
  1467. PSRCHBUF pSrchBuf,
  1468. CHAR *pFileName,
  1469. USHORT SearchAttr
  1470. )
  1471. {
  1472. CHAR *pch;
  1473. PDIRENT pDirEnt = &pSrchBuf->DirEnt;
  1474. CHAR FullPathBuffer[MAX_PATH];
  1475. CHAR achBaseName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.', and null
  1476. CHAR achVolumeName[NT_VOLUME_NAME_SIZE];
  1477. //
  1478. // form a path without base name
  1479. // this makes sure only on root directory will get the
  1480. // volume label(the GetVolumeInformationOem will fail
  1481. // if the given path is not root directory)
  1482. //
  1483. strncpy(FullPathBuffer,pFileName,MAX_PATH);
  1484. FullPathBuffer[MAX_PATH-1] = 0;
  1485. pch = strrchr(FullPathBuffer, '\\');
  1486. if (pch) {
  1487. pch++;
  1488. // truncate to dos file name length (including period)
  1489. pch[DOS_VOLUME_NAME_SIZE + 1] = '\0';
  1490. strcpy(achBaseName, pch);
  1491. #ifdef DBCS
  1492. CharUpper(achBaseName);
  1493. #else // !DBCS
  1494. _strupr(achBaseName);
  1495. #endif // !DBCS
  1496. *pch = '\0';
  1497. }
  1498. else {
  1499. achBaseName[0] = '\0';
  1500. }
  1501. //
  1502. // if searching for volume only the DOS uses first 3 letters for
  1503. // root drive path ignoring the rest of the path
  1504. // as long as the full pathname is valid.
  1505. //
  1506. if (SearchAttr == ATTR_VOLUME_ID &&
  1507. (pch = strchr(FullPathBuffer, '\\')) &&
  1508. DPM_GetFileAttributes(FullPathBuffer) != 0xffffffff )
  1509. {
  1510. pch++;
  1511. *pch = '\0';
  1512. strcpy(achBaseName, szStartDotStar);
  1513. }
  1514. if (GetVolumeInformationOem(FullPathBuffer,
  1515. achVolumeName,
  1516. NT_VOLUME_NAME_SIZE,
  1517. NULL,
  1518. NULL,
  1519. NULL,
  1520. NULL,
  1521. 0) == FALSE)
  1522. {
  1523. demClientError(INVALID_HANDLE_VALUE, *pFileName);
  1524. return;
  1525. }
  1526. // truncate to dos volumen max size (no period)
  1527. achVolumeName[DOS_VOLUME_NAME_SIZE] = '\0';
  1528. if (!achVolumeName[0] || !MatchVolLabel(achVolumeName, achBaseName)) {
  1529. SetLastError(ERROR_NO_MORE_FILES);
  1530. demClientError(INVALID_HANDLE_VALUE, *pFileName);
  1531. return;
  1532. }
  1533. // warning !!! this assumes the FileExt follows FileName immediately
  1534. memset(pSrchBuf->FileName, ' ', DOS_VOLUME_NAME_SIZE);
  1535. strncpy(pSrchBuf->FileName, achVolumeName, strlen(achVolumeName));
  1536. // Now copy the directory entry
  1537. strncpy(pDirEnt->FileName,pSrchBuf->FileName,8);
  1538. strncpy(pDirEnt->FileExt,pSrchBuf->FileExt,3);
  1539. setCF (0);
  1540. return;
  1541. }
  1542. /* FillDtaVolume - fill Volume info in the DTA
  1543. *
  1544. * Entry - CHAR lpSearchName - name to match with volume name
  1545. *
  1546. *
  1547. * Exit - SUCCESS
  1548. * Returns - TRUE
  1549. * pSrchBuf is filled with volume info
  1550. *
  1551. * FAILURE
  1552. * Returns - FALSE
  1553. * sets last error code
  1554. */
  1555. BOOL FillDtaVolume(
  1556. CHAR *pFileName,
  1557. PSRCHDTA pDta,
  1558. USHORT SearchAttr
  1559. )
  1560. {
  1561. CHAR *pch;
  1562. CHAR FullPathBuffer[MAX_PATH];
  1563. CHAR achBaseName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.' and null
  1564. CHAR achVolumeName[NT_VOLUME_NAME_SIZE];
  1565. //
  1566. // form a path without base name
  1567. // this makes sure only on root directory will get the
  1568. // volume label(the GetVolumeInformationOem will fail
  1569. // if the given path is not root directory)
  1570. //
  1571. strncpy(FullPathBuffer, pFileName,MAX_PATH);
  1572. FullPathBuffer[MAX_PATH-1] = 0;
  1573. pch = strrchr(FullPathBuffer, '\\');
  1574. if (pch) {
  1575. pch++;
  1576. pch[DOS_VOLUME_NAME_SIZE + 1] = '\0'; // max len (including period)
  1577. strcpy(achBaseName, pch);
  1578. #ifdef DBCS
  1579. CharUpper(achBaseName);
  1580. #else // !DBCS
  1581. _strupr(achBaseName);
  1582. #endif // !DBCS
  1583. *pch = '\0';
  1584. }
  1585. else {
  1586. achBaseName[0] = '\0';
  1587. }
  1588. //
  1589. // if searching for volume only the DOS uses first 3 letters for
  1590. // root drive path ignoring the rest of the path, if there is no basename assume *.*
  1591. //
  1592. if (SearchAttr == ATTR_VOLUME_ID &&
  1593. (pch = strchr(FullPathBuffer, '\\')) &&
  1594. DPM_GetFileAttributes(FullPathBuffer) != 0xffffffff )
  1595. {
  1596. pch++;
  1597. if(!*pch) {
  1598. strcpy(achBaseName, szStartDotStar);
  1599. }
  1600. *pch = '\0';
  1601. }
  1602. if (GetVolumeInformationOem(FullPathBuffer,
  1603. achVolumeName,
  1604. NT_VOLUME_NAME_SIZE,
  1605. NULL,
  1606. NULL,
  1607. NULL,
  1608. NULL,
  1609. 0) == FALSE)
  1610. {
  1611. return FALSE;
  1612. }
  1613. // truncate to dos file name length (no period)
  1614. achVolumeName[DOS_VOLUME_NAME_SIZE] = '\0';
  1615. if (!achVolumeName[0] || !MatchVolLabel(achVolumeName, achBaseName)) {
  1616. SetLastError(ERROR_NO_MORE_FILES);
  1617. return FALSE;
  1618. }
  1619. //
  1620. // DOS Dta search returns volume label in 8.3 format. But if label is
  1621. // more than 8 characters long than NT just returns that as it is
  1622. // without adding a ".". So here we have to add a "." in volume
  1623. // labels, if needed. But note that FCB based volume search does'nt
  1624. // add the "." So nothing need to be done there.
  1625. //
  1626. NtVolumeNameToDosVolumeName(pDta->achFileName, achVolumeName);
  1627. pDta->uchFileAttr = ATTR_VOLUME_ID;
  1628. STOREWORD(pDta->usLowSize,0);
  1629. STOREWORD(pDta->usHighSize,0);
  1630. // Zero out dates as we can not fetch dates for volume labels.
  1631. STOREWORD(pDta->usTimeLastWrite,0);
  1632. STOREWORD(pDta->usDateLastWrite,0);
  1633. return TRUE;
  1634. }
  1635. /*
  1636. * MatchVolLabel
  1637. * Does a string compare to see if the vol label matches
  1638. * a FAT search string. The search string is expected to
  1639. * have the '*' character already expanded into '?' characters.
  1640. *
  1641. * WARNING: maintanes dos5.0 quirk of not caring about characters past
  1642. * the defined len of each part of the vol label.
  1643. * 12345678.123
  1644. * ^ ^
  1645. *
  1646. * foovol foovol1 (srch string)
  1647. * foo.vol foo.vol1 (srch string)
  1648. *
  1649. * entry: CHAR *pVol -- NT volume name
  1650. * CHAR *pSrch -- dos volume name
  1651. *
  1652. * exit: TRUE for a match
  1653. */
  1654. BOOL MatchVolLabel(CHAR *pVol, CHAR *pSrch )
  1655. {
  1656. WORD w;
  1657. CHAR achDosVolumeName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.' and null
  1658. NtVolumeNameToDosVolumeName(achDosVolumeName, pVol);
  1659. pVol = achDosVolumeName;
  1660. w = 8;
  1661. while (w--) {
  1662. if (*pVol == *pSrch) {
  1663. if (!*pVol && !*pSrch)
  1664. return TRUE;
  1665. }
  1666. else if (*pSrch == '.') {
  1667. if (*pVol)
  1668. return FALSE;
  1669. }
  1670. else if (*pSrch != '?') {
  1671. return FALSE;
  1672. }
  1673. // move on to the next character
  1674. // but not past second component part
  1675. if (*pVol && *pVol != '.')
  1676. pVol++;
  1677. if (*pSrch && *pSrch != '.')
  1678. pSrch++;
  1679. }
  1680. // skip trailing part of search string, in the first comp
  1681. while (*pSrch && *pSrch != '.')
  1682. pSrch++;
  1683. w = 4;
  1684. while (w--) {
  1685. if (*pVol == *pSrch) {
  1686. if (!*pVol && !*pSrch)
  1687. return TRUE;
  1688. }
  1689. else if (*pSrch == '.') {
  1690. if (*pVol)
  1691. return FALSE;
  1692. }
  1693. else if (*pSrch != '?') {
  1694. return FALSE;
  1695. }
  1696. // move on to the next character
  1697. if (*pVol)
  1698. pVol++;
  1699. if (*pSrch)
  1700. pSrch++;
  1701. }
  1702. return TRUE;
  1703. }
  1704. VOID NtVolumeNameToDosVolumeName(CHAR * pDosName, CHAR * pNtName)
  1705. {
  1706. char NtNameBuffer[NT_VOLUME_NAME_SIZE];
  1707. int i;
  1708. char char8, char9, char10;
  1709. // make a local copy so that the caller can use the same
  1710. // buffer
  1711. strncpy(NtNameBuffer, pNtName, NT_VOLUME_NAME_SIZE);
  1712. NtNameBuffer[NT_VOLUME_NAME_SIZE-1] = 0;
  1713. if (strlen(NtNameBuffer) > 8) {
  1714. char8 = NtNameBuffer[8];
  1715. char9 = NtNameBuffer[9];
  1716. char10 = NtNameBuffer[10];
  1717. // eat spaces from first 8 characters
  1718. i = 7;
  1719. while (NtNameBuffer[i] == ' ')
  1720. i--;
  1721. NtNameBuffer[i+1] = '.';
  1722. NtNameBuffer[i+2] = char8;
  1723. NtNameBuffer[i+3] = char9;
  1724. NtNameBuffer[i+4] = char10;
  1725. NtNameBuffer[i+5] = '\0';
  1726. }
  1727. strcpy(pDosName, NtNameBuffer);
  1728. }
  1729. /* FillFCBSrchBuf - Fill the FCB Search buffer.
  1730. *
  1731. * Entry - pSrchBuf FCB Search buffer to be filled in
  1732. * hFind Search Handle
  1733. * fFirst TRUE if call from FindFirstFCB
  1734. *
  1735. * Exit - None (pSrchBuf filled in)
  1736. *
  1737. */
  1738. VOID FillFCBSrchBuf(
  1739. PFFINDDOSDATA pFFindDD,
  1740. PSRCHBUF pSrchBuf,
  1741. BOOL IsOnCD)
  1742. {
  1743. PDIRENT pDirEnt = &pSrchBuf->DirEnt;
  1744. PCHAR pDot;
  1745. USHORT usDate,usTime,i;
  1746. FILETIME ftLocal;
  1747. #if DBG
  1748. if (fShowSVCMsg & DEMFILIO) {
  1749. sprintf(demDebugBuffer, "FillFCBSrchBuf<%s>\n", pFFindDD->cFileName);
  1750. OutputDebugStringOem(demDebugBuffer);
  1751. }
  1752. #endif
  1753. // Copy file name (Max Name = 8 and Max ext = 3)
  1754. if ((pDot = strchr(pFFindDD->cFileName,'.')) == NULL) {
  1755. strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8);
  1756. _strnset(pSrchBuf->FileExt,'\x020',3);
  1757. }
  1758. else if (pDot == pFFindDD->cFileName) {
  1759. strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8);
  1760. _strnset(pSrchBuf->FileExt,'\x020',3);
  1761. }
  1762. else {
  1763. *pDot = '\0';
  1764. strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8);
  1765. *pDot++ = '\0';
  1766. strncpy(pSrchBuf->FileExt,pDot,3);
  1767. }
  1768. for (i=0;i<8;i++) {
  1769. if (pSrchBuf->FileName[i] == '\0')
  1770. pSrchBuf->FileName[i]='\x020';
  1771. }
  1772. for (i=0;i<3;i++) {
  1773. if (pSrchBuf->FileExt[i] == '\0')
  1774. pSrchBuf->FileExt[i]='\x020';
  1775. }
  1776. STOREWORD(pSrchBuf->usCurBlkNumber,0);
  1777. STOREWORD(pSrchBuf->usRecordSize,0);
  1778. STOREDWORD(pSrchBuf->ulFileSize, pFFindDD->dwFileSizeLow);
  1779. // Convert NT File time/date to DOS time/date
  1780. FileTimeToLocalFileTime (&pFFindDD->ftLastWriteTime,&ftLocal);
  1781. FileTimeToDosDateTime (&ftLocal,
  1782. &usDate,
  1783. &usTime);
  1784. // Now copy the directory entry
  1785. strncpy(pDirEnt->FileName,pSrchBuf->FileName,8);
  1786. strncpy(pDirEnt->FileExt,pSrchBuf->FileExt,3);
  1787. // SudeepB - 28-Jul-1997
  1788. //
  1789. // For CDFS, Win3.1/DOS/Win95, only return FILE_ATTRIBUTE_DIRECTORY (10)
  1790. // for directories while WinNT returns
  1791. // FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY (11).
  1792. // Some VB controls that app setups use, depend on getting
  1793. // FILE_ATTRIBUTE_DIRECTORY (10) only or otherwise are broken.
  1794. // An example of this is Cliffs StudyWare series.
  1795. //
  1796. if (IsOnCD && pFFindDD->uchFileAttributes == (ATTR_DIRECTORY | ATTR_READ_ONLY))
  1797. pDirEnt->uchAttributes = ATTR_DIRECTORY;
  1798. else
  1799. pDirEnt->uchAttributes = pFFindDD->uchFileAttributes;
  1800. STOREWORD(pDirEnt->usTime,usTime);
  1801. STOREWORD(pDirEnt->usDate,usDate);
  1802. STOREDWORD(pDirEnt->ulFileSize,pFFindDD->dwFileSizeLow);
  1803. return;
  1804. }
  1805. /* FillSrchDta - Fill DTA for FIND_FIRST,FIND_NEXT operations.
  1806. *
  1807. * Entry - pW32FindData Buffer containing file data
  1808. * hFind - Handle returned by FindFirstFile
  1809. * PSRCHDTA pDta
  1810. *
  1811. * Exit - None
  1812. *
  1813. * Note : It is guranteed that file name adhers to 8:3 convention.
  1814. * demSrchFile makes sure of that condition.
  1815. *
  1816. */
  1817. VOID
  1818. FillSrchDta(
  1819. PFFINDDOSDATA pFFindDD,
  1820. PSRCHDTA pDta,
  1821. BOOL IsOnCD)
  1822. {
  1823. USHORT usDate,usTime;
  1824. FILETIME ftLocal;
  1825. // SudeepB - 28-Jul-1997
  1826. //
  1827. // For CDFS, Win3.1/DOS/Win95, only return FILE_ATTRIBUTE_DIRECTORY (10)
  1828. // for directories while WinNT returns
  1829. // FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY (11).
  1830. // Some VB controls that app setups use, depend on getting
  1831. // FILE_ATTRIBUTE_DIRECTORY (10) only or otherwise are broken.
  1832. // An example of this is Cliffs StudyWare series.
  1833. //
  1834. if (IsOnCD && pFFindDD->uchFileAttributes == (ATTR_DIRECTORY | ATTR_READ_ONLY))
  1835. pDta->uchFileAttr = ATTR_DIRECTORY;
  1836. else
  1837. pDta->uchFileAttr = pFFindDD->uchFileAttributes;
  1838. // Convert NT File time/date to DOS time/date
  1839. FileTimeToLocalFileTime (&pFFindDD->ftLastWriteTime,&ftLocal);
  1840. FileTimeToDosDateTime (&ftLocal,
  1841. &usDate,
  1842. &usTime);
  1843. STOREWORD(pDta->usTimeLastWrite,usTime);
  1844. STOREWORD(pDta->usDateLastWrite,usDate);
  1845. STOREWORD(pDta->usLowSize,(USHORT)pFFindDD->dwFileSizeLow);
  1846. STOREWORD(pDta->usHighSize,(USHORT)(pFFindDD->dwFileSizeLow >> 16));
  1847. #if DBG
  1848. if (fShowSVCMsg & DEMFILIO) {
  1849. sprintf(demDebugBuffer, "FillSrchDta<%s>\n", pFFindDD->cFileName);
  1850. OutputDebugStringOem(demDebugBuffer);
  1851. }
  1852. #endif
  1853. strncpy(pDta->achFileName,pFFindDD->cFileName, 13);
  1854. pDta->achFileName[12] = '\0';
  1855. return;
  1856. }
  1857. VOID demCloseAllPSPRecords (VOID)
  1858. {
  1859. PLIST_ENTRY Next;
  1860. PPSP_FFINDLIST pPspFFindEntry;
  1861. Next = PspFFindHeadList.Flink;
  1862. while (Next != &PspFFindHeadList) {
  1863. pPspFFindEntry = CONTAINING_RECORD(Next,PSP_FFINDLIST,PspFFindEntry);
  1864. FreeFFindList( &pPspFFindEntry->FFindHeadList);
  1865. Next= Next->Flink;
  1866. RemoveEntryList(&pPspFFindEntry->PspFFindEntry);
  1867. free(pPspFFindEntry);
  1868. }
  1869. }
  1870. void
  1871. DemHeartBeat(void)
  1872. {
  1873. PLIST_ENTRY Next;
  1874. PLIST_ENTRY pFFindHeadList;
  1875. PPSP_FFINDLIST pPspFFindEntry;
  1876. PFFINDLIST pFFindEntry;
  1877. if (!NumFindBuffer ||
  1878. NextFindFileTics.QuadPart > ++FindFileTics.QuadPart)
  1879. {
  1880. return;
  1881. }
  1882. pPspFFindEntry = GetPspFFindList(FETCHWORD(pusCurrentPDB[0]));
  1883. if (!pPspFFindEntry) {
  1884. return;
  1885. }
  1886. pFFindHeadList = &pPspFFindEntry->FFindHeadList;
  1887. Next = pFFindHeadList->Blink;
  1888. while (Next != pFFindHeadList) {
  1889. pFFindEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry);
  1890. if (pFFindEntry->FindFileTics.QuadPart) {
  1891. if (pFFindEntry->FindFileTics.QuadPart <= FindFileTics.QuadPart) {
  1892. FileFindClose(pFFindEntry);
  1893. }
  1894. else {
  1895. NextFindFileTics.QuadPart = pFFindEntry->FindFileTics.QuadPart;
  1896. return;
  1897. }
  1898. }
  1899. Next = Next->Blink;
  1900. }
  1901. NextFindFileTics.QuadPart = 0;
  1902. FindFileTics.QuadPart = 0;
  1903. }
  1904. //
  1905. // CloseOldestFileFindBuffer
  1906. // walks the psp file find list backwards to find the oldest
  1907. // entry with FindBuffers, directory handles and closes it.
  1908. //
  1909. void
  1910. CloseOldestFileFindBuffer(
  1911. void
  1912. )
  1913. {
  1914. PLIST_ENTRY Next, NextPsp;
  1915. PLIST_ENTRY pFFindHeadList;
  1916. PPSP_FFINDLIST pPspFFindEntry;
  1917. PFFINDLIST pFFEntry;
  1918. NextPsp = PspFFindHeadList.Blink;
  1919. while (NextPsp != &PspFFindHeadList) {
  1920. pPspFFindEntry = CONTAINING_RECORD(NextPsp,PSP_FFINDLIST,PspFFindEntry);
  1921. pFFindHeadList = &pPspFFindEntry->FFindHeadList;
  1922. Next = pFFindHeadList->Blink;
  1923. while (Next != pFFindHeadList) {
  1924. pFFEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry);
  1925. if (NumFindBuffer >= MAX_FINDBUFFER) {
  1926. FileFindClose(pFFEntry);
  1927. }
  1928. else if (pFFEntry->DirectoryHandle &&
  1929. NumDirectoryHandle >= MAX_DIRECTORYHANDLE)
  1930. {
  1931. NumDirectoryHandle--;
  1932. NtClose(pFFEntry->DirectoryHandle);
  1933. pFFEntry->DirectoryHandle = 0;
  1934. }
  1935. if (NumFindBuffer < MAX_FINDBUFFER &&
  1936. NumDirectoryHandle < MAX_DIRECTORYHANDLE)
  1937. {
  1938. return;
  1939. }
  1940. Next = Next->Blink;
  1941. }
  1942. NextPsp= NextPsp->Blink;
  1943. }
  1944. }
  1945. /*
  1946. * GetFFindEntryByFindId
  1947. */
  1948. PFFINDLIST GetFFindEntryByFindId(ULONG NextFFindId)
  1949. {
  1950. PLIST_ENTRY NextPsp;
  1951. PLIST_ENTRY Next;
  1952. PPSP_FFINDLIST pPspFFindEntry;
  1953. PFFINDLIST pFFindEntry;
  1954. PLIST_ENTRY pFFindHeadList;
  1955. NextPsp = PspFFindHeadList.Flink;
  1956. while (NextPsp != &PspFFindHeadList) {
  1957. pPspFFindEntry = CONTAINING_RECORD(NextPsp,PSP_FFINDLIST,PspFFindEntry);
  1958. pFFindHeadList = &pPspFFindEntry->FFindHeadList;
  1959. Next = pFFindHeadList->Flink;
  1960. while (Next != pFFindHeadList) {
  1961. pFFindEntry = CONTAINING_RECORD(Next, FFINDLIST, FFindEntry);
  1962. if (pFFindEntry->FFindId == NextFFindId) {
  1963. return pFFindEntry;
  1964. }
  1965. Next= Next->Flink;
  1966. }
  1967. NextPsp= NextPsp->Flink;
  1968. }
  1969. return NULL;
  1970. }
  1971. /* AddFFindEntry - Adds a new File Find entry to the current
  1972. * PSP's PspFileFindList
  1973. *
  1974. * Entry -
  1975. *
  1976. * Exit - PFFINDLIST pFFindList;
  1977. */
  1978. PFFINDLIST
  1979. AddFFindEntry(
  1980. PWCHAR pwcFile,
  1981. PFFINDLIST pFFindEntrySrc
  1982. )
  1983. {
  1984. PPSP_FFINDLIST pPspFFindEntry;
  1985. PFFINDLIST pFFindEntry;
  1986. ULONG Len;
  1987. pPspFFindEntry = GetPspFFindList(FETCHWORD(pusCurrentPDB[0]));
  1988. //
  1989. // if a Psp entry doesn't exist
  1990. // Allocate one, initialize it and insert it into the list
  1991. //
  1992. if (!pPspFFindEntry) {
  1993. pPspFFindEntry = (PPSP_FFINDLIST) malloc(sizeof(PSP_FFINDLIST));
  1994. if (!pPspFFindEntry)
  1995. return NULL;
  1996. pPspFFindEntry->usPsp = FETCHWORD(pusCurrentPDB[0]);
  1997. InitializeListHead(&pPspFFindEntry->FFindHeadList);
  1998. InsertHeadList(&PspFFindHeadList, &pPspFFindEntry->PspFFindEntry);
  1999. }
  2000. //
  2001. // Create the FileFindEntry and add to the FileFind list
  2002. //
  2003. pFFindEntry = (PFFINDLIST) malloc(sizeof(FFINDLIST));
  2004. if (!pFFindEntry) {
  2005. return pFFindEntry;
  2006. }
  2007. //
  2008. // Fill in FFindList
  2009. //
  2010. *pFFindEntry = *pFFindEntrySrc;
  2011. //
  2012. // Insert at the head of this psp list
  2013. //
  2014. InsertHeadList(&pPspFFindEntry->FFindHeadList, &pFFindEntry->FFindEntry);
  2015. return pFFindEntry;
  2016. }
  2017. /* FreeFFindEntry
  2018. *
  2019. * Entry - PFFINDLIST pFFindEntry
  2020. *
  2021. * Exit - None
  2022. *
  2023. */
  2024. VOID FreeFFindEntry(PFFINDLIST pFFindEntry)
  2025. {
  2026. RemoveEntryList(&pFFindEntry->FFindEntry);
  2027. FileFindClose(pFFindEntry);
  2028. RtlFreeUnicodeString(&pFFindEntry->FileName);
  2029. RtlFreeUnicodeString(&pFFindEntry->PathName);
  2030. free(pFFindEntry);
  2031. return;
  2032. }
  2033. /* FreeFFindList
  2034. *
  2035. * Entry - Frees the entire list
  2036. *
  2037. * Exit - None
  2038. *
  2039. */
  2040. VOID FreeFFindList(PLIST_ENTRY pFFindHeadList)
  2041. {
  2042. PLIST_ENTRY Next;
  2043. PFFINDLIST pFFindEntry;
  2044. Next = pFFindHeadList->Flink;
  2045. while (Next != pFFindHeadList) {
  2046. pFFindEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry);
  2047. Next= Next->Flink;
  2048. FreeFFindEntry(pFFindEntry);
  2049. }
  2050. return;
  2051. }
  2052. /* GetPspFFindList
  2053. *
  2054. * Entry - USHORT CurrPsp
  2055. *
  2056. * Exit - Success - PPSP_FFINDLIST
  2057. * Failure - NULL
  2058. *
  2059. */
  2060. PPSP_FFINDLIST GetPspFFindList(USHORT CurrPsp)
  2061. {
  2062. PLIST_ENTRY Next;
  2063. PPSP_FFINDLIST pPspFFindEntry;
  2064. Next = PspFFindHeadList.Flink;
  2065. while (Next != &PspFFindHeadList) {
  2066. pPspFFindEntry = CONTAINING_RECORD(Next,PSP_FFINDLIST,PspFFindEntry);
  2067. if (CurrPsp == pPspFFindEntry->usPsp) {
  2068. return pPspFFindEntry;
  2069. }
  2070. Next= Next->Flink;
  2071. }
  2072. return NULL;
  2073. }