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.

1241 lines
32 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. fsp_fd.c
  5. Abstract:
  6. This module contains the entry points for the AFP file-dir APIs queued to
  7. the FSP. These are all callable from FSP Only.
  8. Author:
  9. Jameel Hyder (microsoft!jameelh)
  10. Revision History:
  11. 25 Apr 1992 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #define FILENUM FILE_FSP_FD
  15. #include <afp.h>
  16. #include <gendisp.h>
  17. #include <fdparm.h>
  18. #include <pathmap.h>
  19. #include <client.h>
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text( PAGE, AfpFspDispGetFileDirParms)
  22. #pragma alloc_text( PAGE, AfpFspDispSetFileDirParms)
  23. #pragma alloc_text( PAGE, AfpFspDispDelete)
  24. #pragma alloc_text( PAGE, AfpFspDispRename)
  25. #pragma alloc_text( PAGE, AfpFspDispMoveAndRename)
  26. #pragma alloc_text( PAGE, AfpFspDispCatSearch)
  27. #endif
  28. /*** AfpFspDispGetFileDirParms
  29. *
  30. * This is the worker routine for the AfpGetFileDirParms API.
  31. *
  32. * The request packet is represented below
  33. *
  34. * sda_ReqBlock PCONNDESC pConnDesc
  35. * sda_ReqBlock DWORD ParentId
  36. * sda_ReqBlock DWORD File Bitmap
  37. * sda_ReqBlock DWORD Dir Bitmap
  38. * sda_Name1 ANSI_STRING Path
  39. */
  40. AFPSTATUS FASTCALL
  41. AfpFspDispGetFileDirParms(
  42. IN PSDA pSda
  43. )
  44. {
  45. FILEDIRPARM FDParm;
  46. PATHMAPENTITY PME;
  47. BOOLEAN NeedHandle = False;
  48. PVOLDESC pVolDesc;
  49. DWORD BitmapF, BitmapD, BitmapI = 0;
  50. AFPSTATUS Status = AFP_ERR_PARAM;
  51. struct _RequestPacket
  52. {
  53. PCONNDESC _pConnDesc;
  54. DWORD _ParentId;
  55. DWORD _FileBitmap;
  56. DWORD _DirBitmap;
  57. };
  58. struct _ResponsePacket
  59. {
  60. BYTE __FileBitmap[2];
  61. BYTE __DirBitmap[2];
  62. BYTE __FileDirFlag;
  63. BYTE __Pad;
  64. };
  65. PAGED_CODE();
  66. DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
  67. ("AfpFspDispGetFileDirParms: Entered\n"));
  68. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
  69. pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
  70. ASSERT(VALID_VOLDESC(pVolDesc));
  71. BitmapF = pReqPkt->_FileBitmap;
  72. BitmapD = pReqPkt->_DirBitmap;
  73. do
  74. {
  75. AfpInitializeFDParms(&FDParm);
  76. AfpInitializePME(&PME, 0, NULL);
  77. if (IS_VOLUME_NTFS(pVolDesc) &&
  78. (BitmapD & (DIR_BITMAP_ACCESSRIGHTS |
  79. DIR_BITMAP_OWNERID |
  80. DIR_BITMAP_GROUPID)))
  81. {
  82. NeedHandle = True;
  83. }
  84. if (BitmapD & DIR_BITMAP_ACCESSRIGHTS)
  85. {
  86. BitmapI = FD_INTERNAL_BITMAP_OPENACCESS_READCTRL;
  87. }
  88. if ((Status = AfpMapAfpPathForLookup(pReqPkt->_pConnDesc,
  89. pReqPkt->_ParentId,
  90. &pSda->sda_Name1,
  91. pSda->sda_PathType,
  92. DFE_ANY,
  93. BitmapF | BitmapD | BitmapI,
  94. NeedHandle ? &PME : NULL,
  95. &FDParm)) != AFP_ERR_NONE)
  96. {
  97. PME.pme_Handle.fsh_FileHandle = NULL;
  98. break;
  99. }
  100. pSda->sda_ReplySize = SIZE_RESPPKT +
  101. EVENALIGN(AfpGetFileDirParmsReplyLength(&FDParm,
  102. IsDir(&FDParm) ? BitmapD : BitmapF));
  103. if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
  104. {
  105. AfpPackFileDirParms(&FDParm,
  106. IsDir(&FDParm) ? BitmapD : BitmapF,
  107. pSda->sda_ReplyBuf + SIZE_RESPPKT);
  108. PUTDWORD2SHORT(&pRspPkt->__FileBitmap, BitmapF);
  109. PUTDWORD2SHORT(&pRspPkt->__DirBitmap, BitmapD);
  110. pRspPkt->__FileDirFlag = IsDir(&FDParm) ?
  111. FILEDIR_FLAG_DIR : FILEDIR_FLAG_FILE;
  112. pRspPkt->__Pad = 0;
  113. }
  114. } while (False);
  115. // Return before we close thus saving some time
  116. AfpCompleteApiProcessing(pSda, Status);
  117. if (NeedHandle && (PME.pme_Handle.fsh_FileHandle != NULL))
  118. AfpIoClose(&PME.pme_Handle); // Close the handle to the entity
  119. return AFP_ERR_EXTENDED;
  120. }
  121. /*** AfpFspDispSetFileDirParms
  122. *
  123. * This is the worker routine for the AfpSetFileDirParms API.
  124. *
  125. * The request packet is represented below
  126. *
  127. * sda_ReqBlock PCONNDESC pConnDesc
  128. * sda_ReqBlock DWORD ParentId
  129. * sda_ReqBlock DWORD File or Directory Bitmap
  130. * sda_Name1 ANSI_STRING Path
  131. * sda_Name2 BLOCK File or Directory parameters
  132. */
  133. AFPSTATUS FASTCALL
  134. AfpFspDispSetFileDirParms(
  135. IN PSDA pSda
  136. )
  137. {
  138. PATHMAPENTITY PME;
  139. PVOLDESC pVolDesc;
  140. FILEDIRPARM FDParm;
  141. DWORD Bitmap, BitmapI;
  142. AFPSTATUS Status = AFP_ERR_PARAM;
  143. WCHAR PathBuf[BIG_PATH_LEN];
  144. struct _RequestPacket
  145. {
  146. PCONNDESC _pConnDesc;
  147. DWORD _ParentId;
  148. DWORD _Bitmap;
  149. };
  150. PAGED_CODE();
  151. DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
  152. ("AfpFspDispSetFileDirParms: Entered\n"));
  153. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
  154. pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
  155. ASSERT(VALID_VOLDESC(pVolDesc));
  156. Bitmap = pReqPkt->_Bitmap;
  157. // Force the FD_BITMAP_LONGNAME in case a *file* is missing the afpinfo
  158. // stream we will be able to generate the correct type/creator in
  159. // AfpSetAfpInfo
  160. BitmapI = FD_INTERNAL_BITMAP_OPENACCESS_RW_ATTR |
  161. FD_BITMAP_LONGNAME |
  162. FD_INTERNAL_BITMAP_RETURN_PMEPATHS;
  163. // For a directory only the owner can change certain attributes like the
  164. // various inhibit bits. Check for access if an attempt is made to modify
  165. // any of these bits. We do not know at this point whether any of these
  166. // attributes are being set/cleared yet !!!
  167. if (Bitmap & FD_BITMAP_ATTR)
  168. BitmapI = FD_INTERNAL_BITMAP_OPENACCESS_READCTRL|
  169. FD_BITMAP_LONGNAME |
  170. DIR_BITMAP_OWNERID |
  171. DIR_BITMAP_GROUPID |
  172. DIR_BITMAP_ACCESSRIGHTS |
  173. FD_INTERNAL_BITMAP_RETURN_PMEPATHS;
  174. AfpInitializeFDParms(&FDParm);
  175. AfpInitializePME(&PME, sizeof(PathBuf), PathBuf);
  176. do
  177. {
  178. Status = AfpMapAfpPathForLookup(pReqPkt->_pConnDesc,
  179. pReqPkt->_ParentId,
  180. &pSda->sda_Name1,
  181. pSda->sda_PathType,
  182. DFE_ANY,
  183. Bitmap | BitmapI,
  184. &PME,
  185. &FDParm);
  186. if (!NT_SUCCESS(Status))
  187. {
  188. PME.pme_Handle.fsh_FileHandle = NULL;
  189. break;
  190. }
  191. if ((Status = AfpUnpackFileDirParms(pSda->sda_Name2.Buffer,
  192. (LONG)pSda->sda_Name2.Length,
  193. &Bitmap,
  194. &FDParm)) != AFP_ERR_NONE)
  195. break;
  196. if (Bitmap != 0)
  197. {
  198. // Make sure they are not trying to set/clear any attributes
  199. // that are not common to both files and directories
  200. if ((Bitmap & FD_BITMAP_ATTR) &&
  201. (FDParm._fdp_Attr & ~(FD_BITMAP_ATTR_SET |
  202. FD_BITMAP_ATTR_INVISIBLE |
  203. FD_BITMAP_ATTR_DELETEINH |
  204. FILE_BITMAP_ATTR_WRITEINH |
  205. FD_BITMAP_ATTR_RENAMEINH |
  206. FD_BITMAP_ATTR_SYSTEM)))
  207. {
  208. Status = AFP_ERR_PARAM;
  209. break;
  210. }
  211. Status = AfpSetFileDirParms(pVolDesc,
  212. &PME,
  213. Bitmap,
  214. &FDParm);
  215. }
  216. } while (False);
  217. // Return before we close thus saving some time
  218. AfpCompleteApiProcessing(pSda, Status);
  219. if (PME.pme_Handle.fsh_FileHandle != NULL)
  220. AfpIoClose(&PME.pme_Handle);
  221. if ((PME.pme_FullPath.Buffer != NULL) &&
  222. (PME.pme_FullPath.Buffer != PathBuf))
  223. {
  224. AfpFreeMemory(PME.pme_FullPath.Buffer);
  225. }
  226. return AFP_ERR_EXTENDED;
  227. }
  228. /*** AfpFspDispDelete
  229. *
  230. * This is the worker routine for the AfpDelete API. Deleting an open file
  231. * or a directory that is not empty is not permitted under AFP.
  232. *
  233. * The request packet is represented below
  234. *
  235. * sda_ReqBlock PCONNDESC pConnDesc
  236. * sda_ReqBlock DWORD ParentId
  237. * sda_Name1 ANSI_STRING Path
  238. */
  239. AFPSTATUS FASTCALL
  240. AfpFspDispDelete(
  241. IN PSDA pSda
  242. )
  243. {
  244. PATHMAPENTITY PME;
  245. PVOLDESC pVolDesc;
  246. PCONNDESC pConnDesc;
  247. FILEDIRPARM FDParm;
  248. DWORD Bitmap, NTAttr;
  249. AFPSTATUS Status = AFP_ERR_PARAM;
  250. FILESYSHANDLE hParent;
  251. WCHAR PathBuf[BIG_PATH_LEN];
  252. BOOLEAN InRoot;
  253. struct _RequestPacket
  254. {
  255. PCONNDESC _pConnDesc;
  256. DWORD _ParentId;
  257. };
  258. PAGED_CODE();
  259. DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
  260. ("AfpFspDispDelete: Entered\n"));
  261. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
  262. pConnDesc = pReqPkt->_pConnDesc;
  263. pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
  264. ASSERT(VALID_VOLDESC(pVolDesc));
  265. AfpInitializeFDParms(&FDParm);
  266. AfpInitializePME(&PME, sizeof(PathBuf), PathBuf);
  267. Bitmap = FD_BITMAP_ATTR | FD_INTERNAL_BITMAP_OPENACCESS_DELETE;
  268. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  269. do
  270. {
  271. hParent.fsh_FileHandle = NULL;
  272. if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
  273. pReqPkt->_ParentId,
  274. &pSda->sda_Name1,
  275. pSda->sda_PathType,
  276. Lookup,
  277. DFE_ANY,
  278. Bitmap,
  279. &PME,
  280. &FDParm)))
  281. {
  282. PME.pme_Handle.fsh_FileHandle = NULL;
  283. break;
  284. }
  285. if ((FDParm._fdp_AfpId == AFP_ID_ROOT) ||
  286. (FDParm._fdp_AfpId == AFP_ID_NETWORK_TRASH))
  287. {
  288. Status = AFP_ERR_ACCESS_DENIED;
  289. break;
  290. }
  291. if (FDParm._fdp_Attr & (FILE_BITMAP_ATTR_DATAOPEN | FILE_BITMAP_ATTR_RESCOPEN))
  292. {
  293. ASSERT(!(FDParm._fdp_Flags & DFE_FLAGS_DIR));
  294. Status = AFP_ERR_FILE_BUSY; // Cannot delete an open file
  295. break;
  296. }
  297. if (!NT_SUCCESS(Status = AfpCheckForInhibit(&PME.pme_Handle,
  298. FD_BITMAP_ATTR_DELETEINH,
  299. FDParm._fdp_Attr,
  300. &NTAttr)))
  301. {
  302. break;
  303. }
  304. // Check for SeeFiles or SeeFolders on the parent dir
  305. if (!NT_SUCCESS(Status = AfpCheckParentPermissions(pReqPkt->_pConnDesc,
  306. FDParm._fdp_ParentId,
  307. &PME.pme_ParentPath,
  308. (FDParm._fdp_Flags & DFE_FLAGS_DIR) ?
  309. DIR_ACCESS_SEARCH : DIR_ACCESS_READ,
  310. &hParent,
  311. NULL)))
  312. {
  313. break;
  314. }
  315. if (NTAttr & FILE_ATTRIBUTE_READONLY)
  316. {
  317. // We must remove the ReadOnly attribute to delete the file/dir
  318. Status = AfpIoSetTimesnAttr(&PME.pme_Handle,
  319. NULL,
  320. NULL,
  321. 0,
  322. FILE_ATTRIBUTE_READONLY,
  323. pVolDesc,
  324. &PME.pme_FullPath);
  325. }
  326. if (NT_SUCCESS(Status))
  327. {
  328. InRoot = (PME.pme_ParentPath.Length == 0) ? True : False;
  329. Status = AfpIoMarkFileForDelete(&PME.pme_Handle,
  330. pVolDesc,
  331. &PME.pme_FullPath,
  332. InRoot ? NULL : &PME.pme_ParentPath);
  333. if (!NT_SUCCESS(Status))
  334. {
  335. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  336. }
  337. // !!! HACK ALERT !!!
  338. // At this point we are pretty much done i.e. the delete has either
  339. // succeeded or failed and we can return doing the rest of the work
  340. // post-reply. Any errors from now on SHOULD BE IGNORED. Also NO
  341. // REFERENCE SHOULD BE MADE TO the pSda & pConnDesc. Status should
  342. // not be changed either. Also reference the Volume for good measure.
  343. // It cannot fail !!!
  344. AfpVolumeReference(pVolDesc);
  345. AfpCompleteApiProcessing(pSda, Status);
  346. if (NT_SUCCESS(Status)) // Delete succeeded
  347. {
  348. ASSERT(VALID_DFE(PME.pme_pDfEntry));
  349. ASSERT(PME.pme_pDfEntry->dfe_AfpId == FDParm._fdp_AfpId);
  350. AfpDeleteDfEntry(pVolDesc, PME.pme_pDfEntry);
  351. AfpIoClose(&PME.pme_Handle);
  352. AfpCacheParentModTime(pVolDesc,
  353. &hParent,
  354. NULL,
  355. NULL,
  356. FDParm._fdp_ParentId);
  357. }
  358. else if (NTAttr & FILE_ATTRIBUTE_READONLY) // Delete failed
  359. {
  360. // Set the ReadOnly attribute back on the file/dir if need be
  361. Status = AfpIoSetTimesnAttr(&PME.pme_Handle,
  362. NULL,
  363. NULL,
  364. FILE_ATTRIBUTE_READONLY,
  365. 0,
  366. pVolDesc,
  367. &PME.pme_FullPath);
  368. ASSERT(NT_SUCCESS(Status));
  369. }
  370. Status = AFP_ERR_EXTENDED;
  371. }
  372. ASSERT (Status == AFP_ERR_EXTENDED);
  373. AfpVolumeDereference(pVolDesc);
  374. } while (False);
  375. // Close file handle so file really gets deleted before mac can come
  376. // back in with another request using same filename (like create)
  377. if (PME.pme_Handle.fsh_FileHandle != NULL)
  378. AfpIoClose(&PME.pme_Handle);
  379. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  380. if (hParent.fsh_FileHandle != NULL)
  381. AfpIoClose(&hParent);
  382. if ((PME.pme_FullPath.Buffer != NULL) &&
  383. (PME.pme_FullPath.Buffer != PathBuf))
  384. {
  385. AfpFreeMemory(PME.pme_FullPath.Buffer);
  386. }
  387. return Status;
  388. }
  389. /*** AfpFspDispRename
  390. *
  391. * This is the worker routine for the AfpRename API. Renaming a file does
  392. * NOT provoke a new Extension-Type/Creator mapping. Renaming an open file
  393. * is permitted under AFP.
  394. *
  395. * The request packet is represented below
  396. *
  397. * sda_ReqBlock PCONNDESC pConnDesc
  398. * sda_ReqBlock DWORD ParentId
  399. * sda_Name1 ANSI_STRING Path
  400. * sda_Name2 ANSI_STRING New name
  401. */
  402. AFPSTATUS FASTCALL
  403. AfpFspDispRename(
  404. IN PSDA pSda
  405. )
  406. {
  407. PATHMAPENTITY PME;
  408. PVOLDESC pVolDesc;
  409. FILEDIRPARM FDParm;
  410. DWORD Bitmap, NTAttr;
  411. AFPSTATUS Status = AFP_ERR_PARAM;
  412. UNICODE_STRING uNewName;
  413. WCHAR wcbuf[AFP_FILENAME_LEN+1];
  414. WCHAR PathBuf[BIG_PATH_LEN];
  415. PDFENTRY pDfEntry;
  416. FILESYSHANDLE hParent;
  417. BOOLEAN InRoot;
  418. struct _RequestPacket
  419. {
  420. PCONNDESC _pConnDesc;
  421. DWORD _ParentId;
  422. };
  423. PAGED_CODE();
  424. DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
  425. ("AfpFspDispRename: Entered\n"));
  426. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
  427. pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
  428. ASSERT(VALID_VOLDESC(pVolDesc));
  429. AfpInitializeFDParms(&FDParm);
  430. AfpInitializePME(&PME, sizeof(PathBuf), PathBuf);
  431. AfpSetEmptyUnicodeString(&uNewName, sizeof(wcbuf), wcbuf);
  432. Bitmap = FD_BITMAP_ATTR | FD_INTERNAL_BITMAP_OPENACCESS_DELETE;
  433. hParent.fsh_FileHandle = NULL;
  434. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  435. do
  436. {
  437. // Make sure the new name is not a null string or too long
  438. if ((pSda->sda_Name2.Length == 0) ||
  439. (pSda->sda_Name2.Length > AFP_FILENAME_LEN) ||
  440. ((pSda->sda_PathType == AFP_SHORTNAME) &&
  441. !AfpIsLegalShortname(&pSda->sda_Name2)) ||
  442. (!NT_SUCCESS(AfpConvertStringToMungedUnicode(&pSda->sda_Name2,
  443. &uNewName))))
  444. break;
  445. if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
  446. pReqPkt->_ParentId,
  447. &pSda->sda_Name1,
  448. pSda->sda_PathType,
  449. Lookup,
  450. DFE_ANY,
  451. Bitmap,
  452. &PME,
  453. &FDParm)))
  454. {
  455. PME.pme_Handle.fsh_FileHandle = NULL;
  456. break;
  457. }
  458. if ((FDParm._fdp_AfpId == AFP_ID_ROOT) ||
  459. (FDParm._fdp_AfpId == AFP_ID_NETWORK_TRASH))
  460. {
  461. Status = AFP_ERR_CANT_RENAME;
  462. break;
  463. }
  464. // Check if the RO bit is on & retain the mod time
  465. if (!NT_SUCCESS(Status = AfpCheckForInhibit(&PME.pme_Handle,
  466. FD_BITMAP_ATTR_RENAMEINH,
  467. FDParm._fdp_Attr,
  468. &NTAttr)))
  469. {
  470. break;
  471. }
  472. // Check for SeeFiles or SeeFolders on the parent dir
  473. if (!NT_SUCCESS(Status = AfpCheckParentPermissions(pReqPkt->_pConnDesc,
  474. FDParm._fdp_ParentId,
  475. &PME.pme_ParentPath,
  476. (FDParm._fdp_Flags & DFE_FLAGS_DIR) ?
  477. DIR_ACCESS_SEARCH : DIR_ACCESS_READ,
  478. &hParent,
  479. NULL)))
  480. {
  481. break;
  482. }
  483. if (NTAttr & FILE_ATTRIBUTE_READONLY)
  484. {
  485. // We must temporarily remove the ReadOnly attribute so that
  486. // we can rename the file/dir
  487. Status = AfpIoSetTimesnAttr(&PME.pme_Handle,
  488. NULL,
  489. NULL,
  490. 0,
  491. FILE_ATTRIBUTE_READONLY,
  492. pVolDesc,
  493. &PME.pme_FullPath);
  494. }
  495. if (NT_SUCCESS(Status))
  496. {
  497. // We must impersonate to do the rename since it is name based
  498. AfpImpersonateClient(pSda);
  499. InRoot = (PME.pme_ParentPath.Length == 0) ? True : False;
  500. Status = AfpIoMoveAndOrRename(&PME.pme_Handle,
  501. NULL,
  502. &uNewName,
  503. pVolDesc,
  504. &PME.pme_FullPath,
  505. InRoot ? NULL : &PME.pme_ParentPath,
  506. NULL,
  507. NULL);
  508. AfpRevertBack();
  509. if (NT_SUCCESS(Status)) // Rename succeeded
  510. {
  511. if ((pDfEntry = AfpFindDfEntryById(pVolDesc,
  512. FDParm._fdp_AfpId,
  513. DFE_ANY)) != NULL)
  514. {
  515. ASSERT(((pDfEntry->dfe_Flags & DFE_FLAGS_DFBITS) &
  516. FDParm._fdp_Flags) != 0);
  517. pDfEntry = AfpRenameDfEntry(pVolDesc,
  518. pDfEntry,
  519. &uNewName);
  520. if (pDfEntry == NULL)
  521. {
  522. // We could not rename the id entry, so
  523. // just delete it, and hope the parent dir
  524. // gets enumerated again
  525. // NOTE: How will the parent directory
  526. // get re-enumerated now ?
  527. ASSERT(VALID_DFE(PME.pme_pDfEntry));
  528. ASSERT(PME.pme_pDfEntry->dfe_AfpId == FDParm._fdp_AfpId);
  529. AfpDeleteDfEntry(pVolDesc, PME.pme_pDfEntry);
  530. Status = AFP_ERR_MISC; // Out of memory
  531. }
  532. else
  533. {
  534. AfpCacheParentModTime(pVolDesc,
  535. &hParent,
  536. NULL,
  537. pDfEntry->dfe_Parent,
  538. 0);
  539. }
  540. }
  541. }
  542. }
  543. else
  544. {
  545. Status = AFP_ERR_MISC; // Could not delete ReadOnly attribute
  546. break;
  547. }
  548. // Set the ReadOnly attribute back on the file/dir if need be.
  549. if (NTAttr & FILE_ATTRIBUTE_READONLY)
  550. AfpIoSetTimesnAttr(&PME.pme_Handle,
  551. NULL,
  552. NULL,
  553. FILE_ATTRIBUTE_READONLY,
  554. 0,
  555. pVolDesc,
  556. &PME.pme_FullPath);
  557. } while (False);
  558. // Return before we close thus saving some time
  559. AfpCompleteApiProcessing(pSda, Status);
  560. if (PME.pme_Handle.fsh_FileHandle != NULL)
  561. AfpIoClose(&PME.pme_Handle);
  562. if (hParent.fsh_FileHandle != NULL)
  563. {
  564. AfpIoClose(&hParent);
  565. }
  566. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  567. if ((PME.pme_FullPath.Buffer != NULL) &&
  568. (PME.pme_FullPath.Buffer != PathBuf))
  569. {
  570. AfpFreeMemory(PME.pme_FullPath.Buffer);
  571. }
  572. return AFP_ERR_EXTENDED;
  573. }
  574. /*** AfpFspDispMoveAndRename
  575. *
  576. * This is the worker routine for the AfpMoveAndRename API. Note that
  577. * in AFP 2.x, a FILE (not a dir) CAN BE MOVED when its RenameInhibit bit
  578. * is set if it is NOT BEING RENAMED.
  579. *
  580. * The request packet is represented below
  581. *
  582. * sda_ReqBlock PCONNDESC pConnDesc
  583. * sda_ReqBlock DWORD Source ParentId
  584. * sda_ReqBlock DWORD Dest ParentId
  585. * sda_Name1 ANSI_STRING Source Path
  586. * sda_Name2 ANSI_STRING Dest Path
  587. * sda_Name3 ANSI_STRING New Name
  588. */
  589. AFPSTATUS FASTCALL
  590. AfpFspDispMoveAndRename(
  591. IN PSDA pSda
  592. )
  593. {
  594. PATHMAPENTITY PMEsrc, PMEdst;
  595. PVOLDESC pVolDesc;
  596. FILEDIRPARM FDParmsrc, FDParmdst;
  597. DWORD Bitmap, NTAttr;
  598. AFPSTATUS Status = AFP_ERR_PARAM;
  599. UNICODE_STRING uNewName;
  600. WCHAR wcbuf[AFP_FILENAME_LEN+1];
  601. BOOLEAN Rename = True, Move = True, SrcInRoot, DstInRoot;
  602. PDFENTRY pDfesrc, pDfedst, pDfeParentsrc;
  603. FILESYSHANDLE hSrcParent;
  604. struct _RequestPacket
  605. {
  606. PCONNDESC _pConnDesc;
  607. DWORD _SrcParentId;
  608. DWORD _DstParentId;
  609. };
  610. PAGED_CODE();
  611. DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
  612. ("AfpFspDispMoveAndRename: Entered\n"));
  613. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
  614. pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
  615. ASSERT(VALID_VOLDESC(pVolDesc));
  616. AfpInitializeFDParms(&FDParmsrc);
  617. AfpInitializeFDParms(&FDParmdst);
  618. AfpInitializePME(&PMEsrc, 0, NULL);
  619. AfpInitializePME(&PMEdst, 0, NULL);
  620. Bitmap = FD_BITMAP_ATTR | FD_BITMAP_LONGNAME | FD_INTERNAL_BITMAP_OPENACCESS_DELETE;
  621. AfpSetEmptyUnicodeString(&uNewName, sizeof(wcbuf), wcbuf);
  622. hSrcParent.fsh_FileHandle = NULL;
  623. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  624. do
  625. {
  626. // Make sure the new name is not too long
  627. if ((pSda->sda_Name3.Length > 0) &&
  628. ((pSda->sda_Name3.Length > AFP_FILENAME_LEN) ||
  629. ((pSda->sda_PathType == AFP_SHORTNAME) &&
  630. !AfpIsLegalShortname(&pSda->sda_Name3)) ||
  631. (!NT_SUCCESS(AfpConvertStringToMungedUnicode(&pSda->sda_Name3,
  632. &uNewName)))))
  633. break;
  634. // Map source path for lookup (could be file or dir).
  635. // We ask for the finderinfo in case the user is moving an
  636. // application file to another directory, we can update its
  637. // parent dirid in the APPL desktop database
  638. if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
  639. pReqPkt->_SrcParentId,
  640. &pSda->sda_Name1,
  641. pSda->sda_PathType,
  642. Lookup,
  643. DFE_ANY,
  644. Bitmap | FD_BITMAP_FINDERINFO,
  645. &PMEsrc,
  646. &FDParmsrc)))
  647. {
  648. PMEsrc.pme_Handle.fsh_FileHandle = NULL;
  649. break;
  650. }
  651. // Map the destination parent directory path for lookup
  652. if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
  653. pReqPkt->_DstParentId,
  654. &pSda->sda_Name2,
  655. pSda->sda_PathType,
  656. Lookup,
  657. DFE_DIR,
  658. 0,
  659. &PMEdst,
  660. &FDParmdst)))
  661. {
  662. PMEdst.pme_Handle.fsh_FileHandle = NULL;
  663. break;
  664. }
  665. if ((FDParmsrc._fdp_AfpId == AFP_ID_ROOT) ||
  666. (FDParmsrc._fdp_AfpId == AFP_ID_NETWORK_TRASH))
  667. {
  668. Status = AFP_ERR_CANT_MOVE;
  669. break;
  670. }
  671. if (!NT_SUCCESS(Status = AfpCheckForInhibit(&PMEsrc.pme_Handle,
  672. FD_BITMAP_ATTR_RENAMEINH,
  673. FDParmsrc._fdp_Attr,
  674. &NTAttr)))
  675. {
  676. // Files (not dirs) marked RenameInhibit that are NOT being
  677. // renamed are allowed to be moved in AFP 2.x
  678. if (!((Status == AFP_ERR_OBJECT_LOCKED) &&
  679. (!IsDir(&FDParmsrc)) &&
  680. (pSda->sda_Name3.Length == 0)))
  681. {
  682. break;
  683. }
  684. }
  685. if (FDParmsrc._fdp_ParentId == FDParmdst._fdp_AfpId)
  686. {
  687. // if the parent directories are the same, we are not
  688. // moving anything to a new directory, so the change
  689. // notify we expect will be a rename in the source dir.
  690. Move = False;
  691. //
  692. // Trying to move a file onto itself. Just return success.
  693. // (some apps move files onto
  694. // themselves for who knows what reason)
  695. //
  696. if ((pSda->sda_Name3.Length == 0) ||
  697. RtlEqualString(&pSda->sda_Name3,
  698. &FDParmsrc._fdp_LongName,
  699. False))
  700. {
  701. Status = AFP_ERR_NONE;
  702. break;
  703. }
  704. }
  705. // Check for SeeFiles or SeeFolders on the source parent dir
  706. if (!NT_SUCCESS(Status = AfpCheckParentPermissions(pReqPkt->_pConnDesc,
  707. FDParmsrc._fdp_ParentId,
  708. &PMEsrc.pme_ParentPath,
  709. (FDParmsrc._fdp_Flags & DFE_FLAGS_DIR) ?
  710. DIR_ACCESS_SEARCH : DIR_ACCESS_READ,
  711. &hSrcParent,
  712. NULL)))
  713. {
  714. break;
  715. }
  716. if (NTAttr & FILE_ATTRIBUTE_READONLY)
  717. {
  718. // We must temporarily remove the ReadOnly attribute so that
  719. // we can move the file/dir
  720. Status = AfpIoSetTimesnAttr(&PMEsrc.pme_Handle,
  721. NULL,
  722. NULL,
  723. 0,
  724. FILE_ATTRIBUTE_READONLY,
  725. pVolDesc,
  726. &PMEsrc.pme_FullPath);
  727. }
  728. if (NT_SUCCESS(Status))
  729. {
  730. // If no new name was supplied, we need to use the
  731. // current name
  732. if (pSda->sda_Name3.Length == 0)
  733. {
  734. Rename = False;
  735. uNewName = PMEsrc.pme_UTail;
  736. }
  737. // We must impersonate to do the move since it is name based
  738. AfpImpersonateClient(pSda);
  739. if (Move)
  740. {
  741. // if we are moving, we will also get an ADDED notification
  742. // for the destination directory. Since we have the path
  743. // of the parent dir, but we really want the name of the
  744. // thing we are about to move and/or rename, munge the
  745. // destination paths to reflect the new name of the thing
  746. // we are moving/renaming
  747. PMEdst.pme_ParentPath = PMEdst.pme_FullPath;
  748. if (PMEdst.pme_FullPath.Length > 0)
  749. {
  750. PMEdst.pme_FullPath.Buffer[PMEdst.pme_FullPath.Length / sizeof(WCHAR)] = L'\\';
  751. PMEdst.pme_FullPath.Length += sizeof(WCHAR);
  752. }
  753. Status = RtlAppendUnicodeStringToString(&PMEdst.pme_FullPath,
  754. &uNewName);
  755. ASSERT(NT_SUCCESS(Status));
  756. }
  757. SrcInRoot = (PMEsrc.pme_ParentPath.Length == 0) ? True : False;
  758. DstInRoot = (PMEdst.pme_ParentPath.Length == 0) ? True : False;
  759. Status = AfpIoMoveAndOrRename(&PMEsrc.pme_Handle,
  760. Move ? &PMEdst.pme_Handle : NULL,
  761. &uNewName,
  762. pVolDesc,
  763. &PMEsrc.pme_FullPath,
  764. SrcInRoot ? NULL : &PMEsrc.pme_ParentPath,
  765. Move ? &PMEdst.pme_FullPath : NULL,
  766. (Move && !DstInRoot) ? &PMEdst.pme_ParentPath : NULL);
  767. AfpRevertBack();
  768. if (NT_SUCCESS(Status)) // Move succeeded
  769. {
  770. if (((pDfesrc = AfpFindDfEntryById(pVolDesc,
  771. FDParmsrc._fdp_AfpId,
  772. DFE_ANY)) != NULL) &&
  773. ((pDfedst = AfpFindDfEntryById(pVolDesc,
  774. FDParmdst._fdp_AfpId,
  775. DFE_DIR)) != NULL))
  776. {
  777. ASSERT(((pDfesrc->dfe_Flags & DFE_FLAGS_DFBITS) &
  778. FDParmsrc._fdp_Flags) != 0);
  779. pDfeParentsrc = pDfesrc->dfe_Parent;
  780. pDfesrc = AfpMoveDfEntry(pVolDesc,
  781. pDfesrc,
  782. pDfedst,
  783. Rename ? &uNewName : NULL);
  784. if (pDfesrc == NULL)
  785. {
  786. // We could not move the id entry, so
  787. // just delete it.
  788. ASSERT(VALID_DFE(PMEsrc.pme_pDfEntry));
  789. ASSERT(PMEsrc.pme_pDfEntry->dfe_AfpId == FDParmsrc._fdp_AfpId);
  790. AfpDeleteDfEntry(pVolDesc, PMEsrc.pme_pDfEntry);
  791. Status = AFP_ERR_MISC; // Out of memory
  792. }
  793. // update cached mod time of source parent directory
  794. AfpCacheParentModTime(pVolDesc,
  795. &hSrcParent,
  796. NULL,
  797. pDfeParentsrc,
  798. 0);
  799. if (Move)
  800. {
  801. // update cached mod time of destination directory
  802. AfpCacheParentModTime(pVolDesc,
  803. &PMEdst.pme_Handle,
  804. NULL,
  805. pDfedst,
  806. 0);
  807. //
  808. // if we just moved an application program, update
  809. // the parentID in the corresponding APPL mapping.
  810. //
  811. if ((!IsDir(&FDParmsrc)) &&
  812. (FDParmsrc._fdp_FinderInfo.fd_TypeD == *(PDWORD)"APPL"))
  813. {
  814. AfpAddAppl(pVolDesc,
  815. FDParmsrc._fdp_FinderInfo.fd_CreatorD,
  816. 0,
  817. FDParmsrc._fdp_AfpId,
  818. True,
  819. FDParmdst._fdp_AfpId);
  820. }
  821. }
  822. }
  823. }
  824. }
  825. else
  826. {
  827. Status = AFP_ERR_MISC; // Could not delete ReadOnly attribute
  828. break;
  829. }
  830. // Set the ReadOnly attribute back on the file/dir if need be
  831. if (NTAttr & FILE_ATTRIBUTE_READONLY)
  832. AfpIoSetTimesnAttr(&PMEsrc.pme_Handle,
  833. NULL,
  834. NULL,
  835. FILE_ATTRIBUTE_READONLY,
  836. 0,
  837. pVolDesc,
  838. &PMEsrc.pme_FullPath);
  839. } while (False);
  840. // Return before we close thus saving some time
  841. AfpCompleteApiProcessing(pSda, Status);
  842. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  843. if (PMEsrc.pme_Handle.fsh_FileHandle != NULL)
  844. AfpIoClose(&PMEsrc.pme_Handle);
  845. if (PMEdst.pme_Handle.fsh_FileHandle != NULL)
  846. AfpIoClose(&PMEdst.pme_Handle);
  847. if (hSrcParent.fsh_FileHandle != NULL)
  848. AfpIoClose(&hSrcParent);
  849. if (PMEsrc.pme_FullPath.Buffer != NULL)
  850. AfpFreeMemory(PMEsrc.pme_FullPath.Buffer);
  851. if (PMEdst.pme_FullPath.Buffer != NULL)
  852. AfpFreeMemory(PMEdst.pme_FullPath.Buffer);
  853. return AFP_ERR_EXTENDED;
  854. }
  855. /*** AfpFspDispCatSearch
  856. *
  857. * This is the worker routine for the AfpCatSearch API.
  858. *
  859. * The request packet is represented below
  860. *
  861. * sda_ReqBlock PCONNDESC pConnDesc
  862. * sda_ReqBlock DWORD RequestedMatches
  863. * sda_Name1 ANSI_STRING Catalog Position - 16 bytes
  864. * sda_Name2 ANSI_STRING Everything else - needs unmarshalling
  865. *
  866. * The reason we could not unmarshall all the parameters is because this
  867. * API's parameters do not conform to the common way all the other APIs'
  868. * parameters do, and therefore we cannot use the common code and table
  869. * structures in afpapi.c.
  870. */
  871. AFPSTATUS FASTCALL
  872. AfpFspDispCatSearch(
  873. IN PSDA pSda
  874. )
  875. {
  876. AFPSTATUS Status = AFP_ERR_PARAM;
  877. PBYTE pEndOfBuffer;
  878. USHORT Flags;
  879. SHORT SizeLeft = 0;
  880. PVOLDESC pVolDesc;
  881. DWORD FileResultBitmap;
  882. DWORD DirResultBitmap;
  883. DWORD RequestBitmap;
  884. DWORD Count;
  885. BOOLEAN fPartialName = False, FreeReplyBuf = False;
  886. FILEDIRPARM FDPLowerAndValue, FDPUpperAndMask;
  887. PCATSEARCHSPEC pSpec1, pSpec2;
  888. UNICODE_STRING MatchString;
  889. WCHAR strbuf[AFP_LONGNAME_LEN+1];
  890. struct _RequestPacket
  891. {
  892. PCONNDESC _pConnDesc;
  893. DWORD _RequestedMatches;
  894. };
  895. // The part of the request buffer that could not be unmarshalled into
  896. // fields in the Sda because they don't conform to any of the other APIs.
  897. // These will be unmarshalled here into local variables, the sda_Name2
  898. // can be cast to this structure for easy access.
  899. struct _RestOfRawRequest
  900. {
  901. USHORT _FileResultBitmap;
  902. USHORT _DirResultBitmap;
  903. BYTE _fPartialName;
  904. BYTE _Pad1;
  905. USHORT _RequestBitmap;
  906. // Spec1 and Spec2 follow
  907. };
  908. #define pRawPkt ((struct _RestOfRawRequest *)(pSda->sda_Name2.Buffer))
  909. struct _ResponsePacket
  910. {
  911. BYTE __CatPosition[16];
  912. BYTE __FileBitmap[2];
  913. BYTE __DirBitmap[2];
  914. BYTE __ActualCount[4];
  915. };
  916. PAGED_CODE();
  917. DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_INFO,
  918. ("AfpFspDispCatSearch: Entered\n"));
  919. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
  920. do
  921. {
  922. if (pSda->sda_Name2.Length < (sizeof(struct _RestOfRawRequest) +
  923. (2 * sizeof(CATSEARCHSPEC))))
  924. {
  925. // The request buffer must be at least as big as the rest of the
  926. // parameters that weren't yet unmarshalled, plus 2 Spec structs
  927. break;
  928. }
  929. GETSHORT2DWORD(&FileResultBitmap, &pRawPkt->_FileResultBitmap);
  930. GETSHORT2DWORD(&DirResultBitmap, &pRawPkt->_DirResultBitmap);
  931. GETSHORT2DWORD(&RequestBitmap, &pRawPkt->_RequestBitmap);
  932. if ( (pRawPkt->_fPartialName & 0x80) != 0 )
  933. {
  934. fPartialName = True;
  935. }
  936. //
  937. // Validate the bitmaps
  938. //
  939. if (((FileResultBitmap | DirResultBitmap) == 0) ||
  940. ((FileResultBitmap | DirResultBitmap) & ~FD_VALID_SEARCH_RESULT) ||
  941. (RequestBitmap == 0))
  942. {
  943. Status = AFP_ERR_BITMAP;
  944. break;
  945. }
  946. // make sure CatSearch is enabled: if it's disabled, reject the call
  947. if (!(pReqPkt->_pConnDesc->cds_pVolDesc->vds_Flags & AFP_VOLUME_SUPPORTS_CATSRCH))
  948. {
  949. DBGPRINT(DBG_COMP_AFPAPI_FD, DBG_LEVEL_ERR,
  950. ("AfpFspDispCatSearch: CATSRCH not supported by volume\n"));
  951. Status = AFP_ERR_CALL_NOT_SUPPORTED;
  952. break;
  953. }
  954. AfpInitializeFDParms(&FDPLowerAndValue);
  955. AfpInitializeFDParms(&FDPUpperAndMask);
  956. if (DirResultBitmap == 0)
  957. {
  958. FDPLowerAndValue._fdp_Flags = FDPUpperAndMask._fdp_Flags = DFE_FLAGS_FILE_WITH_ID;
  959. if (RequestBitmap & ~FILE_VALID_SEARCH_CRITERIA)
  960. {
  961. Status = AFP_ERR_BITMAP;
  962. break;
  963. }
  964. }
  965. else if (FileResultBitmap == 0)
  966. {
  967. FDPLowerAndValue._fdp_Flags = FDPUpperAndMask._fdp_Flags = DFE_FLAGS_DIR;
  968. if (RequestBitmap & ~DIR_VALID_SEARCH_CRITERIA)
  969. {
  970. Status = AFP_ERR_BITMAP;
  971. break;
  972. }
  973. }
  974. else
  975. {
  976. FDPLowerAndValue._fdp_Flags = FDPUpperAndMask._fdp_Flags = DFE_FLAGS_FILE_WITH_ID | DFE_FLAGS_DIR;
  977. if (RequestBitmap & ~FD_VALID_SEARCH_CRITERIA)
  978. {
  979. Status = AFP_ERR_BITMAP;
  980. break;
  981. }
  982. }
  983. Flags = ((PCATALOGPOSITION)pSda->sda_Name1.Buffer)->cp_Flags;
  984. // The caller should not muck with the catalog position at all
  985. if ((Flags & ~CATFLAGS_VALID) ||
  986. // Writelock should only be required if we were about to search files
  987. ((Flags & CATFLAGS_WRITELOCK_REQUIRED) && !(Flags & CATFLAGS_SEARCHING_FILES)))
  988. // NOTE: also should make sure ONLY ONE of the SEARCHING bits is on
  989. break;
  990. //
  991. // Now unpack the search criteria
  992. //
  993. MatchString.Length = 0;
  994. MatchString.MaximumLength = sizeof(strbuf);
  995. MatchString.Buffer = strbuf;
  996. Status = AfpUnpackCatSearchSpecs((PBYTE)pSda->sda_Name2.Buffer + sizeof(struct _RestOfRawRequest),
  997. (USHORT)(pSda->sda_Name2.Length - sizeof(struct _RestOfRawRequest)),
  998. RequestBitmap,
  999. &FDPLowerAndValue,
  1000. &FDPUpperAndMask,
  1001. &MatchString);
  1002. if (!NT_SUCCESS(Status))
  1003. {
  1004. break;
  1005. }
  1006. //
  1007. // Allocate the reply buffer. Estimate the required size by using
  1008. // the maximum possible filename length plus potential pad bytes for
  1009. // even alignment of each entry plus the length of the parent dirid.
  1010. //
  1011. pSda->sda_ReplySize = (USHORT)(SIZE_RESPPKT + (pReqPkt->_RequestedMatches *
  1012. ((2 * sizeof(BYTE)) + sizeof(DWORD) + sizeof(USHORT) + sizeof(BYTE) + AFP_LONGNAME_LEN + 1)));
  1013. if (pSda->sda_ReplySize > MAX_CATSEARCH_REPLY)
  1014. {
  1015. pSda->sda_ReplySize = MAX_CATSEARCH_REPLY;
  1016. }
  1017. AfpIOAllocBackFillBuffer(pSda);
  1018. if (pSda->sda_ReplyBuf == NULL)
  1019. {
  1020. pSda->sda_ReplySize = 0;
  1021. Status = AFP_ERR_MISC;
  1022. break;
  1023. }
  1024. #if DBG
  1025. AfpPutGuardSignature(pSda);
  1026. #endif
  1027. FreeReplyBuf = True;
  1028. //
  1029. // Perform the search
  1030. //
  1031. FDPUpperAndMask._fdp_fPartialName = fPartialName;
  1032. Count = pReqPkt->_RequestedMatches;
  1033. Status = AfpCatSearch(pReqPkt->_pConnDesc,
  1034. (PCATALOGPOSITION)pSda->sda_Name1.Buffer, // CatalogPosition
  1035. RequestBitmap,
  1036. FileResultBitmap,
  1037. DirResultBitmap,
  1038. &FDPLowerAndValue,
  1039. &FDPUpperAndMask,
  1040. &MatchString,
  1041. &Count, // IN OUT
  1042. (SHORT)(pSda->sda_ReplySize - SIZE_RESPPKT),
  1043. &SizeLeft,
  1044. pSda->sda_ReplyBuf + SIZE_RESPPKT,
  1045. (PCATALOGPOSITION)pSda->sda_ReplyBuf);
  1046. if (!NT_SUCCESS(Status) && ((Status != AFP_ERR_EOF) &&
  1047. (Status != AFP_ERR_CATALOG_CHANGED)))
  1048. {
  1049. break;
  1050. }
  1051. PUTSHORT2SHORT(&pRspPkt->__FileBitmap, FileResultBitmap);
  1052. PUTSHORT2SHORT(&pRspPkt->__DirBitmap, DirResultBitmap);
  1053. PUTDWORD2DWORD(&pRspPkt->__ActualCount, Count);
  1054. pSda->sda_ReplySize -= SizeLeft;
  1055. ASSERT(pSda->sda_ReplySize <= MAX_CATSEARCH_REPLY);
  1056. FreeReplyBuf = False;
  1057. } while (False);
  1058. if (FreeReplyBuf)
  1059. {
  1060. AfpIOFreeBackFillBuffer(pSda);
  1061. }
  1062. return Status;
  1063. }