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.

1509 lines
39 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. pathmap.c
  5. Abstract:
  6. This module contains the routines that manipulate AFP paths.
  7. Author:
  8. Sue Adams (microsoft!suea)
  9. Revision History:
  10. 04 Jun 1992 Initial Version
  11. 05 Oct 1993 JameelH Performance Changes. Merge cached afpinfo into the
  12. idindex structure. Make both the ANSI and the UNICODE
  13. names part of idindex. Added EnumCache for improving
  14. enumerate perf.
  15. Notes: Tab stop: 4
  16. --*/
  17. #define _PATHMAP_LOCALS
  18. #define FILENUM FILE_PATHMAP
  19. #include <afp.h>
  20. #include <fdparm.h>
  21. #include <pathmap.h>
  22. #include <afpinfo.h>
  23. #include <client.h>
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text( PAGE, AfpMapAfpPath)
  26. #pragma alloc_text( PAGE, AfpMapAfpPathForLookup)
  27. #pragma alloc_text( PAGE, AfpMapAfpIdForLookup)
  28. #pragma alloc_text( PAGE, afpGetMappedForLookupFDInfo)
  29. #pragma alloc_text( PAGE, afpMapAfpPathToMappedPath)
  30. #pragma alloc_text( PAGE, AfpHostPathFromDFEntry)
  31. #pragma alloc_text( PAGE, AfpCheckParentPermissions)
  32. #pragma alloc_text( PAGE, afpOpenUserHandle)
  33. #endif
  34. /*** AfpMapAfpPath
  35. *
  36. * If mapping is for lookup operation, a FILESYSHANDLE open in the user's
  37. * context is returned, The caller MUST close this handle when done with it.
  38. *
  39. * If pFDParm is non-null, it will be filled in as appropriate according to Bitmap.
  40. *
  41. * If mapping is for create operation, the volume root-relative host pathname
  42. * (in unicode) of the item we are about to create is returned. For lookup
  43. * operation the paths refer to the item being pathmapped. This routine
  44. * always returns the paths in the PME. It is the caller's responsibility
  45. * to free the Full HostPath Buffer, if it is not supplied already.
  46. *
  47. * The caller MUST have the IdDb locked for Exclusive access.
  48. *
  49. * LOCKS_ASSUMED: vds_IdDbAccessLock (SWMR, Exclusive)
  50. *
  51. */
  52. AFPSTATUS
  53. AfpMapAfpPath(
  54. IN PCONNDESC pConnDesc,
  55. IN DWORD DirId,
  56. IN PANSI_STRING pPath,
  57. IN BYTE PathType, // short names or long names
  58. IN PATHMAP_TYPE MapReason, // for lookup or hard/soft create?
  59. IN DWORD DFFlag, // map to file? dir? or either?
  60. IN DWORD Bitmap, // what fields of FDParm to fill in
  61. OUT PPATHMAPENTITY pPME,
  62. OUT PFILEDIRPARM pFDParm OPTIONAL // for lookups only
  63. )
  64. {
  65. PVOLDESC pVolDesc;
  66. MAPPEDPATH mappedpath;
  67. AFPSTATUS Status;
  68. #ifdef PROFILING
  69. TIME TimeS, TimeE, TimeD;
  70. #endif
  71. PAGED_CODE( );
  72. ASSERT((pConnDesc != NULL));
  73. #ifdef PROFILING
  74. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_PathMapCount);
  75. AfpGetPerfCounter(&TimeS);
  76. #endif
  77. pVolDesc = pConnDesc->cds_pVolDesc;
  78. ASSERT(IS_VOLUME_NTFS(pVolDesc));
  79. ASSERT(AfpSwmrLockedExclusive(&pVolDesc->vds_IdDbAccessLock));
  80. // initialize some fields in the PME
  81. AfpSetEmptyUnicodeString(&pPME->pme_ParentPath, 0, NULL);
  82. do
  83. {
  84. Status = afpMapAfpPathToMappedPath(pVolDesc,
  85. DirId,
  86. pPath,
  87. PathType,
  88. MapReason,
  89. DFFlag,
  90. True,
  91. &mappedpath);
  92. if ((Status != AFP_ERR_NONE) &&
  93. !((MapReason == HardCreate) &&
  94. (Status == AFP_ERR_OBJECT_EXISTS) &&
  95. (DFFlag == DFE_FILE)))
  96. {
  97. break;
  98. }
  99. ASSERT(pPME != NULL);
  100. // Get the volume relative path to the parent directory for
  101. // creates, or to the item for lookups
  102. if ((Status = AfpHostPathFromDFEntry(mappedpath.mp_pdfe,
  103. // since CopyFile and Move have to lookup
  104. // the destination parent dir paths, we
  105. // need to allocate extra room for them in
  106. // the path to append the filename
  107. (MapReason == Lookup) ?
  108. (AFP_LONGNAME_LEN + 1) * sizeof(WCHAR):
  109. mappedpath.mp_Tail.Length + sizeof(WCHAR),
  110. &pPME->pme_FullPath)) != AFP_ERR_NONE)
  111. break;
  112. // if Pathmap is for hard (files only) or soft create (file or dir)
  113. if (MapReason != Lookup)
  114. {
  115. ASSERT(pFDParm == NULL);
  116. // fill in the dfe of parent dir in which create will take place
  117. pPME->pme_pDfeParent = mappedpath.mp_pdfe;
  118. // fill in path to parent
  119. pPME->pme_ParentPath = pPME->pme_FullPath;
  120. // Add a path separator if we are not at the root
  121. if (pPME->pme_FullPath.Length > 0)
  122. {
  123. pPME->pme_FullPath.Buffer[pPME->pme_FullPath.Length / sizeof(WCHAR)] = L'\\';
  124. pPME->pme_FullPath.Length += sizeof(WCHAR);
  125. }
  126. pPME->pme_UTail.Length = pPME->pme_UTail.MaximumLength = mappedpath.mp_Tail.Length;
  127. pPME->pme_UTail.Buffer = (PWCHAR)((PBYTE)pPME->pme_FullPath.Buffer +
  128. pPME->pme_FullPath.Length);
  129. Status = RtlAppendUnicodeStringToString(&pPME->pme_FullPath,
  130. &mappedpath.mp_Tail);
  131. ASSERT(NT_SUCCESS(Status));
  132. }
  133. else // lookup operation
  134. {
  135. pPME->pme_pDfEntry = mappedpath.mp_pdfe;
  136. pPME->pme_UTail.Length = mappedpath.mp_pdfe->dfe_UnicodeName.Length;
  137. pPME->pme_UTail.Buffer = (PWCHAR)((PBYTE)pPME->pme_FullPath.Buffer +
  138. pPME->pme_FullPath.Length -
  139. pPME->pme_UTail.Length);
  140. pPME->pme_ParentPath.Length =
  141. pPME->pme_ParentPath.MaximumLength = pPME->pme_FullPath.Length - pPME->pme_UTail.Length;
  142. if (pPME->pme_FullPath.Length > pPME->pme_UTail.Length)
  143. {
  144. // subtract the path separator if not in root dir
  145. pPME->pme_ParentPath.Length -= sizeof(WCHAR);
  146. ASSERT(pPME->pme_ParentPath.Length >= 0);
  147. }
  148. pPME->pme_ParentPath.Buffer = pPME->pme_FullPath.Buffer;
  149. pPME->pme_UTail.MaximumLength = pPME->pme_FullPath.MaximumLength - pPME->pme_ParentPath.Length;
  150. Status = afpGetMappedForLookupFDInfo(pConnDesc,
  151. mappedpath.mp_pdfe,
  152. Bitmap,
  153. pPME,
  154. pFDParm);
  155. // if this fails do not free path buffer and set it back to
  156. // null. We don't know that the path buffer isn't on
  157. // the callers stack. Caller should always clean it up himself.
  158. }
  159. } while (False);
  160. #ifdef PROFILING
  161. AfpGetPerfCounter(&TimeE);
  162. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  163. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_PathMapTime,
  164. TimeD,
  165. &AfpStatisticsLock);
  166. #endif
  167. return Status;
  168. }
  169. /*** AfpMapAfpPathForLookup
  170. *
  171. * Maps an AFP dirid/pathname pair to an open handle (in the user's context)
  172. * to the DATA stream of the file/dir.
  173. * The DirID database is locked for read for the duration of this
  174. * routine, unless afpMapAfpPathToMappedPath returns
  175. * AFP_ERR_WRITE_LOCK_REQUIRED in which case the DirID database will be locked
  176. * for write. This will only happen the first time a mac tries to access
  177. * a directory who's files have not yet been cached in.
  178. *
  179. * LOCKS: vds_IdDbAccessLock (SWMR, Shared OR Exclusive)
  180. */
  181. AFPSTATUS
  182. AfpMapAfpPathForLookup(
  183. IN PCONNDESC pConnDesc,
  184. IN DWORD DirId,
  185. IN PANSI_STRING pPath,
  186. IN BYTE PathType, // short names or long names
  187. IN DWORD DFFlag,
  188. IN DWORD Bitmap,
  189. OUT PPATHMAPENTITY pPME OPTIONAL,
  190. OUT PFILEDIRPARM pFDParm OPTIONAL
  191. )
  192. {
  193. MAPPEDPATH mappedpath;
  194. PVOLDESC pVolDesc;
  195. PSWMR pIdDbLock;
  196. AFPSTATUS Status;
  197. BOOLEAN swmrLockedExclusive = False;
  198. PATHMAP_TYPE mapReason = Lookup;
  199. #ifdef PROFILING
  200. TIME TimeS, TimeE, TimeD;
  201. #endif
  202. PAGED_CODE( );
  203. ASSERT((pConnDesc != NULL));
  204. #ifdef PROFILING
  205. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_PathMapCount);
  206. AfpGetPerfCounter(&TimeS);
  207. #endif
  208. #ifndef GET_CORRECT_OFFSPRING_COUNTS
  209. if (pConnDesc->cds_pSda->sda_AfpFunc == _AFP_ENUMERATE)
  210. {
  211. mapReason = LookupForEnumerate;
  212. }
  213. #endif
  214. pVolDesc = pConnDesc->cds_pVolDesc;
  215. pIdDbLock = &(pVolDesc->vds_IdDbAccessLock);
  216. AfpSwmrAcquireShared(pIdDbLock);
  217. do
  218. {
  219. do
  220. {
  221. Status = afpMapAfpPathToMappedPath(pVolDesc,
  222. DirId,
  223. pPath,
  224. PathType,
  225. mapReason, // lookups only
  226. DFFlag,
  227. swmrLockedExclusive,
  228. &mappedpath);
  229. if (Status == AFP_ERR_WRITE_LOCK_REQUIRED)
  230. {
  231. ASSERT (!swmrLockedExclusive);
  232. // Pathmap needed to cache in the files for the last directory
  233. // in the path but didn't have the write lock to the ID database
  234. AfpSwmrRelease(pIdDbLock);
  235. AfpSwmrAcquireExclusive(pIdDbLock);
  236. swmrLockedExclusive = True;
  237. continue;
  238. }
  239. break;
  240. } while (True);
  241. if (!NT_SUCCESS(Status))
  242. {
  243. DBGPRINT (DBG_COMP_IDINDEX, DBG_LEVEL_ERR,
  244. ("AfpMapAfpPathForLookup: afpMapAfpPathToMappedPath failed: Error = %lx\n", Status));
  245. break;
  246. }
  247. if (ARGUMENT_PRESENT(pPME))
  248. {
  249. pPME->pme_FullPath.Length = 0;
  250. }
  251. if (Bitmap & FD_INTERNAL_BITMAP_RETURN_PMEPATHS)
  252. {
  253. ASSERT(ARGUMENT_PRESENT(pPME));
  254. if ((Status = AfpHostPathFromDFEntry(mappedpath.mp_pdfe,
  255. (Bitmap & FD_INTERNAL_BITMAP_OPENFORK_RESC) ?
  256. AfpResourceStream.Length : 0,
  257. &pPME->pme_FullPath)) != AFP_ERR_NONE)
  258. break;
  259. pPME->pme_UTail.Length = mappedpath.mp_pdfe->dfe_UnicodeName.Length;
  260. pPME->pme_UTail.Buffer = (PWCHAR)((PBYTE)pPME->pme_FullPath.Buffer +
  261. pPME->pme_FullPath.Length - pPME->pme_UTail.Length);
  262. pPME->pme_ParentPath.Length =
  263. pPME->pme_ParentPath.MaximumLength = pPME->pme_FullPath.Length - pPME->pme_UTail.Length;
  264. if (pPME->pme_FullPath.Length > pPME->pme_UTail.Length)
  265. {
  266. // subtract the path separator if not in root dir
  267. pPME->pme_ParentPath.Length -= sizeof(WCHAR);
  268. ASSERT(pPME->pme_ParentPath.Length >= 0);
  269. }
  270. pPME->pme_ParentPath.Buffer = pPME->pme_FullPath.Buffer;
  271. pPME->pme_UTail.MaximumLength = pPME->pme_FullPath.MaximumLength - pPME->pme_ParentPath.Length;
  272. }
  273. Status = afpGetMappedForLookupFDInfo(pConnDesc,
  274. mappedpath.mp_pdfe,
  275. Bitmap,
  276. pPME,
  277. pFDParm);
  278. } while (False);
  279. AfpSwmrRelease(pIdDbLock);
  280. #ifdef PROFILING
  281. AfpGetPerfCounter(&TimeE);
  282. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  283. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_PathMapTime,
  284. TimeD,
  285. &AfpStatisticsLock);
  286. #endif
  287. return Status;
  288. }
  289. /*** AfpMapAfpIdForLookup
  290. *
  291. * Maps an AFP id to an open FILESYSTEMHANDLE (in the user's context) to
  292. * to the DATA stream of the file/dir.
  293. * The DirID database is locked for shared or exclusive access for the duration
  294. * of this routine.
  295. *
  296. * LOCKS: vds_IdDbAccessLock (SWMR, Shared OR Exclusive)
  297. */
  298. AFPSTATUS
  299. AfpMapAfpIdForLookup(
  300. IN PCONNDESC pConnDesc,
  301. IN DWORD AfpId,
  302. IN DWORD DFFlag,
  303. IN DWORD Bitmap,
  304. OUT PPATHMAPENTITY pPME OPTIONAL,
  305. OUT PFILEDIRPARM pFDParm OPTIONAL
  306. )
  307. {
  308. PVOLDESC pVolDesc;
  309. PSWMR pIdDbLock;
  310. AFPSTATUS Status;
  311. PDFENTRY pDfEntry;
  312. BOOLEAN CleanupLock = False;
  313. #ifdef PROFILING
  314. TIME TimeS, TimeE, TimeD;
  315. #endif
  316. PAGED_CODE( );
  317. #ifdef PROFILING
  318. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_PathMapCount);
  319. AfpGetPerfCounter(&TimeS);
  320. #endif
  321. ASSERT((pConnDesc != NULL));
  322. do
  323. {
  324. if (AfpId == 0)
  325. {
  326. Status = AFP_ERR_PARAM;
  327. break;
  328. }
  329. pVolDesc = pConnDesc->cds_pVolDesc;
  330. pIdDbLock = &(pVolDesc->vds_IdDbAccessLock);
  331. AfpSwmrAcquireShared(pIdDbLock);
  332. CleanupLock = True;
  333. if ((AfpId == AFP_ID_PARENT_OF_ROOT) ||
  334. ((pDfEntry = AfpFindDfEntryById(pVolDesc, AfpId, DFE_ANY)) == NULL))
  335. {
  336. Status = AFP_ERR_OBJECT_NOT_FOUND;
  337. break;
  338. }
  339. if (((DFFlag == DFE_DIR) && DFE_IS_FILE(pDfEntry)) ||
  340. ((DFFlag == DFE_FILE) && DFE_IS_DIRECTORY(pDfEntry)))
  341. {
  342. Status = AFP_ERR_OBJECT_TYPE;
  343. break;
  344. }
  345. if (ARGUMENT_PRESENT(pPME))
  346. {
  347. pPME->pme_FullPath.Length = 0;
  348. }
  349. Status = afpGetMappedForLookupFDInfo(pConnDesc,
  350. pDfEntry,
  351. Bitmap,
  352. pPME,
  353. pFDParm);
  354. } while (False);
  355. if (CleanupLock)
  356. {
  357. AfpSwmrRelease(pIdDbLock);
  358. }
  359. #ifdef PROFILING
  360. AfpGetPerfCounter(&TimeE);
  361. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  362. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_PathMapTime,
  363. TimeD,
  364. &AfpStatisticsLock);
  365. #endif
  366. return Status;
  367. }
  368. /*** afpGetMappedForLookupFDInfo
  369. *
  370. * After a pathmap for LOOKUP operation, this routine is called to
  371. * return various FileDir parm information about the mapped file/dir.
  372. * The following FileDir information is always returned:
  373. * AFP DirId/FileId
  374. * Parent DirId
  375. * DFE flags (indicating item is a directory, a file, or a file with an ID)
  376. * Attributes (Inhibit bits and D/R Already open bits normalized with
  377. * the NTFS attributes for RO, System, Hidden, Archive)
  378. * BackupTime
  379. * CreateTime
  380. * ModifiedTime
  381. *
  382. * The following FileDir information is returned according to the flags set
  383. * in word 0 of the Bitmap parameter (these correspond to the AFP file/dir
  384. * bitmap):
  385. * Longname
  386. * Shortname
  387. * FinderInfo
  388. * ProDosInfo
  389. * Directory Access Rights (as stored in AFP_AfpInfo stream)
  390. * Directory OwnerId/GroupId
  391. * Directory Offspring count (file count and dir count are separate)
  392. *
  393. * The open access is stored in word 1 of the Bitmap parameter.
  394. * This is used by AfpOpenUserHandle (for NTFS volumes) or AfpIoOpen (for
  395. * CDFS volumes) when opening the data stream of the file/dir (under
  396. * impersonation for NTFS) who's handle will be returned within the
  397. * pPME parameter if supplied.
  398. *
  399. * LOCKS_ASSUMED: vds_IdDbAccessLock (SWMR, Shared)
  400. *
  401. */
  402. LOCAL
  403. AFPSTATUS
  404. afpGetMappedForLookupFDInfo(
  405. IN PCONNDESC pConnDesc,
  406. IN PDFENTRY pDfEntry,
  407. IN DWORD Bitmap,
  408. OUT PPATHMAPENTITY pPME OPTIONAL, // Supply for NTFS only if need a
  409. // handle in user's context, usually
  410. // for security checking purposes
  411. OUT PFILEDIRPARM pFDParm OPTIONAL // Supply if want returned FDInfo
  412. )
  413. {
  414. BOOLEAN fNtfsVol;
  415. AFPSTATUS Status = STATUS_SUCCESS;
  416. DWORD OpenAccess = FILEIO_ACCESS_NONE;
  417. FILESYSHANDLE fsh;
  418. PFILESYSHANDLE pHandle = NULL;
  419. PAGED_CODE( );
  420. fNtfsVol = IS_VOLUME_NTFS(pConnDesc->cds_pVolDesc);
  421. if (ARGUMENT_PRESENT(pPME))
  422. {
  423. pHandle = &pPME->pme_Handle;
  424. }
  425. else if ((fNtfsVol &&
  426. (Bitmap & (FD_BITMAP_SHORTNAME | FD_BITMAP_PRODOSINFO))))
  427. {
  428. pHandle = &fsh;
  429. }
  430. if (pHandle != NULL)
  431. {
  432. if (!NT_SUCCESS(Status = afpOpenUserHandle(pConnDesc,
  433. pDfEntry,
  434. (ARGUMENT_PRESENT(pPME) &&
  435. (pPME->pme_FullPath.Buffer != NULL)) ?
  436. &pPME->pme_FullPath : NULL,
  437. Bitmap, // encode open/deny modes
  438. pHandle)))
  439. {
  440. if ((Status == AFP_ERR_DENY_CONFLICT) &&
  441. ARGUMENT_PRESENT(pFDParm))
  442. {
  443. // For CreateId/ResolveId/DeleteId
  444. pFDParm->_fdp_AfpId = pDfEntry->dfe_AfpId;
  445. pFDParm->_fdp_Flags = (pDfEntry->dfe_Flags & DFE_FLAGS_DFBITS);
  446. }
  447. return Status;
  448. }
  449. }
  450. do
  451. {
  452. if (ARGUMENT_PRESENT(pFDParm))
  453. {
  454. pFDParm->_fdp_AfpId = pDfEntry->dfe_AfpId;
  455. pFDParm->_fdp_ParentId = pDfEntry->dfe_Parent->dfe_AfpId;
  456. ASSERT(!((pDfEntry->dfe_Flags & DFE_FLAGS_DIR) &&
  457. (pDfEntry->dfe_Flags & (DFE_FLAGS_FILE_WITH_ID | DFE_FLAGS_FILE_NO_ID))));
  458. pFDParm->_fdp_Flags = (pDfEntry->dfe_Flags & DFE_FLAGS_DFBITS);
  459. if (Bitmap & FD_BITMAP_FINDERINFO)
  460. {
  461. pFDParm->_fdp_FinderInfo = pDfEntry->dfe_FinderInfo;
  462. }
  463. pFDParm->_fdp_Attr = pDfEntry->dfe_AfpAttr;
  464. AfpNormalizeAfpAttr(pFDParm, pDfEntry->dfe_NtAttr);
  465. // The Finder uses the Finder isInvisible flag over
  466. // the file system Invisible attribute to tell if the thing is
  467. // displayed or not. If the PC turns off the hidden attribute
  468. // we should clear the Finder isInvisible flag
  469. if ((Bitmap & FD_BITMAP_FINDERINFO) &&
  470. !(pFDParm->_fdp_Attr & FD_BITMAP_ATTR_INVISIBLE))
  471. {
  472. pFDParm->_fdp_FinderInfo.fd_Attr1 &= ~FINDER_FLAG_INVISIBLE;
  473. }
  474. pFDParm->_fdp_BackupTime = pDfEntry->dfe_BackupTime;
  475. pFDParm->_fdp_CreateTime = pDfEntry->dfe_CreateTime;
  476. pFDParm->_fdp_ModifiedTime = AfpConvertTimeToMacFormat(&pDfEntry->dfe_LastModTime);
  477. if (Bitmap & FD_BITMAP_LONGNAME)
  478. {
  479. ASSERT((pFDParm->_fdp_LongName.Buffer != NULL) &&
  480. (pFDParm->_fdp_LongName.MaximumLength >=
  481. pDfEntry->dfe_UnicodeName.Length/(USHORT)sizeof(WCHAR)));
  482. AfpConvertMungedUnicodeToAnsi(&pDfEntry->dfe_UnicodeName,
  483. &pFDParm->_fdp_LongName);
  484. }
  485. if (Bitmap & FD_BITMAP_SHORTNAME)
  486. {
  487. ASSERT(pFDParm->_fdp_ShortName.Buffer != NULL);
  488. if (!fNtfsVol)
  489. {
  490. ASSERT(pFDParm->_fdp_ShortName.MaximumLength >=
  491. (pDfEntry->dfe_UnicodeName.Length/sizeof(WCHAR)));
  492. AfpConvertMungedUnicodeToAnsi(&pDfEntry->dfe_UnicodeName,
  493. &pFDParm->_fdp_ShortName);
  494. // if asking for shortname on CDFS, we will fill in the pFDParm
  495. // shortname with the pDfEntry longname, ONLY if it is an 8.3 name
  496. if (!AfpIsLegalShortname(&pFDParm->_fdp_ShortName))
  497. {
  498. pFDParm->_fdp_ShortName.Length = 0;
  499. }
  500. }
  501. else
  502. {
  503. // get NTFS shortname
  504. ASSERT(pFDParm->_fdp_ShortName.MaximumLength >= AFP_SHORTNAME_LEN);
  505. ASSERT(pHandle != NULL);
  506. Status = AfpIoQueryShortName(pHandle,
  507. &pFDParm->_fdp_ShortName);
  508. if (!NT_SUCCESS(Status))
  509. {
  510. pFDParm->_fdp_ShortName.Length = 0;
  511. break;
  512. }
  513. }
  514. }
  515. if (DFE_IS_FILE(pDfEntry))
  516. {
  517. if (pDfEntry->dfe_Flags & DFE_FLAGS_D_ALREADYOPEN)
  518. pFDParm->_fdp_Attr |= FILE_BITMAP_ATTR_DATAOPEN;
  519. if (pDfEntry->dfe_Flags & DFE_FLAGS_R_ALREADYOPEN)
  520. pFDParm->_fdp_Attr |= FILE_BITMAP_ATTR_RESCOPEN;
  521. if (Bitmap & FILE_BITMAP_RESCLEN)
  522. {
  523. pFDParm->_fdp_RescForkLen = pDfEntry->dfe_RescLen;
  524. }
  525. if (Bitmap & FILE_BITMAP_DATALEN)
  526. {
  527. pFDParm->_fdp_DataForkLen = pDfEntry->dfe_DataLen;
  528. }
  529. }
  530. if (Bitmap & FD_BITMAP_PRODOSINFO)
  531. {
  532. if (fNtfsVol)
  533. {
  534. ASSERT(pHandle != NULL);
  535. Status = AfpQueryProDos(pHandle,
  536. &pFDParm->_fdp_ProDosInfo);
  537. if (!NT_SUCCESS(Status))
  538. {
  539. break;
  540. }
  541. }
  542. else // CDFS File or Directory
  543. {
  544. RtlZeroMemory(&pFDParm->_fdp_ProDosInfo, sizeof(PRODOSINFO));
  545. if (DFE_IS_FILE(pDfEntry)) // CDFS file
  546. {
  547. AfpProDosInfoFromFinderInfo(&pDfEntry->dfe_FinderInfo,
  548. &pFDParm->_fdp_ProDosInfo);
  549. }
  550. else // CDFS Directory
  551. {
  552. pFDParm->_fdp_ProDosInfo.pd_FileType[0] = PRODOS_TYPE_DIR;
  553. pFDParm->_fdp_ProDosInfo.pd_AuxType[1] = PRODOS_AUX_DIR;
  554. }
  555. }
  556. }
  557. // check for dir here since enumerate ANDs the file and dir bitmaps
  558. if (DFE_IS_DIRECTORY(pDfEntry) &&
  559. (Bitmap & (DIR_BITMAP_ACCESSRIGHTS |
  560. DIR_BITMAP_OWNERID |
  561. DIR_BITMAP_GROUPID)))
  562. {
  563. if (fNtfsVol)
  564. {
  565. // Because the file and dir bitmaps are OR'd together,
  566. // and the OwnerId bit is overloaded with the RescLen bit,
  567. // we don't know if this bit was actually included in the
  568. // file bitmap or the dir bitmap. The api would have
  569. // determined whether or not it needed a handle based on
  570. // these bitmaps, so based on the pPME we can tell if we
  571. // actually need to query for security or not.
  572. if (ARGUMENT_PRESENT(pPME))
  573. {
  574. pFDParm->_fdp_OwnerRights = DFE_OWNER_ACCESS(pDfEntry);
  575. pFDParm->_fdp_GroupRights = DFE_GROUP_ACCESS(pDfEntry);
  576. pFDParm->_fdp_WorldRights = DFE_WORLD_ACCESS(pDfEntry);
  577. // Query this user's rights
  578. Status = AfpQuerySecurityIdsAndRights(pConnDesc->cds_pSda,
  579. pHandle,
  580. Bitmap,
  581. pFDParm);
  582. if (!NT_SUCCESS(Status))
  583. {
  584. break;
  585. }
  586. }
  587. }
  588. else
  589. {
  590. pFDParm->_fdp_OwnerRights =
  591. pFDParm->_fdp_GroupRights =
  592. pFDParm->_fdp_WorldRights =
  593. pFDParm->_fdp_UserRights = (DIR_ACCESS_READ | DIR_ACCESS_SEARCH);
  594. pFDParm->_fdp_OwnerId = pFDParm->_fdp_GroupId = 0;
  595. }
  596. }
  597. // Must check for type directory since this Bitmap bit is overloaded
  598. if (DFE_IS_DIRECTORY(pDfEntry) && (Bitmap & DIR_BITMAP_OFFSPRINGS))
  599. {
  600. #ifndef GET_CORRECT_OFFSPRING_COUNTS
  601. if (!DFE_CHILDREN_ARE_PRESENT(pDfEntry) &&
  602. (pDfEntry->dfe_DirOffspring == 0))
  603. {
  604. // If the files have not yet been cached in for this dir,
  605. // return non-zero filecount so that system 7.x view by
  606. // name will enumerate the directory if user clicks the
  607. // triangle for this dir. If you return zero offspring
  608. // What might break from lying like this?
  609. pFDParm->_fdp_FileCount = 1;
  610. }
  611. else
  612. #endif
  613. pFDParm->_fdp_FileCount = pDfEntry->dfe_FileOffspring;
  614. pFDParm->_fdp_DirCount = pDfEntry->dfe_DirOffspring;
  615. }
  616. }
  617. } while (False);
  618. if (pHandle == &fsh)
  619. {
  620. // if we had to open a handle just to query shortname or ProDOS
  621. // close it
  622. AfpIoClose(&fsh);
  623. }
  624. return Status;
  625. }
  626. /*** afpMapAfpPathToMappedPath
  627. *
  628. * Maps an AFP DirId/pathname pair to a MAPPEDPATH structure.
  629. * The CALLER must have the DirId/FileId database locked for shared
  630. * access (or Exclusive access if they need that level of lock for other
  631. * operations on the IDDB, to map a path only requires shared lock)
  632. *
  633. * LOCKS_ASSUMED: vds_IdDbAccessLock (SWMR, Shared OR Exclusive)
  634. */
  635. LOCAL
  636. AFPSTATUS
  637. afpMapAfpPathToMappedPath(
  638. IN PVOLDESC pVolDesc,
  639. IN DWORD DirId,
  640. IN PANSI_STRING Path, // relative to DirId
  641. IN BYTE PathType, // short names or long names
  642. IN PATHMAP_TYPE MapReason, // for lookup or hard/soft create?
  643. IN DWORD DFflag, // file, dir or don't know which
  644. IN BOOLEAN LockedExclusive,
  645. OUT PMAPPEDPATH pMappedPath
  646. )
  647. {
  648. PDFENTRY pDFEntry, ptempDFEntry;
  649. CHAR *position, *tempposition;
  650. int length, templength;
  651. ANSI_STRING acomponent;
  652. CHAR component[AFP_FILENAME_LEN+1];
  653. BOOLEAN checkEnumForParent = False, checkEnumForDir = False;
  654. PAGED_CODE( );
  655. ASSERT(pVolDesc != NULL);
  656. #ifndef GET_CORRECT_OFFSPRING_COUNTS
  657. if (MapReason == LookupForEnumerate)
  658. {
  659. checkEnumForDir = True;
  660. MapReason = Lookup;
  661. }
  662. #endif
  663. // Initialize the returned MappedPath structure
  664. pMappedPath->mp_pdfe = NULL;
  665. AfpSetEmptyUnicodeString(&pMappedPath->mp_Tail,
  666. sizeof(pMappedPath->mp_Tailbuf),
  667. pMappedPath->mp_Tailbuf);
  668. // Lookup the initial DirId in the index database, it better be valid
  669. if ((pDFEntry = AfpFindDfEntryById(pVolDesc,
  670. DirId,
  671. DFE_DIR)) == NULL)
  672. {
  673. return AFP_ERR_OBJECT_NOT_FOUND;
  674. }
  675. ASSERT(Path != NULL);
  676. tempposition = position = Path->Buffer;
  677. templength = length = Path->Length;
  678. do
  679. {
  680. // Lookup by DirId only?
  681. if (length == 0) // no path was given
  682. {
  683. if (MapReason != Lookup) // mapping is for create
  684. {
  685. return AFP_ERR_PARAM; // missing the file or dirname
  686. }
  687. else if (DFE_IS_PARENT_OF_ROOT(pDFEntry))
  688. {
  689. return AFP_ERR_OBJECT_NOT_FOUND;
  690. }
  691. else
  692. {
  693. pMappedPath->mp_pdfe = pDFEntry;
  694. #ifdef GET_CORRECT_OFFSPRING_COUNTS
  695. checkEnumForParent = checkEnumForDir = True;
  696. #endif
  697. break;
  698. }
  699. }
  700. //
  701. // Pre-scan path to munge for easier component breakdown
  702. //
  703. // Get rid of a leading null to make scanning easier
  704. if (*position == AFP_PATHSEP)
  705. {
  706. length--;
  707. position++;
  708. if (length == 0) // The path consisted of just one null byte
  709. {
  710. if (MapReason != Lookup)
  711. {
  712. return AFP_ERR_PARAM;
  713. }
  714. else if (DFE_IS_PARENT_OF_ROOT(pDFEntry))
  715. {
  716. return AFP_ERR_OBJECT_NOT_FOUND;
  717. }
  718. else if (((DFflag == DFE_DIR) && DFE_IS_FILE(pDFEntry)) ||
  719. ((DFflag == DFE_FILE) && DFE_IS_DIRECTORY(pDFEntry)))
  720. {
  721. return AFP_ERR_OBJECT_TYPE;
  722. }
  723. else
  724. {
  725. pMappedPath->mp_pdfe = pDFEntry;
  726. #ifdef GET_CORRECT_OFFSPRING_COUNTS
  727. checkEnumForParent = checkEnumForDir = True;
  728. #endif
  729. break;
  730. }
  731. }
  732. }
  733. //
  734. // Get rid of a trailing null if it is not an "up" token --
  735. // i.e. preceded by another null.
  736. // The 2nd array access is ok because we know we have at
  737. // least 2 chars at that point
  738. //
  739. if ((position[length-1] == AFP_PATHSEP) &&
  740. (position[length-2] != AFP_PATHSEP))
  741. {
  742. length--;
  743. }
  744. // begin parsing out path components, stop when you find the last component
  745. while (1)
  746. {
  747. afpGetNextComponent(position,
  748. length,
  749. PathType,
  750. component,
  751. &templength);
  752. if (templength < 0)
  753. {
  754. // component was too long or an invalid AFP character was found
  755. return AFP_ERR_PARAM;
  756. }
  757. length -= templength;
  758. if (length == 0)
  759. {
  760. // we found the last component
  761. break;
  762. }
  763. position += templength;
  764. if (component[0] == AFP_PATHSEP) // moving up?
  765. { // make sure you don't go above parent of root!
  766. if (DFE_IS_PARENT_OF_ROOT(pDFEntry))
  767. {
  768. return AFP_ERR_OBJECT_NOT_FOUND;
  769. }
  770. else pDFEntry = pDFEntry->dfe_Parent; //backup one level
  771. }
  772. else // Must be a directory component moving DOWN in tree
  773. {
  774. RtlInitString(&acomponent, component);
  775. AfpConvertStringToMungedUnicode(&acomponent, &pMappedPath->mp_Tail);
  776. if ((ptempDFEntry = AfpFindEntryByUnicodeName(pVolDesc,
  777. &pMappedPath->mp_Tail,
  778. PathType,
  779. pDFEntry,
  780. DFE_DIR)) == NULL)
  781. {
  782. return AFP_ERR_OBJECT_NOT_FOUND;
  783. }
  784. else
  785. {
  786. pDFEntry = ptempDFEntry;
  787. }
  788. }
  789. } // end while
  790. //
  791. // we have found the last component
  792. // is the last component an 'up' token?
  793. //
  794. if (component[0] == AFP_PATHSEP)
  795. {
  796. // don't bother walking up beyond the root
  797. switch (pDFEntry->dfe_AfpId)
  798. {
  799. case AFP_ID_PARENT_OF_ROOT:
  800. return AFP_ERR_OBJECT_NOT_FOUND;
  801. case AFP_ID_ROOT:
  802. return ((MapReason == Lookup) ? AFP_ERR_OBJECT_NOT_FOUND :
  803. AFP_ERR_PARAM);
  804. default: // backup one level
  805. pMappedPath->mp_pdfe = pDFEntry->dfe_Parent;
  806. }
  807. // this better be a lookup request
  808. if (MapReason != Lookup)
  809. {
  810. if (DFflag == DFE_DIR)
  811. {
  812. return AFP_ERR_OBJECT_EXISTS;
  813. }
  814. else
  815. {
  816. return AFP_ERR_OBJECT_TYPE;
  817. }
  818. }
  819. // had to have been a lookup operation
  820. if (DFflag == DFE_FILE)
  821. {
  822. return AFP_ERR_OBJECT_TYPE;
  823. }
  824. else
  825. {
  826. #ifdef GET_CORRECT_OFFSPRING_COUNTS
  827. checkEnumForParent = checkEnumForDir = True;
  828. #endif
  829. break;
  830. }
  831. } // endif last component was an 'up' token
  832. // the last component is a file or directory name
  833. RtlInitString(&acomponent, component);
  834. AfpConvertStringToMungedUnicode(&acomponent,
  835. &pMappedPath->mp_Tail);
  836. //
  837. // Before we search our database for the last component of the
  838. // path, make sure all the files have been cached in for this
  839. // directory
  840. //
  841. if (!DFE_CHILDREN_ARE_PRESENT(pDFEntry))
  842. {
  843. if (!LockedExclusive &&
  844. !AfpSwmrUpgradeToExclusive(&pVolDesc->vds_IdDbAccessLock))
  845. {
  846. return AFP_ERR_WRITE_LOCK_REQUIRED;
  847. }
  848. else
  849. {
  850. NTSTATUS status;
  851. LockedExclusive = True;
  852. status = AfpCacheDirectoryTree(pVolDesc,
  853. pDFEntry,
  854. GETFILES,
  855. NULL,
  856. NULL);
  857. if (!NT_SUCCESS(status))
  858. {
  859. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_ERR,
  860. ("afpMapAfpPathToMappedPath: could not cache dir tree for %Z (0x%lx)\n",
  861. &(pDFEntry->dfe_UnicodeName), status) );
  862. return AFP_ERR_MISC;
  863. }
  864. }
  865. }
  866. ptempDFEntry = AfpFindEntryByUnicodeName(pVolDesc,
  867. &pMappedPath->mp_Tail,
  868. PathType,
  869. pDFEntry,
  870. DFE_ANY);
  871. if (MapReason == Lookup) // its a lookup request
  872. {
  873. if (ptempDFEntry == NULL)
  874. {
  875. return AFP_ERR_OBJECT_NOT_FOUND;
  876. }
  877. else if (((DFflag == DFE_DIR) && DFE_IS_FILE(ptempDFEntry)) ||
  878. ((DFflag == DFE_FILE) && DFE_IS_DIRECTORY(ptempDFEntry)))
  879. {
  880. return AFP_ERR_OBJECT_TYPE;
  881. }
  882. else
  883. {
  884. pMappedPath->mp_pdfe = ptempDFEntry;
  885. #ifdef GET_CORRECT_OFFSPRING_COUNTS
  886. if (DFE_IS_DIRECTORY(ptempDFEntry))
  887. // we've already made sure this thing's parent was
  888. // enumerated already above.
  889. checkEnumForDir = True;
  890. #endif
  891. break;
  892. }
  893. }
  894. else // path mapping is for a create
  895. {
  896. ASSERT(DFflag != DFE_ANY); // Create must specify the exact type
  897. // Save the parent DFEntry
  898. pMappedPath->mp_pdfe = pDFEntry;
  899. if (ptempDFEntry != NULL)
  900. {
  901. // A file or dir by that name exists in the database
  902. // (and we will assume it exists on disk)
  903. if (MapReason == SoftCreate)
  904. {
  905. // Attempting create of a directory, or soft create of a file,
  906. // and dir OR file by that name exists,
  907. if ((DFflag == DFE_DIR) || DFE_IS_FILE(ptempDFEntry))
  908. {
  909. return AFP_ERR_OBJECT_EXISTS;
  910. }
  911. else
  912. {
  913. return AFP_ERR_OBJECT_TYPE;
  914. }
  915. }
  916. else if (DFE_IS_FILE(ptempDFEntry))
  917. {
  918. // Must be hard create and file by that name exists
  919. if (ptempDFEntry->dfe_Flags & DFE_FLAGS_OPEN_BITS)
  920. {
  921. return AFP_ERR_FILE_BUSY;
  922. }
  923. else
  924. {
  925. // note we return object_exists instead of no_err
  926. return AFP_ERR_OBJECT_EXISTS;
  927. }
  928. }
  929. else
  930. {
  931. // Attempting hard create of file, but found a directory
  932. return AFP_ERR_OBJECT_TYPE;
  933. }
  934. }
  935. else
  936. {
  937. return AFP_ERR_NONE;
  938. }
  939. }
  940. } while (False);
  941. // The only way we should have gotten here is if we successfully mapped
  942. // the path to a DFENTRY for lookup and would return AFP_ERR_NONE
  943. ASSERT((pMappedPath->mp_pdfe != NULL) && (MapReason == Lookup));
  944. #ifdef GET_CORRECT_OFFSPRING_COUNTS
  945. if (checkEnumForParent)
  946. {
  947. if (!DFE_CHILDREN_ARE_PRESENT(pMappedPath->mp_pdfe->dfe_Parent))
  948. {
  949. if (!LockedExclusive &&
  950. !AfpSwmrUpgradeToExclusive(&pVolDesc->vds_IdDbAccessLock))
  951. {
  952. return AFP_ERR_WRITE_LOCK_REQUIRED;
  953. }
  954. else
  955. {
  956. NTSTATUS status;
  957. LockedExclusive = True;
  958. status = AfpCacheDirectoryTree(pVolDesc,
  959. pMappedPath->mp_pdfe->dfe_Parent,
  960. GETFILES,
  961. NULL,
  962. NULL);
  963. if (!NT_SUCCESS(status))
  964. {
  965. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_ERR,
  966. ("afpMapAfpPathToMappedPath: could not cache dir tree for %Z (0x%lx)\n",
  967. &(pMappedPath->mp_pdfe->dfe_Parent->dfe_UnicodeName), status) );
  968. return AFP_ERR_MISC;
  969. }
  970. }
  971. }
  972. }
  973. #endif
  974. if (checkEnumForDir)
  975. {
  976. if (!DFE_CHILDREN_ARE_PRESENT(pMappedPath->mp_pdfe))
  977. {
  978. if (!LockedExclusive &&
  979. !AfpSwmrUpgradeToExclusive(&pVolDesc->vds_IdDbAccessLock))
  980. {
  981. return AFP_ERR_WRITE_LOCK_REQUIRED;
  982. }
  983. else
  984. {
  985. NTSTATUS status;
  986. LockedExclusive = True;
  987. status = AfpCacheDirectoryTree(pVolDesc,
  988. pMappedPath->mp_pdfe,
  989. GETFILES,
  990. NULL,
  991. NULL);
  992. if (!NT_SUCCESS(status))
  993. {
  994. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_ERR,
  995. ("afpMapAfpPathToMappedPath: could not cache dir tree for %Z (0x%lx)\n",
  996. &(pMappedPath->mp_pdfe->dfe_UnicodeName), status) );
  997. return AFP_ERR_MISC;
  998. }
  999. }
  1000. }
  1001. }
  1002. return AFP_ERR_NONE;
  1003. }
  1004. /*** AfpHostPathFromDFEntry
  1005. *
  1006. * This routine takes a pointer to a DFEntry and builds the full
  1007. * host path (in unicode) to that entity by ascending the ID database
  1008. * tree.
  1009. *
  1010. * IN pDFE -- pointer to DFEntry of which host path is desired
  1011. * IN taillen -- number of extra *bytes*, if any, the caller
  1012. * desires to have allocated for the host path,
  1013. * including room for any path separators
  1014. * OUT ppPath -- pointer to UNICODE string
  1015. *
  1016. * The caller must have the DirID/FileID database locked for read
  1017. * before calling this routine. The caller can supply a buffer which will
  1018. * be used if sufficient. Caller must free the allocated (if any)
  1019. * unicode string buffer.
  1020. *
  1021. * LOCKS_ASSUMED: vds_IdDbAccessLock (SWMR, Shared)
  1022. */
  1023. AFPSTATUS
  1024. AfpHostPathFromDFEntry(
  1025. IN PDFENTRY pDFE,
  1026. IN DWORD taillen,
  1027. OUT PUNICODE_STRING pPath
  1028. )
  1029. {
  1030. AFPSTATUS Status = AFP_ERR_NONE;
  1031. DWORD pathlen = taillen;
  1032. PDFENTRY *pdfelist = NULL, curpdfe = NULL;
  1033. PDFENTRY apdfelist[AVERAGE_NODE_DEPTH];
  1034. int counter;
  1035. PAGED_CODE( );
  1036. pPath->Length = 0;
  1037. do
  1038. {
  1039. if (DFE_IS_FILE(pDFE))
  1040. {
  1041. counter = pDFE->dfe_Parent->dfe_DirDepth;
  1042. }
  1043. else // its a DIRECTORY entry
  1044. {
  1045. ASSERT(DFE_IS_DIRECTORY(pDFE));
  1046. if (DFE_IS_ROOT(pDFE))
  1047. {
  1048. if ((pathlen > 0) && (pPath->MaximumLength < pathlen))
  1049. {
  1050. if ((pPath->Buffer = (PWCHAR)AfpAllocNonPagedMemory(pathlen)) == NULL)
  1051. {
  1052. Status = AFP_ERR_MISC;
  1053. break;
  1054. }
  1055. pPath->MaximumLength = (USHORT)pathlen;
  1056. }
  1057. break; // We are done
  1058. }
  1059. if (DFE_IS_PARENT_OF_ROOT(pDFE))
  1060. {
  1061. Status = AFP_ERR_OBJECT_NOT_FOUND;
  1062. break;
  1063. }
  1064. ASSERT(pDFE->dfe_DirDepth >= 1);
  1065. counter = pDFE->dfe_DirDepth - 1;
  1066. }
  1067. if (counter)
  1068. {
  1069. // if node is within average depth, use the array on the stack,
  1070. // otherwise, allocate an array
  1071. if (counter <= AVERAGE_NODE_DEPTH)
  1072. {
  1073. pdfelist = apdfelist;
  1074. }
  1075. else
  1076. {
  1077. pdfelist = (PDFENTRY *)AfpAllocNonPagedMemory(counter*sizeof(PDFENTRY));
  1078. if (pdfelist == NULL)
  1079. {
  1080. Status = AFP_ERR_MISC;
  1081. break;
  1082. }
  1083. }
  1084. pathlen += counter * sizeof(WCHAR); // room for path separators
  1085. }
  1086. curpdfe = pDFE;
  1087. pathlen += curpdfe->dfe_UnicodeName.Length;
  1088. // walk up the tree till you find the root, collecting string lengths
  1089. // and PDFENTRY values as you go...
  1090. while (counter--)
  1091. {
  1092. pdfelist[counter] = curpdfe;
  1093. curpdfe = curpdfe->dfe_Parent;
  1094. pathlen += curpdfe->dfe_UnicodeName.Length;
  1095. }
  1096. // we are in the root, start building up the host path buffer
  1097. if (pathlen > pPath->MaximumLength)
  1098. {
  1099. pPath->Buffer = (PWCHAR)AfpAllocNonPagedMemory(pathlen);
  1100. if (pPath->Buffer == NULL)
  1101. {
  1102. Status = AFP_ERR_MISC;
  1103. break;
  1104. }
  1105. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_INFO,
  1106. ("AfpHostPathFromDFEntry: Allocated path buffer %lx\n",
  1107. pPath->Buffer));
  1108. pPath->MaximumLength = (USHORT)pathlen;
  1109. }
  1110. counter = 0;
  1111. do
  1112. {
  1113. RtlAppendUnicodeStringToString(pPath, &curpdfe->dfe_UnicodeName);
  1114. if (curpdfe != pDFE)
  1115. { // add a path separator
  1116. pPath->Buffer[pPath->Length / sizeof(WCHAR)] = L'\\';
  1117. pPath->Length += sizeof(WCHAR);
  1118. curpdfe = pdfelist[counter++];
  1119. continue;
  1120. }
  1121. break;
  1122. } while (True);
  1123. if (pdfelist && (pdfelist != apdfelist))
  1124. AfpFreeMemory(pdfelist);
  1125. } while (False);
  1126. return Status;
  1127. }
  1128. /*** AfpCheckParentPermissions
  1129. *
  1130. * Check if this user has the necessary SeeFiles or SeeFolders permissions
  1131. * to the parent directory of a file or dir we have just pathmapped.
  1132. *
  1133. * LOCKS_ASSUMED: vds_IdDbAccessLock (SWMR, Exclusive or Shared)
  1134. */
  1135. AFPSTATUS
  1136. AfpCheckParentPermissions(
  1137. IN PCONNDESC pConnDesc,
  1138. IN DWORD ParentDirId,
  1139. IN PUNICODE_STRING pParentPath, // path of dir to check
  1140. IN DWORD RequiredPerms, // seefiles,seefolders,makechanges mask
  1141. OUT PFILESYSHANDLE pHandle OPTIONAL, // return open parent handle?
  1142. OUT PBYTE pUserRights OPTIONAL // return user rights?
  1143. )
  1144. {
  1145. NTSTATUS Status = AFP_ERR_NONE;
  1146. FILEDIRPARM FDParm;
  1147. PATHMAPENTITY PME;
  1148. PVOLDESC pVolDesc = pConnDesc->cds_pVolDesc;
  1149. PDFENTRY pDfEntry;
  1150. PAGED_CODE( );
  1151. ASSERT(IS_VOLUME_NTFS(pVolDesc) && (ParentDirId != AFP_ID_PARENT_OF_ROOT));
  1152. ASSERT(AfpSwmrLockedExclusive(&pVolDesc->vds_IdDbAccessLock) ||
  1153. AfpSwmrLockedShared(&pVolDesc->vds_IdDbAccessLock));
  1154. do
  1155. {
  1156. PME.pme_Handle.fsh_FileHandle = NULL;
  1157. if (ARGUMENT_PRESENT(pHandle))
  1158. {
  1159. pHandle->fsh_FileHandle = NULL;
  1160. }
  1161. ASSERT(ARGUMENT_PRESENT(pParentPath));
  1162. AfpInitializePME(&PME, pParentPath->MaximumLength, pParentPath->Buffer);
  1163. PME.pme_FullPath.Length = pParentPath->Length;
  1164. if ((pDfEntry = AfpFindDfEntryById(pVolDesc,
  1165. ParentDirId,
  1166. DFE_DIR)) == NULL)
  1167. {
  1168. Status = AFP_ERR_OBJECT_NOT_FOUND;
  1169. break;
  1170. }
  1171. ASSERT(DFE_IS_DIRECTORY(pDfEntry));
  1172. AfpInitializeFDParms(&FDParm);
  1173. Status = afpGetMappedForLookupFDInfo(pConnDesc,
  1174. pDfEntry,
  1175. DIR_BITMAP_ACCESSRIGHTS |
  1176. FD_INTERNAL_BITMAP_OPENACCESS_READCTRL,
  1177. &PME,
  1178. &FDParm);
  1179. if (!NT_SUCCESS(Status))
  1180. {
  1181. if (PME.pme_Handle.fsh_FileHandle != NULL)
  1182. {
  1183. AfpIoClose(&PME.pme_Handle);
  1184. }
  1185. break;
  1186. }
  1187. if ((FDParm._fdp_UserRights & RequiredPerms) != RequiredPerms)
  1188. {
  1189. Status = AFP_ERR_ACCESS_DENIED;
  1190. }
  1191. if (ARGUMENT_PRESENT(pHandle) && NT_SUCCESS(Status))
  1192. {
  1193. *pHandle = PME.pme_Handle;
  1194. }
  1195. else
  1196. {
  1197. AfpIoClose(&PME.pme_Handle);
  1198. }
  1199. if (ARGUMENT_PRESENT(pUserRights))
  1200. {
  1201. *pUserRights = FDParm._fdp_UserRights;
  1202. }
  1203. } while (False);
  1204. return Status;
  1205. }
  1206. /*** afpOpenUserHandle
  1207. *
  1208. * Open a handle to data or resource stream of an entity in the user's
  1209. * context. Only called for NTFS volumes.
  1210. *
  1211. * LOCKS_ASSUMED: vds_idDbAccessLock (SWMR, Shared)
  1212. */
  1213. AFPSTATUS
  1214. afpOpenUserHandle(
  1215. IN PCONNDESC pConnDesc,
  1216. IN PDFENTRY pDfEntry,
  1217. IN PUNICODE_STRING pPath OPTIONAL, // path of file/dir to open
  1218. IN DWORD Bitmap, // to extract the Open access mode
  1219. OUT PFILESYSHANDLE pfshData // Handle of data stream of object
  1220. )
  1221. {
  1222. PVOLDESC pVolDesc = pConnDesc->cds_pVolDesc;
  1223. NTSTATUS Status;
  1224. DWORD OpenAccess;
  1225. DWORD DenyMode;
  1226. BOOLEAN isdir, CheckAccess = False, Revert = False;
  1227. WCHAR HostPathBuf[BIG_PATH_LEN];
  1228. UNICODE_STRING uHostPath;
  1229. PAGED_CODE( );
  1230. pfshData->fsh_FileHandle = NULL;
  1231. isdir = (DFE_IS_DIRECTORY(pDfEntry)) ? True : False;
  1232. OpenAccess = AfpMapFDBitmapOpenAccess(Bitmap, isdir);
  1233. // Extract the index into the AfpDenyModes array from Bitmap
  1234. DenyMode = AfpDenyModes[(Bitmap & FD_INTERNAL_BITMAP_DENYMODE_ALL) >>
  1235. FD_INTERNAL_BITMAP_DENYMODE_SHIFT];
  1236. do
  1237. {
  1238. if (ARGUMENT_PRESENT(pPath))
  1239. {
  1240. uHostPath = *pPath;
  1241. }
  1242. else
  1243. {
  1244. AfpSetEmptyUnicodeString(&uHostPath,
  1245. sizeof(HostPathBuf),
  1246. HostPathBuf);
  1247. ASSERT ((Bitmap & FD_INTERNAL_BITMAP_OPENFORK_RESC) == 0);
  1248. if (!NT_SUCCESS(AfpHostPathFromDFEntry(pDfEntry,
  1249. 0,
  1250. &uHostPath)))
  1251. {
  1252. Status = AFP_ERR_MISC;
  1253. break;
  1254. }
  1255. }
  1256. CheckAccess = False;
  1257. Revert = False;
  1258. // Don't impersonate or check access if this is ADMIN calling
  1259. // or if volume is CDFS. If this handle will be used for setting
  1260. // permissions, impersonate the user token instead. The caller
  1261. // should have determined by now that this chappie has access
  1262. // to change permissions.
  1263. if (Bitmap & FD_INTERNAL_BITMAP_OPENACCESS_RWCTRL)
  1264. {
  1265. Revert = True;
  1266. AfpImpersonateClient(NULL);
  1267. }
  1268. else if (!(Bitmap & FD_INTERNAL_BITMAP_SKIP_IMPERSONATION) &&
  1269. (pConnDesc->cds_pSda->sda_ClientType != SDA_CLIENT_ADMIN) &&
  1270. IS_VOLUME_NTFS(pVolDesc))
  1271. {
  1272. CheckAccess = True;
  1273. Revert = True;
  1274. AfpImpersonateClient(pConnDesc->cds_pSda);
  1275. }
  1276. DBGPRINT(DBG_COMP_AFPINFO, DBG_LEVEL_INFO,
  1277. ("afpOpenUserHandle: OpenMode %lx, DenyMode %lx\n",
  1278. OpenAccess, DenyMode));
  1279. if (Bitmap & FD_INTERNAL_BITMAP_OPENFORK_RESC)
  1280. {
  1281. DWORD crinfo; // was the Resource fork opened or created?
  1282. ASSERT(IS_VOLUME_NTFS(pVolDesc));
  1283. ASSERT((uHostPath.MaximumLength - uHostPath.Length) >= AfpResourceStream.Length);
  1284. RtlCopyMemory((PBYTE)(uHostPath.Buffer) + uHostPath.Length,
  1285. AfpResourceStream.Buffer,
  1286. AfpResourceStream.Length);
  1287. uHostPath.Length += AfpResourceStream.Length;
  1288. Status = AfpIoCreate(&pVolDesc->vds_hRootDir,
  1289. AFP_STREAM_DATA,
  1290. &uHostPath,
  1291. OpenAccess,
  1292. DenyMode,
  1293. FILEIO_OPEN_FILE,
  1294. FILEIO_CREATE_INTERNAL,
  1295. FILE_ATTRIBUTE_NORMAL,
  1296. True,
  1297. NULL,
  1298. pfshData,
  1299. &crinfo,
  1300. NULL,
  1301. NULL,
  1302. NULL);
  1303. }
  1304. else
  1305. {
  1306. Status = AfpIoOpen(&pVolDesc->vds_hRootDir,
  1307. AFP_STREAM_DATA,
  1308. isdir ?
  1309. FILEIO_OPEN_DIR : FILEIO_OPEN_FILE,
  1310. &uHostPath,
  1311. OpenAccess,
  1312. DenyMode,
  1313. CheckAccess,
  1314. pfshData);
  1315. }
  1316. if (Revert)
  1317. AfpRevertBack();
  1318. if (!ARGUMENT_PRESENT(pPath))
  1319. {
  1320. if ((uHostPath.Buffer != NULL) && (uHostPath.Buffer != HostPathBuf))
  1321. AfpFreeMemory(uHostPath.Buffer);
  1322. }
  1323. if (!NT_SUCCESS(Status))
  1324. {
  1325. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  1326. ("afpOpenUserHandle: NtOpenFile/NtCreateFile (Open %lx, Deny %lx) %lx\n",
  1327. OpenAccess, DenyMode, Status));
  1328. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  1329. break;
  1330. }
  1331. } while (False);
  1332. if (!NT_SUCCESS(Status) && (pfshData->fsh_FileHandle != NULL))
  1333. {
  1334. AfpIoClose(pfshData);
  1335. }
  1336. return Status;
  1337. }