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.

336 lines
7.8 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #if SCAN_DEBUG
  4. BOOL dprinton = FALSE;
  5. #endif
  6. //
  7. // This flag indicates whether empty directories should be deleted.
  8. //
  9. BOOL DeleteEmptyDirectories = FALSE;
  10. BOOL ContinueOnError = FALSE;
  11. BOOL Quiet = FALSE;
  12. BOOL ShowWriteableFiles = FALSE;
  13. DWORD
  14. NewFile (
  15. IN PVOID Context,
  16. IN PWCH Path,
  17. IN PSMALL_WIN32_FIND_DATAW ExistingFileData OPTIONAL,
  18. IN PWIN32_FIND_DATAW NewFileData,
  19. IN PVOID *FileUserData,
  20. IN PVOID *ParentDirectoryUserData
  21. )
  22. /*++
  23. Routine Description:
  24. Called when ScanDirectory finds a file.
  25. Arguments:
  26. Context - User-supplied context. Not used by emptydirs.
  27. Path - Directory containing this file.
  28. ExistingFileData - Pointer to data describing previous found file with
  29. same name, if any.
  30. NewFileData - Pointer to data for this file.
  31. FileUserData - Pointer to user-controlled data field for the file.
  32. ParentDirectoryUserData - Pointer to user-controlled data field for the
  33. parent directory.
  34. Return Value:
  35. DWORD - Indicates whether an error occurred.
  36. --*/
  37. {
  38. //
  39. // Increment the directory/file count for the parent. Set the file's
  40. // user data pointer to NULL, indicating that we don't need the
  41. // scan library to remember this file.
  42. //
  43. (*(DWORD *)ParentDirectoryUserData)++;
  44. *FileUserData = NULL;
  45. dprintf(( " NF: File %ws\\%ws: parent count %d, file count %d\n",
  46. Path, NewFileData->cFileName,
  47. *(DWORD *)ParentDirectoryUserData, *FileUserData ));
  48. //
  49. // If we're supposed to show writeable files, check for that now.
  50. //
  51. if ( ShowWriteableFiles &&
  52. ((NewFileData->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) ) {
  53. printf( "FILE: %ws\\%ws\n", Path, NewFileData->cFileName );
  54. }
  55. return 0;
  56. } // NewFile
  57. DWORD
  58. NewDirectory (
  59. IN PVOID Context,
  60. IN PWCH Path,
  61. IN PSMALL_WIN32_FIND_DATAW ExistingDirectoryData OPTIONAL,
  62. IN PWIN32_FIND_DATAW NewDirectoryData,
  63. IN PVOID *DirectoryUserData,
  64. IN PVOID *ParentDirectoryUserData
  65. )
  66. /*++
  67. Routine Description:
  68. Called when ScanDirectory finds a directory.
  69. Arguments:
  70. Context - User-supplied context. Not used by emptydirs.
  71. Path - Directory containing this directory.
  72. ExistingDirectoryData - Pointer to data describing previous found directory with
  73. same name, if any.
  74. NewDirectoryData - Pointer to data for this directory.
  75. DirectoryUserData - Pointer to user-controlled data field for the directory.
  76. ParentDirectoryUserData - Pointer to user-controlled data field for the
  77. parent directory.
  78. Return Value:
  79. DWORD - Indicates whether an error occurred.
  80. --*/
  81. {
  82. //
  83. // Increment the directory/file count for the parent. Set the directory's
  84. // user data pointer to 1, indicating that the scan library should
  85. // remember this directory and scan it.
  86. //
  87. (*(DWORD *)ParentDirectoryUserData)++;
  88. *(DWORD *)DirectoryUserData = 1;
  89. dprintf(( " ND: Dir %ws\\%ws: parent count %d, dir count %d\n",
  90. Path, NewDirectoryData->cFileName,
  91. *(DWORD *)ParentDirectoryUserData, *DirectoryUserData ));
  92. return 0;
  93. } // NewDirectory
  94. DWORD
  95. CheckDirectory (
  96. IN PVOID Context,
  97. IN PWCH Path,
  98. IN PSMALL_WIN32_FIND_DATAW DirectoryData,
  99. IN PVOID *DirectoryUserData,
  100. IN PVOID *ParentDirectoryUserData
  101. )
  102. /*++
  103. Routine Description:
  104. Called when ScanDirectory has completed the recursive scan for a directory.
  105. Arguments:
  106. Context - User-supplied context. Not used by emptydirs.
  107. Path - Path to this directory. (Not to containing directory.)
  108. DirectoryData - Pointer to data for this directory.
  109. DirectoryUserData - Pointer to user-controlled data field for the directory.
  110. ParentDirectoryUserData - Pointer to user-controlled data field for the
  111. parent directory.
  112. Return Value:
  113. DWORD - Indicates whether an error occurred.
  114. --*/
  115. {
  116. BOOL ok;
  117. DWORD error;
  118. //
  119. // If the directory's directory/file count is 1, then the directory
  120. // contains no files or directories (the count is biased by 1), and
  121. // is empty.
  122. //
  123. if ( *(DWORD *)DirectoryUserData == 1 ) {
  124. if ( !Quiet ) {
  125. if ( ShowWriteableFiles ) {
  126. printf( "DIR: " );
  127. }
  128. printf( "%ws", Path );
  129. }
  130. //
  131. // If requested, delete this empty directory.
  132. //
  133. if ( DeleteEmptyDirectories ) {
  134. ok = RemoveDirectory( Path );
  135. if ( !ok ) {
  136. error = GetLastError( );
  137. if ( !Quiet ) printf( " - error %d\n", error );
  138. fprintf( stderr, "Error %d deleting %ws\n", error, Path );
  139. if ( !ContinueOnError ) {
  140. return error;
  141. }
  142. } else {
  143. if ( !Quiet ) printf( " - deleted\n" );
  144. }
  145. } else {
  146. if ( !Quiet ) printf( "\n" );
  147. }
  148. //
  149. // Decrement the parent directory's directory/file count.
  150. //
  151. (*(DWORD *)ParentDirectoryUserData)--;
  152. }
  153. dprintf(( " CD: Dir %ws: parent count %d, dir count %d\n",
  154. Path,
  155. *(DWORD *)ParentDirectoryUserData, *DirectoryUserData ));
  156. return 0;
  157. } // CheckDirectory
  158. int
  159. __cdecl
  160. wmain (
  161. int argc,
  162. WCHAR *argv[]
  163. )
  164. {
  165. BOOL ok;
  166. DWORD error;
  167. WCHAR directory[MAX_PATH];
  168. PVOID scanHandle = NULL;
  169. //
  170. // Parse switches.
  171. //
  172. argc--;
  173. argv++;
  174. while ( (argc != 0) && ((argv[0][0] == '-') || (argv[0][0] == '/')) ) {
  175. argv[0]++;
  176. switch ( towlower(argv[0][0]) ) {
  177. case 'c':
  178. ContinueOnError = TRUE;
  179. break;
  180. case 'd':
  181. DeleteEmptyDirectories = TRUE;
  182. break;
  183. case 'q':
  184. Quiet = TRUE;
  185. break;
  186. case 'w':
  187. ShowWriteableFiles = TRUE;
  188. break;
  189. default:
  190. fprintf( stderr, "usage: emptydirs [-cdqw]\n" );
  191. return 1;
  192. }
  193. argc--;
  194. argv++;
  195. }
  196. //
  197. // If a directory was specified, CD to it and get its path.
  198. //
  199. if ( argc != 0 ) {
  200. ok = SetCurrentDirectory( argv[0] );
  201. if ( !ok ) {
  202. error = GetLastError( );
  203. fprintf( stderr, "error: Unable to change to specified directory %ws: %d\n", argv[0], error );
  204. goto cleanup;
  205. }
  206. }
  207. argc--;
  208. argv++;
  209. GetCurrentDirectory( MAX_PATH, directory );
  210. //
  211. // Initialize the scan library.
  212. //
  213. error = ScanInitialize(
  214. &scanHandle,
  215. TRUE, // recurse
  216. FALSE, // don't skip root
  217. NULL
  218. );
  219. if (error != 0) {
  220. fprintf( stderr, "ScanInitialize(%ws) failed %d\n", directory, error );
  221. error = 1;
  222. goto cleanup;
  223. }
  224. //
  225. // Scan the specified directory.
  226. //
  227. error = ScanDirectory(
  228. scanHandle,
  229. directory,
  230. NULL,
  231. NewDirectory,
  232. CheckDirectory,
  233. NULL,
  234. NewFile,
  235. NULL
  236. );
  237. if (error != 0) {
  238. fprintf( stderr, "ScanDirectory(%ws) failed %d\n", directory, error );
  239. error = 1;
  240. goto cleanup;
  241. }
  242. cleanup:
  243. //
  244. // Close down the scan library.
  245. //
  246. if ( scanHandle != NULL ) {
  247. ScanTerminate( scanHandle );
  248. }
  249. return error;
  250. } // wmain