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.

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