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.

787 lines
18 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. nwtrash.c
  5. Abstract:
  6. This module contains the routines for performing Network Trash Folder
  7. operations.
  8. Author:
  9. Sue Adams (microsoft!suea)
  10. Revision History:
  11. 06 Aug 1992 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #define NWTRASH_LOCALS
  15. #define FILENUM FILE_NWTRASH
  16. #include <afp.h>
  17. #include <fdparm.h>
  18. #include <pathmap.h>
  19. #include <nwtrash.h>
  20. #include <afpinfo.h>
  21. #include <access.h>
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text( PAGE, AfpCreateNetworkTrash)
  24. #pragma alloc_text( PAGE, AfpDeleteNetworkTrash)
  25. #pragma alloc_text( PAGE, afpCleanNetworkTrash)
  26. #pragma alloc_text( PAGE, AfpWalkDirectoryTree)
  27. #pragma alloc_text( PAGE, afpPushDirNode)
  28. #pragma alloc_text( PAGE, afpPopDirNode)
  29. #pragma alloc_text( PAGE, AfpGetNextDirectoryInfo)
  30. #pragma alloc_text( PAGE, afpNwtDeleteFileEntity)
  31. #endif
  32. /*** AfpCreateNetworkTrash
  33. *
  34. * Create the network trash folder for a newly added volume.
  35. * Make sure it is hidden and make sure the streams are intact.
  36. * This routine may only be called for NTFS volumes. Note that even
  37. * ReadOnly NTFS volumes will have a trash created. This is because
  38. * if someone is going to toggle the volume ReadOnly bit, we don't need
  39. * to worry about creating/deleting the trash on the fly.
  40. * We keep an open handle to the network trash stored in the volume
  41. * descriptor so that nobody can come in behind our backs and delete
  42. * it.
  43. */
  44. NTSTATUS
  45. AfpCreateNetworkTrash(
  46. IN PVOLDESC pVolDesc
  47. )
  48. {
  49. FILESYSHANDLE hNWT;
  50. PDFENTRY pDfEntry;
  51. NTSTATUS Status;
  52. ULONG info, Attr;
  53. AFPINFO afpInfo;
  54. BOOLEAN ReleaseSwmr = False;
  55. PISECURITY_DESCRIPTOR pSecDesc;
  56. FILEDIRPARM fdparm; // This is used to set the hidden attribute
  57. // of the FinderInfo for network trash folder
  58. PAGED_CODE( );
  59. DBGPRINT(DBG_COMP_IDINDEX,DBG_LEVEL_INFO,("\tCreating Network Trash...\n"));
  60. ASSERT(pVolDesc->vds_Flags & VOLUME_NTFS);
  61. hNWT.fsh_FileHandle = NULL;
  62. Status = AfpMakeSecurityDescriptorForUser(&AfpSidWorld, &AfpSidWorld, &pSecDesc);
  63. if (!NT_SUCCESS(Status))
  64. return Status;
  65. ASSERT (pSecDesc != NULL);
  66. ASSERT (pSecDesc->Dacl != NULL);
  67. do
  68. {
  69. // NOTE: NTFS allows me to open a Readonly directory for
  70. // delete access.
  71. Status = AfpIoCreate(&pVolDesc->vds_hRootDir,
  72. AFP_STREAM_DATA,
  73. &AfpNetworkTrashNameU,
  74. AFP_NWT_ACCESS | AFP_OWNER_ACCESS,
  75. AFP_NWT_SHAREMODE,
  76. AFP_NWT_OPTIONS,
  77. AFP_NWT_DISPOSITION,
  78. AFP_NWT_ATTRIBS, // makes it hidden
  79. False,
  80. pSecDesc,
  81. &hNWT,
  82. &info,
  83. NULL,
  84. NULL,
  85. NULL);
  86. // Free the memory allocated for the security descriptor
  87. AfpFreeMemory(pSecDesc->Dacl);
  88. AfpFreeMemory(pSecDesc);
  89. if (!NT_SUCCESS(Status))
  90. break;
  91. ASSERT(info == FILE_CREATED);
  92. // Add the AfpInfo stream
  93. Status = AfpSlapOnAfpInfoStream(NULL,
  94. NULL,
  95. &hNWT,
  96. NULL,
  97. AFP_ID_NETWORK_TRASH,
  98. True,
  99. NULL,
  100. &afpInfo);
  101. if (!NT_SUCCESS(Status))
  102. break;
  103. // it does not exist in the ID index database, add it
  104. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  105. ReleaseSwmr = True;
  106. ASSERT(pVolDesc->vds_pDfeRoot != NULL);
  107. pDfEntry = AfpAddDfEntry(pVolDesc,
  108. pVolDesc->vds_pDfeRoot,
  109. &AfpNetworkTrashNameU,
  110. True,
  111. AFP_ID_NETWORK_TRASH);
  112. if (pDfEntry == NULL)
  113. {
  114. Status = STATUS_UNSUCCESSFUL;
  115. break;
  116. }
  117. // NOTE: pDfEntry now points to the "Network Trash Folder"
  118. // Get directory info to cache
  119. Status = AfpIoQueryTimesnAttr(&hNWT,
  120. &pDfEntry->dfe_CreateTime,
  121. &pDfEntry->dfe_LastModTime,
  122. &Attr);
  123. ASSERT(NT_SUCCESS(Status));
  124. ASSERT(Attr & FILE_ATTRIBUTE_HIDDEN);
  125. pDfEntry->dfe_NtAttr = (USHORT)Attr & FILE_ATTRIBUTE_VALID_FLAGS;
  126. pDfEntry->dfe_AfpAttr = afpInfo.afpi_Attributes;
  127. pDfEntry->dfe_FinderInfo = afpInfo.afpi_FinderInfo;
  128. pDfEntry->dfe_BackupTime = afpInfo.afpi_BackupTime;
  129. DFE_OWNER_ACCESS(pDfEntry) = (DIR_ACCESS_SEARCH | DIR_ACCESS_READ);
  130. DFE_GROUP_ACCESS(pDfEntry) = (DIR_ACCESS_SEARCH | DIR_ACCESS_READ);
  131. DFE_WORLD_ACCESS(pDfEntry) = (DIR_ACCESS_SEARCH | DIR_ACCESS_READ);
  132. // ok, we know it now exists both on disk and in the database
  133. if (NT_SUCCESS(Status))
  134. {
  135. RtlZeroMemory(&fdparm, sizeof(fdparm));
  136. fdparm._fdp_Flags = DFE_FLAGS_DIR;
  137. fdparm._fdp_AfpId = AFP_ID_NETWORK_TRASH;
  138. fdparm._fdp_FinderInfo = afpInfo.afpi_FinderInfo;
  139. // We must set the invisible flag in the finder info, because
  140. // System 6 seems to ignore the hidden attribute.
  141. pDfEntry->dfe_FinderInfo.fd_Attr1 |= FINDER_FLAG_INVISIBLE;
  142. fdparm._fdp_FinderInfo.fd_Attr1 |= FINDER_FLAG_INVISIBLE;
  143. Status = AfpSetAfpInfo(&hNWT,
  144. FD_BITMAP_FINDERINFO,
  145. &fdparm,
  146. NULL,
  147. NULL);
  148. }
  149. } while (False);
  150. if (hNWT.fsh_FileHandle != NULL)
  151. AfpIoClose(&hNWT);
  152. if (!NT_SUCCESS(Status))
  153. {
  154. AFPLOG_ERROR(AFPSRVMSG_CREATE_NWTRASH,
  155. Status,
  156. NULL,
  157. 0,
  158. &pVolDesc->vds_Name);
  159. }
  160. else
  161. {
  162. // Open a Network Trash handle to keep around so that no one can
  163. // come in and delete the Network Trash dir out from under us
  164. Status = AfpIoOpen(&pVolDesc->vds_hRootDir,
  165. AFP_STREAM_DATA,
  166. AFP_NWT_OPTIONS,
  167. &AfpNetworkTrashNameU,
  168. FILEIO_ACCESS_READ,
  169. AFP_NWT_SHAREMODE,
  170. False,
  171. &pVolDesc->vds_hNWT);
  172. if (!NT_SUCCESS(Status))
  173. {
  174. AFPLOG_ERROR(AFPSRVMSG_CREATE_NWTRASH, Status, NULL, 0,
  175. &pVolDesc->vds_Name);
  176. }
  177. }
  178. if (ReleaseSwmr)
  179. {
  180. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  181. }
  182. return Status;
  183. }
  184. /*** AfpDeleteNetworkTrash
  185. *
  186. * Delete the network trash folder from disk when a volume is being added,
  187. * deleted or stopped.
  188. *
  189. * NOTE: this must be called in the server's context to ensure that we have
  190. * LOCAL_SYSTEM access to all the trash directories created by users
  191. */
  192. NTSTATUS
  193. AfpDeleteNetworkTrash(
  194. IN PVOLDESC pVolDesc,
  195. IN BOOLEAN VolumeStart // Is volume starting or is it stopping
  196. )
  197. {
  198. FILESYSHANDLE hNWT;
  199. NTSTATUS Status;
  200. PAGED_CODE( );
  201. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_INFO,
  202. ("\tDeleting Network Trash...\n") );
  203. ASSERT(pVolDesc->vds_Flags & VOLUME_NTFS);
  204. if (!VolumeStart)
  205. {
  206. // Close the handle to Network Trash that we keep open so PC users can't
  207. // delete the directory out from under us.
  208. if (pVolDesc->vds_hNWT.fsh_FileHandle != NULL)
  209. {
  210. AfpIoClose(&pVolDesc->vds_hNWT);
  211. pVolDesc->vds_hNWT.fsh_FileHandle = NULL;
  212. }
  213. }
  214. do
  215. {
  216. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  217. // Open for delete access
  218. Status = AfpIoOpen(&pVolDesc->vds_hRootDir,
  219. AFP_STREAM_DATA,
  220. AFP_NWT_OPTIONS,
  221. &AfpNetworkTrashNameU,
  222. AFP_NWT_ACCESS,
  223. AFP_NWT_SHAREMODE,
  224. False,
  225. &hNWT);
  226. // there is no network trash folder to delete
  227. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  228. {
  229. Status = STATUS_SUCCESS;
  230. break;
  231. }
  232. if (NT_SUCCESS(Status))
  233. {
  234. Status = afpCleanNetworkTrash(pVolDesc, &hNWT, NULL);
  235. if (NT_SUCCESS(Status) || !VolumeStart)
  236. {
  237. // NOTE: NTFS will allow me to open the directory for
  238. // DELETE access if it is marked Readonly, but I cannot delete it.
  239. // Clear the Readonly Bit on the Network Trash Folder
  240. AfpIoSetTimesnAttr(&hNWT,
  241. NULL,
  242. NULL,
  243. 0,
  244. FILE_ATTRIBUTE_READONLY,
  245. NULL,
  246. NULL);
  247. Status = AfpIoMarkFileForDelete(&hNWT,
  248. NULL,
  249. NULL,
  250. NULL);
  251. }
  252. AfpIoClose(&hNWT);
  253. }
  254. } while (False);
  255. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  256. if ((!NT_SUCCESS(Status)) && (Status != STATUS_OBJECT_NAME_NOT_FOUND))
  257. {
  258. AFPLOG_ERROR(AFPSRVMSG_DELETE_NWTRASH,
  259. Status,
  260. NULL,
  261. 0,
  262. &pVolDesc->vds_Name);
  263. Status = STATUS_UNSUCCESSFUL;
  264. }
  265. return Status;
  266. }
  267. /*** afpCleanNetworkTrash
  268. *
  269. * Delete the contents of the network trash folder referenced by hNWT.
  270. * If pDfeNWT is non-null, then delete the file/dir entries from the IdIndex
  271. * database. If pDfeNWT is null, the volume is being deleted and the
  272. * IdIndex database is getting blown away too, so don't bother removing the
  273. * entries.
  274. */
  275. LOCAL
  276. NTSTATUS
  277. afpCleanNetworkTrash(
  278. IN PVOLDESC pVolDesc,
  279. IN PFILESYSHANDLE phNWT,
  280. IN PDFENTRY pDfeNWT OPTIONAL
  281. )
  282. {
  283. NTSTATUS Status;
  284. PAGED_CODE( );
  285. DBGPRINT(DBG_COMP_IDINDEX,DBG_LEVEL_INFO,("afpCleanNetworkTrash entered\n"));
  286. if (pDfeNWT != NULL)
  287. {
  288. ASSERT(pDfeNWT->dfe_AfpId == AFP_ID_NETWORK_TRASH);
  289. // clean out all child DFEntries belonging to the network trash
  290. AfpPruneIdDb(pVolDesc,pDfeNWT);
  291. }
  292. Status = AfpWalkDirectoryTree(phNWT, afpNwtDeleteFileEntity);
  293. return Status;
  294. }
  295. NTSTATUS
  296. AfpWalkDirectoryTree(
  297. IN PFILESYSHANDLE phTargetDir,
  298. IN WALKDIR_WORKER NodeWorker
  299. )
  300. {
  301. PFILE_DIRECTORY_INFORMATION tmpptr;
  302. PWALKDIR_NODE DirNodeStacktop = NULL, pcurrentnode;
  303. NTSTATUS rc, status = STATUS_SUCCESS;
  304. PBYTE enumbuf;
  305. PWCHAR nodename;
  306. ULONG nodenamelen;
  307. BOOLEAN isdir;
  308. UNICODE_STRING udirname;
  309. PAGED_CODE( );
  310. //
  311. // allocate the buffer that will hold enumerated files and dirs
  312. //
  313. if ((enumbuf = (PBYTE)AfpAllocPANonPagedMemory(AFP_ENUMBUF_SIZE)) == NULL)
  314. {
  315. return STATUS_INSUFFICIENT_RESOURCES;
  316. }
  317. do // error handling loop
  318. {
  319. //
  320. // prime the pump with the top level (target dir) directory handle
  321. //
  322. if ((rc = afpPushDirNode(&DirNodeStacktop, NULL, NULL))
  323. != STATUS_SUCCESS)
  324. {
  325. status = rc;
  326. break;
  327. }
  328. else
  329. {
  330. DirNodeStacktop->wdn_Handle = *phTargetDir;
  331. }
  332. //
  333. // keep popping enumerated directories off the stack until stack empty
  334. //
  335. while ((pcurrentnode = DirNodeStacktop) != NULL)
  336. {
  337. if (pcurrentnode->wdn_Enumerated == False)
  338. {
  339. //
  340. // get a handle to the directory so it can be enumerated
  341. //
  342. if (pcurrentnode->wdn_Handle.fsh_FileHandle == NULL)
  343. {
  344. RtlInitUnicodeString(&udirname,
  345. pcurrentnode->wdn_RelativePath.Buffer);
  346. // open a handle to the thing relative to the phTargetDir
  347. rc = AfpIoOpen(phTargetDir,
  348. AFP_STREAM_DATA,
  349. FILEIO_OPEN_DIR,
  350. &udirname,
  351. FILEIO_ACCESS_READ,
  352. FILEIO_DENY_NONE,
  353. False,
  354. &pcurrentnode->wdn_Handle);
  355. if (!NT_SUCCESS(rc))
  356. {
  357. status = rc;
  358. break;
  359. }
  360. }
  361. //
  362. // keep enumerating till we get all the entries
  363. //
  364. while (True)
  365. {
  366. rc = AfpIoQueryDirectoryFile(&pcurrentnode->wdn_Handle,
  367. (PFILE_DIRECTORY_INFORMATION)enumbuf,
  368. AFP_ENUMBUF_SIZE,
  369. FileDirectoryInformation,
  370. False, // return multiple entries
  371. False, // don't restart scan
  372. NULL);
  373. ASSERT(rc != STATUS_PENDING);
  374. if ((rc == STATUS_NO_MORE_FILES) ||
  375. (rc == STATUS_NO_SUCH_FILE))
  376. {
  377. pcurrentnode->wdn_Enumerated = True;
  378. break; // that's it, we've seen everything there is
  379. }
  380. //
  381. // NOTE: if we get STATUS_BUFFER_OVERFLOW, the IO status
  382. // information field does NOT tell us the required size
  383. // of the buffer, so we wouldn't know how big to realloc
  384. // the enum buffer if we wanted to retry, so don't bother
  385. else if (!NT_SUCCESS(rc))
  386. {
  387. status = rc;
  388. break; // enumerate failed, bail out
  389. }
  390. //
  391. // process the enumerated files and dirs
  392. //
  393. tmpptr = (PFILE_DIRECTORY_INFORMATION)enumbuf;
  394. while (True)
  395. {
  396. rc = AfpGetNextDirectoryInfo(&tmpptr,
  397. &nodename,
  398. &nodenamelen,
  399. &isdir);
  400. if (rc == STATUS_NO_MORE_ENTRIES)
  401. {
  402. break;
  403. }
  404. if (isdir == True)
  405. {
  406. AfpInitUnicodeStringWithNonNullTerm(&udirname,
  407. (USHORT)nodenamelen,
  408. nodename);
  409. if (RtlEqualUnicodeString(&Dot,&udirname,False) ||
  410. RtlEqualUnicodeString(&DotDot,&udirname,False))
  411. {
  412. continue;
  413. }
  414. //
  415. // push it onto the dir node stack
  416. //
  417. rc = afpPushDirNode(&DirNodeStacktop,
  418. &pcurrentnode->wdn_RelativePath,
  419. &udirname);
  420. if (rc != STATUS_SUCCESS)
  421. {
  422. status = rc;
  423. break;
  424. }
  425. }
  426. else
  427. {
  428. //
  429. // its a file, call worker with its relative handle
  430. // and path
  431. //
  432. rc = NodeWorker(&pcurrentnode->wdn_Handle,
  433. nodename,
  434. nodenamelen,
  435. False);
  436. if (!NT_SUCCESS(rc))
  437. {
  438. status = rc;
  439. break;
  440. }
  441. }
  442. } // while more entries in the enumbuf
  443. if (!NT_SUCCESS(status))
  444. {
  445. break;
  446. }
  447. } // while there are more files to enumerate
  448. if (pcurrentnode->wdn_Handle.fsh_FileHandle != phTargetDir->fsh_FileHandle)
  449. {
  450. AfpIoClose(&pcurrentnode->wdn_Handle);
  451. }
  452. }
  453. else // we have already enumerated this directory
  454. {
  455. if (pcurrentnode->wdn_RelativePath.Length != 0)
  456. {
  457. // call the worker routine on this directory node
  458. rc = NodeWorker(phTargetDir,
  459. pcurrentnode->wdn_RelativePath.Buffer,
  460. pcurrentnode->wdn_RelativePath.Length,
  461. True);
  462. }
  463. else rc = STATUS_SUCCESS;
  464. afpPopDirNode(&DirNodeStacktop);
  465. if (!NT_SUCCESS(rc))
  466. {
  467. status = rc;
  468. break;
  469. }
  470. }
  471. if (!NT_SUCCESS(status))
  472. {
  473. break;
  474. }
  475. } // while there are directories to pop
  476. } while (False); // error handling loop
  477. while (DirNodeStacktop != NULL)
  478. {
  479. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  480. ("AfpWalkDirectoryTree: WARNING: cleaning up dir stack\n") );
  481. // clean up in case of error
  482. afpPopDirNode(&DirNodeStacktop);
  483. }
  484. AfpFreePANonPagedMemory(enumbuf, AFP_ENUMBUF_SIZE);
  485. return status;
  486. }
  487. /*** afpPushDirNode
  488. *
  489. * Keep a record of all the directories we have encountered so far during
  490. * enumeration of the tree. We need to process directories from the
  491. * bottom up because the WalkTree node worker routine does a delete
  492. * on all the items in a tree, and we certainly cant be deleting directories that
  493. * are not empty.
  494. *
  495. */
  496. LOCAL
  497. NTSTATUS
  498. afpPushDirNode(
  499. IN OUT PWALKDIR_NODE *ppStacktop,
  500. IN PUNICODE_STRING pParentPath, // path to parent (NULL iff walk root)
  501. IN PUNICODE_STRING pDirName // name of current node directory
  502. )
  503. {
  504. PWALKDIR_NODE tempptr;
  505. UNICODE_STRING ubackslash;
  506. ULONG memsize;
  507. USHORT namesize = 0;
  508. PAGED_CODE( );
  509. if (pParentPath != NULL)
  510. {
  511. namesize = pParentPath->Length + sizeof(WCHAR) +
  512. pDirName->Length + sizeof(UNICODE_NULL);
  513. }
  514. memsize = namesize + sizeof(WALKDIR_NODE);
  515. if ((tempptr = (PWALKDIR_NODE)AfpAllocNonPagedMemory(memsize)) == NULL)
  516. {
  517. return STATUS_INSUFFICIENT_RESOURCES;
  518. }
  519. tempptr->wdn_Enumerated = False;
  520. tempptr->wdn_Handle.fsh_FileHandle = NULL;
  521. tempptr->wdn_RelativePath.Length = 0;
  522. tempptr->wdn_RelativePath.MaximumLength = namesize;
  523. if (pParentPath != NULL)
  524. {
  525. tempptr->wdn_RelativePath.Buffer = (LPWSTR)((PBYTE)tempptr +
  526. sizeof(WALKDIR_NODE));
  527. if (pParentPath->Length != 0)
  528. {
  529. RtlInitUnicodeString(&ubackslash,L"\\");
  530. AfpCopyUnicodeString(&tempptr->wdn_RelativePath,pParentPath);
  531. RtlAppendUnicodeStringToString(&tempptr->wdn_RelativePath,
  532. &ubackslash);
  533. }
  534. RtlAppendUnicodeStringToString(&tempptr->wdn_RelativePath,pDirName);
  535. tempptr->wdn_RelativePath.Buffer[tempptr->wdn_RelativePath.Length/sizeof(WCHAR)] = UNICODE_NULL;
  536. }
  537. else
  538. {
  539. tempptr->wdn_RelativePath.Buffer = NULL;
  540. }
  541. // push it on the stack
  542. tempptr->wdn_Next = *ppStacktop;
  543. *ppStacktop = tempptr;
  544. return STATUS_SUCCESS;
  545. }
  546. /*** afpPopDirNode
  547. *
  548. * Pop the top DirNode off of the stack and free it
  549. *
  550. ***/
  551. LOCAL
  552. VOID
  553. afpPopDirNode(
  554. IN OUT PWALKDIR_NODE *ppStackTop
  555. )
  556. {
  557. PWALKDIR_NODE tempptr;
  558. PAGED_CODE( );
  559. ASSERT(*ppStackTop != NULL);
  560. tempptr = (*ppStackTop)->wdn_Next;
  561. AfpFreeMemory(*ppStackTop);
  562. *ppStackTop = tempptr;
  563. }
  564. /*** AfpGetNextDirectoryInfo
  565. *
  566. * Given a buffer full of FILE_DIRECTORY_INFORMATION entries as returned
  567. * from a directory enumerate, find the next structure in the buffer and
  568. * return the name information out of it, and whether or not the item
  569. * is a file or directory. Also update the ppInfoBuf to point to the next
  570. * available entry to return for the next time this routine is called.
  571. *
  572. */
  573. NTSTATUS
  574. AfpGetNextDirectoryInfo(
  575. IN OUT PFILE_DIRECTORY_INFORMATION *ppInfoBuf,
  576. OUT PWCHAR *pNodeName,
  577. OUT PULONG pNodeNameLen,
  578. OUT PBOOLEAN pIsDir
  579. )
  580. {
  581. PFILE_DIRECTORY_INFORMATION tempdirinfo;
  582. PAGED_CODE( );
  583. if (*ppInfoBuf == NULL)
  584. {
  585. return STATUS_NO_MORE_ENTRIES;
  586. }
  587. tempdirinfo = *ppInfoBuf;
  588. if (tempdirinfo->NextEntryOffset == 0)
  589. {
  590. *ppInfoBuf = NULL;
  591. }
  592. else
  593. {
  594. (PBYTE)*ppInfoBuf += tempdirinfo->NextEntryOffset;
  595. }
  596. *pIsDir = (tempdirinfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
  597. True : False;
  598. *pNodeNameLen = tempdirinfo->FileNameLength;
  599. *pNodeName = tempdirinfo->FileName;
  600. return STATUS_SUCCESS;
  601. }
  602. /*** afpNwtDeleteFileEntity
  603. *
  604. * Delete a file or directory opening it with the name relative to phRelative
  605. * handle.
  606. * NOTE: can we use NtDeleteFile here since we dont really care about
  607. * any security checking? Then we wouldn't even have to open a handle,
  608. * although that routine opens one for DELETE_ON_CLOSE for us, then
  609. * closes it.
  610. */
  611. LOCAL
  612. NTSTATUS
  613. afpNwtDeleteFileEntity(
  614. IN PFILESYSHANDLE phRelative,
  615. IN PWCHAR Name,
  616. IN ULONG Namelen,
  617. IN BOOLEAN IsDir
  618. )
  619. {
  620. ULONG OpenOptions;
  621. FILESYSHANDLE hEntity;
  622. NTSTATUS rc;
  623. UNICODE_STRING uname;
  624. PAGED_CODE( );
  625. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_INFO,
  626. ("\nafpNwtDeleteFileEntity entered\n"));
  627. OpenOptions = IsDir ? FILEIO_OPEN_DIR : FILEIO_OPEN_FILE;
  628. AfpInitUnicodeStringWithNonNullTerm(&uname,(USHORT)Namelen,Name);
  629. rc = AfpIoOpen(phRelative,
  630. AFP_STREAM_DATA,
  631. OpenOptions,
  632. &uname,
  633. FILEIO_ACCESS_DELETE,
  634. FILEIO_DENY_ALL,
  635. False,
  636. &hEntity);
  637. if (!NT_SUCCESS(rc))
  638. {
  639. return rc;
  640. }
  641. rc = AfpIoMarkFileForDelete(&hEntity, NULL, NULL, NULL);
  642. if (!NT_SUCCESS(rc))
  643. {
  644. // If the file is marked readonly, try clearing the RO attribute
  645. if (((rc == STATUS_ACCESS_DENIED) || (rc == STATUS_CANNOT_DELETE)) &&
  646. (NT_SUCCESS(AfpIoSetTimesnAttr(&hEntity,
  647. NULL,
  648. NULL,
  649. 0,
  650. FILE_ATTRIBUTE_READONLY,
  651. NULL,
  652. NULL))))
  653. {
  654. rc = AfpIoMarkFileForDelete(&hEntity, NULL, NULL, NULL);
  655. }
  656. if (!NT_SUCCESS(rc))
  657. {
  658. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_ERR,
  659. ("\nafpNwtDeleteFileEntity: could not delete file/dir (rc=0x%lx)\n",rc));
  660. DBGBRK(DBG_LEVEL_ERR);
  661. }
  662. }
  663. // NOTE: if marking it for delete fails, at least we could try deleting
  664. // the afpId stream so that we wouldn't find it at some future point...
  665. AfpIoClose(&hEntity);
  666. return rc;
  667. }
  668.