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.

1552 lines
40 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. fsp_file.c
  5. Abstract:
  6. This module contains the entry points for the AFP file 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_FILE
  15. #include <afp.h>
  16. #include <gendisp.h>
  17. #include <fdparm.h>
  18. #include <pathmap.h>
  19. #include <client.h>
  20. #include <afpinfo.h>
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text( PAGE, AfpFspDispCreateFile)
  23. #pragma alloc_text( PAGE, AfpFspDispSetFileParms)
  24. #pragma alloc_text( PAGE, AfpFspDispCopyFile)
  25. #pragma alloc_text( PAGE, AfpFspDispCreateId)
  26. #pragma alloc_text( PAGE, AfpFspDispResolveId)
  27. #pragma alloc_text( PAGE, AfpFspDispDeleteId)
  28. #pragma alloc_text( PAGE, AfpFspDispExchangeFiles)
  29. #endif
  30. /*** AfpFspDispCreateFile
  31. *
  32. * This is the worker routine for the AfpCreateFile API.
  33. *
  34. * The request packet is represented below.
  35. *
  36. * sda_AfpSubFunc BYTE Create option
  37. * sda_ReqBlock PCONNDESC pConnDesc
  38. * sda_ReqBlock DWORD ParentId
  39. * sda_Name1 ANSI_STRING FileName
  40. */
  41. AFPSTATUS FASTCALL
  42. AfpFspDispCreateFile(
  43. IN PSDA pSda
  44. )
  45. {
  46. AFPSTATUS Status = AFP_ERR_PARAM, PostStatus;
  47. PATHMAPENTITY PME;
  48. PDFENTRY pNewDfe;
  49. FILESYSHANDLE hNewFile, hAfpInfo, hParent;
  50. AFPINFO afpinfo;
  51. DWORD crinfo;
  52. PATHMAP_TYPE CreateOption;
  53. WCHAR PathBuf[BIG_PATH_LEN];
  54. PVOLDESC pVolDesc; // For post-create processing
  55. BYTE PathType; // -- ditto --
  56. BOOLEAN InRoot;
  57. struct _RequestPacket
  58. {
  59. PCONNDESC _pConnDesc;
  60. DWORD _ParentId;
  61. };
  62. PAGED_CODE( );
  63. DBGPRINT(DBG_COMP_AFPAPI_FILE, DBG_LEVEL_INFO,
  64. ("AfpFspDispCreateFile: Entered\n"));
  65. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
  66. pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
  67. ASSERT(VALID_VOLDESC(pVolDesc));
  68. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  69. do
  70. {
  71. hNewFile.fsh_FileHandle = NULL;
  72. hAfpInfo.fsh_FileHandle = NULL;
  73. hParent.fsh_FileHandle = NULL;
  74. CreateOption = (pSda->sda_AfpSubFunc == AFP_HARDCREATE_FLAG) ?
  75. HardCreate : SoftCreate;
  76. AfpInitializePME(&PME, sizeof(PathBuf), PathBuf);
  77. if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
  78. pReqPkt->_ParentId,
  79. &pSda->sda_Name1,
  80. PathType = pSda->sda_PathType,
  81. CreateOption,
  82. DFE_FILE,
  83. 0,
  84. &PME,
  85. NULL)))
  86. {
  87. break;
  88. }
  89. // check for seefiles on the parent directory if hard create
  90. if (CreateOption == HardCreate)
  91. {
  92. if (!NT_SUCCESS(Status = AfpCheckParentPermissions(
  93. pReqPkt->_pConnDesc,
  94. PME.pme_pDfeParent->dfe_AfpId,
  95. &PME.pme_ParentPath,
  96. DIR_ACCESS_READ,
  97. &hParent,
  98. NULL)))
  99. {
  100. break;
  101. }
  102. }
  103. AfpImpersonateClient(pSda);
  104. InRoot = (PME.pme_ParentPath.Length == 0) ? True : False;
  105. Status = AfpIoCreate(&pVolDesc->vds_hRootDir,
  106. AFP_STREAM_DATA,
  107. &PME.pme_FullPath,
  108. FILEIO_ACCESS_NONE | FILEIO_ACCESS_DELETE,
  109. FILEIO_DENY_NONE,
  110. FILEIO_OPEN_FILE,
  111. AfpCreateDispositions[pSda->sda_AfpSubFunc / AFP_HARDCREATE_FLAG],
  112. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE,
  113. True,
  114. NULL,
  115. &hNewFile,
  116. &crinfo,
  117. pVolDesc,
  118. &PME.pme_FullPath,
  119. // we don't get notified of parent mod time changing if there is no handle
  120. // open for the parent dir at the time of create, which we cannot predict here.
  121. &PME.pme_ParentPath);
  122. AfpRevertBack();
  123. if (!NT_SUCCESS(Status))
  124. {
  125. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  126. break;
  127. }
  128. // !!! HACK ALERT !!!
  129. // At this point we are pretty much done i.e. the create has succeeded
  130. // and we can return doing the rest of the work post-reply. Any errors
  131. // from now on SHOULD BE IGNORED. Also NO REFERENCE SHOULD BE MADE TO
  132. // the PSda & pConnDesc. Status should not be changed either. Also
  133. // reference the Volume for good measure. It cannot fail !!!
  134. AfpVolumeReference(pVolDesc);
  135. AfpCompleteApiProcessing(pSda, AFP_ERR_NONE);
  136. Status = AFP_ERR_EXTENDED;
  137. // Add this entry to the IdDb
  138. if (crinfo == FILE_CREATED)
  139. {
  140. pNewDfe = AfpAddDfEntry(pVolDesc,
  141. PME.pme_pDfeParent,
  142. &PME.pme_UTail,
  143. False,
  144. 0);
  145. }
  146. else if (crinfo == FILE_SUPERSEDED)
  147. {
  148. ASSERT(CreateOption == HardCreate);
  149. pNewDfe = AfpFindEntryByUnicodeName(pVolDesc,
  150. &PME.pme_UTail,
  151. PathType,
  152. PME.pme_pDfeParent,
  153. DFE_FILE);
  154. if (pNewDfe == NULL)
  155. {
  156. pNewDfe = AfpAddDfEntry(pVolDesc,
  157. PME.pme_pDfeParent,
  158. &PME.pme_UTail,
  159. False,
  160. 0);
  161. }
  162. }
  163. else ASSERTMSG("AfpFspDispCreateFile: unexpected create action", 0);
  164. if (pNewDfe != NULL)
  165. {
  166. afpinfo.afpi_Id = pNewDfe->dfe_AfpId;
  167. // Create the AfpInfo stream
  168. if (!NT_SUCCESS(AfpCreateAfpInfoStream(pVolDesc,
  169. &hNewFile,
  170. afpinfo.afpi_Id,
  171. False,
  172. &PME.pme_UTail,
  173. &PME.pme_FullPath,
  174. &afpinfo,
  175. &hAfpInfo)))
  176. {
  177. // If we fail to add the AFP_AfpInfo stream, we must
  178. // rewind back to the original state. i.e. delete
  179. // the file we just created, and remove it from
  180. // the Id database.
  181. AfpIoMarkFileForDelete(&hNewFile,
  182. pVolDesc,
  183. &PME.pme_FullPath,
  184. InRoot ? NULL : &PME.pme_ParentPath);
  185. AfpDeleteDfEntry(pVolDesc, pNewDfe);
  186. }
  187. else
  188. {
  189. DWORD Attr;
  190. // Get the rest of the File info, and cache it
  191. PostStatus = AfpIoQueryTimesnAttr(&hNewFile,
  192. &pNewDfe->dfe_CreateTime,
  193. &pNewDfe->dfe_LastModTime,
  194. &Attr);
  195. if (NT_SUCCESS(PostStatus))
  196. {
  197. pNewDfe->dfe_NtAttr = (USHORT)Attr & FILE_ATTRIBUTE_VALID_FLAGS;
  198. pNewDfe->dfe_FinderInfo = afpinfo.afpi_FinderInfo;
  199. pNewDfe->dfe_BackupTime = afpinfo.afpi_BackupTime;
  200. pNewDfe->dfe_AfpAttr = afpinfo.afpi_Attributes;
  201. pNewDfe->dfe_DataLen = 0;
  202. pNewDfe->dfe_RescLen = 0;
  203. AfpVolumeSetModifiedTime(pVolDesc);
  204. AfpCacheParentModTime(pVolDesc,
  205. (hParent.fsh_FileHandle == NULL) ? NULL : &hParent,
  206. (hParent.fsh_FileHandle == NULL) ? &PME.pme_ParentPath : NULL,
  207. PME.pme_pDfeParent,
  208. 0);
  209. }
  210. else
  211. {
  212. AfpIoMarkFileForDelete(&hNewFile,
  213. pVolDesc,
  214. &PME.pme_FullPath,
  215. InRoot ? NULL : &PME.pme_ParentPath);
  216. AfpDeleteDfEntry(pVolDesc, pNewDfe);
  217. }
  218. }
  219. }
  220. AfpVolumeDereference(pVolDesc);
  221. ASSERT (Status == AFP_ERR_EXTENDED);
  222. } while (False);
  223. if (hNewFile.fsh_FileHandle != NULL)
  224. AfpIoClose(&hNewFile);
  225. if (hAfpInfo.fsh_FileHandle != NULL)
  226. AfpIoClose(&hAfpInfo);
  227. // If you release the lock before closing the handles,
  228. // for datahandle the FPOpenFork could get a sharing violation.
  229. // For AfpInfo stream CopyFile can get a sharing violation.
  230. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  231. if (hParent.fsh_FileHandle != NULL)
  232. AfpIoClose(&hParent);
  233. if ((PME.pme_FullPath.Buffer != NULL) &&
  234. (PME.pme_FullPath.Buffer != PathBuf))
  235. AfpFreeMemory(PME.pme_FullPath.Buffer);
  236. return Status;
  237. }
  238. /*** AfpFspDispSetFileParms
  239. *
  240. * This is the worker routine for the AfpSetFileParms API.
  241. *
  242. * The request packet is represented below.
  243. *
  244. * sda_ReqBlock PCONNDESC pConnDesc
  245. * sda_ReqBlock DWORD ParentId
  246. * sda_ReqBlock DWORD File Bitmap
  247. * sda_Name1 ANSI_STRING Path
  248. * sda_Name2 BLOCK File Parameters
  249. */
  250. AFPSTATUS FASTCALL
  251. AfpFspDispSetFileParms(
  252. IN PSDA pSda
  253. )
  254. {
  255. FILEDIRPARM FDParm;
  256. PATHMAPENTITY PME;
  257. PVOLDESC pVolDesc;
  258. DWORD Bitmap;
  259. AFPSTATUS Status = AFP_ERR_PARAM;
  260. struct _RequestPacket
  261. {
  262. PCONNDESC _pConnDesc;
  263. DWORD _ParentId;
  264. DWORD _Bitmap;
  265. };
  266. PAGED_CODE( );
  267. DBGPRINT(DBG_COMP_AFPAPI_FILE, DBG_LEVEL_INFO,
  268. ("AfpFspDispSetFileParms: Entered\n"));
  269. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc));
  270. pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
  271. ASSERT(VALID_VOLDESC(pVolDesc));
  272. Bitmap = pReqPkt->_Bitmap;
  273. AfpInitializeFDParms(&FDParm);
  274. AfpInitializePME(&PME, 0, NULL);
  275. do
  276. {
  277. // Force the FD_BITMAP_LONGNAME in case a *file* is missing the afpinfo
  278. // stream we will be able to generate the correct type/creator in
  279. // AfpSetAfpInfo
  280. Status = AfpMapAfpPathForLookup(pReqPkt->_pConnDesc,
  281. pReqPkt->_ParentId,
  282. &pSda->sda_Name1,
  283. pSda->sda_PathType,
  284. DFE_FILE,
  285. Bitmap | FD_INTERNAL_BITMAP_OPENACCESS_RW_ATTR |
  286. FD_INTERNAL_BITMAP_RETURN_PMEPATHS |
  287. FD_BITMAP_LONGNAME,
  288. &PME,
  289. &FDParm);
  290. if (!NT_SUCCESS(Status))
  291. {
  292. PME.pme_Handle.fsh_FileHandle = NULL;
  293. break;
  294. }
  295. if (Bitmap & (FD_BITMAP_ATTR |
  296. FD_BITMAP_CREATETIME |
  297. FD_BITMAP_MODIFIEDTIME))
  298. {
  299. DWORD Attr;
  300. TIME ModTime;
  301. if (!NT_SUCCESS(Status = AfpIoQueryTimesnAttr(&PME.pme_Handle,
  302. &FDParm._fdp_CreateTime,
  303. &ModTime,
  304. &Attr)))
  305. break;
  306. FDParm._fdp_ModifiedTime = AfpConvertTimeToMacFormat(&ModTime);
  307. if (Bitmap & FD_BITMAP_ATTR)
  308. AfpNormalizeAfpAttr(&FDParm, Attr);
  309. }
  310. if ((Status = AfpUnpackFileDirParms(pSda->sda_Name2.Buffer,
  311. (LONG)pSda->sda_Name2.Length,
  312. &Bitmap,
  313. &FDParm)) != AFP_ERR_NONE)
  314. break;
  315. if (Bitmap != 0)
  316. {
  317. if ((Bitmap & FD_BITMAP_ATTR) &&
  318. (FDParm._fdp_Attr & (FILE_BITMAP_ATTR_DATAOPEN |
  319. FILE_BITMAP_ATTR_RESCOPEN |
  320. FILE_BITMAP_ATTR_COPYPROT)))
  321. {
  322. Status = AFP_ERR_PARAM;
  323. break;
  324. }
  325. AfpSetFileDirParms(pVolDesc, &PME, Bitmap, &FDParm);
  326. }
  327. } while (False);
  328. // Return before we close thus saving some time
  329. AfpCompleteApiProcessing(pSda, Status);
  330. if (PME.pme_Handle.fsh_FileHandle != NULL)
  331. AfpIoClose(&PME.pme_Handle);
  332. if (PME.pme_FullPath.Buffer != NULL)
  333. {
  334. AfpFreeMemory(PME.pme_FullPath.Buffer);
  335. }
  336. return AFP_ERR_EXTENDED;
  337. }
  338. /*** AfpFspDispCopyFile
  339. *
  340. * This is the worker routine for the AfpCopyFile API.
  341. *
  342. * The request packet is represented below.
  343. *
  344. * sda_ReqBlock PCONNDESC Source pConnDesc
  345. * sda_ReqBlock DWORD Source ParentId
  346. * sda_ReqBlock DWORD Dest VolId
  347. * sda_ReqBlock DWORD Dest ParentId
  348. * sda_Name1 ANSI_STRING Source Path
  349. * sda_Name2 ANSI_STRING Dest Path
  350. * sda_Name3 ANSI_STRING New Name
  351. */
  352. AFPSTATUS FASTCALL
  353. AfpFspDispCopyFile(
  354. IN PSDA pSda
  355. )
  356. {
  357. PCONNDESC pConnDescD;
  358. PATHMAPENTITY PMESrc, PMEDst;
  359. FILEDIRPARM FDParmSrc, FDParmDst;
  360. PANSI_STRING pAnsiName;
  361. UNICODE_STRING uNewName;
  362. WCHAR wcbuf[AFP_FILENAME_LEN+1];
  363. PSWMR pSwmr;
  364. PDFENTRY pDfeParent, pNewDfe;
  365. AFPSTATUS Status = AFP_ERR_PARAM;
  366. BOOLEAN DstLockTaken = False, Rename = True, InRoot;
  367. LONG i;
  368. COPY_FILE_INFO CopyFileInfo;
  369. PCOPY_FILE_INFO pCopyFileInfo = &CopyFileInfo;
  370. DWORD CreateTime = 0;
  371. AFPTIME aModTime;
  372. TIME ModTime;
  373. struct _RequestPacket
  374. {
  375. PCONNDESC _pConnDescS;
  376. DWORD _SrcParentId;
  377. DWORD _DstVolId;
  378. DWORD _DstParentId;
  379. };
  380. PAGED_CODE( );
  381. DBGPRINT(DBG_COMP_AFPAPI_FILE, DBG_LEVEL_INFO,
  382. ("AfpFspDispCopyFile: Entered\n"));
  383. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDescS) &&
  384. VALID_VOLDESC(pReqPkt->_pConnDescS->cds_pVolDesc));
  385. if ((pConnDescD =
  386. AfpConnectionReference(pSda, pReqPkt->_DstVolId)) != NULL)
  387. {
  388. ASSERT(VALID_CONNDESC(pConnDescD) &&
  389. VALID_VOLDESC(pConnDescD->cds_pVolDesc));
  390. AfpInitializeFDParms(&FDParmSrc);
  391. AfpInitializeFDParms(&FDParmDst);
  392. AfpInitializePME(&PMESrc, 0, NULL);
  393. AfpInitializePME(&PMEDst, 0, NULL);
  394. AfpSetEmptyUnicodeString(&uNewName, sizeof(wcbuf), wcbuf);
  395. RtlZeroMemory(&CopyFileInfo, sizeof(COPY_FILE_INFO));
  396. PMESrc.pme_Handle.fsh_FileHandle = NULL;
  397. PMEDst.pme_Handle.fsh_FileHandle = NULL;
  398. do
  399. {
  400. if (pConnDescD->cds_pVolDesc->vds_Flags & AFP_VOLUME_READONLY)
  401. {
  402. Status = AFP_ERR_VOLUME_LOCKED;
  403. break;
  404. }
  405. // Make sure the new name is valid
  406. pAnsiName = &pSda->sda_Name3;
  407. if ((pSda->sda_Name3.Length > 0) &&
  408. ((pSda->sda_Name3.Length > AFP_FILENAME_LEN) ||
  409. ((pSda->sda_PathType == AFP_SHORTNAME) &&
  410. !AfpIsLegalShortname(&pSda->sda_Name3)) ||
  411. (!NT_SUCCESS(AfpConvertStringToMungedUnicode(&pSda->sda_Name3,
  412. &uNewName)))))
  413. break;
  414. Status = AfpMapAfpPathForLookup(pReqPkt->_pConnDescS,
  415. pReqPkt->_SrcParentId,
  416. &pSda->sda_Name1,
  417. pSda->sda_PathType,
  418. DFE_FILE,
  419. FD_INTERNAL_BITMAP_OPENACCESS_READ |
  420. FD_BITMAP_ATTR |
  421. FD_BITMAP_LONGNAME |
  422. FD_BITMAP_FINDERINFO |
  423. FILE_BITMAP_RESCLEN |
  424. FILE_BITMAP_DATALEN |
  425. FD_INTERNAL_BITMAP_DENYMODE_WRITE,
  426. &PMESrc,
  427. &FDParmSrc);
  428. if (!NT_SUCCESS(Status))
  429. {
  430. break;
  431. }
  432. // Source opened ok. However we may have an internal deny conflict
  433. // Check that
  434. if (((Status = AfpCheckDenyConflict(pReqPkt->_pConnDescS->cds_pVolDesc,
  435. FDParmSrc._fdp_AfpId,
  436. False,
  437. FORK_OPEN_READ,
  438. FORK_DENY_WRITE,
  439. NULL)) != AFP_ERR_NONE) ||
  440. ((Status = AfpCheckDenyConflict(pReqPkt->_pConnDescS->cds_pVolDesc,
  441. FDParmSrc._fdp_AfpId,
  442. True,
  443. FORK_OPEN_READ,
  444. FORK_DENY_WRITE,
  445. NULL)) != AFP_ERR_NONE))
  446. {
  447. Status = AFP_ERR_DENY_CONFLICT;
  448. break;
  449. }
  450. pSwmr = &pConnDescD->cds_pVolDesc->vds_IdDbAccessLock;
  451. AfpSwmrAcquireExclusive(pSwmr);
  452. DstLockTaken = True;
  453. // Map the destination directory for Lookup
  454. if (!NT_SUCCESS(Status = AfpMapAfpPath(pConnDescD,
  455. pReqPkt->_DstParentId,
  456. &pSda->sda_Name2,
  457. pSda->sda_PathType,
  458. Lookup,
  459. DFE_DIR,
  460. 0,
  461. &PMEDst,
  462. &FDParmDst)))
  463. {
  464. break;
  465. }
  466. AfpImpersonateClient(pSda);
  467. // If no new name was supplied, we need to use the
  468. // current name
  469. if (pSda->sda_Name3.Length == 0)
  470. {
  471. Rename = False;
  472. pAnsiName = &FDParmSrc._fdp_LongName;
  473. AfpConvertStringToMungedUnicode(pAnsiName,
  474. &uNewName);
  475. }
  476. // since we really want the path of the thing we are about
  477. // to create, munge the strings in the PMEDst
  478. PMEDst.pme_ParentPath = PMEDst.pme_FullPath;
  479. if (PMEDst.pme_FullPath.Length > 0)
  480. {
  481. PMEDst.pme_FullPath.Buffer[PMEDst.pme_FullPath.Length / sizeof(WCHAR)] = L'\\';
  482. PMEDst.pme_FullPath.Length += sizeof(WCHAR);
  483. }
  484. Status = RtlAppendUnicodeStringToString(&PMEDst.pme_FullPath,
  485. &uNewName);
  486. ASSERT(NT_SUCCESS(Status));
  487. InRoot = (PMEDst.pme_ParentPath.Length == 0) ? True : False;
  488. Status = AfpIoCopyFile1(&PMESrc.pme_Handle,
  489. &PMEDst.pme_Handle,
  490. &uNewName,
  491. pConnDescD->cds_pVolDesc,
  492. &PMEDst.pme_FullPath,
  493. InRoot ? NULL : &PMEDst.pme_ParentPath,
  494. &CopyFileInfo);
  495. AfpRevertBack();
  496. if (!NT_SUCCESS(Status))
  497. {
  498. break;
  499. }
  500. // Add this entry to the IdDb. First find the parent directory
  501. pDfeParent = AfpFindDfEntryById(pConnDescD->cds_pVolDesc,
  502. FDParmDst._fdp_AfpId,
  503. DFE_DIR);
  504. ASSERT(pDfeParent != NULL);
  505. pNewDfe = AfpAddDfEntry(pConnDescD->cds_pVolDesc,
  506. pDfeParent,
  507. &uNewName,
  508. False,
  509. 0);
  510. Status = AFP_ERR_MISC; // Assume failure
  511. if (pNewDfe != NULL)
  512. {
  513. // Put the new file's AFPId into the AfpInfo stream
  514. AfpInitializeFDParms(&FDParmDst);
  515. FDParmDst._fdp_Flags = DFE_FLAGS_FILE_NO_ID;
  516. FDParmDst._fdp_AfpId = pNewDfe->dfe_AfpId;
  517. FDParmDst._fdp_BackupTime = BEGINNING_OF_TIME;
  518. // Copy the finderinfo from the source to the destination
  519. // Also clear the inited bit so that finder will assign
  520. // new coordinates for the new file.
  521. FDParmDst._fdp_FinderInfo = FDParmSrc._fdp_FinderInfo;
  522. FDParmDst._fdp_FinderInfo.fd_Attr1 &= ~FINDER_FLAG_SET;
  523. AfpConvertMungedUnicodeToAnsi(&pNewDfe->dfe_UnicodeName,
  524. &FDParmDst._fdp_LongName);
  525. Status = AfpSetAfpInfo(&CopyFileInfo.cfi_DstStreamHandle[0],
  526. FILE_BITMAP_FILENUM |
  527. FD_BITMAP_BACKUPTIME |
  528. FD_BITMAP_FINDERINFO,
  529. &FDParmDst,
  530. NULL,
  531. NULL);
  532. if (NT_SUCCESS(Status))
  533. {
  534. // Get the rest of the File info, and cache it
  535. Status = AfpIoQueryTimesnAttr(&CopyFileInfo.cfi_SrcStreamHandle[0],
  536. &pNewDfe->dfe_CreateTime,
  537. &pNewDfe->dfe_LastModTime,
  538. NULL);
  539. if (NT_SUCCESS(Status))
  540. {
  541. // Copy the finderinfo into the destination DFE.
  542. // Use the FDParmDst version since it has the right
  543. // version - see above.
  544. pNewDfe->dfe_FinderInfo = FDParmDst._fdp_FinderInfo;
  545. pNewDfe->dfe_BackupTime = BEGINNING_OF_TIME;
  546. pNewDfe->dfe_AfpAttr = FDParmSrc._fdp_Attr &
  547. ~(FD_BITMAP_ATTR_SET |
  548. FILE_BITMAP_ATTR_DATAOPEN |
  549. FILE_BITMAP_ATTR_RESCOPEN);
  550. pNewDfe->dfe_NtAttr = (USHORT)AfpConvertAfpAttrToNTAttr(pNewDfe->dfe_AfpAttr);
  551. pNewDfe->dfe_DataLen = FDParmSrc._fdp_DataForkLen;
  552. pNewDfe->dfe_RescLen = FDParmSrc._fdp_RescForkLen;
  553. AfpCacheParentModTime(pConnDescD->cds_pVolDesc,
  554. NULL,
  555. &PMEDst.pme_ParentPath,
  556. pNewDfe->dfe_Parent,
  557. 0);
  558. }
  559. // Set the attributes such that it matches the source
  560. Status = AfpIoSetTimesnAttr(&CopyFileInfo.cfi_DstStreamHandle[0],
  561. NULL,
  562. NULL,
  563. pNewDfe->dfe_NtAttr,
  564. 0,
  565. pConnDescD->cds_pVolDesc,
  566. &PMEDst.pme_FullPath);
  567. }
  568. if (!NT_SUCCESS(Status))
  569. {
  570. // If we failed to write the correct AfpId onto the
  571. // new file, then delete the file, and remove it from
  572. // the Id database.
  573. AfpIoMarkFileForDelete(&CopyFileInfo.cfi_DstStreamHandle[0],
  574. pConnDescD->cds_pVolDesc,
  575. &PMEDst.pme_FullPath,
  576. InRoot ? NULL : &PMEDst.pme_ParentPath);
  577. AfpDeleteDfEntry(pConnDescD->cds_pVolDesc, pNewDfe);
  578. Status = AFP_ERR_MISC;
  579. }
  580. }
  581. } while (False);
  582. if (DstLockTaken == True)
  583. AfpSwmrRelease(pSwmr);
  584. // If we have successfully come so far, go ahead and complete the copy
  585. if (Status == AFP_ERR_NONE)
  586. {
  587. Status = AfpIoCopyFile2(&CopyFileInfo,
  588. pConnDescD->cds_pVolDesc,
  589. &PMEDst.pme_FullPath,
  590. InRoot ? NULL : &PMEDst.pme_ParentPath);
  591. if (Status == AFP_ERR_NONE)
  592. {
  593. // We need to get the create and modified time from the source
  594. // file before we close it.
  595. AfpIoQueryTimesnAttr(&pCopyFileInfo->cfi_SrcStreamHandle[0],
  596. &CreateTime,
  597. &ModTime,
  598. NULL);
  599. aModTime = AfpConvertTimeToMacFormat(&ModTime);
  600. } else {
  601. AfpSwmrAcquireExclusive(pSwmr);
  602. // Note that we cannot use pNewDfe. We need to remap. It could have
  603. // got deleted when we relinquished the Swmr.
  604. pNewDfe = AfpFindDfEntryById(pConnDescD->cds_pVolDesc,
  605. FDParmDst._fdp_AfpId,
  606. DFE_FILE);
  607. if (pNewDfe != NULL)
  608. AfpDeleteDfEntry(pConnDescD->cds_pVolDesc, pNewDfe);
  609. AfpSwmrRelease(pSwmr);
  610. }
  611. // update the disk quota for this user on the destination volume
  612. if (pConnDescD->cds_pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
  613. {
  614. if (AfpConnectionReferenceByPointer(pConnDescD) != NULL)
  615. {
  616. afpUpdateDiskQuotaInfo(pConnDescD);
  617. }
  618. }
  619. }
  620. // Close the source file and dest directory handles
  621. if (PMESrc.pme_Handle.fsh_FileHandle != NULL)
  622. AfpIoClose(&PMESrc.pme_Handle);
  623. if (PMEDst.pme_Handle.fsh_FileHandle != NULL)
  624. AfpIoClose(&PMEDst.pme_Handle);
  625. // Close all the handles, Free the handle space. We come here regardless
  626. // of success/error. MAKE SURE THE SOURCE HANDLE IS NOT CLOSED HERE SINCE
  627. // IT HAS BEEN CLOSED ABOVE.
  628. // MAKE SURE THE DESTINATION HANDLE IS NOT CLOSED HERE SINCE WE NEED IT TO
  629. // SET THE FILE TIME.
  630. for (i = 1; i < CopyFileInfo.cfi_NumStreams; i++)
  631. {
  632. if (CopyFileInfo.cfi_SrcStreamHandle[i].fsh_FileHandle != NULL)
  633. {
  634. AfpIoClose(&CopyFileInfo.cfi_SrcStreamHandle[i]);
  635. }
  636. if (CopyFileInfo.cfi_DstStreamHandle[i].fsh_FileHandle != NULL)
  637. {
  638. AfpIoClose(&CopyFileInfo.cfi_DstStreamHandle[i]);
  639. }
  640. }
  641. if ((CopyFileInfo.cfi_DstStreamHandle != NULL) &&
  642. (CopyFileInfo.cfi_DstStreamHandle[0].fsh_FileHandle != NULL))
  643. {
  644. if (Status == AFP_ERR_NONE)
  645. {
  646. // Set the creation and modification date on the destination
  647. // file to match that of the source file
  648. AfpIoSetTimesnAttr(&pCopyFileInfo->cfi_DstStreamHandle[0],
  649. &CreateTime,
  650. &aModTime,
  651. 0,
  652. 0,
  653. pConnDescD->cds_pVolDesc,
  654. &PMEDst.pme_FullPath);
  655. }
  656. AfpIoClose(&CopyFileInfo.cfi_DstStreamHandle[0]);
  657. }
  658. if (PMEDst.pme_FullPath.Buffer != NULL)
  659. AfpFreeMemory(PMEDst.pme_FullPath.Buffer);
  660. if (CopyFileInfo.cfi_SrcStreamHandle != NULL)
  661. AfpFreeMemory(CopyFileInfo.cfi_SrcStreamHandle);
  662. if (CopyFileInfo.cfi_DstStreamHandle != NULL)
  663. AfpFreeMemory(CopyFileInfo.cfi_DstStreamHandle);
  664. AfpConnectionDereference(pConnDescD);
  665. }
  666. return Status;
  667. }
  668. /*** AfpFspDispCreateId
  669. *
  670. * This is the worker routine for the AfpCreateId API.
  671. *
  672. * The request packet is represented below.
  673. *
  674. * sda_ReqBlock PCONNDESC pConnDesc
  675. * sda_ReqBlock DWORD ParentId
  676. * sda_Name1 ANSI_STRING Path
  677. */
  678. AFPSTATUS FASTCALL
  679. AfpFspDispCreateId(
  680. IN PSDA pSda
  681. )
  682. {
  683. AFPSTATUS Status = AFP_ERR_PARAM, Status2;
  684. FILEDIRPARM FDParm;
  685. PATHMAPENTITY PME;
  686. struct _RequestPacket
  687. {
  688. PCONNDESC _pConnDesc;
  689. DWORD _ParentId;
  690. };
  691. struct _ResponsePacket
  692. {
  693. BYTE __FileId[4];
  694. };
  695. PAGED_CODE( );
  696. DBGPRINT(DBG_COMP_AFPAPI_FILE, DBG_LEVEL_INFO,
  697. ("AfpFspDispCreateId: Entered\n"));
  698. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc) &&
  699. VALID_VOLDESC(pReqPkt->_pConnDesc->cds_pVolDesc));
  700. do
  701. {
  702. AfpInitializePME(&PME, 0, NULL);
  703. Status = AfpMapAfpPathForLookup(pReqPkt->_pConnDesc,
  704. pReqPkt->_ParentId,
  705. &pSda->sda_Name1,
  706. pSda->sda_PathType,
  707. DFE_FILE,
  708. FILE_BITMAP_FILENUM | FD_INTERNAL_BITMAP_OPENACCESS_READ,
  709. &PME,
  710. &FDParm);
  711. // if we get sharing violation we know we have read access to the file
  712. if (!NT_SUCCESS(Status) && (Status != AFP_ERR_DENY_CONFLICT))
  713. break;
  714. // Set the bit in DF Entry
  715. Status = AfpSetDFFileFlags(pReqPkt->_pConnDesc->cds_pVolDesc,
  716. FDParm._fdp_AfpId,
  717. 0,
  718. True,
  719. False);
  720. } while (False);
  721. if ((Status == AFP_ERR_VOLUME_LOCKED) && (FDParm._fdp_Flags & DFE_FLAGS_FILE_WITH_ID))
  722. {
  723. // If the volume is locked, but an Id exists, return it
  724. Status = AFP_ERR_ID_EXISTS;
  725. }
  726. if ((Status == AFP_ERR_NONE) || (Status == AFP_ERR_ID_EXISTS))
  727. {
  728. pSda->sda_ReplySize = SIZE_RESPPKT;
  729. if ((Status2 = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
  730. {
  731. PUTDWORD2DWORD(pRspPkt->__FileId, FDParm._fdp_AfpId);
  732. }
  733. else
  734. {
  735. Status = Status2;
  736. }
  737. }
  738. // Return before we close thus saving some time
  739. AfpCompleteApiProcessing(pSda, Status);
  740. if (PME.pme_Handle.fsh_FileHandle != NULL)
  741. AfpIoClose(&PME.pme_Handle);
  742. return AFP_ERR_EXTENDED;
  743. }
  744. /*** AfpFspDispResolveId
  745. *
  746. * This is the worker routine for the AfpResolveId API.
  747. *
  748. * The request packet is represented below.
  749. *
  750. * sda_ReqBlock PCONNDESC pConnDesc
  751. * sda_ReqBlock DWORD FileId
  752. * sda_ReqBlock DWORD Bitmap
  753. */
  754. AFPSTATUS FASTCALL
  755. AfpFspDispResolveId(
  756. IN PSDA pSda
  757. )
  758. {
  759. DWORD Bitmap;
  760. AFPSTATUS Status = AFP_ERR_PARAM;
  761. FILEDIRPARM FDParm;
  762. PATHMAPENTITY PME;
  763. struct _RequestPacket
  764. {
  765. PCONNDESC _pConnDesc;
  766. DWORD _FileId;
  767. DWORD _Bitmap;
  768. };
  769. struct _ResponsePacket
  770. {
  771. BYTE __Bitmap[2];
  772. // Rest of the parameters
  773. };
  774. PAGED_CODE( );
  775. DBGPRINT(DBG_COMP_AFPAPI_FILE, DBG_LEVEL_INFO,
  776. ("AfpFspDispResolveId: Entered\n"));
  777. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc) &&
  778. VALID_VOLDESC(pReqPkt->_pConnDesc->cds_pVolDesc));
  779. Bitmap = pReqPkt->_Bitmap;
  780. do
  781. {
  782. AfpInitializeFDParms(&FDParm);
  783. AfpInitializePME(&PME, 0, NULL);
  784. // HACK: this is to make System 7.5 FindFile not grey out the first
  785. // item in the list of items found. Normally we would check for
  786. // parameter non-zero in the api table in afpapi.c and return an
  787. // error there, but this is a special case.
  788. if (pReqPkt->_FileId == 0)
  789. {
  790. Status = AFP_ERR_ID_NOT_FOUND;
  791. break;
  792. }
  793. Status = AfpMapAfpIdForLookup(pReqPkt->_pConnDesc,
  794. pReqPkt->_FileId,
  795. DFE_FILE,
  796. Bitmap | FD_INTERNAL_BITMAP_OPENACCESS_READ,
  797. &PME,
  798. &FDParm);
  799. if (!NT_SUCCESS(Status) && (Status != AFP_ERR_DENY_CONFLICT))
  800. {
  801. if (Status == AFP_ERR_OBJECT_NOT_FOUND)
  802. {
  803. Status = AFP_ERR_ID_NOT_FOUND;
  804. }
  805. break;
  806. }
  807. // a deny conflict means the user actually has access to the file, so
  808. // we need to open for nothing with no sharing modes to get the
  809. // bitmap parameters.
  810. if (Status == AFP_ERR_DENY_CONFLICT)
  811. {
  812. Status = AfpMapAfpIdForLookup(pReqPkt->_pConnDesc,
  813. pReqPkt->_FileId,
  814. DFE_FILE,
  815. Bitmap,
  816. &PME,
  817. &FDParm);
  818. if (!NT_SUCCESS(Status))
  819. {
  820. if (Status == AFP_ERR_OBJECT_NOT_FOUND)
  821. {
  822. Status = AFP_ERR_ID_NOT_FOUND;
  823. }
  824. break;
  825. }
  826. }
  827. if (!(FDParm._fdp_Flags & DFE_FLAGS_FILE_WITH_ID))
  828. {
  829. Status = AFP_ERR_ID_NOT_FOUND;
  830. break;
  831. }
  832. pSda->sda_ReplySize = SIZE_RESPPKT +
  833. EVENALIGN(AfpGetFileDirParmsReplyLength(&FDParm, Bitmap));
  834. if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
  835. {
  836. AfpPackFileDirParms(&FDParm, Bitmap, pSda->sda_ReplyBuf + SIZE_RESPPKT);
  837. PUTDWORD2SHORT(pRspPkt->__Bitmap, Bitmap);
  838. }
  839. } while (False);
  840. if (PME.pme_Handle.fsh_FileHandle != NULL)
  841. AfpIoClose(&PME.pme_Handle);
  842. return Status;
  843. }
  844. /*** AfpFspDispDeleteId
  845. *
  846. * This is the worker routine for the AfpDeleteId API.
  847. *
  848. * The request packet is represented below.
  849. *
  850. * sda_ReqBlock PCONNDESC pConnDesc
  851. * sda_ReqBlock DWORD FileId
  852. */
  853. AFPSTATUS FASTCALL
  854. AfpFspDispDeleteId(
  855. IN PSDA pSda
  856. )
  857. {
  858. AFPSTATUS Status = AFP_ERR_PARAM;
  859. FILEDIRPARM FDParm;
  860. PATHMAPENTITY PME;
  861. struct _RequestPacket
  862. {
  863. PCONNDESC _pConnDesc;
  864. DWORD _FileId;
  865. };
  866. PAGED_CODE( );
  867. DBGPRINT(DBG_COMP_AFPAPI_FILE, DBG_LEVEL_INFO,
  868. ("AfpFspDispDeleteId: Entered\n"));
  869. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc) &&
  870. VALID_VOLDESC(pReqPkt->_pConnDesc->cds_pVolDesc));
  871. do
  872. {
  873. AfpInitializePME(&PME, 0, NULL);
  874. Status = AfpMapAfpIdForLookup(pReqPkt->_pConnDesc,
  875. pReqPkt->_FileId,
  876. DFE_FILE,
  877. FILE_BITMAP_FILENUM |
  878. FD_INTERNAL_BITMAP_OPENACCESS_READWRITE,
  879. &PME,
  880. &FDParm);
  881. if (!NT_SUCCESS(Status) && (Status != AFP_ERR_DENY_CONFLICT))
  882. {
  883. if (Status == AFP_ERR_OBJECT_NOT_FOUND)
  884. {
  885. Status = AFP_ERR_ID_NOT_FOUND;
  886. }
  887. break;
  888. }
  889. // Set the bit in DF Entry
  890. Status = AfpSetDFFileFlags(pReqPkt->_pConnDesc->cds_pVolDesc,
  891. FDParm._fdp_AfpId,
  892. 0,
  893. False,
  894. True);
  895. } while (False);
  896. // Return before we close thus saving some time
  897. AfpCompleteApiProcessing(pSda, Status);
  898. if (PME.pme_Handle.fsh_FileHandle != NULL)
  899. AfpIoClose(&PME.pme_Handle);
  900. return AFP_ERR_EXTENDED;
  901. }
  902. /*** AfpFspDispExchangeFiles
  903. *
  904. * This is the worker routine for the AfpExchangeFiles API.
  905. *
  906. * Acquire the IdDb Swmr for Write and map both source and destination for
  907. * lookup (set to open the entities for DELETE access since we are going to
  908. * rename them). Check that we have the appropriate parent
  909. * permissions. Then rename source to destiation and vice versa (will need an
  910. * intermediate name - use a name > 31 chars so that it does not collide with
  911. * an existing name. Use characters that cannot be accessed by Win32 so that
  912. * side is taken care of as well (40 spaces should do it). Since we have the
  913. * Swmr held for WRITE, there is no issue of two different AfpExchangeFile
  914. * apis trying to rename to the same name). Then inter-change the file ids
  915. * and the FinderInfo in the AfpInfo streams. Also interchange the create
  916. * times (retain original ID and create time) on the files. Swap all the other
  917. * cached info in the 2 DFEntries.
  918. * Make sure the stuff is setup so that ChangeNotify filters are handled
  919. * appropriately.
  920. *
  921. * If either of the files are currently open, the name and ID in the
  922. * OpenForkDesc (that each OpenForkEntry points to) has to change to
  923. * the new name. Note that because the name and Id can now change in
  924. * the OpenForkDesc, we must make sure that everyone who accesses these
  925. * is taking appropriate locks.
  926. *
  927. *
  928. * The request packet is represented below.
  929. *
  930. * sda_ReqBlock PCONNDESC pConnDesc
  931. * sda_ReqBlock DWORD Srce. DirId
  932. * sda_ReqBlock DWORD Dest. DirId
  933. * sda_Name1 ANSI_STRING Srce. Path
  934. * sda_Name2 ANSI_STRING Dest. Path
  935. */
  936. AFPSTATUS FASTCALL
  937. AfpFspDispExchangeFiles(
  938. IN PSDA pSda
  939. )
  940. {
  941. PATHMAPENTITY PMESrc, PMEDst;
  942. PVOLDESC pVolDesc;
  943. FILEDIRPARM FDParmSrc, FDParmDst;
  944. AFPSTATUS Status = AFP_ERR_NONE, Status2 = AFP_ERR_NONE;
  945. BOOLEAN Move = True, RevertBack = False, SrcInRoot, DstInRoot;
  946. BOOLEAN RestoreSrcRO = False, RestoreDstRO = False;
  947. FILESYSHANDLE hSrcParent, hDstParent;
  948. DWORD checkpoint = 0; // denotes what needs cleanup on error
  949. DWORD NTAttrSrc = 0, NTAttrDst = 0;
  950. WCHAR PathBuf[BIG_PATH_LEN];
  951. UNICODE_STRING TempPath; // temporary filename for renaming files
  952. struct _RequestPacket
  953. {
  954. PCONNDESC _pConnDesc;
  955. DWORD _SrcParentId;
  956. DWORD _DstParentId;
  957. };
  958. #define _CHKPOINT_XCHG_DSTTOTEMP 1
  959. #define _CHKPOINT_XCHG_SRCTODST 2
  960. #define _CHKPOINT_XCHG_TEMPTOSRC 3
  961. PAGED_CODE( );
  962. DBGPRINT(DBG_COMP_AFPAPI_FILE, DBG_LEVEL_INFO,
  963. ("AfpFspDispExchangeFiles: Entered\n"));
  964. ASSERT(VALID_CONNDESC(pReqPkt->_pConnDesc) &&
  965. VALID_VOLDESC(pReqPkt->_pConnDesc->cds_pVolDesc));
  966. pVolDesc = pReqPkt->_pConnDesc->cds_pVolDesc;
  967. AfpInitializeFDParms(&FDParmSrc);
  968. AfpInitializeFDParms(&FDParmDst);
  969. AfpInitializePME(&PMESrc, 0, NULL);
  970. AfpInitializePME(&PMEDst, 0, NULL);
  971. AfpSetEmptyUnicodeString(&TempPath, 0, NULL);
  972. hSrcParent.fsh_FileHandle = NULL;
  973. hDstParent.fsh_FileHandle = NULL;
  974. // Don't allow any fork operations that might access the FileId
  975. // in an OpenForkDesc that could get exchanged.
  976. AfpSwmrAcquireExclusive(&pVolDesc->vds_ExchangeFilesLock);
  977. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  978. do
  979. {
  980. if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
  981. pReqPkt->_SrcParentId,
  982. &pSda->sda_Name1,
  983. pSda->sda_PathType,
  984. Lookup,
  985. DFE_FILE,
  986. FD_INTERNAL_BITMAP_OPENACCESS_DELETE |
  987. (FILE_BITMAP_MASK &
  988. ~(FD_BITMAP_SHORTNAME | FD_BITMAP_PRODOSINFO)),
  989. &PMESrc,
  990. &FDParmSrc)))
  991. {
  992. break;
  993. }
  994. // Check for SeeFiles on the source parent dir
  995. if (!NT_SUCCESS(Status = AfpCheckParentPermissions(
  996. pReqPkt->_pConnDesc,
  997. FDParmSrc._fdp_ParentId,
  998. &PMESrc.pme_ParentPath,
  999. DIR_ACCESS_READ,
  1000. &hSrcParent,
  1001. NULL)))
  1002. {
  1003. break;
  1004. }
  1005. if (!NT_SUCCESS(Status = AfpCheckForInhibit(&PMESrc.pme_Handle,
  1006. FD_BITMAP_ATTR_RENAMEINH,
  1007. FDParmSrc._fdp_Attr,
  1008. &NTAttrSrc)))
  1009. {
  1010. break;
  1011. }
  1012. if (!NT_SUCCESS(Status = AfpMapAfpPath(pReqPkt->_pConnDesc,
  1013. pReqPkt->_DstParentId,
  1014. &pSda->sda_Name2,
  1015. pSda->sda_PathType,
  1016. Lookup,
  1017. DFE_FILE,
  1018. FD_INTERNAL_BITMAP_OPENACCESS_DELETE |
  1019. (FILE_BITMAP_MASK &
  1020. ~(FD_BITMAP_SHORTNAME | FD_BITMAP_PRODOSINFO)),
  1021. &PMEDst,
  1022. &FDParmDst)))
  1023. {
  1024. break;
  1025. }
  1026. if (FDParmSrc._fdp_AfpId == FDParmDst._fdp_AfpId)
  1027. {
  1028. // make sure the src and dst are not the same file
  1029. Status = AFP_ERR_SAME_OBJECT;
  1030. break;
  1031. }
  1032. if (FDParmSrc._fdp_ParentId == FDParmDst._fdp_ParentId)
  1033. {
  1034. // if the parent directories are the same, we are not
  1035. // moving anything to a new directory, so the change
  1036. // notify we expect will be a rename in the source dir.
  1037. Move = False;
  1038. }
  1039. else
  1040. {
  1041. // Check for SeeFiles on the destination parent dir
  1042. if (!NT_SUCCESS(Status = AfpCheckParentPermissions(
  1043. pReqPkt->_pConnDesc,
  1044. FDParmDst._fdp_ParentId,
  1045. &PMEDst.pme_ParentPath,
  1046. DIR_ACCESS_READ,
  1047. &hDstParent,
  1048. NULL)))
  1049. {
  1050. break;
  1051. }
  1052. }
  1053. if (!NT_SUCCESS(Status = AfpCheckForInhibit(&PMEDst.pme_Handle,
  1054. FD_BITMAP_ATTR_RENAMEINH,
  1055. FDParmDst._fdp_Attr,
  1056. &NTAttrDst)))
  1057. {
  1058. break;
  1059. }
  1060. //
  1061. // Construct the path to the temporary filename for renaming during
  1062. // the name exchange
  1063. //
  1064. TempPath.MaximumLength = PMEDst.pme_ParentPath.Length + sizeof(WCHAR) +
  1065. AfpExchangeName.Length;
  1066. TempPath.Buffer = PathBuf;
  1067. if ((TempPath.MaximumLength > sizeof(PathBuf)) &&
  1068. (TempPath.Buffer = (PWCHAR)AfpAllocNonPagedMemory(TempPath.MaximumLength)) == NULL)
  1069. {
  1070. Status = AFP_ERR_MISC;
  1071. break;
  1072. }
  1073. AfpCopyUnicodeString(&TempPath, &PMEDst.pme_ParentPath);
  1074. if (TempPath.Length != 0)
  1075. {
  1076. TempPath.Buffer[TempPath.Length / sizeof(WCHAR)] = L'\\';
  1077. TempPath.Length += sizeof(WCHAR);
  1078. ASSERT((TempPath.MaximumLength - TempPath.Length) >= AfpExchangeName.Length);
  1079. }
  1080. Status = RtlAppendUnicodeStringToString(&TempPath, &AfpExchangeName);
  1081. ASSERT(NT_SUCCESS(Status));
  1082. if (NTAttrSrc & FILE_ATTRIBUTE_READONLY)
  1083. {
  1084. // We must temporarily remove the ReadOnly attribute so that
  1085. // we can rename the file/dir
  1086. Status = AfpIoSetTimesnAttr(&PMESrc.pme_Handle,
  1087. NULL,
  1088. NULL,
  1089. 0,
  1090. FILE_ATTRIBUTE_READONLY,
  1091. pVolDesc,
  1092. &PMESrc.pme_FullPath);
  1093. if (!NT_SUCCESS(Status))
  1094. {
  1095. break;
  1096. }
  1097. else
  1098. RestoreSrcRO = True;
  1099. }
  1100. if (NTAttrDst & FILE_ATTRIBUTE_READONLY)
  1101. {
  1102. // We must temporarily remove the ReadOnly attribute so that
  1103. // we can rename the file/dir
  1104. Status = AfpIoSetTimesnAttr(&PMEDst.pme_Handle,
  1105. NULL,
  1106. NULL,
  1107. 0,
  1108. FILE_ATTRIBUTE_READONLY,
  1109. pVolDesc,
  1110. &PMEDst.pme_FullPath);
  1111. if (!NT_SUCCESS(Status))
  1112. {
  1113. break;
  1114. }
  1115. else
  1116. RestoreDstRO = True;
  1117. }
  1118. // We must impersonate to do the move since it is name based
  1119. AfpImpersonateClient(pSda);
  1120. RevertBack = True;
  1121. SrcInRoot = (PMESrc.pme_ParentPath.Length == 0) ? True : False;
  1122. DstInRoot = (PMEDst.pme_ParentPath.Length == 0) ? True : False;
  1123. // First, rename the destination to a temporary name in the same
  1124. // directory
  1125. Status = AfpIoMoveAndOrRename(&PMEDst.pme_Handle,
  1126. NULL,
  1127. &AfpExchangeName,
  1128. pVolDesc,
  1129. &PMEDst.pme_FullPath,
  1130. DstInRoot ? NULL : &PMEDst.pme_ParentPath,
  1131. NULL,
  1132. NULL);
  1133. if (NT_SUCCESS(Status))
  1134. {
  1135. checkpoint = _CHKPOINT_XCHG_DSTTOTEMP;
  1136. }
  1137. else
  1138. {
  1139. break;
  1140. }
  1141. // Next, rename the source to the destination name
  1142. Status = AfpIoMoveAndOrRename(&PMESrc.pme_Handle,
  1143. Move ? &hDstParent : NULL,
  1144. &PMEDst.pme_UTail,
  1145. pVolDesc,
  1146. &PMESrc.pme_FullPath,
  1147. SrcInRoot ? NULL : &PMESrc.pme_ParentPath,
  1148. Move ? &PMEDst.pme_FullPath : NULL,
  1149. (Move && !DstInRoot) ? &PMEDst.pme_ParentPath : NULL);
  1150. if (NT_SUCCESS(Status))
  1151. {
  1152. checkpoint = _CHKPOINT_XCHG_SRCTODST;
  1153. }
  1154. else
  1155. {
  1156. break;
  1157. }
  1158. // Finally, rename the temporary name to the source name
  1159. Status = AfpIoMoveAndOrRename(&PMEDst.pme_Handle,
  1160. Move ? &hSrcParent : NULL,
  1161. &PMESrc.pme_UTail,
  1162. pVolDesc,
  1163. &TempPath,
  1164. DstInRoot ? NULL : &PMEDst.pme_ParentPath,
  1165. Move ? &PMESrc.pme_FullPath : NULL,
  1166. (Move && !SrcInRoot) ? &PMESrc.pme_ParentPath : NULL);
  1167. if (NT_SUCCESS(Status))
  1168. {
  1169. checkpoint = _CHKPOINT_XCHG_TEMPTOSRC;
  1170. }
  1171. else
  1172. {
  1173. break;
  1174. }
  1175. AfpRevertBack();
  1176. RevertBack = False;
  1177. // Swap the FileIds and FinderInfo in the AfpInfo streams
  1178. Status = AfpSetAfpInfo(&PMESrc.pme_Handle,
  1179. FILE_BITMAP_FILENUM | FD_BITMAP_FINDERINFO,
  1180. &FDParmDst,
  1181. NULL,
  1182. NULL);
  1183. ASSERT(NT_SUCCESS(Status));
  1184. Status = AfpSetAfpInfo(&PMEDst.pme_Handle,
  1185. FILE_BITMAP_FILENUM | FD_BITMAP_FINDERINFO,
  1186. &FDParmSrc,
  1187. NULL,
  1188. NULL);
  1189. ASSERT(NT_SUCCESS(Status));
  1190. // Swap the creation dates on the files
  1191. Status = AfpIoSetTimesnAttr(&PMESrc.pme_Handle,
  1192. &FDParmDst._fdp_CreateTime,
  1193. NULL,
  1194. 0,
  1195. 0,
  1196. pVolDesc,
  1197. &PMEDst.pme_FullPath);
  1198. ASSERT(NT_SUCCESS(Status));
  1199. Status = AfpIoSetTimesnAttr(&PMEDst.pme_Handle,
  1200. &FDParmSrc._fdp_CreateTime,
  1201. NULL,
  1202. 0,
  1203. 0,
  1204. pVolDesc,
  1205. &PMESrc.pme_FullPath);
  1206. ASSERT(NT_SUCCESS(Status));
  1207. // All the physical file info that we *didn't* swap on the real
  1208. // files, we need to swap in the DFEntries
  1209. AfpExchangeIdEntries(pVolDesc,
  1210. FDParmSrc._fdp_AfpId,
  1211. FDParmDst._fdp_AfpId);
  1212. // Now, if either of the 2 files is open, we have to update the
  1213. // OpenForkDesc to contain the correct FileId (we don't bother
  1214. // updating the path since we don't care if Admin shows the
  1215. // original name of the file, even though it has been renamed)
  1216. AfpExchangeForkAfpIds(pVolDesc,
  1217. FDParmSrc._fdp_AfpId,
  1218. FDParmDst._fdp_AfpId);
  1219. // update the cached src and dest parent dir mod times
  1220. AfpCacheParentModTime(pVolDesc,
  1221. &hSrcParent,
  1222. NULL,
  1223. NULL,
  1224. FDParmSrc._fdp_ParentId);
  1225. if (Move)
  1226. {
  1227. AfpCacheParentModTime(pVolDesc,
  1228. &hDstParent,
  1229. NULL,
  1230. NULL,
  1231. FDParmDst._fdp_ParentId);
  1232. }
  1233. } while (False);
  1234. // Use the checkpoint value to undo any renames that
  1235. // need undoing if there was an error
  1236. if (!NT_SUCCESS(Status))
  1237. {
  1238. switch(checkpoint)
  1239. {
  1240. case _CHKPOINT_XCHG_TEMPTOSRC:
  1241. {
  1242. // Need to rename the original dest back to temp name
  1243. Status2 = AfpIoMoveAndOrRename(&PMEDst.pme_Handle,
  1244. Move ? &hDstParent : NULL,
  1245. &AfpExchangeName,
  1246. pVolDesc,
  1247. &PMESrc.pme_FullPath,
  1248. SrcInRoot ? NULL : &PMESrc.pme_ParentPath,
  1249. Move ? &TempPath : NULL,
  1250. (Move && !DstInRoot) ? &PMEDst.pme_ParentPath : NULL);
  1251. if (!NT_SUCCESS(Status2))
  1252. {
  1253. break;
  1254. }
  1255. // fall thru;
  1256. }
  1257. case _CHKPOINT_XCHG_SRCTODST:
  1258. {
  1259. // Need to rename the dest back to original src name
  1260. Status2 = AfpIoMoveAndOrRename(&PMESrc.pme_Handle,
  1261. Move ? &hSrcParent : NULL,
  1262. &PMESrc.pme_UTail,
  1263. pVolDesc,
  1264. &PMEDst.pme_FullPath,
  1265. DstInRoot ? NULL : &PMEDst.pme_ParentPath,
  1266. Move ? &PMESrc.pme_FullPath : NULL,
  1267. (Move && !SrcInRoot) ? &PMESrc.pme_ParentPath : NULL);
  1268. if (!NT_SUCCESS(Status2))
  1269. {
  1270. break;
  1271. }
  1272. // fall thru;
  1273. }
  1274. case _CHKPOINT_XCHG_DSTTOTEMP:
  1275. {
  1276. // Need to rename the temp back to original dest name
  1277. Status2 = AfpIoMoveAndOrRename(&PMEDst.pme_Handle,
  1278. NULL,
  1279. &PMEDst.pme_UTail,
  1280. pVolDesc,
  1281. &TempPath,
  1282. DstInRoot ? NULL : &PMEDst.pme_ParentPath,
  1283. NULL,
  1284. NULL);
  1285. // update the cached src parent dir mod time
  1286. AfpCacheParentModTime(pVolDesc,
  1287. &hSrcParent,
  1288. NULL,
  1289. NULL,
  1290. FDParmSrc._fdp_ParentId);
  1291. if (Move)
  1292. {
  1293. // update the cached dest parent dir mod time
  1294. AfpCacheParentModTime(pVolDesc,
  1295. &hDstParent,
  1296. NULL,
  1297. NULL,
  1298. FDParmDst._fdp_ParentId);
  1299. }
  1300. break;
  1301. }
  1302. default:
  1303. {
  1304. break;
  1305. }
  1306. } // end switch
  1307. }
  1308. // Set the ReadOnly attribute back on the files if need be
  1309. // NOTE: will we get a notify for this since we havn't closed
  1310. // the handle yet?
  1311. if (RestoreSrcRO)
  1312. AfpIoSetTimesnAttr(&PMESrc.pme_Handle,
  1313. NULL,
  1314. NULL,
  1315. FILE_ATTRIBUTE_READONLY,
  1316. 0,
  1317. NULL,
  1318. NULL);
  1319. if (RestoreDstRO)
  1320. AfpIoSetTimesnAttr(&PMEDst.pme_Handle,
  1321. NULL,
  1322. NULL,
  1323. FILE_ATTRIBUTE_READONLY,
  1324. 0,
  1325. NULL,
  1326. NULL);
  1327. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  1328. AfpSwmrRelease(&pVolDesc->vds_ExchangeFilesLock);
  1329. if (RevertBack)
  1330. AfpRevertBack();
  1331. if (PMESrc.pme_Handle.fsh_FileHandle != NULL)
  1332. AfpIoClose(&PMESrc.pme_Handle);
  1333. if (PMEDst.pme_Handle.fsh_FileHandle != NULL)
  1334. AfpIoClose(&PMEDst.pme_Handle);
  1335. if (hSrcParent.fsh_FileHandle != NULL)
  1336. AfpIoClose(&hSrcParent);
  1337. if (hDstParent.fsh_FileHandle != NULL)
  1338. AfpIoClose(&hDstParent);
  1339. if ((TempPath.Buffer != NULL) &&
  1340. (TempPath.Buffer != PathBuf))
  1341. AfpFreeMemory(TempPath.Buffer);
  1342. if (PMESrc.pme_FullPath.Buffer != NULL)
  1343. AfpFreeMemory(PMESrc.pme_FullPath.Buffer);
  1344. if (PMEDst.pme_FullPath.Buffer != NULL)
  1345. AfpFreeMemory(PMEDst.pme_FullPath.Buffer);
  1346. return Status;
  1347. }
  1348.