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.

1723 lines
54 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. filefind.c
  5. Abstract:
  6. This module implements Win32 FindFirst/FindNext
  7. Author:
  8. Mark Lucovsky (markl) 26-Sep-1990
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. VOID
  13. WINAPI
  14. BasepIoCompletion(
  15. PVOID ApcContext,
  16. PIO_STATUS_BLOCK IoStatusBlock,
  17. DWORD Reserved
  18. );
  19. VOID
  20. WINAPI
  21. BasepIoCompletionSimple(
  22. PVOID ApcContext,
  23. PIO_STATUS_BLOCK IoStatusBlock,
  24. DWORD Reserved
  25. );
  26. #define FIND_BUFFER_SIZE 4096
  27. PFINDFILE_HANDLE
  28. BasepInitializeFindFileHandle(
  29. IN HANDLE DirectoryHandle
  30. )
  31. {
  32. PFINDFILE_HANDLE FindFileHandle;
  33. FindFileHandle = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( FIND_TAG ), sizeof(*FindFileHandle));
  34. if ( FindFileHandle ) {
  35. FindFileHandle->DirectoryHandle = DirectoryHandle;
  36. FindFileHandle->FindBufferBase = NULL;
  37. FindFileHandle->FindBufferNext = NULL;
  38. FindFileHandle->FindBufferLength = 0;
  39. FindFileHandle->FindBufferValidLength = 0;
  40. if ( !NT_SUCCESS(RtlInitializeCriticalSection(&FindFileHandle->FindBufferLock)) ){
  41. RtlFreeHeap(RtlProcessHeap(), 0,FindFileHandle);
  42. FindFileHandle = NULL;
  43. }
  44. }
  45. return FindFileHandle;
  46. }
  47. HANDLE
  48. APIENTRY
  49. FindFirstFileA(
  50. LPCSTR lpFileName,
  51. LPWIN32_FIND_DATAA lpFindFileData
  52. )
  53. /*++
  54. Routine Description:
  55. ANSI thunk to FindFirstFileW
  56. --*/
  57. {
  58. HANDLE ReturnValue;
  59. PUNICODE_STRING Unicode;
  60. NTSTATUS Status;
  61. UNICODE_STRING UnicodeString;
  62. WIN32_FIND_DATAW FindFileData;
  63. ANSI_STRING AnsiString;
  64. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  65. if (Unicode == NULL) {
  66. return INVALID_HANDLE_VALUE;
  67. }
  68. ReturnValue = FindFirstFileExW(
  69. (LPCWSTR)Unicode->Buffer,
  70. FindExInfoStandard,
  71. &FindFileData,
  72. FindExSearchNameMatch,
  73. NULL,
  74. 0
  75. );
  76. if ( ReturnValue == INVALID_HANDLE_VALUE ) {
  77. return ReturnValue;
  78. }
  79. RtlMoveMemory(
  80. lpFindFileData,
  81. &FindFileData,
  82. (ULONG_PTR)&FindFileData.cFileName[0] - (ULONG_PTR)&FindFileData
  83. );
  84. RtlInitUnicodeString(&UnicodeString,(PWSTR)FindFileData.cFileName);
  85. AnsiString.Buffer = lpFindFileData->cFileName;
  86. AnsiString.MaximumLength = MAX_PATH;
  87. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  88. if (NT_SUCCESS(Status)) {
  89. RtlInitUnicodeString(&UnicodeString,(PWSTR)FindFileData.cAlternateFileName);
  90. AnsiString.Buffer = lpFindFileData->cAlternateFileName;
  91. AnsiString.MaximumLength = 14;
  92. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  93. }
  94. if ( !NT_SUCCESS(Status) ) {
  95. FindClose(ReturnValue);
  96. BaseSetLastNTError(Status);
  97. return INVALID_HANDLE_VALUE;
  98. }
  99. return ReturnValue;
  100. }
  101. HANDLE
  102. APIENTRY
  103. FindFirstFileW(
  104. LPCWSTR lpFileName,
  105. LPWIN32_FIND_DATAW lpFindFileData
  106. )
  107. /*++
  108. Routine Description:
  109. A directory can be searched for the first entry whose name and
  110. attributes match the specified name using FindFirstFile.
  111. This API is provided to open a find file handle and return
  112. information about the first file whose name match the specified
  113. pattern. Once established, the find file handle can be used to
  114. search for other files that match the same pattern. When the find
  115. file handle is no longer needed, it should be closed.
  116. Note that while this interface only returns information for a single
  117. file, an implementation is free to buffer several matching files
  118. that can be used to satisfy subsequent calls to FindNextFile. Also
  119. not that matches are done by name only. This API does not do
  120. attribute based matching.
  121. This API is similar to DOS (int 21h, function 4Eh), and OS/2's
  122. DosFindFirst. For portability reasons, its data structures and
  123. parameter passing is somewhat different.
  124. Arguments:
  125. lpFileName - Supplies the file name of the file to find. The file name
  126. may contain the DOS wild card characters '*' and '?'.
  127. lpFindFileData - On a successful find, this parameter returns information
  128. about the located file:
  129. WIN32_FIND_DATA Structure:
  130. DWORD dwFileAttributes - Returns the file attributes of the found
  131. file.
  132. FILETIME ftCreationTime - Returns the time that the file was created.
  133. A value of 0,0 specifies that the file system containing the
  134. file does not support this time field.
  135. FILETIME ftLastAccessTime - Returns the time that the file was last
  136. accessed. A value of 0,0 specifies that the file system
  137. containing the file does not support this time field.
  138. FILETIME ftLastWriteTime - Returns the time that the file was last
  139. written. A file systems support this time field.
  140. DWORD nFileSizeHigh - Returns the high order 32 bits of the
  141. file's size.
  142. DWORD nFileSizeLow - Returns the low order 32-bits of the file's
  143. size in bytes.
  144. UCHAR cFileName[MAX_PATH] - Returns the null terminated name of
  145. the file.
  146. Return Value:
  147. Not -1 - Returns a find first handle
  148. that can be used in a subsequent call to FindNextFile or FindClose.
  149. 0xffffffff - The operation failed. Extended error status is available
  150. using GetLastError.
  151. --*/
  152. {
  153. return FindFirstFileExW(
  154. lpFileName,
  155. FindExInfoStandard,
  156. lpFindFileData,
  157. FindExSearchNameMatch,
  158. NULL,
  159. 0
  160. );
  161. }
  162. BOOL
  163. APIENTRY
  164. FindNextFileA(
  165. HANDLE hFindFile,
  166. LPWIN32_FIND_DATAA lpFindFileData
  167. )
  168. /*++
  169. Routine Description:
  170. ANSI thunk to FindFileDataW
  171. --*/
  172. {
  173. BOOL ReturnValue;
  174. ANSI_STRING AnsiString;
  175. NTSTATUS Status;
  176. UNICODE_STRING UnicodeString;
  177. WIN32_FIND_DATAW FindFileData;
  178. ReturnValue = FindNextFileW(hFindFile,&FindFileData);
  179. if ( !ReturnValue ) {
  180. return ReturnValue;
  181. }
  182. RtlMoveMemory(
  183. lpFindFileData,
  184. &FindFileData,
  185. (ULONG_PTR)&FindFileData.cFileName[0] - (ULONG_PTR)&FindFileData
  186. );
  187. RtlInitUnicodeString(&UnicodeString,(PWSTR)FindFileData.cFileName);
  188. AnsiString.Buffer = lpFindFileData->cFileName;
  189. AnsiString.MaximumLength = MAX_PATH;
  190. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  191. if (NT_SUCCESS(Status)) {
  192. RtlInitUnicodeString(&UnicodeString,(PWSTR)FindFileData.cAlternateFileName);
  193. AnsiString.Buffer = lpFindFileData->cAlternateFileName;
  194. AnsiString.MaximumLength = 14;
  195. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  196. }
  197. if ( !NT_SUCCESS(Status) ) {
  198. BaseSetLastNTError(Status);
  199. return FALSE;
  200. }
  201. return ReturnValue;
  202. }
  203. BOOL
  204. APIENTRY
  205. FindNextFileW(
  206. HANDLE hFindFile,
  207. LPWIN32_FIND_DATAW lpFindFileData
  208. )
  209. /*++
  210. Routine Description:
  211. Once a successful call has been made to FindFirstFile, subsequent
  212. matching files can be located using FindNextFile.
  213. This API is used to continue a file search from a previous call to
  214. FindFirstFile. This API returns successfully with the next file
  215. that matches the search pattern established in the original
  216. FindFirstFile call. If no file match can be found NO_MORE_FILES is
  217. returned.
  218. Note that while this interface only returns information for a single
  219. file, an implementation is free to buffer several matching files
  220. that can be used to satisfy subsequent calls to FindNextFile. Also
  221. not that matches are done by name only. This API does not do
  222. attribute based matching.
  223. This API is similar to DOS (int 21h, function 4Fh), and OS/2's
  224. DosFindNext. For portability reasons, its data structures and
  225. parameter passing is somewhat different.
  226. Arguments:
  227. hFindFile - Supplies a find file handle returned in a previous call
  228. to FindFirstFile.
  229. lpFindFileData - On a successful find, this parameter returns information
  230. about the located file.
  231. Return Value:
  232. TRUE - The operation was successful.
  233. FALSE/NULL - The operation failed. Extended error status is available
  234. using GetLastError.
  235. --*/
  236. {
  237. NTSTATUS Status;
  238. IO_STATUS_BLOCK IoStatusBlock;
  239. PFINDFILE_HANDLE FindFileHandle;
  240. BOOL ReturnValue;
  241. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  242. if ( hFindFile == BASE_FIND_FIRST_DEVICE_HANDLE ) {
  243. BaseSetLastNTError(STATUS_NO_MORE_FILES);
  244. return FALSE;
  245. }
  246. if ( hFindFile == INVALID_HANDLE_VALUE ) {
  247. SetLastError(ERROR_INVALID_HANDLE);
  248. return FALSE;
  249. }
  250. ReturnValue = TRUE;
  251. FindFileHandle = (PFINDFILE_HANDLE)hFindFile;
  252. RtlEnterCriticalSection(&FindFileHandle->FindBufferLock);
  253. try {
  254. //
  255. // If we haven't called find next yet, then
  256. // allocate the find buffer.
  257. //
  258. if ( !FindFileHandle->FindBufferBase ) {
  259. FindFileHandle->FindBufferBase = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( FIND_TAG ), FIND_BUFFER_SIZE);
  260. if (FindFileHandle->FindBufferBase) {
  261. FindFileHandle->FindBufferNext = FindFileHandle->FindBufferBase;
  262. FindFileHandle->FindBufferLength = FIND_BUFFER_SIZE;
  263. FindFileHandle->FindBufferValidLength = 0;
  264. }
  265. else {
  266. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  267. ReturnValue = FALSE;
  268. goto leavefinally;
  269. }
  270. }
  271. //
  272. // Test to see if there is no data in the find file buffer
  273. //
  274. DirectoryInfo = (PFILE_BOTH_DIR_INFORMATION)FindFileHandle->FindBufferNext;
  275. if ( FindFileHandle->FindBufferBase == (PVOID)DirectoryInfo ) {
  276. Status = NtQueryDirectoryFile(
  277. FindFileHandle->DirectoryHandle,
  278. NULL,
  279. NULL,
  280. NULL,
  281. &IoStatusBlock,
  282. DirectoryInfo,
  283. FindFileHandle->FindBufferLength,
  284. FileBothDirectoryInformation,
  285. FALSE,
  286. NULL,
  287. FALSE
  288. );
  289. //
  290. // ***** Do a kludge hack fix for now *****
  291. //
  292. // Forget about the last, partial, entry.
  293. //
  294. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  295. PULONG Ptr;
  296. PULONG PriorPtr;
  297. Ptr = (PULONG)DirectoryInfo;
  298. PriorPtr = NULL;
  299. while ( *Ptr != 0 ) {
  300. PriorPtr = Ptr;
  301. Ptr += (*Ptr / sizeof(ULONG));
  302. }
  303. if (PriorPtr != NULL) { *PriorPtr = 0; }
  304. Status = STATUS_SUCCESS;
  305. }
  306. if ( !NT_SUCCESS(Status) ) {
  307. BaseSetLastNTError(Status);
  308. ReturnValue = FALSE;
  309. goto leavefinally;
  310. }
  311. }
  312. if ( DirectoryInfo->NextEntryOffset ) {
  313. FindFileHandle->FindBufferNext = (PVOID)(
  314. (PUCHAR)DirectoryInfo + DirectoryInfo->NextEntryOffset);
  315. }
  316. else {
  317. FindFileHandle->FindBufferNext = FindFileHandle->FindBufferBase;
  318. }
  319. //
  320. // Attributes are composed of the attributes returned by NT.
  321. //
  322. lpFindFileData->dwFileAttributes = DirectoryInfo->FileAttributes;
  323. lpFindFileData->ftCreationTime = *(LPFILETIME)&DirectoryInfo->CreationTime;
  324. lpFindFileData->ftLastAccessTime = *(LPFILETIME)&DirectoryInfo->LastAccessTime;
  325. lpFindFileData->ftLastWriteTime = *(LPFILETIME)&DirectoryInfo->LastWriteTime;
  326. lpFindFileData->nFileSizeHigh = DirectoryInfo->EndOfFile.HighPart;
  327. lpFindFileData->nFileSizeLow = DirectoryInfo->EndOfFile.LowPart;
  328. RtlMoveMemory( lpFindFileData->cFileName,
  329. DirectoryInfo->FileName,
  330. DirectoryInfo->FileNameLength );
  331. lpFindFileData->cFileName[DirectoryInfo->FileNameLength >> 1] = UNICODE_NULL;
  332. RtlMoveMemory( lpFindFileData->cAlternateFileName,
  333. DirectoryInfo->ShortName,
  334. DirectoryInfo->ShortNameLength );
  335. lpFindFileData->cAlternateFileName[DirectoryInfo->ShortNameLength >> 1] = UNICODE_NULL;
  336. //
  337. // For NTFS reparse points we return the reparse point data tag in dwReserved0.
  338. //
  339. if ( DirectoryInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
  340. lpFindFileData->dwReserved0 = DirectoryInfo->EaSize;
  341. }
  342. leavefinally:;
  343. }
  344. finally{
  345. RtlLeaveCriticalSection(&FindFileHandle->FindBufferLock);
  346. }
  347. return ReturnValue;
  348. }
  349. BOOL
  350. FindClose(
  351. HANDLE hFindFile
  352. )
  353. /*++
  354. Routine Description:
  355. A find file context created by FindFirstFile can be closed using
  356. FindClose.
  357. This API is used to inform the system that a find file handle
  358. created by FindFirstFile is no longer needed. On systems that
  359. maintain internal state for each find file context, this API informs
  360. the system that this state no longer needs to be maintained.
  361. Once this call has been made, the hFindFile may not be used in a
  362. subsequent call to either FindNextFile or FindClose.
  363. This API has no DOS counterpart, but is similar to OS/2's
  364. DosFindClose.
  365. Arguments:
  366. hFindFile - Supplies a find file handle returned in a previous call
  367. to FindFirstFile that is no longer needed.
  368. Return Value:
  369. TRUE - The operation was successful.
  370. FALSE/NULL - The operation failed. Extended error status is available
  371. using GetLastError.
  372. --*/
  373. {
  374. NTSTATUS Status;
  375. PFINDFILE_HANDLE FindFileHandle;
  376. HANDLE DirectoryHandle;
  377. PVOID FindBufferBase;
  378. if ( hFindFile == BASE_FIND_FIRST_DEVICE_HANDLE ) {
  379. return TRUE;
  380. }
  381. if ( hFindFile == INVALID_HANDLE_VALUE ) {
  382. SetLastError(ERROR_INVALID_HANDLE);
  383. return FALSE;
  384. }
  385. try {
  386. FindFileHandle = (PFINDFILE_HANDLE)hFindFile;
  387. RtlEnterCriticalSection(&FindFileHandle->FindBufferLock);
  388. DirectoryHandle = FindFileHandle->DirectoryHandle;
  389. FindBufferBase = FindFileHandle->FindBufferBase;
  390. FindFileHandle->DirectoryHandle = INVALID_HANDLE_VALUE;
  391. FindFileHandle->FindBufferBase = NULL;
  392. RtlLeaveCriticalSection(&FindFileHandle->FindBufferLock);
  393. Status = NtClose(DirectoryHandle);
  394. if ( NT_SUCCESS(Status) ) {
  395. if (FindBufferBase) {
  396. RtlFreeHeap(RtlProcessHeap(), 0,FindBufferBase);
  397. }
  398. RtlDeleteCriticalSection(&FindFileHandle->FindBufferLock);
  399. RtlFreeHeap(RtlProcessHeap(), 0,FindFileHandle);
  400. return TRUE;
  401. }
  402. else {
  403. BaseSetLastNTError(Status);
  404. return FALSE;
  405. }
  406. }
  407. except ( EXCEPTION_EXECUTE_HANDLER ) {
  408. BaseSetLastNTError(GetExceptionCode());
  409. return FALSE;
  410. }
  411. return FALSE;
  412. }
  413. HANDLE
  414. WINAPI
  415. FindFirstFileExA(
  416. LPCSTR lpFileName,
  417. FINDEX_INFO_LEVELS fInfoLevelId,
  418. LPVOID lpFindFileData,
  419. FINDEX_SEARCH_OPS fSearchOp,
  420. LPVOID lpSearchFilter,
  421. DWORD dwAdditionalFlags
  422. )
  423. {
  424. HANDLE ReturnValue;
  425. PUNICODE_STRING Unicode;
  426. NTSTATUS Status;
  427. UNICODE_STRING UnicodeString;
  428. WIN32_FIND_DATAW FindFileData;
  429. LPWIN32_FIND_DATAA lpFindFileDataA;
  430. ANSI_STRING AnsiString;
  431. //
  432. // this code assumes that only FindExInfoStandard is supperted by ExW version
  433. // when more info levels are added, the W->A translation code needs to be modified
  434. //
  435. lpFindFileDataA = (LPWIN32_FIND_DATAA)lpFindFileData;
  436. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  437. if (Unicode == NULL) {
  438. return INVALID_HANDLE_VALUE;
  439. }
  440. ReturnValue = FindFirstFileExW(
  441. (LPCWSTR)Unicode->Buffer,
  442. fInfoLevelId,
  443. (LPVOID)&FindFileData,
  444. fSearchOp,
  445. lpSearchFilter,
  446. dwAdditionalFlags
  447. );
  448. if ( ReturnValue == INVALID_HANDLE_VALUE ) {
  449. return ReturnValue;
  450. }
  451. RtlMoveMemory(
  452. lpFindFileData,
  453. &FindFileData,
  454. (ULONG_PTR)&FindFileData.cFileName[0] - (ULONG_PTR)&FindFileData
  455. );
  456. RtlInitUnicodeString(&UnicodeString,(PWSTR)FindFileData.cFileName);
  457. AnsiString.Buffer = lpFindFileDataA->cFileName;
  458. AnsiString.MaximumLength = MAX_PATH;
  459. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  460. if (NT_SUCCESS(Status)) {
  461. RtlInitUnicodeString(&UnicodeString,(PWSTR)FindFileData.cAlternateFileName);
  462. AnsiString.Buffer = lpFindFileDataA->cAlternateFileName;
  463. AnsiString.MaximumLength = 14;
  464. Status = BasepUnicodeStringTo8BitString(&AnsiString,&UnicodeString,FALSE);
  465. }
  466. if ( !NT_SUCCESS(Status) ) {
  467. FindClose(ReturnValue);
  468. BaseSetLastNTError(Status);
  469. return INVALID_HANDLE_VALUE;
  470. }
  471. return ReturnValue;
  472. }
  473. HANDLE
  474. WINAPI
  475. FindFirstFileExW(
  476. LPCWSTR lpFileName,
  477. FINDEX_INFO_LEVELS fInfoLevelId,
  478. LPVOID lpFindFileData,
  479. FINDEX_SEARCH_OPS fSearchOp,
  480. LPVOID lpSearchFilter,
  481. DWORD dwAdditionalFlags
  482. )
  483. /*++
  484. Routine Description:
  485. A directory can be searched for the first entry whose name and
  486. attributes match the specified name using FindFirstFileEx.
  487. This API is provided to open a find file handle and return
  488. information about the first file whose name matchs the specified
  489. pattern. If the fSearchOp is FindExSearchNameMatch, then that is
  490. the extent of the filtering, and lpSearchFilter MUST be NULL.
  491. Otherwise, additional subfiltering is done depending on this value.
  492. FindExSearchLimitToDirectories - If this search op is specified,
  493. then lpSearchFilter MUST be NULL. For each file that
  494. matches the specified filename, and that is a directory, and
  495. entry for that file is returned.
  496. If the underlying file/io system does not support this type
  497. of filtering, the API will fail with ERROR_NOT_SUPPORTED,
  498. and the application will have to perform its own filtering
  499. by calling this API with FindExSearchNameMatch.
  500. FindExSearchLimitToDevices - If this search op is specified, the
  501. lpFileName MUST be *, and FIND_FIRST_EX_CASE_SENSITIVE
  502. must NOT be specified. Only device names are returned.
  503. Device names are generally accessible through
  504. \\.\name-of-device naming.
  505. The data returned by this API is dependent on the fInfoLevelId.
  506. FindExInfoStandard - The lpFindFileData pointer is the standard
  507. LPWIN32_FIND_DATA structure.
  508. At this time, no other information levels are supported
  509. Once established, the find file handle can be used to search for
  510. other files that match the same pattern with the same filtering
  511. being performed. When the find file handle is no longer needed, it
  512. should be closed.
  513. Note that while this interface only returns information for a single
  514. file, an implementation is free to buffer several matching files
  515. that can be used to satisfy subsequent calls to FindNextFileEx.
  516. This API is a complete superset of existing FindFirstFile. FindFirstFile
  517. could be coded as the following macro:
  518. #define FindFirstFile(a,b)
  519. FindFirstFileEx((a),FindExInfoStandard,(b),FindExSearchNameMatch,NULL,0);
  520. Arguments:
  521. lpFileName - Supplies the file name of the file to find. The file name
  522. may contain the DOS wild card characters '*' and '?'.
  523. fInfoLevelId - Supplies the info level of the returned data.
  524. lpFindFileData - Supplies a pointer whose type is dependent on the value
  525. of fInfoLevelId. This buffer returns the appropriate file data.
  526. fSearchOp - Specified the type of filtering to perform above and
  527. beyond simple wildcard matching.
  528. lpSearchFilter - If the specified fSearchOp needs structured search
  529. information, this pointer points to the search criteria. At
  530. this point in time, both search ops do not require extended
  531. search information, so this pointer is NULL.
  532. dwAdditionalFlags - Supplies additional flag values that control the
  533. search. A flag value of FIND_FIRST_EX_CASE_SENSITIVE can be
  534. used to cause case sensitive searches to occur. The default is
  535. case insensitive.
  536. Return Value:
  537. Not -1 - Returns a find first handle that can be used in a
  538. subsequent call to FindNextFileEx or FindClose.
  539. 0xffffffff - The operation failed. Extended error status is available
  540. using GetLastError.
  541. --*/
  542. {
  543. #define FIND_FIRST_EX_INVALID_FLAGS (~FIND_FIRST_EX_CASE_SENSITIVE)
  544. HANDLE hFindFile;
  545. NTSTATUS Status;
  546. OBJECT_ATTRIBUTES Obja;
  547. UNICODE_STRING FileName;
  548. UNICODE_STRING PathName;
  549. IO_STATUS_BLOCK IoStatusBlock;
  550. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  551. struct SEARCH_BUFFER {
  552. FILE_BOTH_DIR_INFORMATION DirInfo;
  553. WCHAR Names[MAX_PATH];
  554. } Buffer;
  555. BOOLEAN TranslationStatus;
  556. RTL_RELATIVE_NAME RelativeName;
  557. PVOID FreeBuffer;
  558. UNICODE_STRING UnicodeInput;
  559. PFINDFILE_HANDLE FindFileHandle;
  560. BOOLEAN EndsInDot;
  561. LPWIN32_FIND_DATAW FindFileData;
  562. BOOLEAN StrippedTrailingSlash;
  563. //
  564. // check parameters
  565. //
  566. if ( fInfoLevelId >= FindExInfoMaxInfoLevel ||
  567. fSearchOp >= FindExSearchLimitToDevices ||
  568. dwAdditionalFlags & FIND_FIRST_EX_INVALID_FLAGS ) {
  569. SetLastError(fSearchOp == FindExSearchLimitToDevices ? ERROR_NOT_SUPPORTED : ERROR_INVALID_PARAMETER);
  570. return INVALID_HANDLE_VALUE;
  571. }
  572. FindFileData = (LPWIN32_FIND_DATAW)lpFindFileData;
  573. RtlInitUnicodeString(&UnicodeInput,lpFileName);
  574. //
  575. // Bogus code to workaround ~* problem
  576. //
  577. if ( UnicodeInput.Buffer[(UnicodeInput.Length>>1)-1] == (WCHAR)'.' ) {
  578. EndsInDot = TRUE;
  579. }
  580. else {
  581. EndsInDot = FALSE;
  582. }
  583. TranslationStatus = RtlDosPathNameToNtPathName_U(
  584. lpFileName,
  585. &PathName,
  586. &FileName.Buffer,
  587. &RelativeName
  588. );
  589. if ( !TranslationStatus ) {
  590. SetLastError(ERROR_PATH_NOT_FOUND);
  591. return INVALID_HANDLE_VALUE;
  592. }
  593. FreeBuffer = PathName.Buffer;
  594. //
  595. // If there is a a file portion of this name, determine the length
  596. // of the name for a subsequent call to NtQueryDirectoryFile.
  597. //
  598. if (FileName.Buffer) {
  599. FileName.Length =
  600. PathName.Length - (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)PathName.Buffer);
  601. } else {
  602. FileName.Length = 0;
  603. }
  604. FileName.MaximumLength = FileName.Length;
  605. if ( RelativeName.RelativeName.Length &&
  606. RelativeName.RelativeName.Buffer != (PUCHAR)FileName.Buffer ) {
  607. if (FileName.Buffer) {
  608. PathName.Length = (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)RelativeName.RelativeName.Buffer);
  609. PathName.MaximumLength = PathName.Length;
  610. PathName.Buffer = (PWSTR)RelativeName.RelativeName.Buffer;
  611. }
  612. }
  613. else {
  614. RelativeName.ContainingDirectory = NULL;
  615. if (FileName.Buffer) {
  616. PathName.Length = (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)PathName.Buffer);
  617. PathName.MaximumLength = PathName.Length;
  618. }
  619. }
  620. if ( PathName.Buffer[(PathName.Length>>1)-2] != (WCHAR)':' &&
  621. PathName.Buffer[(PathName.Length>>1)-1] != (WCHAR)'\\' ) {
  622. PathName.Length -= sizeof(UNICODE_NULL);
  623. StrippedTrailingSlash = TRUE;
  624. }
  625. else {
  626. StrippedTrailingSlash = FALSE;
  627. }
  628. InitializeObjectAttributes(
  629. &Obja,
  630. &PathName,
  631. dwAdditionalFlags & FIND_FIRST_EX_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE,
  632. RelativeName.ContainingDirectory,
  633. NULL
  634. );
  635. //
  636. // Open the directory for list access
  637. //
  638. Status = NtOpenFile(
  639. &hFindFile,
  640. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  641. &Obja,
  642. &IoStatusBlock,
  643. FILE_SHARE_READ | FILE_SHARE_WRITE,
  644. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  645. );
  646. if ( (Status == STATUS_INVALID_PARAMETER ||
  647. Status == STATUS_NOT_A_DIRECTORY) && StrippedTrailingSlash ) {
  648. //
  649. // open of a pnp style path failed, so try putting back the trailing slash
  650. //
  651. PathName.Length += sizeof(UNICODE_NULL);
  652. Status = NtOpenFile(
  653. &hFindFile,
  654. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  655. &Obja,
  656. &IoStatusBlock,
  657. FILE_SHARE_READ | FILE_SHARE_WRITE,
  658. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  659. );
  660. PathName.Length -= sizeof(UNICODE_NULL);
  661. }
  662. if ( !NT_SUCCESS(Status) ) {
  663. ULONG DeviceNameData;
  664. UNICODE_STRING DeviceName;
  665. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  666. //
  667. // The full path does not refer to a directory. This could
  668. // be a device. Check for a device name.
  669. //
  670. if ( DeviceNameData = RtlIsDosDeviceName_U(UnicodeInput.Buffer) ) {
  671. DeviceName.Length = (USHORT)(DeviceNameData & 0xffff);
  672. DeviceName.MaximumLength = (USHORT)(DeviceNameData & 0xffff);
  673. DeviceName.Buffer = (PWSTR)
  674. ((PUCHAR)UnicodeInput.Buffer + (DeviceNameData >> 16));
  675. return BaseFindFirstDevice(&DeviceName,FindFileData);
  676. }
  677. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  678. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  679. }
  680. if ( Status == STATUS_OBJECT_TYPE_MISMATCH ) {
  681. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  682. }
  683. BaseSetLastNTError(Status);
  684. return INVALID_HANDLE_VALUE;
  685. }
  686. //
  687. // Get an entry
  688. //
  689. //
  690. // If there is no file part, but we are not looking at a device,
  691. // then bail.
  692. //
  693. if ( !FileName.Length ) {
  694. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  695. NtClose(hFindFile);
  696. SetLastError(ERROR_FILE_NOT_FOUND);
  697. return INVALID_HANDLE_VALUE;
  698. }
  699. DirectoryInfo = &Buffer.DirInfo;
  700. //
  701. // Special case *.* to * since it is so common. Otherwise transmogrify
  702. // the input name according to the following rules:
  703. //
  704. // - Change all ? to DOS_QM
  705. // - Change all . followed by ? or * to DOS_DOT
  706. // - Change all * followed by a . into DOS_STAR
  707. //
  708. // These transmogrifications are all done in place.
  709. //
  710. if ( (FileName.Length == 6) &&
  711. (RtlCompareMemory(FileName.Buffer, L"*.*", 6) == 6) ) {
  712. FileName.Length = 2;
  713. } else {
  714. ULONG Index;
  715. WCHAR *NameChar;
  716. for ( Index = 0, NameChar = FileName.Buffer;
  717. Index < FileName.Length/sizeof(WCHAR);
  718. Index += 1, NameChar += 1) {
  719. if (Index && (*NameChar == L'.') && (*(NameChar - 1) == L'*')) {
  720. *(NameChar - 1) = DOS_STAR;
  721. }
  722. if ((*NameChar == L'?') || (*NameChar == L'*')) {
  723. if (*NameChar == L'?') { *NameChar = DOS_QM; }
  724. if (Index && *(NameChar-1) == L'.') { *(NameChar-1) = DOS_DOT; }
  725. }
  726. }
  727. if (EndsInDot && *(NameChar - 1) == L'*') { *(NameChar-1) = DOS_STAR; }
  728. }
  729. Status = NtQueryDirectoryFile(
  730. hFindFile,
  731. NULL,
  732. NULL,
  733. NULL,
  734. &IoStatusBlock,
  735. DirectoryInfo,
  736. sizeof(Buffer),
  737. FileBothDirectoryInformation,
  738. TRUE,
  739. &FileName,
  740. FALSE
  741. );
  742. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  743. if ( !NT_SUCCESS(Status) ) {
  744. NtClose(hFindFile);
  745. BaseSetLastNTError(Status);
  746. return INVALID_HANDLE_VALUE;
  747. }
  748. //
  749. // Attributes are composed of the attributes returned by NT.
  750. //
  751. FindFileData->dwFileAttributes = DirectoryInfo->FileAttributes;
  752. FindFileData->ftCreationTime = *(LPFILETIME)&DirectoryInfo->CreationTime;
  753. FindFileData->ftLastAccessTime = *(LPFILETIME)&DirectoryInfo->LastAccessTime;
  754. FindFileData->ftLastWriteTime = *(LPFILETIME)&DirectoryInfo->LastWriteTime;
  755. FindFileData->nFileSizeHigh = DirectoryInfo->EndOfFile.HighPart;
  756. FindFileData->nFileSizeLow = DirectoryInfo->EndOfFile.LowPart;
  757. RtlMoveMemory( FindFileData->cFileName,
  758. DirectoryInfo->FileName,
  759. DirectoryInfo->FileNameLength );
  760. FindFileData->cFileName[DirectoryInfo->FileNameLength >> 1] = UNICODE_NULL;
  761. RtlMoveMemory( FindFileData->cAlternateFileName,
  762. DirectoryInfo->ShortName,
  763. DirectoryInfo->ShortNameLength );
  764. FindFileData->cAlternateFileName[DirectoryInfo->ShortNameLength >> 1] = UNICODE_NULL;
  765. //
  766. // For NTFS reparse points we return the reparse point data tag in dwReserved0.
  767. //
  768. if ( DirectoryInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
  769. FindFileData->dwReserved0 = DirectoryInfo->EaSize;
  770. }
  771. FindFileHandle = BasepInitializeFindFileHandle(hFindFile);
  772. if ( !FindFileHandle ) {
  773. NtClose(hFindFile);
  774. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  775. return INVALID_HANDLE_VALUE;
  776. }
  777. return (HANDLE)FindFileHandle;
  778. }
  779. HANDLE
  780. BaseFindFirstDevice(
  781. PCUNICODE_STRING FileName,
  782. LPWIN32_FIND_DATAW lpFindFileData
  783. )
  784. /*++
  785. Routine Description:
  786. This function is called when find first file encounters a device
  787. name. This function returns a successful psuedo file handle and
  788. fills in the find file data with all zeros and the devic name.
  789. Arguments:
  790. FileName - Supplies the device name of the file to find.
  791. lpFindFileData - On a successful find, this parameter returns information
  792. about the located file.
  793. Return Value:
  794. Always returns a static find file handle value of
  795. BASE_FIND_FIRST_DEVICE_HANDLE
  796. --*/
  797. {
  798. RtlZeroMemory(lpFindFileData,sizeof(*lpFindFileData));
  799. lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
  800. RtlMoveMemory(
  801. &lpFindFileData->cFileName[0],
  802. FileName->Buffer,
  803. FileName->MaximumLength
  804. );
  805. return BASE_FIND_FIRST_DEVICE_HANDLE;
  806. }
  807. HANDLE
  808. APIENTRY
  809. FindFirstChangeNotificationA(
  810. LPCSTR lpPathName,
  811. BOOL bWatchSubtree,
  812. DWORD dwNotifyFilter
  813. )
  814. /*++
  815. Routine Description:
  816. ANSI thunk to FindFirstChangeNotificationW
  817. --*/
  818. {
  819. PUNICODE_STRING Unicode;
  820. ANSI_STRING AnsiString;
  821. NTSTATUS Status;
  822. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  823. RtlInitAnsiString(&AnsiString,lpPathName);
  824. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  825. if ( !NT_SUCCESS(Status) ) {
  826. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  827. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  828. }
  829. else {
  830. BaseSetLastNTError(Status);
  831. }
  832. return FALSE;
  833. }
  834. return ( FindFirstChangeNotificationW(
  835. (LPCWSTR)Unicode->Buffer,
  836. bWatchSubtree,
  837. dwNotifyFilter
  838. )
  839. );
  840. }
  841. //
  842. // this is a hack... darrylh, please remove when NT supports null
  843. // buffers to change notify
  844. //
  845. char staticchangebuff[sizeof(FILE_NOTIFY_INFORMATION) + 16];
  846. IO_STATUS_BLOCK staticIoStatusBlock;
  847. HANDLE
  848. APIENTRY
  849. FindFirstChangeNotificationW(
  850. LPCWSTR lpPathName,
  851. BOOL bWatchSubtree,
  852. DWORD dwNotifyFilter
  853. )
  854. /*++
  855. Routine Description:
  856. This API is used to create a change notification handle and to set
  857. up the initial change notification filter conditions.
  858. If successful, this API returns a waitable notification handle. A
  859. wait on a notification handle is successful when a change matching
  860. the filter conditions occurs in the directory or subtree being
  861. watched.
  862. Once a change notification object is created and the initial filter
  863. conditions are set, the appropriate directory or subtree is
  864. monitored by the system for changes that match the specified filter
  865. conditions. When one of these changes occurs, a change notification
  866. wait is satisfied. If a change occurs without an outstanding change
  867. notification request, it is remembered by the system and will
  868. satisfy the next change notification wait.
  869. Note that this means that after a call to
  870. FindFirstChangeNotification is made, the application should wait on
  871. the notification handle before making another call to
  872. FindNextChangeNotification.
  873. Arguments:
  874. lpPathName - Supplies the pathname of the directory to be watched.
  875. This path must specify the pathname of a directory.
  876. bWatchSubtree - Supplies a boolean value that if TRUE causes the
  877. system to monitor the directory tree rooted at the specified
  878. directory. A value of FALSE causes the system to monitor only
  879. the specified directory.
  880. dwNotifyFilter - Supplies a set of flags that specify the filter
  881. conditions the system uses to satisfy a change notification
  882. wait.
  883. FILE_NOTIFY_CHANGE_FILENAME - Any file name changes that occur
  884. in a directory or subtree being watched will satisfy a
  885. change notification wait. This includes renames, creations,
  886. and deletes.
  887. FILE_NOTIFY_CHANGE_DIRNAME - Any directory name changes that occur
  888. in a directory or subtree being watched will satisfy a
  889. change notification wait. This includes directory creations
  890. and deletions.
  891. FILE_NOTIFY_CHANGE_ATTRIBUTES - Any attribute changes that occur
  892. in a directory or subtree being watched will satisfy a
  893. change notification wait.
  894. FILE_NOTIFY_CHANGE_SIZE - Any file size changes that occur in a
  895. directory or subtree being watched will satisfy a change
  896. notification wait. File sizes only cause a change when the
  897. on disk structure is updated. For systems with extensive
  898. caching this may only occur when the system cache is
  899. sufficiently flushed.
  900. FILE_NOTIFY_CHANGE_LAST_WRITE - Any last write time changes that
  901. occur in a directory or subtree being watched will satisfy a
  902. change notification wait. Last write time change only cause
  903. a change when the on disk structure is updated. For systems
  904. with extensive caching this may only occur when the system
  905. cache is sufficiently flushed.
  906. FILE_NOTIFY_CHANGE_SECURITY - Any security descriptor changes
  907. that occur in a directory or subtree being watched will
  908. satisfy a change notification wait.
  909. Return Value:
  910. Not -1 - Returns a find change notification handle. The handle is a
  911. waitable handle. A wait is satisfied when one of the filter
  912. conditions occur in a directory or subtree being monitored. The
  913. handle may also be used in a subsequent call to
  914. FindNextChangeNotify and in FindCloseChangeNotify.
  915. 0xffffffff - The operation failed. Extended error status is available
  916. using GetLastError.
  917. --*/
  918. {
  919. NTSTATUS Status;
  920. OBJECT_ATTRIBUTES Obja;
  921. HANDLE Handle;
  922. UNICODE_STRING FileName;
  923. IO_STATUS_BLOCK IoStatusBlock;
  924. BOOLEAN TranslationStatus;
  925. RTL_RELATIVE_NAME RelativeName;
  926. PVOID FreeBuffer;
  927. TranslationStatus = RtlDosPathNameToNtPathName_U(
  928. lpPathName,
  929. &FileName,
  930. NULL,
  931. &RelativeName
  932. );
  933. if ( !TranslationStatus ) {
  934. SetLastError(ERROR_PATH_NOT_FOUND);
  935. return FALSE;
  936. }
  937. FreeBuffer = FileName.Buffer;
  938. if ( RelativeName.RelativeName.Length ) {
  939. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  940. }
  941. else {
  942. RelativeName.ContainingDirectory = NULL;
  943. }
  944. InitializeObjectAttributes(
  945. &Obja,
  946. &FileName,
  947. OBJ_CASE_INSENSITIVE,
  948. RelativeName.ContainingDirectory,
  949. NULL
  950. );
  951. //
  952. // Open the file
  953. //
  954. Status = NtOpenFile(
  955. &Handle,
  956. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  957. &Obja,
  958. &IoStatusBlock,
  959. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  960. FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
  961. );
  962. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  963. if ( !NT_SUCCESS(Status) ) {
  964. BaseSetLastNTError(Status);
  965. return INVALID_HANDLE_VALUE;
  966. }
  967. //
  968. // call change notify
  969. //
  970. Status = NtNotifyChangeDirectoryFile(
  971. Handle,
  972. NULL,
  973. NULL,
  974. NULL,
  975. &staticIoStatusBlock,
  976. staticchangebuff, // should be NULL
  977. sizeof(staticchangebuff),
  978. dwNotifyFilter,
  979. (BOOLEAN)bWatchSubtree
  980. );
  981. if ( !NT_SUCCESS(Status) ) {
  982. BaseSetLastNTError(Status);
  983. NtClose(Handle);
  984. Handle = INVALID_HANDLE_VALUE;
  985. }
  986. return Handle;
  987. }
  988. BOOL
  989. APIENTRY
  990. FindNextChangeNotification(
  991. HANDLE hChangeHandle
  992. )
  993. /*++
  994. Routine Description:
  995. This API is used to request that a change notification handle
  996. be signaled the next time the system dectects an appropriate
  997. change.
  998. If a change occurs prior to this call that would otherwise satisfy
  999. a change request, it is remembered by the system and will satisfy
  1000. this request.
  1001. Once a successful change notification request has been made, the
  1002. application should wait on the change notification handle to
  1003. pick up the change.
  1004. If an application calls this API with a change request outstanding,
  1005. .
  1006. .
  1007. FindNextChangeNotification(h);
  1008. FindNextChangeNotification(h);
  1009. WaitForSingleObject(h,-1);
  1010. .
  1011. .
  1012. it may miss a change notification.
  1013. Arguments:
  1014. hChangeHandle - Supplies a change notification handle created
  1015. using FindFirstChangeNotification.
  1016. Return Value:
  1017. TRUE - The change notification request was registered. A wait on the
  1018. change handle should be issued to pick up the change notification.
  1019. FALSE - The operation failed. Extended error status is available
  1020. using GetLastError.
  1021. --*/
  1022. {
  1023. NTSTATUS Status;
  1024. BOOL ReturnValue;
  1025. ReturnValue = TRUE;
  1026. //
  1027. // call change notify
  1028. //
  1029. Status = NtNotifyChangeDirectoryFile(
  1030. hChangeHandle,
  1031. NULL,
  1032. NULL,
  1033. NULL,
  1034. &staticIoStatusBlock,
  1035. staticchangebuff, // should be NULL
  1036. sizeof(staticchangebuff),
  1037. FILE_NOTIFY_CHANGE_NAME, // not needed bug workaround
  1038. TRUE // not needed bug workaround
  1039. );
  1040. if ( !NT_SUCCESS(Status) ) {
  1041. BaseSetLastNTError(Status);
  1042. ReturnValue = FALSE;
  1043. }
  1044. return ReturnValue;
  1045. }
  1046. BOOL
  1047. APIENTRY
  1048. FindCloseChangeNotification(
  1049. HANDLE hChangeHandle
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. This API is used close a change notification handle and to tell the
  1054. system to stop monitoring changes on the notification handle.
  1055. Arguments:
  1056. hChangeHandle - Supplies a change notification handle created
  1057. using FindFirstChangeNotification.
  1058. Return Value:
  1059. TRUE - The change notification handle was closed.
  1060. FALSE - The operation failed. Extended error status is available
  1061. using GetLastError.
  1062. --*/
  1063. {
  1064. return CloseHandle(hChangeHandle);
  1065. }
  1066. BOOL
  1067. WINAPI
  1068. ReadDirectoryChangesW(
  1069. HANDLE hDirectory,
  1070. LPVOID lpBuffer,
  1071. DWORD nBufferLength,
  1072. BOOL bWatchSubtree,
  1073. DWORD dwNotifyFilter,
  1074. LPDWORD lpBytesReturned,
  1075. LPOVERLAPPED lpOverlapped,
  1076. LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. This rountine allows you to read changes that occur in a directory
  1081. or a tree rooted at the specified directory. It is similar to the
  1082. FindxxxChangeNotification family of APIs, but this API can return
  1083. structured data describing the changes occuring within a directory.
  1084. This API requires the caller to pass in an open directory handle to
  1085. the directory that is to be read. The handle must be opened with
  1086. FILE_LIST_DIRECTORY acces. GENERIC_READ includes this and may also
  1087. be used. The directory may be opened for overlapped access. This
  1088. technique should be used whenever you call this API asynchronously
  1089. (by specifying and lpOverlapped value). Opening a directory in
  1090. Win32 is easy. Use CreateFile, pass in the name of a directory, and
  1091. make sure you specify FILE_FLAG_BACKUP_SEMANTICS. This will allow
  1092. you to open a directory. This technique will not force a directory
  1093. to be opened. It simply allows you to open a directory. Calling
  1094. this API with a handle to a regular file will fail.
  1095. The following code fragment illustrates how to open a directory using
  1096. CreateFile.
  1097. hDir = CreateFile(
  1098. DirName,
  1099. FILE_LIST_DIRECTORY,
  1100. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1101. NULL,
  1102. OPEN_EXISTING,
  1103. FILE_FLAG_BACKUP_SEMANTICS | (fASync ? FILE_FLAG_OVERLAPPED : 0),
  1104. NULL
  1105. );
  1106. This API returns it's data in a structured format. The structure is defined by
  1107. the FILE_NOTIFY_INFORMATION structure.
  1108. typedef struct _FILE_NOTIFY_INFORMATION {
  1109. DWORD NextEntryOffset;
  1110. DWORD Action;
  1111. DWORD FileNameLength;
  1112. WCHAR FileName[1];
  1113. } FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
  1114. The lpBuffer/nBufferLength parameters are used to describe the
  1115. callers buffer to the system. This API fills in the buffer either
  1116. syncronously or asynchronously depending on how the directory is
  1117. opened and the presence of the lpOverlapped parameter.
  1118. Upon successful I/O completion, a formated buffer, and number of
  1119. bytes transfered into the buffer is available to the caller. If the
  1120. number of bytes transfered is 0, this means that the system was
  1121. unable to provide detailed information on all of the changes that
  1122. occured in the directory or tree. The application should manually
  1123. compute this information by enumerating the directory or tree.
  1124. Otherwise, structured data is returned to the caller.
  1125. Each record contains:
  1126. NextEntryOffest - This is the number of bytes to be skipped to get
  1127. to the next record. A value of 0 indicates that this is the last
  1128. record.
  1129. Action - This is used to describe the type of change that occured:
  1130. FILE_ACTION_ADDED - The file was added to the directory
  1131. FILE_ACTION_REMOVED - The file was removed from the
  1132. directory
  1133. FILE_ACTION_MODIFIED - The file was modified (time change,
  1134. attribute change...)
  1135. FILE_ACTION_RENAMED_OLD_NAME - The file was renamed and this
  1136. is the old name.
  1137. FILE_ACTION_RENAMED_NEW_NAME - The file was renamed and this
  1138. is the new name.
  1139. FileNameLength - This is the length in bytes of the file name portion
  1140. of this record. Note that the file name is NOT null terminated. This
  1141. length does not include a trailing NULL.
  1142. FileName - This variable length portion of the recorn contains a file name
  1143. relative to the directory handle. The name is in the UNICODE character
  1144. format and is NOT NULL terminated.
  1145. The caller of this API can specify a filter that describes to sort
  1146. of changes that should trigger a read completion on thie directory.
  1147. The first call to this API on a directory establishes the filter to
  1148. be used for that call and all subsequent calls.
  1149. The caller can also tell the system to watch for changes in the
  1150. directory, or the entire subtree under the directory. Again, the
  1151. first call to this API establishes this condition.
  1152. This call can complete either synchronously or asynchronously.
  1153. For synchronous completion, the directory should be opened without
  1154. the FILE_FLAG_OVERLAPPED flag. The I/O will complete when the
  1155. callers buffer either fills up or overflows. When this condition
  1156. occurs, the caller may parse the returned buffer. If the
  1157. *lpBytesReturned value is 0, this means that the buffer was too
  1158. small to hold all of the changes, and the caller will have to
  1159. manually enumerate the directory or tree.
  1160. For asynchronous completion, the directory should be opened with the
  1161. FILE_FLAG_OVERLAPPED flag, and an lpOverlapped parameter must be
  1162. specified. I/O completion is returned to the caller via
  1163. GetOverlappedResult(), GetQueuedCompletionStatus(), or via an I/O
  1164. completion callback.
  1165. To receive notification via GetOverlappedResult(), DO NOT specify an
  1166. lpCompletionRoutine. Set the hEvent field of the overlapped
  1167. structure to an hEvent unique to this I/O operation. Pick up your I/O completion
  1168. using GetOverlappedResult().
  1169. To receive notification via GetQueuedCompletionSTatus(), DO NOT
  1170. specify an lpCompletionRoutine. Associate the directory handle with
  1171. a completion port using CreateIoCompletionPort(). Pick up your I/O
  1172. completion using GetQueuedCompletionStatus(). To disable a
  1173. completion packet from being used on an associated directory, set
  1174. the low order bit of the hEvent in the lpOverlapped structure and
  1175. use GetOverlappedResult().
  1176. To receive notification via an I/O completion callback, DO NOT
  1177. associate the directory with a completion port. Specify an
  1178. lpCompletionRoutine. This function will be called whenever an
  1179. outstanding I/O completes while you are in an alertable wait. If an
  1180. I/O completes, but you are not waiting, the I/O notification stays
  1181. pending and will occur when you wait. Only the thread that issues
  1182. the I/O is notified. The hEvent field of the overlapped structure is not
  1183. used by the system and may be used by the caller.
  1184. Arguments:
  1185. hDirectory - SUpplies an open handle to a directory to be watched.
  1186. The directory must be opened with FILE_LIST_DIRECTORY access.
  1187. lpBuffer - Supplies the address of a buffer that will be used to return the
  1188. results of the read. The format of this buffer is described above.
  1189. nBufferLength - Supplies the length of the buffer.
  1190. bWatchSubtree - Supplies a boolean value that if TRUE causes the
  1191. system to monitor the directory tree rooted at the specified
  1192. directory. A value of FALSE causes the system to monitor only
  1193. the specified directory.
  1194. dwNotifyFilter - Supplies a set of flags that specify the filter
  1195. conditions the system uses to satisfy a read.
  1196. FILE_NOTIFY_CHANGE_FILENAME - Any file name changes that occur
  1197. in a directory or subtree being watched will satisfy a read.
  1198. This includes renames, creations, and deletes.
  1199. FILE_NOTIFY_CHANGE_DIRNAME - Any directory name changes that
  1200. occur in a directory or subtree being watched will satisfy a
  1201. read. This includes directory creations and deletions.
  1202. FILE_NOTIFY_CHANGE_ATTRIBUTES - Any attribute changes that occur
  1203. in a directory or subtree being watched will satisfy a
  1204. read.
  1205. FILE_NOTIFY_CHANGE_SIZE - Any file size changes that occur in a
  1206. directory or subtree being watched will satisfy a read.
  1207. File sizes only cause a change when the on disk structure is
  1208. updated. For systems with extensive caching this may only
  1209. occur when the system cache is sufficiently flushed.
  1210. FILE_NOTIFY_CHANGE_LAST_WRITE - Any last write time changes that
  1211. occur in a directory or subtree being watched will satisfy a
  1212. read. Last write time change only cause a change when the
  1213. on disk structure is updated. For systems with extensive
  1214. caching this may only occur when the system cache is
  1215. sufficiently flushed.
  1216. FILE_NOTIFY_CHANGE_LAST_ACCESS - Any last access time changes that
  1217. occur in a directory or subtree being watched will satisfy a
  1218. read. Last access time change only cause a change when the
  1219. on disk structure is updated. For systems with extensive
  1220. caching this may only occur when the system cache is
  1221. sufficiently flushed.
  1222. FILE_NOTIFY_CHANGE_CREATION - Any creation time changes that
  1223. occur in a directory or subtree being watched will satisfy a
  1224. read. Last creation time change only cause a change when the
  1225. on disk structure is updated. For systems with extensive
  1226. caching this may only occur when the system cache is
  1227. sufficiently flushed.
  1228. FILE_NOTIFY_CHANGE_SECURITY - Any security descriptor changes
  1229. that occur in a directory or subtree being watched will
  1230. satisfy a read.
  1231. lpBytesReturned - For synchronous calls, this returns the number of
  1232. bytes transfered into the buffer. A successful call coupled
  1233. with a value of 0 means that the buffer was too small, and the
  1234. caller must manually enumerate the directory/tree. For
  1235. asynchronous calls, this value is undefined. The system does
  1236. not attempt to store anything here. The caller must use an
  1237. asynchronous notification technique to pick up I/O completion
  1238. and number of bytes transfered.
  1239. lpOverlapped - Supplies an overlapped structure to be used in
  1240. conjunction with asynchronous I/O completion notification. The
  1241. offset fields of this structure are not used. Using this on a
  1242. directory that was not opened with FILE_FLAG_OVERLAPPED is
  1243. undefined.
  1244. lpCompletionRoutine - Supplies the address of a completion routine
  1245. that is called when this I/O completes, AND the thread that
  1246. issues the I/O enters an alertable wait. The threads wait will
  1247. be interrupted with a return code of WAIT_IO_COMPLETION, and
  1248. this I/O completion routine will be called. The routine is
  1249. passed the error code of the operation, the number of bytes
  1250. transfered, and the address of the lpOverlapped structure used
  1251. in the call. An error will occur if this parameter is specified
  1252. on a directory handle that is associated with a completion port.
  1253. Return Value:
  1254. TRUE - For synchronous calls, the operation succeeded.
  1255. lpBytesReturned is the number of bytes transferred into your
  1256. buffer. A value of 0 means that your buffer was too small to
  1257. hold all of the changes that occured and that you need to
  1258. enumerate the directory yourself to see the changes. For
  1259. asyncronous calls, the operation was queued successfully.
  1260. Results will be delivered using asynch I/O notification
  1261. (GetOverlappedResult(), GetQueuedCompletionStatus(), or your
  1262. completion callback routine).
  1263. FALSE - An error occured. GetLastError() can be used to obtain detailed
  1264. error status.
  1265. --*/
  1266. {
  1267. NTSTATUS Status;
  1268. BOOL ReturnValue;
  1269. IO_STATUS_BLOCK IoStatusBlock;
  1270. HANDLE Event;
  1271. PIO_APC_ROUTINE ApcRoutine = NULL;
  1272. PVOID ApcContext = NULL;
  1273. PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK ActivationBlock = NULL;
  1274. ReturnValue = TRUE;
  1275. if ( ARGUMENT_PRESENT(lpOverlapped) ) {
  1276. if ( ARGUMENT_PRESENT(lpCompletionRoutine) ) {
  1277. //
  1278. // completion is via APC routine
  1279. //
  1280. Event = NULL;
  1281. Status = BasepAllocateActivationContextActivationBlock(
  1282. BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_FREE_AFTER_CALLBACK |
  1283. BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_ALLOCATE_IF_PROCESS_DEFAULT,
  1284. lpCompletionRoutine,
  1285. lpOverlapped,
  1286. &ActivationBlock);
  1287. if (!NT_SUCCESS(Status)) {
  1288. BaseSetLastNTError(Status);
  1289. return FALSE;
  1290. }
  1291. if (ActivationBlock != NULL) {
  1292. ApcRoutine = &BasepIoCompletion;
  1293. ApcContext = (PVOID) ActivationBlock;
  1294. } else {
  1295. ApcRoutine = &BasepIoCompletionSimple;
  1296. ApcContext = lpCompletionRoutine;
  1297. }
  1298. } else {
  1299. //
  1300. // completion is via completion port or get overlapped result
  1301. //
  1302. Event = lpOverlapped->hEvent;
  1303. ApcRoutine = NULL;
  1304. ApcContext = (ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped;
  1305. }
  1306. lpOverlapped->Internal = (DWORD)STATUS_PENDING;
  1307. Status = NtNotifyChangeDirectoryFile(
  1308. hDirectory,
  1309. Event,
  1310. ApcRoutine,
  1311. ApcContext,
  1312. (PIO_STATUS_BLOCK)&lpOverlapped->Internal,
  1313. lpBuffer,
  1314. nBufferLength,
  1315. dwNotifyFilter,
  1316. (BOOLEAN)bWatchSubtree
  1317. );
  1318. //
  1319. // Anything other than an error means that I/O completion will
  1320. // occur and caller only gets return data via completion mechanism
  1321. //
  1322. if ( NT_ERROR(Status) ) {
  1323. if (ActivationBlock != NULL)
  1324. BasepFreeActivationContextActivationBlock(ActivationBlock);
  1325. BaseSetLastNTError(Status);
  1326. ReturnValue = FALSE;
  1327. }
  1328. }
  1329. else {
  1330. Status = NtNotifyChangeDirectoryFile(
  1331. hDirectory,
  1332. NULL,
  1333. NULL,
  1334. NULL,
  1335. &IoStatusBlock,
  1336. lpBuffer,
  1337. nBufferLength,
  1338. dwNotifyFilter,
  1339. (BOOLEAN)bWatchSubtree
  1340. );
  1341. if ( Status == STATUS_PENDING) {
  1342. //
  1343. // Operation must complete before return & IoStatusBlock destroyed
  1344. //
  1345. Status = NtWaitForSingleObject( hDirectory, FALSE, NULL );
  1346. if ( NT_SUCCESS(Status)) {
  1347. Status = IoStatusBlock.Status;
  1348. }
  1349. }
  1350. if ( NT_SUCCESS(Status) ) {
  1351. *lpBytesReturned = (DWORD)IoStatusBlock.Information;
  1352. }
  1353. else {
  1354. BaseSetLastNTError(Status);
  1355. ReturnValue = FALSE;
  1356. }
  1357. }
  1358. return ReturnValue;
  1359. }