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

601 lines
22 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #if SCAN_DEBUG
  4. BOOL scan_dprinton = FALSE;
  5. #define dprintf(_x_) if (scan_dprinton) printf _x_
  6. #else
  7. #define dprintf(_x_)
  8. #endif
  9. #define FlagOn(_mask,_flag) (((_mask) & (_flag)) != 0)
  10. #define FlagOff(_mask,_flag) (((_mask) & (_flag)) == 0)
  11. #define SetFlag(_mask,_flag) ((_mask) |= (_flag))
  12. #define ClearFlag(_mask,_flag) ((_mask) &= ~(_flag))
  13. typedef struct _CONTAINER_ENTRY {
  14. LIST_ENTRY SiblingListEntry;
  15. LIST_ENTRY ContainerList;
  16. LIST_ENTRY ObjectList;
  17. struct _CONTAINER_ENTRY *Parent;
  18. PVOID UserData;
  19. } CONTAINER_ENTRY, *PCONTAINER_ENTRY;
  20. typedef struct _OBJECT_ENTRY {
  21. LIST_ENTRY SiblingListEntry;
  22. PVOID UserData;
  23. } OBJECT_ENTRY, *POBJECT_ENTRY;
  24. #define InitializeContainer(_container,_parent) { \
  25. InitializeListHead(&(_container)->ContainerList); \
  26. InitializeListHead(&(_container)->ObjectList); \
  27. (_container)->Parent = (PCONTAINER_ENTRY)(_parent); \
  28. }
  29. #define InitializeObject(_object)
  30. #define InsertContainer(_container,_subcontainer) \
  31. InsertTailList(&(_container)->ContainerList,&(_subcontainer)->SiblingListEntry)
  32. #define InsertObject(_container,_object) \
  33. InsertTailList(&(_container)->ObjectList,&(_object)->SiblingListEntry)
  34. #define RemoveObject(_object) RemoveEntryList(&(_object)->SiblingListEntry)
  35. #define RemoveContainer(_container) RemoveEntryList(&(_container)->SiblingListEntry)
  36. #define GetFirstObject(_container) \
  37. ((_container)->ObjectList.Flink != &(_container)->ObjectList ? \
  38. CONTAINING_RECORD( (_container)->ObjectList.Flink, \
  39. OBJECT_ENTRY, \
  40. SiblingListEntry ) : NULL)
  41. #define GetNextObject(_container,_object) \
  42. ((_object)->SiblingListEntry.Flink != &(_container)->ObjectList ? \
  43. CONTAINING_RECORD( (_object)->SiblingListEntry.Flink, \
  44. OBJECT_ENTRY, \
  45. SiblingListEntry ) : NULL)
  46. #define GetFirstContainer(_container) \
  47. ((_container)->ContainerList.Flink != &(_container)->ContainerList ? \
  48. CONTAINING_RECORD( (_container)->ContainerList.Flink, \
  49. CONTAINER_ENTRY, \
  50. SiblingListEntry ) : NULL)
  51. #define GetNextContainer(_container) \
  52. ((_container)->SiblingListEntry.Flink != &(_container)->Parent->ContainerList ? \
  53. CONTAINING_RECORD( (_container)->SiblingListEntry.Flink, \
  54. CONTAINER_ENTRY, \
  55. SiblingListEntry ) : NULL)
  56. #define GetParent(_container) ((_container)->Parent)
  57. #define GetParentUserData(_container) &(GetParent(_container))->UserData
  58. typedef struct _DIRECTORY_ENTRY {
  59. CONTAINER_ENTRY ;
  60. SMALL_WIN32_FIND_DATAW FindData;
  61. } DIRECTORY_ENTRY, *PDIRECTORY_ENTRY;
  62. typedef struct _FILE_ENTRY {
  63. OBJECT_ENTRY ;
  64. SMALL_WIN32_FIND_DATAW FindData;
  65. } FILE_ENTRY, *PFILE_ENTRY;
  66. typedef struct _SCAN_PARAMETERS {
  67. PSCAN_FREE_USER_DATA_CALLBACK FreeUserDataCallback;
  68. BOOL Recurse;
  69. BOOL SkipRoot;
  70. DIRECTORY_ENTRY RootDirectoryEntry;
  71. } SCAN_PARAMETERS, *PSCAN_PARAMETERS;
  72. VOID
  73. ScanFreeChildren (
  74. IN PSCAN_PARAMETERS Parameters,
  75. IN PCONTAINER_ENTRY Container
  76. );
  77. DWORD
  78. ScanInitialize (
  79. OUT PVOID *ScanHandle,
  80. IN BOOL Recurse,
  81. IN BOOL SkipRoot,
  82. IN PSCAN_FREE_USER_DATA_CALLBACK FreeUserDataCallback OPTIONAL
  83. )
  84. {
  85. PSCAN_PARAMETERS params;
  86. DWORD size;
  87. DWORD error;
  88. params = malloc( sizeof(SCAN_PARAMETERS) );
  89. if ( params == NULL ) {
  90. return ERROR_NOT_ENOUGH_MEMORY;
  91. }
  92. *ScanHandle = params;
  93. params->Recurse = Recurse;
  94. params->SkipRoot = SkipRoot;
  95. params->FreeUserDataCallback = FreeUserDataCallback;
  96. InitializeContainer( &params->RootDirectoryEntry, NULL );
  97. params->RootDirectoryEntry.UserData = NULL;
  98. params->RootDirectoryEntry.FindData.cFileName[0] = 0;
  99. return NO_ERROR;
  100. }
  101. DWORD
  102. ScanDirectory (
  103. IN PVOID ScanHandle,
  104. IN PWCH ScanPath,
  105. IN PVOID Context OPTIONAL,
  106. IN PSCAN_NEW_DIRECTORY_CALLBACK NewDirectoryCallback OPTIONAL,
  107. IN PSCAN_CHECK_DIRECTORY_CALLBACK CheckDirectoryCallback OPTIONAL,
  108. IN PSCAN_RECURSE_DIRECTORY_CALLBACK RecurseDirectoryCallback OPTIONAL,
  109. IN PSCAN_NEW_FILE_CALLBACK NewFileCallback OPTIONAL,
  110. IN PSCAN_CHECK_FILE_CALLBACK CheckFileCallback OPTIONAL
  111. )
  112. {
  113. BOOL ok;
  114. DWORD error;
  115. PSCAN_PARAMETERS params;
  116. PDIRECTORY_ENTRY rootDirectory;
  117. PDIRECTORY_ENTRY currentDirectory;
  118. PDIRECTORY_ENTRY newDirectory;
  119. PFILE_ENTRY newFile;
  120. WIN32_FIND_DATA fileData;
  121. HANDLE findHandle;
  122. PVOID userData;
  123. WCHAR currentDirectoryName[MAX_PATH + 1];
  124. params = ScanHandle;
  125. rootDirectory = &params->RootDirectoryEntry;
  126. currentDirectory = rootDirectory;
  127. wcscpy( currentDirectoryName, ScanPath );
  128. do {
  129. wcscat( currentDirectoryName, L"\\*" );
  130. dprintf(( "FindFirst for %ws\n", currentDirectoryName ));
  131. findHandle = FindFirstFile( currentDirectoryName, &fileData );
  132. currentDirectoryName[wcslen(currentDirectoryName) - 2] = 0;
  133. if ( findHandle != INVALID_HANDLE_VALUE ) {
  134. do {
  135. if ( FlagOff(fileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) &&
  136. (!params->SkipRoot || (currentDirectory != rootDirectory)) ) {
  137. dprintf(( " found file %ws\\%ws\n", currentDirectoryName, fileData.cFileName ));
  138. newFile = (PFILE_ENTRY)GetFirstObject( currentDirectory );
  139. while ( newFile != NULL ) {
  140. if ( _wcsicmp( newFile->FindData.cFileName, fileData.cFileName ) == 0 ) {
  141. break;
  142. }
  143. newFile = (PFILE_ENTRY)GetNextObject( currentDirectory, newFile );
  144. }
  145. userData = NULL;
  146. if ( newFile != NULL ) {
  147. userData = newFile->UserData;
  148. }
  149. if ( ARGUMENT_PRESENT(NewFileCallback) ) {
  150. error = NewFileCallback(
  151. Context,
  152. currentDirectoryName,
  153. (newFile == NULL) ? NULL : &newFile->FindData,
  154. &fileData,
  155. &userData,
  156. &currentDirectory->UserData
  157. );
  158. if ( error != NO_ERROR ) {
  159. FindClose( findHandle );
  160. return error;
  161. }
  162. }
  163. if ( newFile != NULL ) {
  164. if ( userData != NULL ) {
  165. newFile->UserData = userData;
  166. } else {
  167. RemoveObject( newFile );
  168. free( newFile );
  169. }
  170. } else if ( userData != NULL ) {
  171. newFile = malloc( sizeof(FILE_ENTRY) - sizeof(WCHAR) +
  172. ((wcslen(fileData.cFileName) + 1) * sizeof(WCHAR)) );
  173. if ( newFile == NULL ) {
  174. if ( (userData != NULL) &&
  175. (params->FreeUserDataCallback != NULL) ) {
  176. params->FreeUserDataCallback( userData );
  177. }
  178. FindClose( findHandle );
  179. return ERROR_NOT_ENOUGH_MEMORY;
  180. }
  181. InitializeObject( newFile );
  182. newFile->FindData.dwFileAttributes = fileData.dwFileAttributes;
  183. newFile->FindData.ftCreationTime = fileData.ftCreationTime;
  184. newFile->FindData.ftLastAccessTime = fileData.ftLastAccessTime;
  185. newFile->FindData.ftLastWriteTime = fileData.ftLastWriteTime;
  186. newFile->FindData.nFileSizeHigh = fileData.nFileSizeHigh;
  187. newFile->FindData.nFileSizeLow = fileData.nFileSizeLow;
  188. wcscpy( newFile->FindData.cAlternateFileName, fileData.cAlternateFileName );
  189. wcscpy( newFile->FindData.cFileName, fileData.cFileName );
  190. newFile->UserData = userData;
  191. InsertObject( currentDirectory, newFile );
  192. }
  193. } else if ( params->Recurse &&
  194. (wcscmp(fileData.cFileName,L".") != 0) &&
  195. (wcscmp(fileData.cFileName,L"..") != 0) ) {
  196. dprintf(( " found directory %ws\\%ws\n", currentDirectoryName, fileData.cFileName ));
  197. newDirectory = (PDIRECTORY_ENTRY)GetFirstContainer( currentDirectory );
  198. while ( newDirectory != NULL ) {
  199. if ( _wcsicmp( newDirectory->FindData.cFileName, fileData.cFileName ) == 0 ) {
  200. ok = TRUE;
  201. break;
  202. }
  203. newDirectory = (PDIRECTORY_ENTRY)GetNextContainer( newDirectory );
  204. }
  205. userData = NULL;
  206. if ( newDirectory != NULL ) {
  207. userData = newDirectory->UserData;
  208. }
  209. if ( ARGUMENT_PRESENT(NewDirectoryCallback) ) {
  210. error = NewDirectoryCallback(
  211. Context,
  212. currentDirectoryName,
  213. (newDirectory == NULL) ? NULL : &newDirectory->FindData,
  214. &fileData,
  215. &userData,
  216. &currentDirectory->UserData
  217. );
  218. if ( error != NO_ERROR ) {
  219. FindClose( findHandle );
  220. return error;
  221. }
  222. }
  223. if ( newDirectory != NULL ) {
  224. newDirectory->UserData = userData;
  225. } else if ( userData != NULL ) {
  226. newDirectory = malloc( sizeof(DIRECTORY_ENTRY) - sizeof(WCHAR) +
  227. ((wcslen(fileData.cFileName) + 1) * sizeof(WCHAR)) );
  228. if ( newDirectory == NULL ) {
  229. if ( (userData != NULL) &&
  230. (params->FreeUserDataCallback != NULL) ) {
  231. params->FreeUserDataCallback( userData );
  232. }
  233. FindClose( findHandle );
  234. return ERROR_NOT_ENOUGH_MEMORY;
  235. }
  236. InitializeContainer( newDirectory, currentDirectory );
  237. newDirectory->FindData.dwFileAttributes = fileData.dwFileAttributes;
  238. newDirectory->FindData.ftCreationTime = fileData.ftCreationTime;
  239. newDirectory->FindData.ftLastAccessTime = fileData.ftLastAccessTime;
  240. newDirectory->FindData.ftLastWriteTime = fileData.ftLastWriteTime;
  241. newDirectory->FindData.nFileSizeHigh = fileData.nFileSizeHigh;
  242. newDirectory->FindData.nFileSizeLow = fileData.nFileSizeLow;
  243. wcscpy( newDirectory->FindData.cAlternateFileName, fileData.cAlternateFileName );
  244. wcscpy( newDirectory->FindData.cFileName, fileData.cFileName );
  245. newDirectory->UserData = userData;
  246. InsertContainer( currentDirectory, newDirectory );
  247. }
  248. }
  249. ok = FindNextFile( findHandle, &fileData );
  250. } while ( ok );
  251. FindClose( findHandle );
  252. } // findHandle != INVALID_HANDLE_VALUE
  253. if ( ARGUMENT_PRESENT(CheckFileCallback) ) {
  254. newFile = (PFILE_ENTRY)GetFirstObject( currentDirectory );
  255. while ( newFile != NULL ) {
  256. error = CheckFileCallback(
  257. Context,
  258. currentDirectoryName,
  259. &newFile->FindData,
  260. &newFile->UserData,
  261. &currentDirectory->UserData
  262. );
  263. if ( error != NO_ERROR ) {
  264. return error;
  265. }
  266. newFile = (PFILE_ENTRY)GetNextObject( currentDirectory, newFile );
  267. }
  268. }
  269. newDirectory = (PDIRECTORY_ENTRY)GetFirstContainer( currentDirectory );
  270. while ( newDirectory != NULL ) {
  271. if ( !ARGUMENT_PRESENT(RecurseDirectoryCallback) ||
  272. RecurseDirectoryCallback(
  273. Context,
  274. currentDirectoryName,
  275. &newDirectory->FindData,
  276. &newDirectory->UserData,
  277. &currentDirectory->UserData
  278. ) ) {
  279. break;
  280. }
  281. newDirectory = (PDIRECTORY_ENTRY)GetNextContainer( newDirectory );
  282. }
  283. if ( newDirectory != NULL ) {
  284. currentDirectory = newDirectory;
  285. wcscat( currentDirectoryName, L"\\" );
  286. wcscat( currentDirectoryName, currentDirectory->FindData.cFileName );
  287. } else {
  288. while ( TRUE ) {
  289. if ( currentDirectory == rootDirectory ) {
  290. currentDirectory = NULL;
  291. break;
  292. }
  293. if ( ARGUMENT_PRESENT(CheckDirectoryCallback) ) {
  294. error = CheckDirectoryCallback(
  295. Context,
  296. currentDirectoryName,
  297. &currentDirectory->FindData,
  298. &currentDirectory->UserData,
  299. GetParentUserData(currentDirectory)
  300. );
  301. if ( error != NO_ERROR ) {
  302. return error;
  303. }
  304. }
  305. *wcsrchr(currentDirectoryName, L'\\') = 0;
  306. newDirectory = (PDIRECTORY_ENTRY)GetNextContainer( currentDirectory );
  307. while ( newDirectory != NULL ) {
  308. if ( !ARGUMENT_PRESENT(RecurseDirectoryCallback) ||
  309. RecurseDirectoryCallback(
  310. Context,
  311. currentDirectoryName,
  312. &newDirectory->FindData,
  313. &newDirectory->UserData,
  314. &currentDirectory->UserData
  315. ) ) {
  316. break;
  317. }
  318. newDirectory = (PDIRECTORY_ENTRY)GetNextContainer( newDirectory );
  319. }
  320. if ( newDirectory != NULL ) {
  321. currentDirectory = newDirectory;
  322. wcscat( currentDirectoryName, L"\\" );
  323. wcscat( currentDirectoryName, currentDirectory->FindData.cFileName );
  324. break;
  325. } else {
  326. currentDirectory = (PDIRECTORY_ENTRY)GetParent( currentDirectory );
  327. }
  328. }
  329. }
  330. } while ( currentDirectory != NULL );
  331. return ERROR_SUCCESS;
  332. }
  333. DWORD
  334. ScanEnumTree (
  335. IN PVOID ScanHandle,
  336. IN PVOID Context,
  337. IN PSCAN_ENUM_DIRECTORY_CALLBACK EnumDirectoryCallback OPTIONAL,
  338. IN PSCAN_ENUM_FILE_CALLBACK EnumFileCallback OPTIONAL
  339. )
  340. {
  341. DWORD error;
  342. PSCAN_PARAMETERS params;
  343. PDIRECTORY_ENTRY rootDirectory;
  344. PDIRECTORY_ENTRY currentDirectory;
  345. PDIRECTORY_ENTRY directory;
  346. PFILE_ENTRY file;
  347. WCHAR relativePath[MAX_PATH + 1];
  348. params = ScanHandle;
  349. rootDirectory = (PDIRECTORY_ENTRY)&params->RootDirectoryEntry;
  350. currentDirectory = rootDirectory;
  351. relativePath[0] = 0;
  352. do {
  353. if ( ARGUMENT_PRESENT(EnumFileCallback) ) {
  354. file = (PFILE_ENTRY)GetFirstObject( currentDirectory );
  355. while ( file != NULL ) {
  356. error = EnumFileCallback(
  357. Context,
  358. relativePath,
  359. &file->FindData,
  360. &file->UserData,
  361. &currentDirectory->UserData
  362. );
  363. if ( error != ERROR_SUCCESS ) {
  364. dprintf(( "EnumFileCallback returned %d\n", error ));
  365. return error;
  366. }
  367. file = (PFILE_ENTRY)GetNextObject( currentDirectory, file );
  368. }
  369. }
  370. directory = (PDIRECTORY_ENTRY)GetFirstContainer( currentDirectory );
  371. if ( directory != NULL ) {
  372. currentDirectory = directory;
  373. wcscat( relativePath, L"\\" );
  374. wcscat( relativePath, currentDirectory->FindData.cFileName );
  375. } else {
  376. while ( TRUE ) {
  377. if ( currentDirectory == rootDirectory ) {
  378. currentDirectory = NULL;
  379. break;
  380. }
  381. *wcsrchr(relativePath, L'\\') = 0;
  382. if ( ARGUMENT_PRESENT(EnumDirectoryCallback) ) {
  383. error = EnumDirectoryCallback(
  384. Context,
  385. relativePath,
  386. &currentDirectory->FindData,
  387. &currentDirectory->UserData,
  388. GetParentUserData(currentDirectory)
  389. );
  390. if ( error != ERROR_SUCCESS ) {
  391. dprintf(( "EnumDirectoryCallback returned %d\n", error ));
  392. return error;
  393. }
  394. }
  395. directory = (PDIRECTORY_ENTRY)GetNextContainer( currentDirectory );
  396. if ( directory != NULL ) {
  397. currentDirectory = directory;
  398. wcscat( relativePath, L"\\" );
  399. wcscat( relativePath, currentDirectory->FindData.cFileName );
  400. break;
  401. } else {
  402. currentDirectory = (PDIRECTORY_ENTRY)GetParent( currentDirectory );
  403. }
  404. }
  405. }
  406. } while ( currentDirectory != NULL );
  407. return ERROR_SUCCESS;
  408. }
  409. VOID
  410. ScanTerminate (
  411. IN PVOID ScanHandle
  412. )
  413. {
  414. PSCAN_PARAMETERS params;
  415. params = ScanHandle;
  416. ScanFreeChildren( params, (PCONTAINER_ENTRY)&params->RootDirectoryEntry );
  417. if ( (params->RootDirectoryEntry.UserData != NULL) &&
  418. (params->FreeUserDataCallback != NULL) ) {
  419. params->FreeUserDataCallback( params->RootDirectoryEntry.UserData );
  420. }
  421. free( params );
  422. return;
  423. }
  424. VOID
  425. ScanFreeChildren (
  426. IN PSCAN_PARAMETERS Parameters,
  427. IN PCONTAINER_ENTRY RootContainer
  428. )
  429. {
  430. PCONTAINER_ENTRY currentContainer;
  431. PCONTAINER_ENTRY container;
  432. PCONTAINER_ENTRY parent;
  433. POBJECT_ENTRY object;
  434. #if SCAN_DEBUG
  435. WCHAR currentPath[MAX_PATH + 1];
  436. #endif
  437. #if SCAN_DEBUG
  438. #define CONTAINER_NAME(_container) ((PDIRECTORY_ENTRY)(_container))->FindData.cFileName
  439. #define OBJECT_NAME(_object) ((PFILE_ENTRY)(_object))->FindData.cFileName
  440. currentPath[0] = 0;
  441. #endif
  442. currentContainer = RootContainer;
  443. do {
  444. object = GetFirstObject( currentContainer );
  445. while ( object != NULL ) {
  446. #if SCAN_DEBUG
  447. dprintf(( "Deleting entry for object %ws\\%ws\n", currentPath, OBJECT_NAME(object) ));
  448. #endif
  449. RemoveObject( object );
  450. if ( (object->UserData != NULL) &&
  451. (Parameters->FreeUserDataCallback != NULL) ) {
  452. Parameters->FreeUserDataCallback( object->UserData );
  453. }
  454. free( object );
  455. object = GetFirstObject( currentContainer );
  456. }
  457. container = GetFirstContainer( currentContainer );
  458. if ( container != NULL ) {
  459. currentContainer = container;
  460. #if SCAN_DEBUG
  461. wcscat( currentPath, L"\\" );
  462. wcscat( currentPath, CONTAINER_NAME(currentContainer) );
  463. #endif
  464. } else {
  465. while ( TRUE ) {
  466. if ( currentContainer == RootContainer ) {
  467. currentContainer = NULL;
  468. break;
  469. }
  470. #if SCAN_DEBUG
  471. dprintf(( "Deleting entry for container %ws\n", currentPath ));
  472. *wcsrchr(currentPath, L'\\') = 0;
  473. #endif
  474. parent = GetParent( currentContainer );
  475. RemoveContainer( currentContainer );
  476. if ( (currentContainer->UserData != NULL) &&
  477. (Parameters->FreeUserDataCallback != NULL) ) {
  478. Parameters->FreeUserDataCallback( currentContainer->UserData );
  479. }
  480. free( currentContainer );
  481. currentContainer = GetFirstContainer( parent );
  482. if ( currentContainer != NULL ) {
  483. #if SCAN_DEBUG
  484. wcscat( currentPath, L"\\" );
  485. wcscat( currentPath, CONTAINER_NAME(currentContainer) );
  486. #endif
  487. break;
  488. } else {
  489. currentContainer = parent;
  490. }
  491. }
  492. }
  493. } while ( currentContainer != NULL );
  494. return;
  495. }