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.

2609 lines
68 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. extern BOOL IsFirstCall;
  22. /*
  23. * Internal globals, function prototypes
  24. */
  25. #define FINDFILE_DEVICE (HANDLE)0xffffffff
  26. typedef struct _PSP_FILEFINDLIST {
  27. LIST_ENTRY PspFFindEntry; // Next psp
  28. LIST_ENTRY FFindHeadList; // File Find list for this psp
  29. ULONG usPsp; // PSP id
  30. } PSP_FFINDLIST, *PPSP_FFINDLIST;
  31. typedef struct _FFINDDOSDATA {
  32. ULONG FileIndex;
  33. ULONG FileNameLength;
  34. WCHAR FileName[MAXIMUM_FILENAME_LENGTH + 1];
  35. FILETIME ftLastWriteTime;
  36. DWORD dwFileSizeLow;
  37. UCHAR uchFileAttributes;
  38. CHAR cFileName[14];
  39. } FFINDDOSDATA, *PFFINDDOSDATA;
  40. typedef struct _FILEFINDLIST {
  41. LIST_ENTRY FFindEntry;
  42. ULONG FFindId;
  43. NTSTATUS LastQueryStatus;
  44. LARGE_INTEGER FindFileTics;
  45. HANDLE DirectoryHandle;
  46. PVOID FindBufferBase;
  47. PVOID FindBufferNext;
  48. ULONG FindBufferLength;
  49. FFINDDOSDATA DosData;
  50. USHORT usSrchAttr;
  51. BOOLEAN SupportReset;
  52. UNICODE_STRING PathName;
  53. UNICODE_STRING FileName;
  54. BOOL SearchOnCD;
  55. }FFINDLIST, *PFFINDLIST;
  56. LIST_ENTRY PspFFindHeadList= {&PspFFindHeadList, &PspFFindHeadList};
  57. #define FFINDID_BASE 0x80000000
  58. ULONG NextFFindId = FFINDID_BASE;
  59. BOOLEAN FFindIdWrap = FALSE;
  60. #define MAX_DIRECTORYHANDLE 64
  61. #define MAX_FINDBUFFER 128
  62. ULONG NumDirectoryHandle = 0;
  63. ULONG NumFindBuffer=0;
  64. LARGE_INTEGER FindFileTics = {0,0};
  65. LARGE_INTEGER NextFindFileTics = {0,0};
  66. char szStartDotStar[]="????????.???";
  67. PFFINDLIST
  68. SearchFile(
  69. PWCHAR pwcFile,
  70. USHORT SearchAttr,
  71. PFFINDLIST pFFindEntry,
  72. PFFINDDOSDATA pFFindDDOut
  73. );
  74. NTSTATUS
  75. FileFindNext(
  76. PFFINDDOSDATA pFFindDD,
  77. PFFINDLIST pFFindEntry
  78. );
  79. NTSTATUS
  80. FileFindLast(
  81. PFFINDLIST pFFindEntry
  82. );
  83. VOID
  84. FileFindClose(
  85. PFFINDLIST pFFindEntry
  86. );
  87. NTSTATUS
  88. FileFindOpen(
  89. PWCHAR pwcFile,
  90. PFFINDLIST pFFindEntry,
  91. ULONG BufferSize
  92. );
  93. NTSTATUS
  94. FileFindReset(
  95. PFFINDLIST pFFindEntry
  96. );
  97. HANDLE
  98. FileFindFirstDevice(
  99. PWCHAR FileName,
  100. PFILE_BOTH_DIR_INFORMATION DirectoryInfo
  101. );
  102. void
  103. CloseOldestFileFindBuffer(
  104. void
  105. );
  106. BOOL
  107. CopyDirInfoToDosData(
  108. HANDLE DirectoryHandle,
  109. PFFINDDOSDATA pFFindDD,
  110. PFILE_BOTH_DIR_INFORMATION DirectoryInfo,
  111. USHORT SearchAttr
  112. );
  113. BOOL
  114. DemOemToUni(
  115. PUNICODE_STRING pUnicode,
  116. LPSTR lpstr
  117. );
  118. VOID
  119. FillFcbVolume(
  120. PSRCHBUF pSrchBuf,
  121. CHAR *pFileName,
  122. USHORT SearchAttr
  123. );
  124. BOOL
  125. FillDtaVolume(
  126. CHAR *pFileName,
  127. PSRCHDTA pDta,
  128. USHORT SearchAttr
  129. );
  130. BOOL
  131. MatchVolLabel(
  132. CHAR * pVolLabel,
  133. CHAR * pBaseName
  134. );
  135. VOID
  136. NtVolumeNameToDosVolumeName(
  137. CHAR * pDosName,
  138. CHAR * pNtName
  139. );
  140. VOID
  141. FillFCBSrchBuf(
  142. PFFINDDOSDATA pFFindDD,
  143. PSRCHBUF pSrchBuf,
  144. BOOL IsOnCD
  145. );
  146. VOID
  147. FillSrchDta(
  148. PFFINDDOSDATA pFFindDD,
  149. PSRCHDTA pDta,
  150. BOOL IsOnCD
  151. );
  152. PFFINDLIST
  153. AddFFindEntry(
  154. PWCHAR pwcFile,
  155. PFFINDLIST pFFindEntrySrc
  156. );
  157. PPSP_FFINDLIST
  158. GetPspFFindList(
  159. USHORT CurrPsp
  160. );
  161. PFFINDLIST
  162. GetFFindEntryByFindId(
  163. ULONG NextFFindId
  164. );
  165. VOID
  166. FreeFFindEntry(
  167. PFFINDLIST pFFindEntry
  168. );
  169. VOID
  170. FreeFFindList(
  171. PLIST_ENTRY pFFindHeadList
  172. );
  173. #if defined(NEC_98)
  174. // BUG fix for DBCS small alphabet converted to large it.
  175. void demCharUpper(char *);
  176. #endif // NEC_98
  177. /* demFindFirst - Path-Style Find First File
  178. *
  179. * Entry - Client (DS:DX) - File Path with wildcard
  180. * Client (CX) - Search Attributes
  181. *
  182. * Exit - Success
  183. * Client (CF) = 0
  184. * DTA updated
  185. *
  186. * Failure
  187. * Client (CF) = 1
  188. * Client (AX) = Error Code
  189. *
  190. * NOTES
  191. * Search Rules: Ignore Read_only and Archive bits.
  192. * If CX == ATTR_NORMAL Search only for normal files
  193. * If CX == ATTR_HIDDEN Search Hidden or normal files
  194. * If CX == ATTR_SYSTEM Search System or normal files
  195. * If CX == ATTR_DIRECTORY Search directory or normal files
  196. * If CX == ATTR_VOLUME_ID Search Volume_ID
  197. * if CX == -1 return everytiing you find
  198. *
  199. * Limitations - 21-Sep-1992 Jonle
  200. * cannot return label from a UNC name,just like dos.
  201. * Apps which keep many find handles open can cause
  202. * serious trouble, we must rewrite so that we can
  203. * close the handles
  204. *
  205. */
  206. VOID demFindFirst (VOID)
  207. {
  208. DWORD dwRet;
  209. PVOID pDta;
  210. #ifdef DBCS /* demFindFirst() for CSNW */
  211. CHAR achPath[MAX_PATH];
  212. #endif /* DBCS */
  213. LPSTR lpFile = (LPSTR) GetVDMAddr (getDS(),getDX());
  214. pDta = (PVOID) GetVDMAddr (*((PUSHORT)pulDTALocation + 1),
  215. *((PUSHORT)pulDTALocation));
  216. #ifdef DBCS /* demFindFirst() for CSNW */
  217. /*
  218. * convert Netware path to Dos path
  219. */
  220. ConvNwPathToDosPath(achPath,lpFile);
  221. lpFile = achPath;
  222. #endif /* DBCS */
  223. dwRet = demFileFindFirst (pDta, lpFile, getCX());
  224. if (dwRet == -1) {
  225. dwRet = GetLastError();
  226. demClientError(INVALID_HANDLE_VALUE, *lpFile);
  227. return;
  228. }
  229. if (dwRet != 0) {
  230. setAX((USHORT) dwRet);
  231. setCF (1);
  232. } else {
  233. setCF (0);
  234. }
  235. return;
  236. }
  237. DWORD demFileFindFirst (
  238. PVOID pvDTA,
  239. LPSTR lpFile,
  240. USHORT SearchAttr)
  241. {
  242. PSRCHDTA pDta = (PSRCHDTA)pvDTA;
  243. PFFINDLIST pFFindEntry;
  244. FFINDDOSDATA FFindDD;
  245. UNICODE_STRING FileUni;
  246. WCHAR wcFile[MAX_PATH + sizeof(WCHAR)];
  247. BOOL IsOnCD;
  248. #if DBG
  249. if (SIZEOF_DOSSRCHDTA != sizeof(SRCHDTA)) {
  250. sprintf(demDebugBuffer,
  251. "demsrch: FFirst SIZEOF_DOSSRCHDTA %ld != sizeof(SRCHDTA) %ld\n",
  252. SIZEOF_DOSSRCHDTA,
  253. sizeof(SRCHDTA));
  254. OutputDebugStringOem(demDebugBuffer);
  255. }
  256. if (fShowSVCMsg & DEMFILIO){
  257. sprintf(demDebugBuffer,"demsrch: FindFirst<%s>\n", lpFile);
  258. OutputDebugStringOem(demDebugBuffer);
  259. }
  260. #endif
  261. STOREDWORD(pDta->FFindId,0);
  262. STOREDWORD(pDta->pFFindEntry,0);
  263. FileUni.Buffer = wcFile;
  264. FileUni.MaximumLength = sizeof(wcFile);
  265. DemOemToUni(&FileUni, lpFile);
  266. IsOnCD = IsCdRomFile(lpFile);
  267. //
  268. // Do volume label first.
  269. //
  270. if (SearchAttr & ATTR_VOLUME_ID) {
  271. if (FillDtaVolume(lpFile, pDta, SearchAttr)) {
  272. // got vol label match
  273. // do look ahead before returning
  274. if (SearchAttr != ATTR_VOLUME_ID) {
  275. pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, NULL);
  276. if (pFFindEntry) {
  277. pFFindEntry->SearchOnCD = IsOnCD;
  278. STOREDWORD(pDta->pFFindEntry,pFFindEntry);
  279. STOREDWORD(pDta->FFindId,pFFindEntry->FFindId);
  280. }
  281. }
  282. return 0;
  283. }
  284. // no vol match, if asking for more than vol label
  285. // fall thru to file search code, otherwise ret error
  286. else if (SearchAttr == ATTR_VOLUME_ID) {
  287. return GetLastError();
  288. }
  289. }
  290. //
  291. // Search the dir
  292. //
  293. pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, &FFindDD);
  294. if (!FFindDD.cFileName[0]) {
  295. // search.asm in doskrnl never returns ERROR_FILE_NOT_FOUND
  296. // only ERROR_PATH_NOT_FOUND, ERROR_NO_MORE_FILES
  297. DWORD dw;
  298. dw = GetLastError();
  299. if (dw == ERROR_FILE_NOT_FOUND) {
  300. SetLastError(ERROR_NO_MORE_FILES);
  301. }
  302. else if (dw == ERROR_BAD_PATHNAME || dw == ERROR_DIRECTORY ) {
  303. SetLastError(ERROR_PATH_NOT_FOUND);
  304. }
  305. return (DWORD)-1;
  306. }
  307. FillSrchDta(&FFindDD, pDta, IsOnCD);
  308. if (pFFindEntry) {
  309. pFFindEntry->SearchOnCD = IsOnCD;
  310. STOREDWORD(pDta->pFFindEntry,pFFindEntry);
  311. STOREDWORD(pDta->FFindId,pFFindEntry->FFindId);
  312. }
  313. return 0;
  314. }
  315. /*
  316. * DemOemToUni
  317. *
  318. * returns TRUE\FALSE for success, sets last error if fail
  319. *
  320. */
  321. BOOL DemOemToUni(PUNICODE_STRING pUnicode, LPSTR lpstr)
  322. {
  323. NTSTATUS Status;
  324. OEM_STRING OemString;
  325. RtlInitString(&OemString,lpstr);
  326. Status = RtlOemStringToUnicodeString(pUnicode,&OemString,FALSE);
  327. if (!NT_SUCCESS(Status)) {
  328. if (Status == STATUS_BUFFER_OVERFLOW) {
  329. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  330. }
  331. else {
  332. SetLastError(RtlNtStatusToDosError(Status));
  333. }
  334. return FALSE;
  335. }
  336. *(PWCHAR)((PUCHAR)pUnicode->Buffer + pUnicode->Length) = UNICODE_NULL;
  337. return TRUE;
  338. }
  339. /* demFindNext - Path-Style Find Next File
  340. *
  341. * Entry - None
  342. *
  343. * Exit - Success
  344. * Client (CF) = 0
  345. * DTA updated
  346. *
  347. * Failure
  348. * Client (CF) = 1
  349. * Client (AX) = Error Code
  350. */
  351. VOID demFindNext (VOID)
  352. {
  353. DWORD dwRet;
  354. PVOID pDta;
  355. pDta = (PVOID) GetVDMAddr(*((PUSHORT)pulDTALocation + 1),
  356. *((PUSHORT)pulDTALocation));
  357. dwRet = demFileFindNext (pDta);
  358. if (dwRet != 0) {
  359. setAX((USHORT) dwRet);
  360. setCF (1);
  361. return;
  362. }
  363. setCF (0);
  364. return;
  365. }
  366. DWORD demFileFindNext (
  367. PVOID pvDta)
  368. {
  369. PSRCHDTA pDta = (PSRCHDTA)pvDta;
  370. USHORT SearchAttr;
  371. PFFINDLIST pFFindEntry;
  372. FFINDDOSDATA FFindDD;
  373. BOOL IsOnCD;
  374. pFFindEntry = GetFFindEntryByFindId(FETCHDWORD(pDta->FFindId));
  375. if (!pFFindEntry ||
  376. FETCHDWORD(pDta->pFFindEntry) != (DWORD)pFFindEntry )
  377. {
  378. STOREDWORD(pDta->FFindId,0);
  379. STOREDWORD(pDta->pFFindEntry,0);
  380. // DOS has only one error (no_more_files) for all causes.
  381. return(ERROR_NO_MORE_FILES);
  382. }
  383. #if DBG
  384. if (fShowSVCMsg & DEMFILIO) {
  385. sprintf(demDebugBuffer, "demFileFindNext<%ws>\n", pFFindEntry->PathName.Buffer);
  386. OutputDebugStringOem(demDebugBuffer);
  387. }
  388. #endif
  389. SearchAttr = pFFindEntry->usSrchAttr;
  390. IsOnCD = pFFindEntry->SearchOnCD;
  391. //
  392. // Search the dir
  393. //
  394. pFFindEntry = SearchFile(NULL,
  395. SearchAttr,
  396. pFFindEntry,
  397. &FFindDD
  398. );
  399. if (!FFindDD.cFileName[0]) {
  400. STOREDWORD(pDta->FFindId,0);
  401. STOREDWORD(pDta->pFFindEntry,0);
  402. return GetLastError();
  403. }
  404. FillSrchDta(&FFindDD, pDta, IsOnCD);
  405. if (!pFFindEntry) {
  406. STOREDWORD(pDta->FFindId,0);
  407. STOREDWORD(pDta->pFFindEntry,0);
  408. }
  409. return 0;
  410. }
  411. /* demFindFirstFCB - FCB based Find First file
  412. *
  413. * Entry - Client (DS:SI) - SRCHBUF where the information will be returned
  414. * Client (ES:DI) - Full path file name with possibly wild cards
  415. * Client (Al) - 0 if not an extended FCB
  416. * Client (DL) - Search Attributes
  417. *
  418. * Exit - Success
  419. * Client (CF) = 0
  420. * SRCHBUF is filled in
  421. *
  422. * Failure
  423. * Client (AL) = -1
  424. *
  425. * NOTES
  426. * Search Rules: Ignore Read_only and Archive bits.
  427. * If DL == ATTR_NORMAL Search only for normal files
  428. * If DL == ATTR_HIDDEN Search Hidden or normal files
  429. * If DL == ATTR_SYSTEM Search System or normal files
  430. * If DL == ATTR_DIRECTORY Search directory or normal files
  431. * If DL == ATTR_VOLUME_ID Search only Volume_ID
  432. * if DL == -1 return everytiing you find
  433. */
  434. VOID demFindFirstFCB (VOID)
  435. {
  436. LPSTR lpFile;
  437. USHORT SearchAttr;
  438. PSRCHBUF pFCBSrchBuf;
  439. PDIRENT pDirEnt;
  440. PFFINDLIST pFFindEntry;
  441. FFINDDOSDATA FFindDD;
  442. UNICODE_STRING FileUni;
  443. WCHAR wcFile[MAX_PATH];
  444. BOOL IsOnCD;
  445. lpFile = (LPSTR) GetVDMAddr (getES(),getDI());
  446. #if DBG
  447. if (fShowSVCMsg & DEMFILIO) {
  448. sprintf(demDebugBuffer, "demFindFirstFCB<%s>\n", lpFile);
  449. OutputDebugStringOem(demDebugBuffer);
  450. }
  451. #endif
  452. pFCBSrchBuf = (PSRCHBUF) GetVDMAddr (getDS(),getSI());
  453. pDirEnt = &pFCBSrchBuf->DirEnt;
  454. STOREDWORD(pDirEnt->pFFindEntry,0);
  455. STOREDWORD(pDirEnt->FFindId,0);
  456. if (getDL() == ATTR_VOLUME_ID) {
  457. FillFcbVolume(pFCBSrchBuf,lpFile, ATTR_VOLUME_ID);
  458. return;
  459. }
  460. FileUni.Buffer = wcFile;
  461. FileUni.MaximumLength = sizeof(wcFile);
  462. if (!DemOemToUni(&FileUni ,lpFile)) {
  463. setCF(1);
  464. return;
  465. }
  466. SearchAttr = getAL() ? getDL() : 0;
  467. pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, &FFindDD);
  468. if (!FFindDD.cFileName[0]){
  469. demClientError(INVALID_HANDLE_VALUE, *lpFile);
  470. return;
  471. }
  472. IsOnCD = IsCdRomFile(lpFile);
  473. FillFCBSrchBuf(&FFindDD, pFCBSrchBuf, IsOnCD);
  474. if (pFFindEntry) {
  475. pFFindEntry->SearchOnCD = IsOnCD;
  476. STOREDWORD(pDirEnt->pFFindEntry,pFFindEntry);
  477. STOREDWORD(pDirEnt->FFindId,pFFindEntry->FFindId);
  478. }
  479. setCF(0);
  480. return;
  481. }
  482. /* demFindNextFCB - FCB based Find Next file
  483. *
  484. * Entry - Client (DS:SI) - SRCHBUF where the information will be returned
  485. * Client (Al) - 0 if not an extended FCB
  486. * Client (DL) - Search Attributes
  487. *
  488. * Exit - Success
  489. * Client (CF) = 0
  490. * SRCHBUF is filled in
  491. *
  492. * Failure
  493. * Client (AL) = -1
  494. *
  495. * NOTES
  496. * Search Rules: Ignore Read_only and Archive bits.
  497. * If DL == ATTR_NORMAL Search only for normal files
  498. * If DL == ATTR_HIDDEN Search Hidden or normal files
  499. * If DL == ATTR_SYSTEM Search System or normal files
  500. * If DL == ATTR_DIRECTORY Search directory or normal files
  501. * If DL == ATTR_VOLUME_ID Search only Volume_ID
  502. */
  503. VOID demFindNextFCB (VOID)
  504. {
  505. USHORT SearchAttr;
  506. PSRCHBUF pSrchBuf;
  507. PDIRENT pDirEnt;
  508. PFFINDLIST pFFindEntry;
  509. FFINDDOSDATA FFindDD;
  510. BOOL IsOnCD;
  511. pSrchBuf = (PSRCHBUF) GetVDMAddr (getDS(),getSI());
  512. pDirEnt = &pSrchBuf->DirEnt;
  513. pFFindEntry = GetFFindEntryByFindId(FETCHDWORD(pDirEnt->FFindId));
  514. if (!pFFindEntry ||
  515. FETCHDWORD(pDirEnt->pFFindEntry) != (DWORD)pFFindEntry ||
  516. getDL() == ATTR_VOLUME_ID )
  517. {
  518. if (pFFindEntry &&
  519. FETCHDWORD(pDirEnt->pFFindEntry) != (DWORD)pFFindEntry)
  520. {
  521. FreeFFindEntry(pFFindEntry);
  522. }
  523. STOREDWORD(pDirEnt->pFFindEntry,0);
  524. STOREDWORD(pDirEnt->FFindId,0);
  525. // DOS has only one error (no_more_files) for all causes.
  526. setAX(ERROR_NO_MORE_FILES);
  527. setCF(1);
  528. return;
  529. }
  530. #if DBG
  531. if (fShowSVCMsg & DEMFILIO) {
  532. sprintf(demDebugBuffer, "demFindNextFCB<%ws>\n", pFFindEntry->PathName.Buffer);
  533. OutputDebugStringOem(demDebugBuffer);
  534. }
  535. #endif
  536. SearchAttr = getAL() ? getDL() : 0;
  537. IsOnCD = pFFindEntry->SearchOnCD;
  538. //
  539. // Search the dir
  540. //
  541. pFFindEntry = SearchFile(NULL,
  542. SearchAttr,
  543. pFFindEntry,
  544. &FFindDD
  545. );
  546. if (!FFindDD.cFileName[0]) {
  547. STOREDWORD(pDirEnt->pFFindEntry,0);
  548. STOREDWORD(pDirEnt->FFindId,0);
  549. setAX((USHORT) GetLastError());
  550. setCF(1);
  551. return;
  552. }
  553. FillFCBSrchBuf(&FFindDD, pSrchBuf,IsOnCD);
  554. if (!pFFindEntry) {
  555. STOREDWORD(pDirEnt->FFindId,0);
  556. STOREDWORD(pDirEnt->pFFindEntry,0);
  557. }
  558. setCF(0);
  559. return;
  560. }
  561. /* demTerminatePDB - PDB Terminate Notification
  562. *
  563. * Entry - Client (BX) - Terminating PDB
  564. *
  565. * Exit - None
  566. *
  567. */
  568. VOID demTerminatePDB (VOID)
  569. {
  570. PPSP_FFINDLIST pPspFFindEntry;
  571. USHORT PSP;
  572. PSP = getBX ();
  573. if(!IsFirstCall)
  574. VDDTerminateUserHook(PSP);
  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 = 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 = 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 = TRUE;
  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 = 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 = 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 = 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(pFFindEntry->DirectoryHandle,
  1312. pFFindDD,
  1313. DirectoryInfo,
  1314. pFFindEntry->usSrchAttr
  1315. ));
  1316. return STATUS_SUCCESS;
  1317. }
  1318. BOOL IsVolumeNtfs(
  1319. HANDLE DirectoryHandle)
  1320. {
  1321. union {
  1322. FILE_FS_ATTRIBUTE_INFORMATION AttributeInfo;
  1323. BYTE rgBuffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH*sizeof(WCHAR)];
  1324. } Attrib;
  1325. IO_STATUS_BLOCK IoStatusBlock;
  1326. NTSTATUS Status;
  1327. BOOL fNtfsVolume = TRUE;
  1328. Status = NtQueryVolumeInformationFile(DirectoryHandle,
  1329. &IoStatusBlock,
  1330. &Attrib,
  1331. sizeof(Attrib),
  1332. FileFsAttributeInformation);
  1333. if (NT_SUCCESS(Status)) {
  1334. fNtfsVolume = !_wcsicmp(Attrib.AttributeInfo.FileSystemName, L"Ntfs");
  1335. }
  1336. return(fNtfsVolume);
  1337. }
  1338. /*
  1339. * CopyDirInfoToDosData
  1340. *
  1341. */
  1342. BOOL
  1343. CopyDirInfoToDosData(
  1344. HANDLE DirectoryHandle,
  1345. PFFINDDOSDATA pFFindDD,
  1346. PFILE_BOTH_DIR_INFORMATION DirInfo,
  1347. USHORT SearchAttr
  1348. )
  1349. {
  1350. NTSTATUS Status;
  1351. OEM_STRING OemString;
  1352. UNICODE_STRING UnicodeString;
  1353. DWORD dwAttr;
  1354. BOOLEAN SpacesInName = FALSE;
  1355. BOOLEAN NameValid8Dot3;
  1356. //
  1357. // match the attributes
  1358. // See DOS5.0 sources (dir2.asm, MatchAttributes)
  1359. // ignores READONLY and ARCHIVE bits
  1360. //
  1361. if (FILE_ATTRIBUTE_NORMAL == DirInfo->FileAttributes) {
  1362. DirInfo->FileAttributes = 0;
  1363. }
  1364. else {
  1365. DirInfo->FileAttributes &= DOS_ATTR_MASK;
  1366. }
  1367. dwAttr = DirInfo->FileAttributes;
  1368. dwAttr &= ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY);
  1369. if (((~(ULONG)SearchAttr) & dwAttr) & ATTR_ALL)
  1370. return FALSE;
  1371. //
  1372. // set up the destination oem string buffer
  1373. //
  1374. OemString.Buffer = pFFindDD->cFileName;
  1375. OemString.MaximumLength = 14;
  1376. //
  1377. // see if the name is legal fat
  1378. //
  1379. UnicodeString.Buffer = DirInfo->FileName;
  1380. UnicodeString.Length = (USHORT)DirInfo->FileNameLength;
  1381. UnicodeString.MaximumLength = (USHORT)DirInfo->FileNameLength;
  1382. NameValid8Dot3 = RtlIsNameLegalDOS8Dot3( &UnicodeString,
  1383. &OemString,
  1384. &SpacesInName );
  1385. //
  1386. // if failed (incompatible codepage or illegal FAT name),
  1387. // use the short name
  1388. //
  1389. if (!NameValid8Dot3 ||
  1390. (SpacesInName && (DirInfo->ShortName[0] != UNICODE_NULL))) {
  1391. if (DirInfo->ShortName[0] == UNICODE_NULL) {
  1392. pFFindDD->cFileName[0] = '\0';
  1393. return FALSE;
  1394. }
  1395. UnicodeString.Buffer = DirInfo->ShortName;
  1396. UnicodeString.Length = (USHORT)DirInfo->ShortNameLength;
  1397. UnicodeString.MaximumLength = (USHORT)DirInfo->ShortNameLength;
  1398. if (!NT_SUCCESS(RtlUpcaseUnicodeStringToCountedOemString(&OemString, &UnicodeString, FALSE))) {
  1399. pFFindDD->cFileName[0] = '\0';
  1400. return FALSE;
  1401. }
  1402. }
  1403. OemString.Buffer[OemString.Length] = '\0';
  1404. // fill in time, size and attributes
  1405. //
  1406. // bjm-11/10/97 - for directories, FAT does not update lastwritten time
  1407. // when things actually happen in the directory. NTFS does. This causes
  1408. // a problem for Encore 3.0 (when running on NTFS) which, at install time,
  1409. // gets the lastwritten time for it's directory, then compares it, at app
  1410. // run time, to the "current" last written time and will bail (with a "Not
  1411. // correctly installed" message) if they're different. So, 16 bit apps
  1412. // (which can only reasonably expect FAT info), should only get creation
  1413. // time for this file if it's a directory.
  1414. //
  1415. // VadimB: 11/20/98 -- this hold true ONLY for apps running on NTFS and
  1416. // not FAT -- since older FAT partitions are then given an incorrect
  1417. // creation time
  1418. if ((FILE_ATTRIBUTE_DIRECTORY & DirInfo->FileAttributes) && IsVolumeNtfs(DirectoryHandle)) {
  1419. pFFindDD->ftLastWriteTime = *(LPFILETIME)&DirInfo->CreationTime;
  1420. }
  1421. else {
  1422. pFFindDD->ftLastWriteTime = *(LPFILETIME)&DirInfo->LastWriteTime;
  1423. }
  1424. pFFindDD->dwFileSizeLow = DirInfo->EndOfFile.LowPart;
  1425. pFFindDD->uchFileAttributes = (UCHAR)DirInfo->FileAttributes;
  1426. // Save File Name, Index for restarting searches
  1427. pFFindDD->FileIndex = DirInfo->FileIndex;
  1428. pFFindDD->FileNameLength = DirInfo->FileNameLength;
  1429. RtlCopyMemory(pFFindDD->FileName,
  1430. DirInfo->FileName,
  1431. DirInfo->FileNameLength
  1432. );
  1433. pFFindDD->FileName[DirInfo->FileNameLength >> 1] = UNICODE_NULL;
  1434. return TRUE;
  1435. }
  1436. HANDLE
  1437. FileFindFirstDevice(
  1438. PWCHAR FileName,
  1439. PFILE_BOTH_DIR_INFORMATION DirectoryInfo
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. Determines if the FileName is a device, and copies out the
  1444. device name found if it is.
  1445. Arguments:
  1446. FileName - Supplies the device name of the file to find.
  1447. pQueryDirInfo - On a successful find, this parameter returns information
  1448. about the located file.
  1449. Return Value:
  1450. --*/
  1451. {
  1452. ULONG DeviceNameData;
  1453. PWSTR DeviceName;
  1454. DeviceNameData = RtlIsDosDeviceName_U(FileName);
  1455. if (DeviceNameData) {
  1456. RtlZeroMemory(DirectoryInfo, sizeof(FILE_BOTH_DIR_INFORMATION));
  1457. DirectoryInfo->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
  1458. DeviceName = (PWSTR)((ULONG)FileName + (DeviceNameData >> 16));
  1459. DeviceNameData &= 0xffff;
  1460. DirectoryInfo->FileNameLength = DeviceNameData;
  1461. DirectoryInfo->ShortNameLength = (CCHAR)DeviceNameData;
  1462. RtlCopyMemory(DirectoryInfo->FileName,
  1463. DeviceName,
  1464. DeviceNameData
  1465. );
  1466. RtlCopyMemory(DirectoryInfo->ShortName,
  1467. DeviceName,
  1468. DeviceNameData
  1469. );
  1470. return FINDFILE_DEVICE;
  1471. }
  1472. return NULL;
  1473. }
  1474. /* FillFcbVolume - fill Volume info in the FCB
  1475. *
  1476. * Entry - pSrchBuf FCB Search buffer to be filled in
  1477. * FileName File Name (interesting part is the drive letter)
  1478. *
  1479. * Exit - SUCCESS
  1480. * Client (CF) - 0
  1481. * pSrchBuf is filled with volume info
  1482. *
  1483. * FAILURE
  1484. * Client (CF) - 1
  1485. * Client (AX) = Error Code
  1486. */
  1487. VOID
  1488. FillFcbVolume(
  1489. PSRCHBUF pSrchBuf,
  1490. CHAR *pFileName,
  1491. USHORT SearchAttr
  1492. )
  1493. {
  1494. CHAR *pch;
  1495. PDIRENT pDirEnt = &pSrchBuf->DirEnt;
  1496. CHAR FullPathBuffer[MAX_PATH];
  1497. CHAR achBaseName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.', and null
  1498. CHAR achVolumeName[NT_VOLUME_NAME_SIZE];
  1499. //
  1500. // form a path without base name
  1501. // this makes sure only on root directory will get the
  1502. // volume label(the GetVolumeInformationOem will fail
  1503. // if the given path is not root directory)
  1504. //
  1505. strcpy(FullPathBuffer, pFileName);
  1506. pch = strrchr(FullPathBuffer, '\\');
  1507. if (pch) {
  1508. pch++;
  1509. // truncate to dos file name length (including period)
  1510. pch[DOS_VOLUME_NAME_SIZE + 1] = '\0';
  1511. strcpy(achBaseName, pch);
  1512. #ifdef DBCS
  1513. #if defined(NEC_98)
  1514. // BUG fix for DBCS small alphabet converted to large it.
  1515. demCharUpper(achBaseName);
  1516. #else // !NEC_98
  1517. CharUpper(achBaseName);
  1518. #endif // !NEC_98
  1519. #else // !DBCS
  1520. _strupr(achBaseName);
  1521. #endif // !DBCS
  1522. *pch = '\0';
  1523. }
  1524. else {
  1525. achBaseName[0] = '\0';
  1526. }
  1527. //
  1528. // if searching for volume only the DOS uses first 3 letters for
  1529. // root drive path ignoring the rest of the path
  1530. // as long as the full pathname is valid.
  1531. //
  1532. if (SearchAttr == ATTR_VOLUME_ID &&
  1533. (pch = strchr(FullPathBuffer, '\\')) &&
  1534. GetFileAttributes(FullPathBuffer) != 0xffffffff )
  1535. {
  1536. pch++;
  1537. *pch = '\0';
  1538. strcpy(achBaseName, szStartDotStar);
  1539. }
  1540. if (GetVolumeInformationOem(FullPathBuffer,
  1541. achVolumeName,
  1542. NT_VOLUME_NAME_SIZE,
  1543. NULL,
  1544. NULL,
  1545. NULL,
  1546. NULL,
  1547. 0) == FALSE)
  1548. {
  1549. demClientError(INVALID_HANDLE_VALUE, *pFileName);
  1550. return;
  1551. }
  1552. // truncate to dos volumen max size (no period)
  1553. achVolumeName[DOS_VOLUME_NAME_SIZE] = '\0';
  1554. if (!achVolumeName[0] || !MatchVolLabel(achVolumeName, achBaseName)) {
  1555. SetLastError(ERROR_NO_MORE_FILES);
  1556. demClientError(INVALID_HANDLE_VALUE, *pFileName);
  1557. return;
  1558. }
  1559. // warning !!! this assumes the FileExt follows FileName immediately
  1560. memset(pSrchBuf->FileName, ' ', DOS_VOLUME_NAME_SIZE);
  1561. strncpy(pSrchBuf->FileName, achVolumeName, strlen(achVolumeName));
  1562. // Now copy the directory entry
  1563. strncpy(pDirEnt->FileName,pSrchBuf->FileName,8);
  1564. strncpy(pDirEnt->FileExt,pSrchBuf->FileExt,3);
  1565. setCF (0);
  1566. return;
  1567. }
  1568. /* FillDtaVolume - fill Volume info in the DTA
  1569. *
  1570. * Entry - CHAR lpSearchName - name to match with volume name
  1571. *
  1572. *
  1573. * Exit - SUCCESS
  1574. * Returns - TRUE
  1575. * pSrchBuf is filled with volume info
  1576. *
  1577. * FAILURE
  1578. * Returns - FALSE
  1579. * sets last error code
  1580. */
  1581. BOOL FillDtaVolume(
  1582. CHAR *pFileName,
  1583. PSRCHDTA pDta,
  1584. USHORT SearchAttr
  1585. )
  1586. {
  1587. CHAR *pch;
  1588. CHAR FullPathBuffer[MAX_PATH];
  1589. CHAR achBaseName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.' and null
  1590. CHAR achVolumeName[NT_VOLUME_NAME_SIZE];
  1591. //
  1592. // form a path without base name
  1593. // this makes sure only on root directory will get the
  1594. // volume label(the GetVolumeInformationOem will fail
  1595. // if the given path is not root directory)
  1596. //
  1597. strcpy(FullPathBuffer, pFileName);
  1598. pch = strrchr(FullPathBuffer, '\\');
  1599. if (pch) {
  1600. pch++;
  1601. pch[DOS_VOLUME_NAME_SIZE + 1] = '\0'; // max len (including period)
  1602. strcpy(achBaseName, pch);
  1603. #ifdef DBCS
  1604. #if defined(NEC_98)
  1605. // BUG fix for DBCS small alphabet converted to large it.
  1606. demCharUpper(achBaseName);
  1607. #else // !NEC_98
  1608. CharUpper(achBaseName);
  1609. #endif // !NEC_98
  1610. #else // !DBCS
  1611. _strupr(achBaseName);
  1612. #endif // !DBCS
  1613. *pch = '\0';
  1614. }
  1615. else {
  1616. achBaseName[0] = '\0';
  1617. }
  1618. //
  1619. // if searching for volume only the DOS uses first 3 letters for
  1620. // root drive path ignoring the rest of the path, if there is no basename assume *.*
  1621. //
  1622. if (SearchAttr == ATTR_VOLUME_ID &&
  1623. (pch = strchr(FullPathBuffer, '\\')) &&
  1624. GetFileAttributes(FullPathBuffer) != 0xffffffff )
  1625. {
  1626. pch++;
  1627. if(!*pch) {
  1628. strcpy(achBaseName, szStartDotStar);
  1629. }
  1630. *pch = '\0';
  1631. }
  1632. if (GetVolumeInformationOem(FullPathBuffer,
  1633. achVolumeName,
  1634. NT_VOLUME_NAME_SIZE,
  1635. NULL,
  1636. NULL,
  1637. NULL,
  1638. NULL,
  1639. 0) == FALSE)
  1640. {
  1641. return FALSE;
  1642. }
  1643. // truncate to dos file name length (no period)
  1644. achVolumeName[DOS_VOLUME_NAME_SIZE] = '\0';
  1645. if (!achVolumeName[0] || !MatchVolLabel(achVolumeName, achBaseName)) {
  1646. SetLastError(ERROR_NO_MORE_FILES);
  1647. return FALSE;
  1648. }
  1649. //
  1650. // DOS Dta search returns volume label in 8.3 format. But if label is
  1651. // more than 8 characters long than NT just returns that as it is
  1652. // without adding a ".". So here we have to add a "." in volume
  1653. // labels, if needed. But note that FCB based volume search does'nt
  1654. // add the "." So nothing need to be done there.
  1655. //
  1656. NtVolumeNameToDosVolumeName(pDta->achFileName, achVolumeName);
  1657. pDta->uchFileAttr = ATTR_VOLUME_ID;
  1658. STOREWORD(pDta->usLowSize,0);
  1659. STOREWORD(pDta->usHighSize,0);
  1660. // Zero out dates as we can not fetch dates for volume labels.
  1661. STOREWORD(pDta->usTimeLastWrite,0);
  1662. STOREWORD(pDta->usDateLastWrite,0);
  1663. return TRUE;
  1664. }
  1665. /*
  1666. * MatchVolLabel
  1667. * Does a string compare to see if the vol label matches
  1668. * a FAT search string. The search string is expected to
  1669. * have the '*' character already expanded into '?' characters.
  1670. *
  1671. * WARNING: maintanes dos5.0 quirk of not caring about characters past
  1672. * the defined len of each part of the vol label.
  1673. * 12345678.123
  1674. * ^ ^
  1675. *
  1676. * foovol foovol1 (srch string)
  1677. * foo.vol foo.vol1 (srch string)
  1678. *
  1679. * entry: CHAR *pVol -- NT volume name
  1680. * CHAR *pSrch -- dos volume name
  1681. *
  1682. * exit: TRUE for a match
  1683. */
  1684. BOOL MatchVolLabel(CHAR *pVol, CHAR *pSrch )
  1685. {
  1686. WORD w;
  1687. CHAR achDosVolumeName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.' and null
  1688. NtVolumeNameToDosVolumeName(achDosVolumeName, pVol);
  1689. pVol = achDosVolumeName;
  1690. w = 8;
  1691. while (w--) {
  1692. if (*pVol == *pSrch) {
  1693. if (!*pVol && !*pSrch)
  1694. return TRUE;
  1695. }
  1696. else if (*pSrch == '.') {
  1697. if (*pVol)
  1698. return FALSE;
  1699. }
  1700. else if (*pSrch != '?') {
  1701. return FALSE;
  1702. }
  1703. // move on to the next character
  1704. // but not past second component part
  1705. if (*pVol && *pVol != '.')
  1706. pVol++;
  1707. if (*pSrch && *pSrch != '.')
  1708. pSrch++;
  1709. }
  1710. // skip trailing part of search string, in the first comp
  1711. while (*pSrch && *pSrch != '.')
  1712. pSrch++;
  1713. w = 4;
  1714. while (w--) {
  1715. if (*pVol == *pSrch) {
  1716. if (!*pVol && !*pSrch)
  1717. return TRUE;
  1718. }
  1719. else if (*pSrch == '.') {
  1720. if (*pVol)
  1721. return FALSE;
  1722. }
  1723. else if (*pSrch != '?') {
  1724. return FALSE;
  1725. }
  1726. // move on to the next character
  1727. if (*pVol)
  1728. pVol++;
  1729. if (*pSrch)
  1730. pSrch++;
  1731. }
  1732. return TRUE;
  1733. }
  1734. VOID NtVolumeNameToDosVolumeName(CHAR * pDosName, CHAR * pNtName)
  1735. {
  1736. char NtNameBuffer[NT_VOLUME_NAME_SIZE];
  1737. int i;
  1738. char char8, char9, char10;
  1739. // make a local copy so that the caller can use the same
  1740. // buffer
  1741. strcpy(NtNameBuffer, pNtName);
  1742. if (strlen(NtNameBuffer) > 8) {
  1743. char8 = NtNameBuffer[8];
  1744. char9 = NtNameBuffer[9];
  1745. char10 = NtNameBuffer[10];
  1746. // eat spaces from first 8 characters
  1747. i = 7;
  1748. while (NtNameBuffer[i] == ' ')
  1749. i--;
  1750. NtNameBuffer[i+1] = '.';
  1751. NtNameBuffer[i+2] = char8;
  1752. NtNameBuffer[i+3] = char9;
  1753. NtNameBuffer[i+4] = char10;
  1754. NtNameBuffer[i+5] = '\0';
  1755. }
  1756. strcpy(pDosName, NtNameBuffer);
  1757. }
  1758. /* FillFCBSrchBuf - Fill the FCB Search buffer.
  1759. *
  1760. * Entry - pSrchBuf FCB Search buffer to be filled in
  1761. * hFind Search Handle
  1762. * fFirst TRUE if call from FindFirstFCB
  1763. *
  1764. * Exit - None (pSrchBuf filled in)
  1765. *
  1766. */
  1767. VOID FillFCBSrchBuf(
  1768. PFFINDDOSDATA pFFindDD,
  1769. PSRCHBUF pSrchBuf,
  1770. BOOL IsOnCD)
  1771. {
  1772. PDIRENT pDirEnt = &pSrchBuf->DirEnt;
  1773. PCHAR pDot;
  1774. USHORT usDate,usTime,i;
  1775. FILETIME ftLocal;
  1776. #if DBG
  1777. if (fShowSVCMsg & DEMFILIO) {
  1778. sprintf(demDebugBuffer, "FillFCBSrchBuf<%s>\n", pFFindDD->cFileName);
  1779. OutputDebugStringOem(demDebugBuffer);
  1780. }
  1781. #endif
  1782. // Copy file name (Max Name = 8 and Max ext = 3)
  1783. if ((pDot = strchr(pFFindDD->cFileName,'.')) == NULL) {
  1784. strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8);
  1785. _strnset(pSrchBuf->FileExt,'\x020',3);
  1786. }
  1787. else if (pDot == pFFindDD->cFileName) {
  1788. strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8);
  1789. _strnset(pSrchBuf->FileExt,'\x020',3);
  1790. }
  1791. else {
  1792. *pDot = '\0';
  1793. strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8);
  1794. *pDot++ = '\0';
  1795. strncpy(pSrchBuf->FileExt,pDot,3);
  1796. }
  1797. for (i=0;i<8;i++) {
  1798. if (pSrchBuf->FileName[i] == '\0')
  1799. pSrchBuf->FileName[i]='\x020';
  1800. }
  1801. for (i=0;i<3;i++) {
  1802. if (pSrchBuf->FileExt[i] == '\0')
  1803. pSrchBuf->FileExt[i]='\x020';
  1804. }
  1805. STOREWORD(pSrchBuf->usCurBlkNumber,0);
  1806. STOREWORD(pSrchBuf->usRecordSize,0);
  1807. STOREDWORD(pSrchBuf->ulFileSize, pFFindDD->dwFileSizeLow);
  1808. // Convert NT File time/date to DOS time/date
  1809. FileTimeToLocalFileTime (&pFFindDD->ftLastWriteTime,&ftLocal);
  1810. FileTimeToDosDateTime (&ftLocal,
  1811. &usDate,
  1812. &usTime);
  1813. // Now copy the directory entry
  1814. strncpy(pDirEnt->FileName,pSrchBuf->FileName,8);
  1815. strncpy(pDirEnt->FileExt,pSrchBuf->FileExt,3);
  1816. // SudeepB - 28-Jul-1997
  1817. //
  1818. // For CDFS, Win3.1/DOS/Win95, only return FILE_ATTRIBUTE_DIRECTORY (10)
  1819. // for directories while WinNT returns
  1820. // FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY (11).
  1821. // Some VB controls that app setups use, depend on getting
  1822. // FILE_ATTRIBUTE_DIRECTORY (10) only or otherwise are broken.
  1823. // An example of this is Cliffs StudyWare series.
  1824. //
  1825. if (IsOnCD && pFFindDD->uchFileAttributes == (ATTR_DIRECTORY | ATTR_READ_ONLY))
  1826. pDirEnt->uchAttributes = ATTR_DIRECTORY;
  1827. else
  1828. pDirEnt->uchAttributes = pFFindDD->uchFileAttributes;
  1829. STOREWORD(pDirEnt->usTime,usTime);
  1830. STOREWORD(pDirEnt->usDate,usDate);
  1831. STOREDWORD(pDirEnt->ulFileSize,pFFindDD->dwFileSizeLow);
  1832. return;
  1833. }
  1834. /* FillSrchDta - Fill DTA for FIND_FIRST,FIND_NEXT operations.
  1835. *
  1836. * Entry - pW32FindData Buffer containing file data
  1837. * hFind - Handle returned by FindFirstFile
  1838. * PSRCHDTA pDta
  1839. *
  1840. * Exit - None
  1841. *
  1842. * Note : It is guranteed that file name adhers to 8:3 convention.
  1843. * demSrchFile makes sure of that condition.
  1844. *
  1845. */
  1846. VOID
  1847. FillSrchDta(
  1848. PFFINDDOSDATA pFFindDD,
  1849. PSRCHDTA pDta,
  1850. BOOL IsOnCD)
  1851. {
  1852. USHORT usDate,usTime;
  1853. FILETIME ftLocal;
  1854. // SudeepB - 28-Jul-1997
  1855. //
  1856. // For CDFS, Win3.1/DOS/Win95, only return FILE_ATTRIBUTE_DIRECTORY (10)
  1857. // for directories while WinNT returns
  1858. // FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY (11).
  1859. // Some VB controls that app setups use, depend on getting
  1860. // FILE_ATTRIBUTE_DIRECTORY (10) only or otherwise are broken.
  1861. // An example of this is Cliffs StudyWare series.
  1862. //
  1863. if (IsOnCD && pFFindDD->uchFileAttributes == (ATTR_DIRECTORY | ATTR_READ_ONLY))
  1864. pDta->uchFileAttr = ATTR_DIRECTORY;
  1865. else
  1866. pDta->uchFileAttr = pFFindDD->uchFileAttributes;
  1867. // Convert NT File time/date to DOS time/date
  1868. FileTimeToLocalFileTime (&pFFindDD->ftLastWriteTime,&ftLocal);
  1869. FileTimeToDosDateTime (&ftLocal,
  1870. &usDate,
  1871. &usTime);
  1872. STOREWORD(pDta->usTimeLastWrite,usTime);
  1873. STOREWORD(pDta->usDateLastWrite,usDate);
  1874. STOREWORD(pDta->usLowSize,(USHORT)pFFindDD->dwFileSizeLow);
  1875. STOREWORD(pDta->usHighSize,(USHORT)(pFFindDD->dwFileSizeLow >> 16));
  1876. #if DBG
  1877. if (fShowSVCMsg & DEMFILIO) {
  1878. sprintf(demDebugBuffer, "FillSrchDta<%s>\n", pFFindDD->cFileName);
  1879. OutputDebugStringOem(demDebugBuffer);
  1880. }
  1881. #endif
  1882. strncpy(pDta->achFileName,pFFindDD->cFileName, 13);
  1883. return;
  1884. }
  1885. VOID demCloseAllPSPRecords (VOID)
  1886. {
  1887. PLIST_ENTRY Next;
  1888. PPSP_FFINDLIST pPspFFindEntry;
  1889. Next = PspFFindHeadList.Flink;
  1890. while (Next != &PspFFindHeadList) {
  1891. pPspFFindEntry = CONTAINING_RECORD(Next,PSP_FFINDLIST,PspFFindEntry);
  1892. FreeFFindList( &pPspFFindEntry->FFindHeadList);
  1893. Next= Next->Flink;
  1894. RemoveEntryList(&pPspFFindEntry->PspFFindEntry);
  1895. free(pPspFFindEntry);
  1896. }
  1897. }
  1898. void
  1899. DemHeartBeat(void)
  1900. {
  1901. PLIST_ENTRY Next;
  1902. PLIST_ENTRY pFFindHeadList;
  1903. PPSP_FFINDLIST pPspFFindEntry;
  1904. PFFINDLIST pFFindEntry;
  1905. if (!NumFindBuffer ||
  1906. NextFindFileTics.QuadPart > ++FindFileTics.QuadPart)
  1907. {
  1908. return;
  1909. }
  1910. pPspFFindEntry = GetPspFFindList(FETCHWORD(pusCurrentPDB[0]));
  1911. if (!pPspFFindEntry) {
  1912. return;
  1913. }
  1914. pFFindHeadList = &pPspFFindEntry->FFindHeadList;
  1915. Next = pFFindHeadList->Blink;
  1916. while (Next != pFFindHeadList) {
  1917. pFFindEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry);
  1918. if (pFFindEntry->FindFileTics.QuadPart) {
  1919. if (pFFindEntry->FindFileTics.QuadPart <= FindFileTics.QuadPart) {
  1920. FileFindClose(pFFindEntry);
  1921. }
  1922. else {
  1923. NextFindFileTics.QuadPart = pFFindEntry->FindFileTics.QuadPart;
  1924. return;
  1925. }
  1926. }
  1927. Next = Next->Blink;
  1928. }
  1929. NextFindFileTics.QuadPart = 0;
  1930. FindFileTics.QuadPart = 0;
  1931. }
  1932. //
  1933. // CloseOldestFileFindBuffer
  1934. // walks the psp file find list backwards to find the oldest
  1935. // entry with FindBuffers, directory handles and closes it.
  1936. //
  1937. void
  1938. CloseOldestFileFindBuffer(
  1939. void
  1940. )
  1941. {
  1942. PLIST_ENTRY Next, NextPsp;
  1943. PLIST_ENTRY pFFindHeadList;
  1944. PPSP_FFINDLIST pPspFFindEntry;
  1945. PFFINDLIST pFFEntry;
  1946. NextPsp = PspFFindHeadList.Blink;
  1947. while (NextPsp != &PspFFindHeadList) {
  1948. pPspFFindEntry = CONTAINING_RECORD(NextPsp,PSP_FFINDLIST,PspFFindEntry);
  1949. pFFindHeadList = &pPspFFindEntry->FFindHeadList;
  1950. Next = pFFindHeadList->Blink;
  1951. while (Next != pFFindHeadList) {
  1952. pFFEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry);
  1953. if (NumFindBuffer >= MAX_FINDBUFFER) {
  1954. FileFindClose(pFFEntry);
  1955. }
  1956. else if (pFFEntry->DirectoryHandle &&
  1957. NumDirectoryHandle >= MAX_DIRECTORYHANDLE)
  1958. {
  1959. NumDirectoryHandle--;
  1960. NtClose(pFFEntry->DirectoryHandle);
  1961. pFFEntry->DirectoryHandle = 0;
  1962. }
  1963. if (NumFindBuffer < MAX_FINDBUFFER &&
  1964. NumDirectoryHandle < MAX_DIRECTORYHANDLE)
  1965. {
  1966. return;
  1967. }
  1968. Next = Next->Blink;
  1969. }
  1970. NextPsp= NextPsp->Blink;
  1971. }
  1972. }
  1973. /*
  1974. * GetFFindEntryByFindId
  1975. */
  1976. PFFINDLIST GetFFindEntryByFindId(ULONG NextFFindId)
  1977. {
  1978. PLIST_ENTRY NextPsp;
  1979. PLIST_ENTRY Next;
  1980. PPSP_FFINDLIST pPspFFindEntry;
  1981. PFFINDLIST pFFindEntry;
  1982. PLIST_ENTRY pFFindHeadList;
  1983. NextPsp = PspFFindHeadList.Flink;
  1984. while (NextPsp != &PspFFindHeadList) {
  1985. pPspFFindEntry = CONTAINING_RECORD(NextPsp,PSP_FFINDLIST,PspFFindEntry);
  1986. pFFindHeadList = &pPspFFindEntry->FFindHeadList;
  1987. Next = pFFindHeadList->Flink;
  1988. while (Next != pFFindHeadList) {
  1989. pFFindEntry = CONTAINING_RECORD(Next, FFINDLIST, FFindEntry);
  1990. if (pFFindEntry->FFindId == NextFFindId) {
  1991. return pFFindEntry;
  1992. }
  1993. Next= Next->Flink;
  1994. }
  1995. NextPsp= NextPsp->Flink;
  1996. }
  1997. return NULL;
  1998. }
  1999. /* AddFFindEntry - Adds a new File Find entry to the current
  2000. * PSP's PspFileFindList
  2001. *
  2002. * Entry -
  2003. *
  2004. * Exit - PFFINDLIST pFFindList;
  2005. */
  2006. PFFINDLIST
  2007. AddFFindEntry(
  2008. PWCHAR pwcFile,
  2009. PFFINDLIST pFFindEntrySrc
  2010. )
  2011. {
  2012. PPSP_FFINDLIST pPspFFindEntry;
  2013. PFFINDLIST pFFindEntry;
  2014. ULONG Len;
  2015. pPspFFindEntry = GetPspFFindList(FETCHWORD(pusCurrentPDB[0]));
  2016. //
  2017. // if a Psp entry doesn't exist
  2018. // Allocate one, initialize it and insert it into the list
  2019. //
  2020. if (!pPspFFindEntry) {
  2021. pPspFFindEntry = (PPSP_FFINDLIST) malloc(sizeof(PSP_FFINDLIST));
  2022. if (!pPspFFindEntry)
  2023. return NULL;
  2024. pPspFFindEntry->usPsp = FETCHWORD(pusCurrentPDB[0]);
  2025. InitializeListHead(&pPspFFindEntry->FFindHeadList);
  2026. InsertHeadList(&PspFFindHeadList, &pPspFFindEntry->PspFFindEntry);
  2027. }
  2028. //
  2029. // Create the FileFindEntry and add to the FileFind list
  2030. //
  2031. pFFindEntry = (PFFINDLIST) malloc(sizeof(FFINDLIST));
  2032. if (!pFFindEntry) {
  2033. return pFFindEntry;
  2034. }
  2035. //
  2036. // Fill in FFindList
  2037. //
  2038. *pFFindEntry = *pFFindEntrySrc;
  2039. //
  2040. // Insert at the head of this psp list
  2041. //
  2042. InsertHeadList(&pPspFFindEntry->FFindHeadList, &pFFindEntry->FFindEntry);
  2043. return pFFindEntry;
  2044. }
  2045. /* FreeFFindEntry
  2046. *
  2047. * Entry - PFFINDLIST pFFindEntry
  2048. *
  2049. * Exit - None
  2050. *
  2051. */
  2052. VOID FreeFFindEntry(PFFINDLIST pFFindEntry)
  2053. {
  2054. RemoveEntryList(&pFFindEntry->FFindEntry);
  2055. FileFindClose(pFFindEntry);
  2056. RtlFreeUnicodeString(&pFFindEntry->FileName);
  2057. RtlFreeUnicodeString(&pFFindEntry->PathName);
  2058. free(pFFindEntry);
  2059. return;
  2060. }
  2061. /* FreeFFindList
  2062. *
  2063. * Entry - Frees the entire list
  2064. *
  2065. * Exit - None
  2066. *
  2067. */
  2068. VOID FreeFFindList(PLIST_ENTRY pFFindHeadList)
  2069. {
  2070. PLIST_ENTRY Next;
  2071. PFFINDLIST pFFindEntry;
  2072. Next = pFFindHeadList->Flink;
  2073. while (Next != pFFindHeadList) {
  2074. pFFindEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry);
  2075. Next= Next->Flink;
  2076. FreeFFindEntry(pFFindEntry);
  2077. }
  2078. return;
  2079. }
  2080. /* GetPspFFindList
  2081. *
  2082. * Entry - USHORT CurrPsp
  2083. *
  2084. * Exit - Success - PPSP_FFINDLIST
  2085. * Failure - NULL
  2086. *
  2087. */
  2088. PPSP_FFINDLIST GetPspFFindList(USHORT CurrPsp)
  2089. {
  2090. PLIST_ENTRY Next;
  2091. PPSP_FFINDLIST pPspFFindEntry;
  2092. Next = PspFFindHeadList.Flink;
  2093. while (Next != &PspFFindHeadList) {
  2094. pPspFFindEntry = CONTAINING_RECORD(Next,PSP_FFINDLIST,PspFFindEntry);
  2095. if (CurrPsp == pPspFFindEntry->usPsp) {
  2096. return pPspFFindEntry;
  2097. }
  2098. Next= Next->Flink;
  2099. }
  2100. return NULL;
  2101. }
  2102. #if defined(NEC_98)
  2103. // BUG fix for DBCS small alphabet in file name converted to large it.
  2104. extern int dbcs_first[];
  2105. void demCharUpper(char * pszStr)
  2106. {
  2107. for(;*pszStr;)
  2108. {
  2109. if(dbcs_first[*pszStr&0xFF])
  2110. {
  2111. pszStr++;
  2112. if(*pszStr == '\0')
  2113. break;
  2114. }
  2115. else
  2116. {
  2117. if(*pszStr >= 'a' && *pszStr <= 'z')
  2118. *pszStr -= 0x20;
  2119. }
  2120. pszStr++;
  2121. }
  2122. }
  2123. #endif // NEC_98