Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

789 lines
20 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. afpinfo.c
  5. Abstract:
  6. This module contains the routines for manipulating the afpinfo stream.
  7. Author:
  8. Jameel Hyder (microsoft!jameelh)
  9. Revision History:
  10. 19 Jun 1992 Initial Version
  11. Notes: Tab stop: 4
  12. --*/
  13. #define FILENUM FILE_AFPINFO
  14. #include <afp.h>
  15. #include <fdparm.h>
  16. #include <pathmap.h>
  17. #include <afpinfo.h>
  18. #include <afpadmin.h>
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text( PAGE, AfpSetAfpInfo)
  21. #pragma alloc_text( PAGE, AfpReadAfpInfo)
  22. #pragma alloc_text( PAGE, AfpSetFinderInfoByExtension)
  23. #pragma alloc_text( PAGE, AfpProDosInfoFromFinderInfo)
  24. #pragma alloc_text( PAGE, AfpFinderInfoFromProDosInfo)
  25. #pragma alloc_text( PAGE, AfpSlapOnAfpInfoStream)
  26. #pragma alloc_text( PAGE, AfpCreateAfpInfoStream)
  27. #pragma alloc_text( PAGE, AfpExamineAndClearROAttr)
  28. #pragma alloc_text( PAGE, AfpQueryProDos)
  29. #endif
  30. /*** AfpSetAfpInfo
  31. *
  32. * Sets the values specified by Bitmap in the AFP_AfpInfo stream of a file
  33. * or directory. If FinderInfo is specified without ProDosInfo, or
  34. * vice-versa, the one not specified is deduced from the other and also set.
  35. * If the file/dir is marked ReadOnly, we must clear the readonly bit in order
  36. * to write to the Afp_AfpInfo stream, and then set the RO bit back again.
  37. * If pVolDesc is specified, then also update the cached AfpInfo in the
  38. * IdDb DFENTRY.
  39. *
  40. */
  41. AFPSTATUS
  42. AfpSetAfpInfo(
  43. IN PFILESYSHANDLE pfshData, // handle to data stream of object
  44. IN DWORD Bitmap,
  45. IN PFILEDIRPARM pFDParms,
  46. IN PVOLDESC pVolDesc OPTIONAL, // if present, update cached afpinfo
  47. IN PDFENTRY * ppDFE OPTIONAL // pVolDesc must also be specified
  48. )
  49. {
  50. NTSTATUS Status;
  51. DWORD crinfo, NTAttr = 0;
  52. AFPINFO afpinfo;
  53. FILESYSHANDLE fshAfpInfo;
  54. BOOLEAN isdir, WriteBackROAttr = False, mapprodos = False;
  55. PDFENTRY pDfEntry = NULL;
  56. PAGED_CODE( );
  57. fshAfpInfo.fsh_FileHandle = NULL;
  58. isdir = IsDir(pFDParms);
  59. if (ARGUMENT_PRESENT(pVolDesc))
  60. {
  61. ASSERT(AfpSwmrLockedExclusive(&pVolDesc->vds_IdDbAccessLock));
  62. pDfEntry = AfpFindDfEntryById(pVolDesc,
  63. pFDParms->_fdp_AfpId,
  64. isdir ? DFE_DIR : DFE_FILE);
  65. if (pDfEntry == NULL)
  66. {
  67. return AFP_ERR_OBJECT_NOT_FOUND;
  68. }
  69. }
  70. do
  71. {
  72. if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData, &fshAfpInfo, &crinfo)))
  73. {
  74. if (Status == STATUS_ACCESS_DENIED)
  75. {
  76. // We may have failed to open the AFP_Afpinfo stream because
  77. // the file/dir is marked ReadOnly. Clear the ReadOnly bit
  78. // and try to open it again.
  79. Status = AfpExamineAndClearROAttr(pfshData,
  80. &WriteBackROAttr,
  81. NULL,
  82. NULL);
  83. if (NT_SUCCESS(Status))
  84. {
  85. if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData, &fshAfpInfo, &crinfo)))
  86. {
  87. AfpPutBackROAttr(pfshData, WriteBackROAttr);
  88. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  89. break;
  90. }
  91. }
  92. else
  93. {
  94. Status = AFP_ERR_MISC;
  95. break;
  96. }
  97. }
  98. else
  99. {
  100. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  101. break;
  102. }
  103. }
  104. // If it was newly created or it existed but was corrupted, then initialize
  105. // it with default data. Otherwise read in the current data
  106. if ((crinfo == FILE_CREATED) ||
  107. (!NT_SUCCESS(AfpReadAfpInfo(&fshAfpInfo, &afpinfo))))
  108. {
  109. UNICODE_STRING UName;
  110. WCHAR NameBuf[AFP_LONGNAME_LEN+1];
  111. if (crinfo != FILE_CREATED)
  112. {
  113. AFPLOG_HERROR(AFPSRVMSG_AFPINFO,
  114. 0,
  115. NULL,
  116. 0,
  117. pfshData->fsh_FileHandle);
  118. }
  119. if (!isdir)
  120. {
  121. AfpSetEmptyUnicodeString(&UName, sizeof(NameBuf), NameBuf);
  122. AfpConvertStringToMungedUnicode(&pFDParms->_fdp_LongName, &UName);
  123. }
  124. // All callers of this routine must have the FD_BITMAP_LONGNAME
  125. // bit forced in their bitmap to pathmap, so that in this case
  126. // where the afpinfo stream must be recreated for a *file*, we
  127. // will always have a valid _fdp_Longname set in FDParm and can
  128. // deduce the type/creator
  129. if (!NT_SUCCESS(AfpSlapOnAfpInfoStream(NULL,
  130. NULL,
  131. pfshData,
  132. &fshAfpInfo,
  133. pFDParms->_fdp_AfpId,
  134. isdir,
  135. isdir ? NULL : &UName,
  136. &afpinfo)))
  137. {
  138. Status = AFP_ERR_MISC;
  139. break;
  140. }
  141. else if (pDfEntry != NULL)
  142. DFE_UPDATE_CACHED_AFPINFO(pDfEntry, &afpinfo);
  143. }
  144. if (Bitmap & FD_BITMAP_BACKUPTIME)
  145. {
  146. afpinfo.afpi_BackupTime = pFDParms->_fdp_BackupTime;
  147. if (pDfEntry != NULL)
  148. pDfEntry->dfe_BackupTime = afpinfo.afpi_BackupTime;
  149. }
  150. if (Bitmap & FD_BITMAP_FINDERINFO)
  151. { // Only map new ProDOS info if there has been a change in the
  152. // type/creator, and FD_BITMAP_PRODOSINFO is not set (files only)
  153. if (!(Bitmap & FD_BITMAP_PRODOSINFO) &&
  154. !isdir &&
  155. ((RtlCompareMemory(afpinfo.afpi_FinderInfo.fd_Type,
  156. pFDParms->_fdp_FinderInfo.fd_Type,
  157. AFP_TYPE_LEN) != AFP_TYPE_LEN) ||
  158. (RtlCompareMemory(afpinfo.afpi_FinderInfo.fd_Creator,
  159. pFDParms->_fdp_FinderInfo.fd_Creator,
  160. AFP_CREATOR_LEN) != AFP_CREATOR_LEN)))
  161. {
  162. mapprodos = True;
  163. }
  164. afpinfo.afpi_FinderInfo = pFDParms->_fdp_FinderInfo;
  165. if (mapprodos)
  166. {
  167. AfpProDosInfoFromFinderInfo(&afpinfo.afpi_FinderInfo,
  168. &afpinfo.afpi_ProDosInfo);
  169. }
  170. if (pDfEntry != NULL)
  171. pDfEntry->dfe_FinderInfo = afpinfo.afpi_FinderInfo;
  172. }
  173. if (Bitmap & FD_BITMAP_PRODOSINFO)
  174. {
  175. if ((IsDir(pFDParms)) &&
  176. (pFDParms->_fdp_ProDosInfo.pd_FileType[0] != PRODOS_TYPE_DIR))
  177. {
  178. Status = AFP_ERR_ACCESS_DENIED;
  179. break;
  180. }
  181. afpinfo.afpi_ProDosInfo = pFDParms->_fdp_ProDosInfo;
  182. if (!(Bitmap & FD_BITMAP_FINDERINFO) && !isdir)
  183. {
  184. AfpFinderInfoFromProDosInfo(&afpinfo.afpi_ProDosInfo,
  185. &afpinfo.afpi_FinderInfo);
  186. if (pDfEntry != NULL)
  187. pDfEntry->dfe_FinderInfo = afpinfo.afpi_FinderInfo;
  188. }
  189. }
  190. if (Bitmap & FD_BITMAP_ATTR)
  191. {
  192. afpinfo.afpi_Attributes =
  193. pFDParms->_fdp_EffectiveAttr & ~FD_BITMAP_ATTR_SET;
  194. if (pDfEntry != NULL)
  195. pDfEntry->dfe_AfpAttr = afpinfo.afpi_Attributes;
  196. }
  197. if (Bitmap & DIR_BITMAP_ACCESSRIGHTS)
  198. {
  199. ASSERT(isdir == True);
  200. afpinfo.afpi_AccessOwner = pFDParms->_fdp_OwnerRights;
  201. afpinfo.afpi_AccessGroup = pFDParms->_fdp_GroupRights;
  202. afpinfo.afpi_AccessWorld = pFDParms->_fdp_WorldRights;
  203. if (pDfEntry != NULL)
  204. {
  205. DFE_OWNER_ACCESS(pDfEntry) = afpinfo.afpi_AccessOwner;
  206. DFE_GROUP_ACCESS(pDfEntry) = afpinfo.afpi_AccessGroup;
  207. DFE_WORLD_ACCESS(pDfEntry) = afpinfo.afpi_AccessWorld;
  208. }
  209. }
  210. // FILE_BITMAP_FILENUM can ONLY be set by the internal CopyFile code
  211. // and internal ExchangeFiles code
  212. if (Bitmap & FILE_BITMAP_FILENUM)
  213. {
  214. ASSERT(isdir == False);
  215. afpinfo.afpi_Id = pFDParms->_fdp_AfpId;
  216. }
  217. Status = AfpWriteAfpInfo(&fshAfpInfo, &afpinfo);
  218. if (!NT_SUCCESS(Status))
  219. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  220. } while (False);
  221. AfpPutBackROAttr(pfshData, WriteBackROAttr);
  222. if (fshAfpInfo.fsh_FileHandle != NULL)
  223. AfpIoClose(&fshAfpInfo);
  224. if (ARGUMENT_PRESENT(ppDFE))
  225. {
  226. ASSERT(ARGUMENT_PRESENT(pVolDesc));
  227. *ppDFE = pDfEntry;
  228. }
  229. return Status;
  230. }
  231. /*** AfpReadAfpInfo
  232. *
  233. * When discovering a file/dir that has the AfpInfo stream, read it in
  234. *
  235. */
  236. NTSTATUS FASTCALL
  237. AfpReadAfpInfo(
  238. IN PFILESYSHANDLE pfshAfpInfo,
  239. OUT PAFPINFO pAfpInfo
  240. )
  241. {
  242. NTSTATUS Status;
  243. LONG sizeRead;
  244. PAGED_CODE( );
  245. Status = AfpIoRead(pfshAfpInfo,
  246. &LIZero,
  247. sizeof(AFPINFO),
  248. &sizeRead,
  249. (PBYTE)pAfpInfo);
  250. if (!NT_SUCCESS(Status) ||
  251. (sizeRead != sizeof(AFPINFO)) ||
  252. (pAfpInfo->afpi_Signature != AFP_SERVER_SIGNATURE) ||
  253. (pAfpInfo->afpi_Version != AFP_SERVER_VERSION))
  254. {
  255. if (NT_SUCCESS(Status) &&
  256. (sizeRead != 0) &&
  257. ((pAfpInfo->afpi_Signature != AFP_SERVER_SIGNATURE) ||
  258. (pAfpInfo->afpi_Version != AFP_SERVER_VERSION)))
  259. {
  260. AFPLOG_HERROR(AFPSRVMSG_AFPINFO,
  261. Status,
  262. NULL,
  263. 0,
  264. pfshAfpInfo->fsh_FileHandle);
  265. }
  266. if ((sizeRead != sizeof(AFPINFO)) && (sizeRead != 0))
  267. {
  268. DBGPRINT(DBG_COMP_AFPINFO, DBG_LEVEL_ERR,
  269. ("AfpReadAfpInfo: sizeRead (%d) != sizeof AFPINFO (%d)",
  270. sizeRead, sizeof(AFPINFO)));
  271. }
  272. AfpIoSetSize(pfshAfpInfo, 0);
  273. Status = STATUS_UNSUCCESSFUL;
  274. }
  275. return Status;
  276. }
  277. /*** AfpSetFinderInfoByExtension
  278. *
  279. * Set the finder info (type/creator) based on the file extension. Only long
  280. * name is used for this mapping.
  281. *
  282. * LOCKS: AfpEtcMapLock (SWMR, Shared)
  283. */
  284. VOID FASTCALL
  285. AfpSetFinderInfoByExtension(
  286. IN PUNICODE_STRING pFileName,
  287. OUT PFINDERINFO pFinderInfo
  288. )
  289. {
  290. PETCMAPINFO pEtcMap = NULL;
  291. PWCHAR pch;
  292. DWORD len, i = AFP_EXTENSION_LEN;
  293. UCHAR ext[AFP_EXTENSION_LEN+1];
  294. WCHAR wext[AFP_EXTENSION_LEN+1];
  295. ANSI_STRING aext;
  296. UNICODE_STRING uext;
  297. PAGED_CODE( );
  298. RtlZeroMemory(ext, sizeof(ext));
  299. ASSERT(pFileName != NULL);
  300. // Find the last character of the filename
  301. pch = pFileName->Buffer + (pFileName->Length - sizeof(WCHAR))/sizeof(WCHAR);
  302. len = pFileName->Length/sizeof(WCHAR);
  303. AfpSwmrAcquireShared(&AfpEtcMapLock);
  304. while ((AFP_EXTENSION_LEN - i) < len)
  305. {
  306. if (*pch == L'.')
  307. {
  308. if (i < AFP_EXTENSION_LEN)
  309. {
  310. AfpSetEmptyAnsiString(&aext, sizeof(ext), ext);
  311. AfpInitUnicodeStringWithNonNullTerm(&uext,
  312. (USHORT)((AFP_EXTENSION_LEN - i)*sizeof(WCHAR)),
  313. &wext[i]);
  314. AfpConvertMungedUnicodeToAnsi(&uext, &aext);
  315. pEtcMap = AfpLookupEtcMapEntry(ext);
  316. }
  317. break;
  318. }
  319. if (i == 0)
  320. break;
  321. wext[--i] = *(pch--);
  322. }
  323. if (pEtcMap == NULL)
  324. pEtcMap = &AfpDefaultEtcMap;
  325. RtlCopyMemory(&pFinderInfo->fd_Type, &pEtcMap->etc_type, AFP_TYPE_LEN);
  326. RtlCopyMemory(&pFinderInfo->fd_Creator, &pEtcMap->etc_creator, AFP_CREATOR_LEN);
  327. AfpSwmrRelease(&AfpEtcMapLock);
  328. }
  329. /*** AfpProDosInfoFromFinderInfo
  330. *
  331. * Given finder info, deduce the corresponding prodos info. It is up to the
  332. * caller to decide whether or not FinderInfo type/creator is actually
  333. * changing (if client is just resetting the same values or not), in which
  334. * case the prodos info should be left untouched. (Inside Appletalk p. 13-19)
  335. * NOTE: see layout of ProDOS info on p. 13-18 of Inside Appletalk, 2nd Ed.)
  336. */
  337. VOID FASTCALL
  338. AfpProDosInfoFromFinderInfo(
  339. IN PFINDERINFO pFinderInfo,
  340. OUT PPRODOSINFO pProDosInfo
  341. )
  342. {
  343. CHAR buf[3];
  344. ULONG filetype;
  345. NTSTATUS Status;
  346. PAGED_CODE( );
  347. RtlZeroMemory(pProDosInfo, sizeof(PRODOSINFO));
  348. if (RtlCompareMemory(pFinderInfo->fd_Type, "TEXT", AFP_TYPE_LEN) == AFP_TYPE_LEN)
  349. {
  350. pProDosInfo->pd_FileType[0] = PRODOS_TYPE_FILE;
  351. }
  352. else if (RtlCompareMemory(pFinderInfo->fd_Creator,
  353. "pdos",
  354. AFP_CREATOR_LEN) == AFP_CREATOR_LEN)
  355. {
  356. if (RtlCompareMemory(pFinderInfo->fd_Type,
  357. "PSYS",
  358. AFP_TYPE_LEN) == AFP_TYPE_LEN)
  359. {
  360. pProDosInfo->pd_FileType[0] = PRODOS_FILETYPE_PSYS;
  361. }
  362. else if (RtlCompareMemory(pFinderInfo->fd_Type,
  363. "PS16",
  364. AFP_TYPE_LEN) == AFP_TYPE_LEN)
  365. {
  366. pProDosInfo->pd_FileType[0] = PRODOS_FILETYPE_PS16;
  367. }
  368. else if (pFinderInfo->fd_Type[0] == 'p')
  369. {
  370. pProDosInfo->pd_FileType[0] = pFinderInfo->fd_Type[1];
  371. pProDosInfo->pd_AuxType[0] = pFinderInfo->fd_Type[3];
  372. pProDosInfo->pd_AuxType[1] = pFinderInfo->fd_Type[2];
  373. }
  374. else if ((pFinderInfo->fd_Type[2] == ' ') &&
  375. (pFinderInfo->fd_Type[3] == ' ') &&
  376. (isxdigit(pFinderInfo->fd_Type[0])) &&
  377. (isxdigit(pFinderInfo->fd_Type[1])))
  378. {
  379. buf[0] = pFinderInfo->fd_Type[0];
  380. buf[1] = pFinderInfo->fd_Type[1];
  381. buf[2] = 0;
  382. Status = RtlCharToInteger(buf, 16, &filetype);
  383. ASSERT(NT_SUCCESS(Status));
  384. pProDosInfo->pd_FileType[0] = (BYTE)filetype;
  385. }
  386. }
  387. }
  388. /*** AfpFinderInfoFromProDosInfo
  389. *
  390. * Given the prodos info, deduce the corresponding finder info.
  391. */
  392. VOID FASTCALL
  393. AfpFinderInfoFromProDosInfo(
  394. IN PPRODOSINFO pProDosInfo,
  395. OUT PFINDERINFO pFinderInfo
  396. )
  397. {
  398. PAGED_CODE( );
  399. RtlCopyMemory(pFinderInfo->fd_Creator,"pdos",AFP_CREATOR_LEN);
  400. if ((pProDosInfo->pd_FileType[0] == PRODOS_TYPE_FILE) &&
  401. (pProDosInfo->pd_AuxType[0] == 0) &&
  402. (pProDosInfo->pd_AuxType[1] == 0))
  403. {
  404. RtlCopyMemory(&pFinderInfo->fd_Type,"TEXT",AFP_TYPE_LEN);
  405. }
  406. else if (pProDosInfo->pd_FileType[0] == PRODOS_FILETYPE_PSYS)
  407. {
  408. RtlCopyMemory(&pFinderInfo->fd_Type,"PSYS",AFP_TYPE_LEN);
  409. }
  410. else if (pProDosInfo->pd_FileType[0] == PRODOS_FILETYPE_PS16)
  411. {
  412. RtlCopyMemory(&pFinderInfo->fd_Type,"PS16",AFP_TYPE_LEN);
  413. }
  414. else if (pProDosInfo->pd_FileType[0] == 0)
  415. {
  416. RtlCopyMemory(&pFinderInfo->fd_Type,"BINA",AFP_TYPE_LEN);
  417. }
  418. else
  419. {
  420. pFinderInfo->fd_Type[0] = 'p';
  421. pFinderInfo->fd_Type[1] = pProDosInfo->pd_FileType[0];
  422. pFinderInfo->fd_Type[2] = pProDosInfo->pd_AuxType[1];
  423. pFinderInfo->fd_Type[3] = pProDosInfo->pd_AuxType[0];
  424. }
  425. }
  426. /*** AfpSlapOnAfpInfoStream
  427. *
  428. * When creating a file or directory, this is called to add the AFP_AfpInfo
  429. * stream. No client impersonation is done to open/read/write this stream.
  430. * If pfshAfpInfoStream is supplied, that handle is used, else a handle is
  431. * opened (and pfshData MUST be supplied);
  432. */
  433. NTSTATUS
  434. AfpSlapOnAfpInfoStream(
  435. IN PVOLDESC pVolDesc OPTIONAL, // only if catching
  436. IN PUNICODE_STRING pNotifyPath OPTIONAL, // changes to size of
  437. // Afpinfo stream
  438. IN PFILESYSHANDLE pfshData OPTIONAL,
  439. IN PFILESYSHANDLE pfshAfpInfoStream OPTIONAL,
  440. IN DWORD AfpId,
  441. IN BOOLEAN IsDirectory,
  442. IN PUNICODE_STRING pName OPTIONAL, // needed for files
  443. OUT PAFPINFO pAfpInfo
  444. )
  445. {
  446. NTSTATUS Status;
  447. FILESYSHANDLE fshAfpInfo;
  448. BOOLEAN WriteBackROAttr = False;
  449. PAGED_CODE( );
  450. ASSERT((pfshData != NULL) || (pfshAfpInfoStream != NULL));
  451. if (!ARGUMENT_PRESENT(pfshAfpInfoStream))
  452. {
  453. if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData, &fshAfpInfo, NULL)))
  454. {
  455. if (Status == STATUS_ACCESS_DENIED)
  456. {
  457. // We may have failed to open the AFP_Afpinfo stream because
  458. // the file/dir is marked ReadOnly. Clear the ReadOnly bit
  459. // and try to open it again.
  460. Status = AfpExamineAndClearROAttr(pfshData,
  461. &WriteBackROAttr,
  462. pVolDesc,
  463. pNotifyPath);
  464. if (NT_SUCCESS(Status))
  465. {
  466. if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData,
  467. &fshAfpInfo,
  468. NULL)))
  469. {
  470. AfpPutBackROAttr(pfshData, WriteBackROAttr);
  471. }
  472. }
  473. }
  474. if (!NT_SUCCESS(Status))
  475. return Status;
  476. }
  477. }
  478. else fshAfpInfo = *pfshAfpInfoStream;
  479. AfpInitAfpInfo(pAfpInfo, AfpId, IsDirectory, BEGINNING_OF_TIME);
  480. if (!IsDirectory)
  481. {
  482. ASSERT(pName != NULL);
  483. AfpSetFinderInfoByExtension(pName,
  484. &pAfpInfo->afpi_FinderInfo);
  485. AfpProDosInfoFromFinderInfo(&pAfpInfo->afpi_FinderInfo,
  486. &pAfpInfo->afpi_ProDosInfo);
  487. }
  488. AfpIoSetSize(&fshAfpInfo, 0);
  489. Status = AfpWriteAfpInfo(&fshAfpInfo, pAfpInfo);
  490. if (NT_SUCCESS(Status) &&
  491. ARGUMENT_PRESENT(pVolDesc) &&
  492. ARGUMENT_PRESENT(pNotifyPath))
  493. {
  494. // Do both FILE_ACTION_MODIFIED_STREAM and FILE_ACTION_MODIFIED in one go
  495. AfpQueueOurChange(pVolDesc,
  496. FILE_ACTION_MODIFIED_STREAM,
  497. pNotifyPath,
  498. pNotifyPath);
  499. }
  500. if (!ARGUMENT_PRESENT(pfshAfpInfoStream))
  501. {
  502. AfpIoClose(&fshAfpInfo);
  503. AfpPutBackROAttr(pfshData, WriteBackROAttr);
  504. }
  505. return Status;
  506. }
  507. /*** AfpCreateAfpInfoStream
  508. *
  509. * Similar to AfpSlapOnAfpInfoStream but tuned to Create file/directory case.
  510. */
  511. NTSTATUS
  512. AfpCreateAfpInfoStream(
  513. IN PVOLDESC pVolDesc,
  514. IN PFILESYSHANDLE pfshData,
  515. IN DWORD AfpId,
  516. IN BOOLEAN IsDirectory,
  517. IN PUNICODE_STRING pName OPTIONAL, // only needed for files
  518. IN PUNICODE_STRING pNotifyPath,
  519. OUT PAFPINFO pAfpInfo,
  520. OUT PFILESYSHANDLE pfshAfpInfo
  521. )
  522. {
  523. NTSTATUS Status;
  524. BOOLEAN WriteBackROAttr = False;
  525. DWORD crinfo;
  526. PAGED_CODE( );
  527. ASSERT((pfshData != NULL) && (pfshAfpInfo != NULL));
  528. do
  529. {
  530. if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData, pfshAfpInfo, &crinfo)))
  531. {
  532. if (Status == STATUS_ACCESS_DENIED)
  533. {
  534. // We may have failed to open the AFP_Afpinfo stream because
  535. // the file/dir is marked ReadOnly. Clear the ReadOnly bit
  536. // and try to open it again.
  537. Status = AfpExamineAndClearROAttr(pfshData,
  538. &WriteBackROAttr,
  539. pVolDesc,
  540. pNotifyPath);
  541. if (NT_SUCCESS(Status))
  542. {
  543. if (!NT_SUCCESS(Status = AfpCreateAfpInfo(pfshData,
  544. pfshAfpInfo,
  545. &crinfo)))
  546. {
  547. AfpPutBackROAttr(pfshData, WriteBackROAttr);
  548. }
  549. }
  550. }
  551. if (!NT_SUCCESS(Status))
  552. break;
  553. }
  554. AfpInitAfpInfo(pAfpInfo, AfpId, IsDirectory, BEGINNING_OF_TIME);
  555. if (!IsDirectory)
  556. {
  557. ASSERT(pName != NULL);
  558. AfpSetFinderInfoByExtension(pName,
  559. &pAfpInfo->afpi_FinderInfo);
  560. AfpProDosInfoFromFinderInfo(&pAfpInfo->afpi_FinderInfo,
  561. &pAfpInfo->afpi_ProDosInfo);
  562. }
  563. Status = AfpWriteAfpInfo(pfshAfpInfo, pAfpInfo);
  564. if (NT_SUCCESS(Status) && (crinfo == FILE_CREATED))
  565. {
  566. // Do both FILE_ACTION_MODIFIED_STREAM and FILE_ACTION_MODIFIED in one go
  567. AfpQueueOurChange(pVolDesc,
  568. FILE_ACTION_MODIFIED_STREAM,
  569. pNotifyPath,
  570. pNotifyPath);
  571. }
  572. AfpPutBackROAttr(pfshData, WriteBackROAttr);
  573. } while (False);
  574. return Status;
  575. }
  576. /*** AfpExamineAndClearROAttr
  577. *
  578. * If the ReadOnly attribute is set on a file or directory, clear it.
  579. * pWriteBackROAttr is a boolean indicating whether or not the caller must
  580. * subsequently reset the Readonly bit on the file/dir. (see AfpPutBackROAttr)
  581. */
  582. NTSTATUS FASTCALL
  583. AfpExamineAndClearROAttr(
  584. IN PFILESYSHANDLE pfshData,
  585. OUT PBOOLEAN pWriteBackROAttr,
  586. IN PVOLDESC pVolDesc OPTIONAL,
  587. IN PUNICODE_STRING pPath OPTIONAL
  588. )
  589. {
  590. NTSTATUS Status;
  591. DWORD NTAttr = 0;
  592. PAGED_CODE( );
  593. ASSERT(VALID_FSH(pfshData));
  594. *pWriteBackROAttr = False;
  595. if (NT_SUCCESS(Status = AfpIoQueryTimesnAttr(pfshData, NULL, NULL, &NTAttr)) &&
  596. (NTAttr & FILE_ATTRIBUTE_READONLY))
  597. {
  598. // We need to clear the readonly bit.
  599. if (NT_SUCCESS(Status = AfpIoSetTimesnAttr(pfshData,
  600. NULL,
  601. NULL,
  602. 0,
  603. FILE_ATTRIBUTE_READONLY,
  604. pVolDesc,
  605. pPath)))
  606. {
  607. *pWriteBackROAttr = True;
  608. }
  609. }
  610. return Status;
  611. }
  612. /*** AfpQueryProDos
  613. *
  614. * Open the afpinfo stream relative to the file's Data handle, and
  615. * read the ProDOS info out of it. If the AfpInfo stream does not
  616. * exist, return an error.
  617. *
  618. */
  619. AFPSTATUS FASTCALL
  620. AfpQueryProDos(
  621. IN PFILESYSHANDLE pfshData,
  622. OUT PPRODOSINFO pProDosInfo
  623. )
  624. {
  625. AFPSTATUS Status = AFP_ERR_NONE;
  626. FILESYSHANDLE hAfpInfo;
  627. AFPINFO afpinfo;
  628. Status = AfpIoOpen(pfshData,
  629. AFP_STREAM_INFO,
  630. FILEIO_OPEN_FILE,
  631. &UNullString,
  632. FILEIO_ACCESS_READ,
  633. FILEIO_DENY_NONE,
  634. False,
  635. &hAfpInfo);
  636. if (NT_SUCCESS(Status))
  637. {
  638. if (NT_SUCCESS(AfpReadAfpInfo(&hAfpInfo, &afpinfo)))
  639. {
  640. *pProDosInfo = afpinfo.afpi_ProDosInfo;
  641. }
  642. else
  643. {
  644. Status = AFP_ERR_MISC;
  645. }
  646. AfpIoClose(&hAfpInfo);
  647. }
  648. else
  649. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  650. return Status;
  651. }
  652. /*** AfpUpdateIdInAfpInfo
  653. *
  654. * Update the afpid in the afpinfo stream.
  655. *
  656. */
  657. AFPSTATUS FASTCALL
  658. AfpUpdateIdInAfpInfo(
  659. IN PVOLDESC pVolDesc,
  660. IN PDFENTRY pDfEntry
  661. )
  662. {
  663. FILESYSHANDLE fshAfpInfo;
  664. AFPINFO AfpInfo;
  665. AFPSTATUS Status;
  666. UNICODE_STRING Path;
  667. AfpSetEmptyUnicodeString(&Path, 0, NULL);
  668. Status = AfpHostPathFromDFEntry(pDfEntry, 0, &Path);
  669. if (NT_SUCCESS(Status))
  670. {
  671. // Open the afpinfo stream
  672. Status = AfpIoOpen(&pVolDesc->vds_hRootDir,
  673. AFP_STREAM_INFO,
  674. FILEIO_OPEN_FILE,
  675. &Path,
  676. FILEIO_ACCESS_READWRITE,
  677. FILEIO_DENY_NONE,
  678. False,
  679. &fshAfpInfo);
  680. if (NT_SUCCESS(Status))
  681. {
  682. Status = AfpReadAfpInfo(&fshAfpInfo, &AfpInfo);
  683. if (NT_SUCCESS(Status))
  684. {
  685. AfpInfo.afpi_Id = pDfEntry->dfe_AfpId;
  686. AfpWriteAfpInfo(&fshAfpInfo, &AfpInfo);
  687. }
  688. AfpIoClose(&fshAfpInfo);
  689. }
  690. if (Path.Buffer != NULL)
  691. {
  692. AfpFreeMemory(Path.Buffer);
  693. }
  694. }
  695. return Status;
  696. }