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.

446 lines
11 KiB

  1. /*************************************************************************
  2. *
  3. * deldir.c
  4. *
  5. * Functions to delete all the files and subdirectories under a given
  6. * directory (similar to rm -rf).
  7. *
  8. * Copyright Microsoft, 1998
  9. *
  10. *
  11. *************************************************************************/
  12. /* include files */
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <windows.h>
  17. #include "winsta.h"
  18. #include "syslib.h"
  19. #if DBG
  20. #define DBGPRINT(x) DbgPrint x
  21. #if DBGTRACE
  22. #define TRACE0(x) DbgPrint x
  23. #define TRACE1(x) DbgPrint x
  24. #else
  25. #define TRACE0(x)
  26. #define TRACE1(x)
  27. #endif
  28. #else
  29. #define DBGPRINT(x)
  30. #define TRACE0(x)
  31. #define TRACE1(x)
  32. #endif
  33. /*
  34. * Data Structure
  35. */
  36. typedef struct dirent {
  37. ULONG d_attr; /* file attributes */
  38. WCHAR d_name[MAX_PATH+1]; /* file name */
  39. WCHAR d_first;
  40. HANDLE d_handle;
  41. } DIR, *PDIR;
  42. /*
  43. * procedure prototypes
  44. */
  45. void remove_file( PWCHAR, ULONG );
  46. PDIR opendir( PWCHAR );
  47. PDIR readdir( PDIR );
  48. int closedir( PDIR );
  49. BOOL QueryFlatTempKey( VOID );
  50. BOOLEAN SetFileTree( PWCHAR pRoot, PWCHAR pAvoidDir );
  51. /*****************************************************************************
  52. *
  53. * RemoveDir
  54. *
  55. * Delete the given subdirectory and all files and subdirectories within it.
  56. *
  57. * ENTRY:
  58. * PWCHAR (In) dirname - directory to delete
  59. *
  60. * EXIT:
  61. * SUCCESS: TRUE
  62. * FAILURE: FALSE
  63. *
  64. ****************************************************************************/
  65. BOOL RemoveDir(PWCHAR dirname)
  66. {
  67. DIR *dirp, *direntp;
  68. WCHAR pathname[MAX_PATH];
  69. PWCHAR namep;
  70. ULONG ulattr;
  71. if ((dirp = opendir(dirname)) == NULL) {
  72. return(FALSE);
  73. }
  74. wcscpy( pathname, dirname );
  75. if ( pathname[wcslen(pathname)-1] != L'\\' &&
  76. pathname[wcslen(pathname)-1] != L'/' )
  77. wcscat( pathname, L"\\" );
  78. namep = pathname + wcslen(pathname);
  79. while ( direntp = readdir( dirp ) ) {
  80. if ( wcscmp( direntp->d_name, L"." ) &&
  81. wcscmp( direntp->d_name, L".." ) ) {
  82. wcscpy( namep, direntp->d_name );
  83. if ( direntp->d_attr & FILE_ATTRIBUTE_DIRECTORY ) {
  84. RemoveDir( pathname );
  85. } else {
  86. remove_file( pathname, direntp->d_attr );
  87. }
  88. }
  89. }
  90. closedir( dirp );
  91. /*
  92. * If directory is read-only, make it writable before trying to remove it
  93. */
  94. ulattr = GetFileAttributes(dirname);
  95. if ((ulattr != 0xffffffff) &&
  96. (ulattr & FILE_ATTRIBUTE_READONLY)) {
  97. SetFileAttributes(dirname, (ulattr & ~FILE_ATTRIBUTE_READONLY));
  98. }
  99. if (!RemoveDirectory(dirname)) {
  100. DBGPRINT(("RemoveDir: unable to remove directory=%ws\n", dirname));
  101. if (ulattr & FILE_ATTRIBUTE_READONLY) { // set back to readonly
  102. SetFileAttributes(dirname, ulattr);
  103. }
  104. }
  105. return(TRUE);
  106. }
  107. /*****************************************************************************
  108. *
  109. * remove_file
  110. *
  111. * Delete the given file.
  112. *
  113. * ENTRY:
  114. * PWCHAR (In) fname - file to delete
  115. * ULONG (In) attr - attributes of file to delete
  116. *
  117. * EXIT:
  118. * void
  119. *
  120. ****************************************************************************/
  121. void remove_file(PWCHAR fname, ULONG attr)
  122. {
  123. /*
  124. * If file is read-only, then make it writable before trying to remove it
  125. */
  126. if (attr & FILE_ATTRIBUTE_READONLY) {
  127. if (!SetFileAttributes(fname, (attr & ~FILE_ATTRIBUTE_READONLY))) {
  128. DBGPRINT(("remove_file: unable to remove file=%ws\n", fname));
  129. return;
  130. }
  131. }
  132. /*
  133. * remove the file
  134. */
  135. if (!DeleteFile(fname)) {
  136. if (!(attr & FILE_ATTRIBUTE_READONLY)) { // if file was read-only,
  137. DBGPRINT(("remove_file: unable to remove file=%ws\n", fname));
  138. SetFileAttributes(fname, attr); // then change it back
  139. }
  140. }
  141. }
  142. /*****************************************************************************
  143. *
  144. * opendir
  145. *
  146. * "Open" (FindFirstFile) the specified directory.
  147. *
  148. * ENTRY:
  149. * PWCHAR (In) dirname - directory to open
  150. *
  151. * EXIT:
  152. * SUCCESS: pointer to DIR struct
  153. * FAILURE: NULL
  154. *
  155. ****************************************************************************/
  156. PDIR opendir( PWCHAR dirname )
  157. {
  158. PDIR dirp;
  159. unsigned count = 1;
  160. WIN32_FIND_DATA fileinfo;
  161. WCHAR pathname[MAX_PATH], sep;
  162. unsigned rc;
  163. if ((dirp = RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(DIR))) == NULL) {
  164. DBGPRINT(("opendir: unable to allocate DIR structure.\n"));
  165. return( NULL );
  166. }
  167. memset( dirp, 0, sizeof(DIR) );
  168. /*
  169. * Build pathname to use for FindFirst call
  170. */
  171. wcscpy( pathname, dirname );
  172. if ( pathname[1] == L':' && pathname[2] == L'\0' )
  173. wcscat( pathname, L".\\*.*" );
  174. else if ( pathname[0] == '\0' ||
  175. (sep = pathname[wcslen(pathname)-1]) == L'\\' || sep == L'/' )
  176. wcscat( pathname, L"*.*" );
  177. else
  178. wcscat( pathname, L"\\*.*" );
  179. if ((dirp->d_handle =
  180. FindFirstFile(pathname, &fileinfo)) == INVALID_HANDLE_VALUE) {
  181. rc = GetLastError();
  182. DBGPRINT(("opendir: unable to open directory=%ws, rc=%d\n", dirname, rc));
  183. } else {
  184. rc = 0;
  185. }
  186. if (rc == NO_ERROR) {
  187. dirp->d_attr = fileinfo.dwFileAttributes;
  188. wcscpy(dirp->d_name, fileinfo.cFileName);
  189. dirp->d_first = TRUE;
  190. return( dirp );
  191. }
  192. if ( rc != ERROR_NO_MORE_FILES ) {
  193. closedir( dirp );
  194. return( NULL );
  195. }
  196. return( dirp );
  197. }
  198. /*****************************************************************************
  199. *
  200. * readdir
  201. *
  202. * Get the next file/directory to be deleted
  203. *
  204. * ENTRY:
  205. * PDIR (In) dirp - pointer to open directory structure
  206. *
  207. * EXIT:
  208. * SUCCESS: pointer to DIR struct
  209. * FAILURE: NULL
  210. *
  211. ****************************************************************************/
  212. PDIR readdir( PDIR dirp )
  213. {
  214. WIN32_FIND_DATA fileinfo;
  215. unsigned count = 1;
  216. unsigned rc;
  217. if ( !dirp ) {
  218. return( NULL );
  219. }
  220. if ( dirp->d_first ) {
  221. dirp->d_first = FALSE;
  222. return( dirp );
  223. }
  224. if ( !(rc = FindNextFile( dirp->d_handle, &fileinfo )) ) {
  225. rc = GetLastError();
  226. DBGPRINT(("readdir: FindNextFile failed, rc=%d\n", rc));
  227. } else {
  228. rc = 0;
  229. }
  230. if ( rc == NO_ERROR ) {
  231. dirp->d_attr = fileinfo.dwFileAttributes;
  232. wcscpy(dirp->d_name, fileinfo.cFileName);
  233. return( dirp );
  234. }
  235. return( NULL );
  236. }
  237. /*****************************************************************************
  238. *
  239. * closedir
  240. *
  241. * Close an open directory handle
  242. *
  243. * ENTRY:
  244. * PDIR (In) dirp - pointer to open directory structure
  245. *
  246. * EXIT:
  247. * SUCCESS: 0
  248. * FAILURE: -1
  249. *
  250. ****************************************************************************/
  251. int closedir( PDIR dirp )
  252. {
  253. if ( !dirp ) {
  254. return( -1 );
  255. }
  256. FindClose( dirp->d_handle );
  257. RtlFreeHeap( RtlProcessHeap(), 0, dirp );
  258. return( 0 );
  259. }
  260. /*****************************************************************************
  261. *
  262. * CtxCreateTempDir
  263. *
  264. * Create and set the temporary environment variable for this user.
  265. *
  266. * ENTRY:
  267. * PWSTR pwcEnvVar (In): Pointer to environment variable to set
  268. * PWSTR pwcLogonID (In): Pointer to user's logon ID
  269. * PVOID *pEnv (In): Pointer to pointer (a handle) to environment to query/set
  270. * PWSTR ppTempName (Out/Optional): Pointer to location to return name
  271. * of temp directory that was created
  272. *
  273. * EXIT:
  274. * SUCCESS: Returns TRUE
  275. * FAILURE: Returns FALSE
  276. *
  277. ****************************************************************************/
  278. BOOL
  279. CtxCreateTempDir( PWSTR pwcEnvVar, PWSTR pwcLogonId, PVOID *pEnv,
  280. PWSTR *ppTempName, PCTX_USER_DATA pCtxUserData )
  281. {
  282. WCHAR Buffer[MAX_PATH];
  283. WCHAR RootPath[]=L"x:\\";
  284. ULONG Dtype;
  285. UNICODE_STRING Name, Value;
  286. ULONG ulattr;
  287. NTSTATUS Status;
  288. BOOL bRC;
  289. HANDLE ImpersonationHandle;
  290. Value.Buffer = Buffer;
  291. Value.Length = 0;
  292. Value.MaximumLength = sizeof(Buffer);
  293. RtlInitUnicodeString(&Name, pwcEnvVar);
  294. //
  295. // Get the temp directory variable
  296. //
  297. Status = RtlQueryEnvironmentVariable_U( *pEnv, &Name, &Value );
  298. if ( !NT_SUCCESS(Status) )
  299. return( FALSE );
  300. //
  301. // If temp directory points to a network (or client) drive,
  302. // or is not accessible, then change it to point to the \temp
  303. // directory on the %SystemRoot% drive.
  304. //
  305. // Took out check for DRIVE_REMOTE, per incident 34313hq. KLB 09-13-96
  306. //
  307. // Need to impersonate user during logon cause drive mapped under
  308. // impersonation. cjc 12-18-96
  309. //
  310. RootPath[0] = Buffer[0];
  311. if (pCtxUserData) {
  312. ImpersonationHandle = CtxImpersonateUser(pCtxUserData, NULL);
  313. if (!ImpersonationHandle) {
  314. return( FALSE );
  315. }
  316. }
  317. Dtype = GetDriveType( RootPath );
  318. if (pCtxUserData) {
  319. CtxStopImpersonating(ImpersonationHandle);
  320. }
  321. if ( Dtype == DRIVE_NO_ROOT_DIR || Dtype == DRIVE_UNKNOWN ||
  322. Dtype == DRIVE_CDROM ) {
  323. UNICODE_STRING SystemRoot;
  324. RtlInitUnicodeString( &SystemRoot, L"SystemRoot" );
  325. Status = RtlQueryEnvironmentVariable_U( *pEnv, &SystemRoot, &Value );
  326. if ( !NT_SUCCESS(Status) )
  327. return( FALSE );
  328. lstrcpy( &Buffer[3], L"temp" );
  329. }
  330. //
  331. // See if the directory already exists and if not try to create it
  332. //
  333. ulattr = GetFileAttributesW(Buffer);
  334. if ( ulattr == 0xffffffff ) {
  335. bRC = CreateDirectory( Buffer, NULL );
  336. DBGPRINT(( "CreateDirectory(%ws) %s.\n", Buffer, bRC ? "successful" : "failed" ));
  337. if ( !bRC ) {
  338. return( FALSE );
  339. }
  340. }
  341. else if ( !(ulattr & FILE_ATTRIBUTE_DIRECTORY) ) {
  342. return ( FALSE );
  343. }
  344. // Append the logonid onto the temp env. variable. We ONLY do this if the
  345. // registry key for "Flat Temporary Directories" is not set. If it is,
  346. // then they want to put their temp directory under the user's directory,
  347. // and DON'T want it to be in a directory under that. This is related to
  348. // incident 34313hq. KLB 09-16-96
  349. if ( !QueryFlatTempKey() ) {
  350. if ( lstrlen(Buffer) + lstrlen(pwcLogonId) >= MAX_PATH ) {
  351. return( FALSE );
  352. }
  353. lstrcat(Buffer, L"\\");
  354. lstrcat(Buffer, pwcLogonId);
  355. //
  356. // See if the directory already exists and if not try to create it
  357. // with the new
  358. //
  359. ulattr = GetFileAttributesW(Buffer);
  360. if ( ulattr == 0xffffffff ) {
  361. bRC = CreateDirectory( Buffer, NULL );
  362. DBGPRINT(( "CreateDirectory(%ws) %s.\n", Buffer, bRC ? "successful" : "failed" ));
  363. if ( !bRC ) {
  364. return( FALSE );
  365. }
  366. }
  367. else if ( !(ulattr & FILE_ATTRIBUTE_DIRECTORY) ) {
  368. return ( FALSE );
  369. }
  370. }
  371. //
  372. // Need to set security on the new directory. This is done by simply
  373. // calling code from JohnR's ACLSET utility that we brought over here.
  374. // KLB 09-25-96
  375. //
  376. SetFileTree( Buffer, NULL );
  377. // Must re-init Value since length of string has changed
  378. RtlInitUnicodeString( &Value, Buffer );
  379. RtlSetEnvironmentVariable( pEnv, &Name, &Value );
  380. RtlSetEnvironmentVariable( NULL, &Name, &Value );
  381. if ( ppTempName )
  382. *ppTempName = _wcsdup( Buffer );
  383. return( TRUE );
  384. } // end of CtxCreateTempDir()