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.

1675 lines
41 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. desktop.c
  5. Abstract:
  6. This module contains the routines for manipulating the desktop database.
  7. Author:
  8. Jameel Hyder (microsoft!jameelh)
  9. Revision History:
  10. 25 Apr 1992 Initial Version
  11. Notes: Tab stop: 4
  12. --*/
  13. #define FILENUM FILE_DESKTOP
  14. #define DESKTOP_LOCALS
  15. #include <afp.h>
  16. #include <scavengr.h>
  17. #include <fdparm.h>
  18. #include <pathmap.h>
  19. #include <client.h>
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text( INIT, AfpDesktopInit)
  22. #pragma alloc_text( PAGE, AfpAddIcon)
  23. #pragma alloc_text( PAGE, AfpLookupIcon)
  24. #pragma alloc_text( PAGE, AfpLookupIconInfo)
  25. #pragma alloc_text( PAGE, AfpAddAppl)
  26. #pragma alloc_text( PAGE, AfpLookupAppl)
  27. #pragma alloc_text( PAGE, AfpRemoveAppl)
  28. #pragma alloc_text( PAGE, AfpAddComment)
  29. #pragma alloc_text( PAGE, AfpGetComment)
  30. #pragma alloc_text( PAGE, AfpRemoveComment)
  31. #pragma alloc_text( PAGE, AfpAddIconToGlobalList)
  32. #pragma alloc_text( PAGE, afpLookupIconInGlobalList)
  33. #pragma alloc_text( PAGE, AfpFreeGlobalIconList)
  34. #pragma alloc_text( PAGE, afpGetGlobalIconInfo)
  35. #pragma alloc_text( PAGE, afpReadDesktopFromDisk)
  36. #pragma alloc_text( PAGE, AfpInitDesktop)
  37. #pragma alloc_text( PAGE, AfpUpdateDesktop)
  38. #pragma alloc_text( PAGE, AfpFreeDesktopTables)
  39. #endif
  40. /*** AfpDesktopInit
  41. *
  42. * Initialize locks for global icons.
  43. */
  44. NTSTATUS
  45. AfpDesktopInit(
  46. VOID
  47. )
  48. {
  49. AfpSwmrInitSwmr(&AfpIconListLock);
  50. return STATUS_SUCCESS;
  51. }
  52. /*** AfpAddIcon
  53. *
  54. * Add an icon to the desktop database. The icon is added in such a way that
  55. * the list is maintained in a sorted fashion - sorted by Creator, Type and
  56. * IconType
  57. *
  58. * LOCKS: vds_DtAccessLock (SWMR, Exclusive);
  59. */
  60. AFPSTATUS
  61. AfpAddIcon(
  62. IN PVOLDESC pVolDesc, // Volume descriptor of referenced desktop
  63. IN DWORD Creator,
  64. IN DWORD Type,
  65. IN DWORD Tag,
  66. IN LONG IconSize,
  67. IN DWORD IconType,
  68. IN PBYTE pIcon // The icon bitmap
  69. )
  70. {
  71. PICONINFO pIconInfo;
  72. PICONINFO * ppIconInfo;
  73. BOOLEAN Found = False;
  74. AFPSTATUS Status = AFP_ERR_NONE;
  75. PAGED_CODE( );
  76. AfpSwmrAcquireExclusive(&pVolDesc->vds_DtAccessLock);
  77. ppIconInfo = &pVolDesc->vds_pIconBuckets[HASH_ICON(Creator)];
  78. do
  79. {
  80. // Find the right slot
  81. for (;(pIconInfo = *ppIconInfo) != NULL;
  82. ppIconInfo = &pIconInfo->icon_Next)
  83. {
  84. if (pIconInfo->icon_Creator < Creator)
  85. continue;
  86. if (pIconInfo->icon_Creator > Creator)
  87. break;
  88. if (pIconInfo->icon_Type < Type)
  89. continue;
  90. if (pIconInfo->icon_Type > Type)
  91. break;
  92. if (pIconInfo->icon_IconType < (USHORT)IconType)
  93. continue;
  94. if (pIconInfo->icon_IconType > (USHORT)IconType)
  95. break;
  96. /*
  97. * If we come this far, we have hit the bulls eye
  98. * Make sure the size matches, before we commit
  99. */
  100. if (pIconInfo->icon_Size != IconSize)
  101. {
  102. Status = AFP_ERR_ICON_TYPE;
  103. break;
  104. }
  105. Found = True;
  106. break;
  107. }
  108. if (!Found && (Status == AFP_ERR_NONE))
  109. {
  110. // ppIconInfo now points to the right place
  111. if ((pIconInfo = ALLOC_ICONINFO(IconSize)) != NULL)
  112. {
  113. pIconInfo->icon_Next = *ppIconInfo;
  114. *ppIconInfo = pIconInfo;
  115. pIconInfo->icon_Creator = Creator;
  116. pIconInfo->icon_Type = Type;
  117. pIconInfo->icon_IconType = (USHORT)IconType;
  118. pIconInfo->icon_Size = (SHORT)IconSize;
  119. pIconInfo->icon_Tag = Tag;
  120. pVolDesc->vds_cIconEnts ++;
  121. Found = True;
  122. }
  123. else Status = AFP_ERR_MISC;
  124. }
  125. if (Found && (Status == AFP_ERR_NONE))
  126. {
  127. RtlCopyMemory((PBYTE)pIconInfo + sizeof(ICONINFO), pIcon, IconSize);
  128. }
  129. } while (False);
  130. AfpSwmrRelease(&pVolDesc->vds_DtAccessLock);
  131. return Status;
  132. }
  133. /*** AfpLookupIcon
  134. *
  135. * Search the desktop for an icon matching the given search parameters.
  136. *
  137. * LOCKS: vds_DtAccessLock (SWMR, Shared), AfpIconListLock (SWMR, Shared)
  138. */
  139. AFPSTATUS
  140. AfpLookupIcon(
  141. IN PVOLDESC pVolDesc, // Volume descriptor of referenced desktop
  142. IN DWORD Creator,
  143. IN DWORD Type,
  144. IN LONG Length,
  145. IN DWORD IconType,
  146. OUT PLONG pActualLength,
  147. OUT PBYTE pIconBitMap // Buffer for icon bit map
  148. )
  149. {
  150. PICONINFO pIconInfo;
  151. LONG LengthToCopy;
  152. AFPSTATUS Status = AFP_ERR_NONE;
  153. PAGED_CODE( );
  154. LengthToCopy = Length;
  155. AfpSwmrAcquireShared(&pVolDesc->vds_DtAccessLock);
  156. pIconInfo = pVolDesc->vds_pIconBuckets[HASH_ICON(Creator)];
  157. // Scan the list looking for the entry
  158. for (;pIconInfo != NULL; pIconInfo = pIconInfo->icon_Next)
  159. {
  160. if (pIconInfo->icon_Creator < Creator)
  161. continue;
  162. if (pIconInfo->icon_Creator > Creator)
  163. {
  164. pIconInfo = NULL;
  165. break;
  166. }
  167. if (pIconInfo->icon_Type < Type)
  168. continue;
  169. if (pIconInfo->icon_Type > Type)
  170. {
  171. pIconInfo = NULL;
  172. break;
  173. }
  174. if (pIconInfo->icon_IconType < (USHORT)IconType)
  175. continue;
  176. if (pIconInfo->icon_IconType > (USHORT)IconType)
  177. {
  178. pIconInfo = NULL;
  179. break;
  180. }
  181. break;
  182. }
  183. // If we did not find it, try the global list
  184. if (pIconInfo == NULL)
  185. {
  186. Status = afpLookupIconInGlobalList(Creator,
  187. Type,
  188. IconType,
  189. &LengthToCopy,
  190. pIconBitMap);
  191. }
  192. else if (Length > 0)
  193. {
  194. if ((LONG)(pIconInfo->icon_Size) < Length)
  195. {
  196. LengthToCopy = (LONG)(pIconInfo->icon_Size);
  197. }
  198. else
  199. {
  200. LengthToCopy = Length;
  201. }
  202. RtlCopyMemory(pIconBitMap, (PBYTE)pIconInfo + sizeof(ICONINFO), LengthToCopy);
  203. }
  204. AfpSwmrRelease(&pVolDesc->vds_DtAccessLock);
  205. *pActualLength = LengthToCopy;
  206. return Status;
  207. }
  208. /*** AfpLookupIconInfo
  209. *
  210. * Search the desktop for an icon matching the given Creator. In case of
  211. * multiple icons corresponding to the same creator, get the nth where n
  212. * is the index.
  213. *
  214. * LOCKS: vds_DtAccessLock (SWMR, Shared), AfpIconListLock (SWMR, Shared)
  215. */
  216. AFPSTATUS
  217. AfpLookupIconInfo(
  218. IN PVOLDESC pVolDesc, // Volume descriptor of referenced desktop
  219. IN DWORD Creator, // Creator associated with the icon
  220. IN LONG Index, // Index number of Icon
  221. OUT PDWORD pType, // Place where Type is returned
  222. OUT PDWORD pIconType, // Icon type e.g. ICN#
  223. OUT PDWORD pTag, // Arbitrary tag
  224. OUT PLONG pSize // Size of the icon
  225. )
  226. {
  227. PICONINFO pIconInfo;
  228. LONG i;
  229. AFPSTATUS Status = AFP_ERR_ITEM_NOT_FOUND;
  230. PAGED_CODE( );
  231. AfpSwmrAcquireShared(&pVolDesc->vds_DtAccessLock);
  232. pIconInfo = pVolDesc->vds_pIconBuckets[HASH_ICON(Creator)];
  233. // Scan the list looking for the first entry
  234. for (;pIconInfo != NULL; pIconInfo = pIconInfo->icon_Next)
  235. {
  236. if (pIconInfo->icon_Creator == Creator)
  237. break; // Found the first one
  238. if (pIconInfo->icon_Creator > Creator)
  239. {
  240. pIconInfo = NULL;
  241. break;
  242. }
  243. }
  244. /*
  245. * We are now either pointing to the first entry or there are none. In the
  246. * latter case, we just fall through
  247. */
  248. for (i = 1; pIconInfo != NULL; pIconInfo = pIconInfo->icon_Next)
  249. {
  250. if ((pIconInfo->icon_Creator > Creator) || (i > Index))
  251. {
  252. pIconInfo = NULL;
  253. break;
  254. }
  255. if (i == Index)
  256. break; // Found the right entry
  257. i++;
  258. }
  259. // If we did find it, extract the information
  260. if (pIconInfo != NULL)
  261. {
  262. *pSize = pIconInfo->icon_Size;
  263. *pType = pIconInfo->icon_Type;
  264. *pTag = pIconInfo->icon_Tag;
  265. *pIconType = pIconInfo->icon_IconType;
  266. Status = AFP_ERR_NONE;
  267. }
  268. // If we did not find it, try the global list, but only for the first one
  269. else if (Index == 1)
  270. {
  271. Status = afpGetGlobalIconInfo(Creator, pType, pIconType, pTag, pSize);
  272. }
  273. else Status = AFP_ERR_ITEM_NOT_FOUND;
  274. AfpSwmrRelease(&pVolDesc->vds_DtAccessLock);
  275. return Status;
  276. }
  277. /*** AfpAddAppl
  278. *
  279. * Add an APPL mapping to the desktop database. Is added in such a way that
  280. * the list is maintained in a sorted fashion - sorted by Creator. It is
  281. * already determined that the application file exists and that the user has
  282. * appropriate access to it.
  283. *
  284. * LOCKS: vds_DtAccessLock (SWMR, Exclusive);
  285. */
  286. AFPSTATUS
  287. AfpAddAppl(
  288. IN PVOLDESC pVolDesc, // Volume descriptor of referenced desktop
  289. IN DWORD Creator,
  290. IN DWORD ApplTag,
  291. IN DWORD FileNum, // File number of the associated file
  292. IN BOOLEAN Internal, // Is the server adding the APPL itself?
  293. IN DWORD ParentID // DirId of parent dir of the application file
  294. )
  295. {
  296. PAPPLINFO2 pApplInfo, *ppApplInfo;
  297. BOOLEAN ApplReplace = False, UpdateDT = True;
  298. AFPSTATUS Status = AFP_ERR_NONE;
  299. PAGED_CODE( );
  300. ASSERT(FileNum != 0);
  301. AfpSwmrAcquireExclusive(&pVolDesc->vds_DtAccessLock);
  302. ppApplInfo = &pVolDesc->vds_pApplBuckets[HASH_APPL(Creator)];
  303. // Find the right slot
  304. for (;(pApplInfo = *ppApplInfo) != NULL; ppApplInfo = &pApplInfo->appl_Next)
  305. {
  306. if (pApplInfo->appl_Creator >= Creator)
  307. break;
  308. }
  309. /*
  310. * If there is already an entry for this creator, make sure it is not for
  311. * the same file, if it is replace it.
  312. */
  313. for ( ; pApplInfo != NULL && pApplInfo->appl_Creator == Creator;
  314. pApplInfo = pApplInfo->appl_Next)
  315. {
  316. if (pApplInfo->appl_FileNum == FileNum)
  317. {
  318. if (!Internal)
  319. {
  320. pApplInfo->appl_Tag = ApplTag;
  321. }
  322. else
  323. {
  324. if (pApplInfo->appl_ParentID == ParentID)
  325. UpdateDT = False;
  326. }
  327. pApplInfo->appl_ParentID = ParentID;
  328. ApplReplace = True;
  329. }
  330. }
  331. if (!ApplReplace)
  332. {
  333. // ppApplInfo now points to the right place
  334. if ((pApplInfo = ALLOC_APPLINFO()) != NULL)
  335. {
  336. pApplInfo->appl_Next = *ppApplInfo;
  337. *ppApplInfo = pApplInfo;
  338. pApplInfo->appl_Creator = Creator;
  339. pApplInfo->appl_Tag = ApplTag;
  340. pApplInfo->appl_FileNum = FileNum;
  341. pApplInfo->appl_ParentID = ParentID;
  342. pVolDesc->vds_cApplEnts ++;
  343. }
  344. else Status = AFP_ERR_MISC;
  345. }
  346. AfpSwmrRelease(&pVolDesc->vds_DtAccessLock);
  347. return Status;
  348. }
  349. /*** AfpLookupAppl
  350. *
  351. * Search the desktop for an appl entry matching the given Creator. In
  352. * case of multiple appl entries corresponding to the same creator, get
  353. * the nth where n is the index.
  354. *
  355. * LOCKS: vds_DtAccessLock (SWMR, Shared);
  356. */
  357. AFPSTATUS
  358. AfpLookupAppl(
  359. IN PVOLDESC pVolDesc, // Volume descriptor of referenced desktop
  360. IN DWORD Creator,
  361. IN LONG Index,
  362. OUT PDWORD pApplTag, // Place holder for Tag
  363. OUT PDWORD pFileNum, // Place holder for file number
  364. OUT PDWORD pParentID
  365. )
  366. {
  367. PAPPLINFO2 pApplInfo;
  368. AFPSTATUS Status = AFP_ERR_NONE;
  369. LONG i;
  370. PAGED_CODE( );
  371. AfpSwmrAcquireShared(&pVolDesc->vds_DtAccessLock);
  372. pApplInfo = pVolDesc->vds_pApplBuckets[HASH_ICON(Creator)];
  373. // Scan the list looking for the entry
  374. for (;pApplInfo != NULL; pApplInfo = pApplInfo->appl_Next)
  375. {
  376. if (pApplInfo->appl_Creator == Creator)
  377. break;
  378. if (pApplInfo->appl_Creator > Creator) {
  379. pApplInfo = NULL;
  380. break;
  381. }
  382. }
  383. /*
  384. * We are now either pointing to the first entry or there are none. In the
  385. * latter case, we just fall through
  386. */
  387. if (Index != 0)
  388. {
  389. for (i = 1; pApplInfo!=NULL; i++, pApplInfo = pApplInfo->appl_Next)
  390. {
  391. if ((i > Index) || (pApplInfo->appl_Creator != Creator))
  392. {
  393. pApplInfo = NULL;
  394. break;
  395. }
  396. if (i == Index)
  397. break; // Found the right entry
  398. }
  399. }
  400. if (pApplInfo == NULL)
  401. Status = AFP_ERR_ITEM_NOT_FOUND;
  402. else
  403. {
  404. *pFileNum = pApplInfo->appl_FileNum;
  405. *pApplTag = pApplInfo->appl_Tag;
  406. *pParentID = pApplInfo->appl_ParentID;
  407. }
  408. AfpSwmrRelease(&pVolDesc->vds_DtAccessLock);
  409. return Status;
  410. }
  411. /*** AfpRemoveAppl
  412. *
  413. * The entries corresponding to the given Creator in the specified directory
  414. * is removed from the desktop database. It is already determined that the
  415. * application file exists and that the user has appropriate access to it.
  416. *
  417. * LOCKS: vds_DtAccessLock (SWMR, Exclusive);
  418. */
  419. AFPSTATUS
  420. AfpRemoveAppl(
  421. IN PVOLDESC pVolDesc, // Open Volume descriptor of ref desktop
  422. IN DWORD Creator,
  423. IN DWORD FileNum // File number of the associated file
  424. )
  425. {
  426. PAPPLINFO2 pApplInfo, *ppApplInfo;
  427. AFPSTATUS Status = AFP_ERR_NONE;
  428. BOOLEAN Found = False;
  429. PAGED_CODE( );
  430. AfpSwmrAcquireExclusive(&pVolDesc->vds_DtAccessLock);
  431. ppApplInfo = &pVolDesc->vds_pApplBuckets[HASH_APPL(Creator)];
  432. // Find the APPL entry in the desktop
  433. for (;(pApplInfo = *ppApplInfo) != NULL; ppApplInfo = &pApplInfo->appl_Next)
  434. {
  435. if (pApplInfo->appl_Creator < Creator)
  436. continue;
  437. if (pApplInfo->appl_Creator > Creator)
  438. break;
  439. /*
  440. * Check if the File number matches, if it does delete.
  441. */
  442. if (pApplInfo->appl_FileNum == FileNum)
  443. {
  444. Found = True;
  445. *ppApplInfo = pApplInfo->appl_Next;
  446. AfpFreeMemory(pApplInfo);
  447. pVolDesc->vds_cApplEnts --;
  448. break;
  449. }
  450. }
  451. if (!Found)
  452. Status = AFP_ERR_ITEM_NOT_FOUND;
  453. AfpSwmrRelease(&pVolDesc->vds_DtAccessLock);
  454. return Status;
  455. }
  456. /*** AfpAddComment
  457. *
  458. * Add the comment to the file or directory in question. Create the comment
  459. * stream on the entity in question (if it does not already exist), convert
  460. * the comment to unicode and write it. Update the flag in the DFEntry.
  461. */
  462. AFPSTATUS
  463. AfpAddComment(
  464. IN PSDA pSda, // Session Data Area
  465. IN PVOLDESC pVolDesc, // Volume descriptor of referenced desktop
  466. IN PANSI_STRING Comment, // Comment to associate with the file/dir
  467. IN PPATHMAPENTITY pPME, // Handle to the entity or its Host Id
  468. IN BOOLEAN Directory, // True if directory
  469. IN DWORD AfpId
  470. )
  471. {
  472. UNICODE_STRING UComment;
  473. WCHAR CommentBuf[AFP_MAXCOMMENTSIZE+1];
  474. FILESYSHANDLE HandleCommentStream;
  475. DWORD CreateInfo;
  476. NTSTATUS Status = AFP_ERR_MISC;
  477. PDFENTRY pDFE = NULL;
  478. BOOLEAN RestoreModTime = FALSE;
  479. AFPTIME aModTime;
  480. TIME ModTime;
  481. PAGED_CODE( );
  482. ASSERT (IS_VOLUME_NTFS(pVolDesc));
  483. if (Comment->Length == 0)
  484. {
  485. AfpRemoveComment(pSda, pVolDesc, pPME, Directory, AfpId);
  486. return AFP_ERR_NONE;
  487. }
  488. if (Comment->Length > AFP_MAXCOMMENTSIZE)
  489. {
  490. // Truncate comment if necessary
  491. Comment->Length = AFP_MAXCOMMENTSIZE;
  492. }
  493. UComment.Buffer = CommentBuf;
  494. UComment.MaximumLength = (USHORT)(RtlAnsiStringToUnicodeSize(Comment) + sizeof(WCHAR));
  495. UComment.Length = 0;
  496. AfpConvertStringToUnicode(Comment, &UComment);
  497. do
  498. {
  499. AfpImpersonateClient(pSda);
  500. // Get the last modified time from the file so we can reset it.
  501. Status = AfpIoQueryTimesnAttr( &pPME->pme_Handle,
  502. NULL,
  503. &ModTime,
  504. NULL );
  505. if (NT_SUCCESS(Status))
  506. {
  507. RestoreModTime = TRUE;
  508. aModTime = AfpConvertTimeToMacFormat(&ModTime);
  509. }
  510. // Open the comment stream on the target entity.
  511. Status = AfpIoCreate(&pPME->pme_Handle,
  512. AFP_STREAM_COMM,
  513. &UNullString,
  514. FILEIO_ACCESS_WRITE,
  515. FILEIO_DENY_NONE,
  516. FILEIO_OPEN_FILE,
  517. FILEIO_CREATE_HARD,
  518. FILE_ATTRIBUTE_NORMAL,
  519. True,
  520. NULL,
  521. &HandleCommentStream,
  522. &CreateInfo,
  523. NULL,
  524. NULL,
  525. NULL);
  526. AfpRevertBack();
  527. if (Status != AFP_ERR_NONE) {
  528. if ((Status = AfpIoConvertNTStatusToAfpStatus(Status)) != AFP_ERR_ACCESS_DENIED)
  529. Status = AFP_ERR_MISC;
  530. break;
  531. }
  532. Status = AfpIoWrite(&HandleCommentStream,
  533. &LIZero,
  534. (LONG)UComment.Length,
  535. (PBYTE)UComment.Buffer);
  536. AfpIoClose(&HandleCommentStream);
  537. if( RestoreModTime )
  538. {
  539. AfpIoSetTimesnAttr( &pPME->pme_Handle,
  540. NULL,
  541. &aModTime,
  542. 0,
  543. 0,
  544. NULL,
  545. NULL );
  546. }
  547. if (NT_SUCCESS(Status))
  548. {
  549. AfpVolumeSetModifiedTime(pVolDesc);
  550. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  551. if ((pDFE = AfpFindDfEntryById(pVolDesc,
  552. AfpId,
  553. DFE_ANY)) != NULL)
  554. {
  555. pDFE->dfe_Flags |= DFE_FLAGS_HAS_COMMENT;
  556. }
  557. else
  558. {
  559. Status = AFP_ERR_MISC;
  560. }
  561. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  562. }
  563. } while (False);
  564. return Status;
  565. }
  566. /*** AfpGetComment
  567. *
  568. * Extract the comment from the file or directory in question. The comment is
  569. * copied to the ReplyBuf.
  570. */
  571. AFPSTATUS
  572. AfpGetComment(
  573. IN PSDA pSda, // Session Data Area
  574. IN PVOLDESC pVolDesc, // Volume descriptor of referenced desktop
  575. IN PPATHMAPENTITY pPME, // Handle to the entity or its Host Id
  576. IN BOOLEAN Directory // True if directory
  577. )
  578. {
  579. NTSTATUS Status = AFP_ERR_MISC;
  580. LONG SizeRead;
  581. UNICODE_STRING UComment;
  582. WCHAR CommentBuf[AFP_MAXCOMMENTSIZE+1];
  583. ANSI_STRING AComment;
  584. FILESYSHANDLE HandleCommentStream;
  585. PAGED_CODE( );
  586. // ASSERT (IS_VOLUME_NTFS(pVolDesc));
  587. // Initialize AComment
  588. AComment.Buffer = pSda->sda_ReplyBuf + 1; // For size of string
  589. AComment.MaximumLength = AFP_MAXCOMMENTSIZE;
  590. AComment.Length = 0;
  591. UComment.MaximumLength = (AFP_MAXCOMMENTSIZE + 1) * sizeof(WCHAR);
  592. UComment.Buffer = CommentBuf;
  593. do
  594. {
  595. AfpImpersonateClient(pSda);
  596. // Open the comment stream on the target entity.
  597. Status = AfpIoOpen(&pPME->pme_Handle,
  598. AFP_STREAM_COMM,
  599. FILEIO_OPEN_FILE,
  600. &UNullString,
  601. FILEIO_ACCESS_READ,
  602. FILEIO_DENY_NONE,
  603. True,
  604. &HandleCommentStream);
  605. AfpRevertBack();
  606. if (Status != AFP_ERR_NONE)
  607. {
  608. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  609. if (Status == AFP_ERR_OBJECT_NOT_FOUND)
  610. Status = AFP_ERR_ITEM_NOT_FOUND;
  611. else if (Status != AFP_ERR_ACCESS_DENIED)
  612. Status = AFP_ERR_OBJECT_NOT_FOUND;
  613. break;
  614. }
  615. Status = AfpIoRead(&HandleCommentStream,
  616. &LIZero,
  617. (LONG)UComment.MaximumLength,
  618. &SizeRead,
  619. (PBYTE)UComment.Buffer);
  620. AfpIoClose(&HandleCommentStream);
  621. if (Status == AFP_ERR_NONE)
  622. {
  623. UComment.Length = (USHORT) SizeRead;
  624. AfpConvertStringToAnsi(&UComment, &AComment);
  625. pSda->sda_ReplyBuf[0] = (BYTE)AComment.Length;
  626. pSda->sda_ReplySize = AComment.Length + 1;
  627. }
  628. } while (False);
  629. return Status;
  630. }
  631. /*** AfpRemoveComment
  632. *
  633. * Remove the comment from the file or directory in question. Essentially
  634. * open the comment stream and set the length to 0.
  635. */
  636. AFPSTATUS
  637. AfpRemoveComment(
  638. IN PSDA pSda, // Session Data Area
  639. IN PVOLDESC pVolDesc, // Volume descriptor of referenced desktop
  640. IN PPATHMAPENTITY pPME, // Handle to the entity or its Host Id
  641. IN BOOLEAN Directory, // True if directory
  642. IN DWORD AfpId
  643. )
  644. {
  645. FILESYSHANDLE HandleCommentStream;
  646. NTSTATUS Status = AFP_ERR_MISC;
  647. PDFENTRY pDFE = NULL;
  648. PAGED_CODE( );
  649. ASSERT (IS_VOLUME_NTFS(pVolDesc));
  650. do
  651. {
  652. AfpImpersonateClient(pSda);
  653. // Open the comment stream on the target entity.
  654. Status = AfpIoOpen(&pPME->pme_Handle,
  655. AFP_STREAM_COMM,
  656. FILEIO_OPEN_FILE,
  657. &UNullString,
  658. FILEIO_ACCESS_DELETE,
  659. FILEIO_DENY_NONE,
  660. True,
  661. &HandleCommentStream);
  662. AfpRevertBack();
  663. if (Status != AFP_ERR_NONE)
  664. {
  665. if ((Status = AfpIoConvertNTStatusToAfpStatus(Status)) != AFP_ERR_ACCESS_DENIED)
  666. Status = AFP_ERR_ITEM_NOT_FOUND;
  667. break;
  668. }
  669. Status = AfpIoMarkFileForDelete(&HandleCommentStream, NULL, NULL, NULL);
  670. AfpIoClose(&HandleCommentStream);
  671. if (NT_SUCCESS(Status))
  672. {
  673. AfpVolumeSetModifiedTime(pVolDesc);
  674. AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
  675. if ((pDFE = AfpFindDfEntryById(pVolDesc,
  676. AfpId,
  677. DFE_ANY)) != NULL)
  678. {
  679. pDFE->dfe_Flags &= ~DFE_FLAGS_HAS_COMMENT;
  680. }
  681. else
  682. {
  683. Status = AFP_ERR_MISC;
  684. }
  685. AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
  686. }
  687. } while (False);
  688. return Status;
  689. }
  690. /*** AfpAddIconToGlobalList
  691. *
  692. * The global list of icons is a server maintained list updated by the service.
  693. * This adds an icon to the list. If an icon exists for the given type and
  694. * creator, it is replaced. This list is maintained via the AfpIconAdd() admin
  695. * api.
  696. *
  697. * LOCKS: AfpIconListLock (SWMR, Exclusive);
  698. */
  699. AFPSTATUS
  700. AfpAddIconToGlobalList(
  701. IN DWORD Type,
  702. IN DWORD Creator,
  703. IN DWORD IconType,
  704. IN LONG IconSize,
  705. IN PBYTE pIconBitMap
  706. )
  707. {
  708. PICONINFO pIconInfo,
  709. pIconInfoNew,
  710. *ppIconInfo;
  711. AFPSTATUS Status = AFP_ERR_NONE;
  712. PAGED_CODE( );
  713. // Pre-allocate memory for the new icon, delete if necessary later
  714. if ((pIconInfoNew = ALLOC_ICONINFO(IconSize)) == NULL)
  715. return AFP_ERR_MISC;
  716. AfpSwmrAcquireExclusive(&AfpIconListLock);
  717. ppIconInfo = &AfpGlobalIconList;
  718. for (; (pIconInfo = *ppIconInfo) != NULL; ppIconInfo = &pIconInfo->icon_Next)
  719. {
  720. if ((pIconInfo->icon_Type == Type) &&
  721. (pIconInfo->icon_Creator == Creator))
  722. break;
  723. }
  724. if (pIconInfo == NULL)
  725. {
  726. if (IconSize > 0)
  727. RtlCopyMemory((PBYTE)pIconInfoNew + sizeof(ICONINFO), pIconBitMap, IconSize);
  728. pIconInfoNew->icon_Creator = Creator;
  729. pIconInfoNew->icon_Type = Type;
  730. pIconInfoNew->icon_IconType = (USHORT)IconType;
  731. pIconInfoNew->icon_Size = (SHORT)IconSize;
  732. pIconInfoNew->icon_Tag = 0;
  733. pIconInfoNew->icon_Next = NULL;
  734. *ppIconInfo = pIconInfoNew;
  735. }
  736. else
  737. {
  738. // We do not need the memory any more, release it
  739. AfpFreeMemory(pIconInfoNew);
  740. if (pIconInfo->icon_IconType != (USHORT)IconType)
  741. Status = AFPERR_InvalidParms;
  742. else if (IconSize > 0)
  743. RtlCopyMemory((PBYTE)pIconInfo + sizeof(ICONINFO), pIconBitMap, IconSize);
  744. }
  745. AfpSwmrRelease(&AfpIconListLock);
  746. return AFP_ERR_NONE;
  747. }
  748. /*** afpLookupIconInGlobalList
  749. *
  750. * The global list of icons is a server maintained list updates by the service.
  751. * This is called by AfpLookupIcon() when the specified icon is not found in
  752. * the volume desktop.
  753. *
  754. * LOCKS: AfpIconListLock (SWMR, Shared);
  755. */
  756. LOCAL AFPSTATUS
  757. afpLookupIconInGlobalList(
  758. IN DWORD Creator,
  759. IN DWORD Type,
  760. IN DWORD IconType,
  761. IN PLONG pSize,
  762. OUT PBYTE pBitMap
  763. )
  764. {
  765. PICONINFO pIconInfo;
  766. AFPSTATUS Status = AFP_ERR_NONE;
  767. PAGED_CODE( );
  768. AfpSwmrAcquireShared(&AfpIconListLock);
  769. pIconInfo = AfpGlobalIconList;
  770. for (pIconInfo = AfpGlobalIconList;
  771. pIconInfo != NULL;
  772. pIconInfo = pIconInfo->icon_Next)
  773. {
  774. if ((pIconInfo->icon_Type == Type) &&
  775. (pIconInfo->icon_Creator == Creator) &&
  776. (pIconInfo->icon_IconType == (USHORT)IconType))
  777. break;
  778. }
  779. if (pIconInfo == NULL)
  780. Status = AFP_ERR_ITEM_NOT_FOUND;
  781. else
  782. {
  783. if (*pSize > pIconInfo->icon_Size)
  784. *pSize = pIconInfo->icon_Size;
  785. if (*pSize > 0)
  786. RtlCopyMemory(pBitMap, (PBYTE)pIconInfo + sizeof(ICONINFO), *pSize);
  787. }
  788. AfpSwmrRelease(&AfpIconListLock);
  789. return Status;
  790. }
  791. /*** AfpFreeGlobalIconList
  792. *
  793. * Called at server stop time to free the memory allocated for the global
  794. * icons.
  795. *
  796. * LOCKS: AfpIconListLock (SWMR, Exclusive);
  797. */
  798. VOID
  799. AfpFreeGlobalIconList(
  800. VOID
  801. )
  802. {
  803. PICONINFO pIconInfo;
  804. PAGED_CODE( );
  805. AfpSwmrAcquireExclusive(&AfpIconListLock);
  806. for (pIconInfo = AfpGlobalIconList; pIconInfo != NULL; )
  807. {
  808. PICONINFO pFree;
  809. pFree = pIconInfo;
  810. pIconInfo = pIconInfo->icon_Next;
  811. AfpFreeMemory (pFree);
  812. }
  813. AfpSwmrRelease(&AfpIconListLock);
  814. }
  815. /*** afpGetGlobalIconInfo
  816. *
  817. * The global list of icons is a server maintained list updates by the service.
  818. * This is called by AfpLookupIconInfo() when the specified icon is not found
  819. * in the volume desktop.
  820. *
  821. * LOCKS: AfpIconListLock (SWMR, Shared)
  822. */
  823. LOCAL AFPSTATUS
  824. afpGetGlobalIconInfo(
  825. IN DWORD Creator,
  826. OUT PDWORD pType,
  827. OUT PDWORD pIconType,
  828. OUT PDWORD pTag,
  829. OUT PLONG pSize
  830. )
  831. {
  832. PICONINFO pIconInfo;
  833. AFPSTATUS Status = AFP_ERR_NONE;
  834. PAGED_CODE( );
  835. AfpSwmrAcquireExclusive(&AfpIconListLock);
  836. pIconInfo = AfpGlobalIconList;
  837. for (pIconInfo = AfpGlobalIconList;
  838. pIconInfo != NULL;
  839. pIconInfo = pIconInfo->icon_Next)
  840. {
  841. if (pIconInfo->icon_Creator == Creator)
  842. break;
  843. }
  844. if (pIconInfo == NULL)
  845. Status = AFP_ERR_ITEM_NOT_FOUND;
  846. else
  847. {
  848. *pType = pIconInfo->icon_Type;
  849. *pIconType = pIconInfo->icon_IconType;
  850. *pTag = pIconInfo->icon_Tag;
  851. *pSize = pIconInfo->icon_Size;
  852. }
  853. AfpSwmrRelease(&AfpIconListLock);
  854. return Status;
  855. }
  856. /*** afpReadDesktopFromDisk
  857. *
  858. * Read the desktop database from the desktop stream. No locks are required
  859. * for this routine since it only operates on volume descriptors which are
  860. * newly created and not yet linked into the global volume list.
  861. */
  862. LOCAL NTSTATUS
  863. afpReadDesktopFromDisk(
  864. IN PVOLDESC pVolDesc,
  865. IN PFILESYSHANDLE pfshDesktop
  866. )
  867. {
  868. DESKTOP Desktop;
  869. PAPPLINFO2 *ppApplInfo;
  870. PICONINFO *ppIconInfo;
  871. NTSTATUS Status;
  872. DWORD DskOffst;
  873. FORKOFFST ForkOffset;
  874. PBYTE pBuffer;
  875. LONG i, SizeRead, BufOffst = 0;
  876. LONG PrevHash, applSize;
  877. PAGED_CODE( );
  878. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_INFO,
  879. ("\tReading Desktop from disk....\n") );
  880. // Work with one page of memory and do multiple I/Os to the disk.
  881. if ((pBuffer = AfpAllocNonPagedMemory(DESKTOPIO_BUFSIZE)) == NULL)
  882. {
  883. return STATUS_INSUFFICIENT_RESOURCES;
  884. }
  885. ForkOffset.QuadPart = DskOffst = 0;
  886. // Read in the desktop header and validate it
  887. Status = AfpIoRead(pfshDesktop,
  888. &ForkOffset,
  889. sizeof(DESKTOP),
  890. &SizeRead,
  891. (PBYTE)&Desktop);
  892. if (!NT_SUCCESS(Status) ||
  893. (SizeRead != sizeof(DESKTOP)) ||
  894. (Desktop.dtp_Signature != AFP_SERVER_SIGNATURE) ||
  895. ((Desktop.dtp_Version != AFP_DESKTOP_VERSION1) &&
  896. (Desktop.dtp_Version != AFP_DESKTOP_VERSION2)) ||
  897. ((Desktop.dtp_cApplEnts > 0) &&
  898. ((ULONG_PTR)(Desktop.dtp_pApplInfo) != sizeof(DESKTOP))) ||
  899. ((Desktop.dtp_cIconEnts > 0) &&
  900. ((ULONG_PTR)(Desktop.dtp_pIconInfo) != sizeof(DESKTOP) +
  901. (Desktop.dtp_cApplEnts *
  902. ((Desktop.dtp_Version == AFP_DESKTOP_VERSION1) ?
  903. sizeof(APPLINFO) : sizeof(APPLINFO2))) )) )
  904. {
  905. AFPLOG_ERROR(AFPSRVMSG_READ_DESKTOP, Status, NULL, 0,
  906. &pVolDesc->vds_Name);
  907. goto desktop_corrupt;
  908. }
  909. switch (Desktop.dtp_Version)
  910. {
  911. case AFP_DESKTOP_VERSION1:
  912. {
  913. AFPLOG_INFO(AFPSRVMSG_UPDATE_DESKTOP_VERSION,
  914. STATUS_SUCCESS,
  915. NULL,
  916. 0,
  917. &pVolDesc->vds_Name);
  918. applSize = sizeof(APPLINFO);
  919. break;
  920. }
  921. case AFP_DESKTOP_VERSION2:
  922. {
  923. applSize = sizeof(APPLINFO2);
  924. break;
  925. }
  926. default:
  927. {
  928. // This should never happen since it was checked above
  929. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_WARN,
  930. ("afpReadDesktopFromDisk: Unexpected DT version 0x%lx\n", Desktop.dtp_Version) );
  931. ASSERTMSG("afpReadDesktopFromDisk: Unexpected DT Version", 0);
  932. goto desktop_corrupt;
  933. }
  934. }
  935. // Initialize the desktop header. Even though we may be reading a
  936. // downlevel version database, set the in-memory desktop database
  937. // version to current version since we are building it with the
  938. // current appl version structure.
  939. AfpDtHdrToVolDesc(&Desktop, pVolDesc);
  940. ForkOffset.QuadPart = DskOffst = sizeof(DESKTOP);
  941. SizeRead = 0;
  942. // Now read in the APPL entries, if any
  943. for (i = 0, PrevHash = -1;
  944. (Status == AFP_ERR_NONE) && (i < Desktop.dtp_cApplEnts);
  945. i++)
  946. {
  947. PAPPLINFO2 pApplInfo;
  948. if ((SizeRead - BufOffst) < applSize)
  949. {
  950. // We have a partial APPLINFO. Backup and read the whole thing
  951. DskOffst -= ((DWORD)SizeRead - (DWORD)BufOffst);
  952. ForkOffset.QuadPart = DskOffst;
  953. Status = AfpIoRead(pfshDesktop,
  954. &ForkOffset,
  955. DESKTOPIO_BUFSIZE,
  956. &SizeRead,
  957. pBuffer);
  958. if ((Status != AFP_ERR_NONE) || (SizeRead < applSize))
  959. {
  960. AFPLOG_ERROR(AFPSRVMSG_READ_DESKTOP, Status, &SizeRead,
  961. sizeof(SizeRead), &pVolDesc->vds_Name);
  962. Status = STATUS_UNEXPECTED_IO_ERROR;
  963. break;
  964. }
  965. DskOffst += SizeRead;
  966. ForkOffset.QuadPart = DskOffst;
  967. BufOffst = 0;
  968. }
  969. if ((pApplInfo = ALLOC_APPLINFO()) == NULL)
  970. {
  971. Status = STATUS_INSUFFICIENT_RESOURCES;
  972. AFPLOG_ERROR(AFPSRVMSG_READ_DESKTOP, Status, NULL, 0,
  973. &pVolDesc->vds_Name);
  974. break;
  975. }
  976. pApplInfo->appl_ParentID = 0;
  977. // If we are reading downlevel appl structures, they will
  978. // get read into the first part of the current appl structures.
  979. // These fields should be identical! If this is the case, the
  980. // appl_ParentId field will be 0 and the volume marked as needing
  981. // its appls rebuilt.
  982. RtlCopyMemory(pApplInfo, pBuffer + BufOffst, applSize);
  983. pApplInfo->appl_Next = NULL;
  984. BufOffst += applSize;
  985. if (PrevHash != (LONG)HASH_APPL(pApplInfo->appl_Creator))
  986. {
  987. PrevHash = (LONG)HASH_APPL(pApplInfo->appl_Creator);
  988. ppApplInfo = &pVolDesc->vds_pApplBuckets[PrevHash];
  989. }
  990. *ppApplInfo = pApplInfo;
  991. ppApplInfo = &pApplInfo->appl_Next;
  992. }
  993. // Now read in the ICON entries, if any
  994. for (i = 0, PrevHash = -1;
  995. (Status == AFP_ERR_NONE) && (i < Desktop.dtp_cIconEnts);
  996. i++)
  997. {
  998. PICONINFO pIconInfo;
  999. if ((SizeRead - BufOffst) < sizeof(ICONINFO))
  1000. {
  1001. // We have a partial ICONINFO. Backup and read the whole thing
  1002. DskOffst -= ((DWORD)SizeRead - (DWORD)BufOffst);
  1003. ForkOffset.QuadPart = DskOffst;
  1004. Status = AfpIoRead(pfshDesktop,
  1005. &ForkOffset,
  1006. DESKTOPIO_BUFSIZE,
  1007. &SizeRead,
  1008. pBuffer);
  1009. if ((Status != AFP_ERR_NONE) || (SizeRead < sizeof(ICONINFO)))
  1010. {
  1011. AFPLOG_ERROR(AFPSRVMSG_READ_DESKTOP, Status, &SizeRead,
  1012. sizeof(SizeRead), &pVolDesc->vds_Name);
  1013. Status = STATUS_UNEXPECTED_IO_ERROR;
  1014. break;
  1015. }
  1016. DskOffst += SizeRead;
  1017. ForkOffset.QuadPart = DskOffst;
  1018. BufOffst = 0;
  1019. }
  1020. // Validate icon size
  1021. if ((((PICONINFO)(pBuffer + BufOffst))->icon_Size > ICONSIZE_ICN8) ||
  1022. (((PICONINFO)(pBuffer + BufOffst))->icon_Size < ICONSIZE_ICS))
  1023. {
  1024. Status = STATUS_UNEXPECTED_IO_ERROR;
  1025. AFPLOG_ERROR(AFPSRVMSG_READ_DESKTOP, Status,
  1026. &((PICONINFO)(pBuffer + BufOffst))->icon_Size,
  1027. sizeof(((PICONINFO)(0))->icon_Size),
  1028. &pVolDesc->vds_Name);
  1029. break;
  1030. }
  1031. if ((pIconInfo = ALLOC_ICONINFO(((PICONINFO)(pBuffer + BufOffst))->icon_Size)) == NULL)
  1032. {
  1033. Status = STATUS_INSUFFICIENT_RESOURCES;
  1034. AFPLOG_ERROR(AFPSRVMSG_READ_DESKTOP, Status, NULL, 0,
  1035. &pVolDesc->vds_Name);
  1036. break;
  1037. }
  1038. // First copy the icon header and then link the icon into the hash table
  1039. RtlCopyMemory(pIconInfo, pBuffer + BufOffst, sizeof(ICONINFO));
  1040. pIconInfo->icon_Next = NULL;
  1041. if (PrevHash != (LONG)HASH_ICON(pIconInfo->icon_Creator))
  1042. {
  1043. PrevHash = (LONG)HASH_ICON(pIconInfo->icon_Creator);
  1044. ppIconInfo = &pVolDesc->vds_pIconBuckets[PrevHash];
  1045. }
  1046. *ppIconInfo = pIconInfo;
  1047. ppIconInfo = &pIconInfo->icon_Next;
  1048. // Now check if there is sufficient stuff here to get the icon
  1049. BufOffst += sizeof(ICONINFO);
  1050. if ((SizeRead - BufOffst) < pIconInfo->icon_Size)
  1051. {
  1052. LONG Size2Copy;
  1053. Size2Copy = SizeRead - BufOffst;
  1054. // Copy what we can first
  1055. RtlCopyMemory((PBYTE)pIconInfo + sizeof(ICONINFO),
  1056. pBuffer + BufOffst, Size2Copy);
  1057. Status = AfpIoRead(pfshDesktop,
  1058. &ForkOffset,
  1059. DESKTOPIO_BUFSIZE,
  1060. &SizeRead,
  1061. pBuffer);
  1062. if ((Status != AFP_ERR_NONE) ||
  1063. (SizeRead < (pIconInfo->icon_Size - Size2Copy)))
  1064. {
  1065. AFPLOG_ERROR(AFPSRVMSG_READ_DESKTOP, Status, &SizeRead,
  1066. sizeof(SizeRead), &pVolDesc->vds_Name);
  1067. Status = STATUS_UNEXPECTED_IO_ERROR;
  1068. break;
  1069. }
  1070. DskOffst += SizeRead;
  1071. ForkOffset.QuadPart = DskOffst;
  1072. // Now copy the rest of the icon
  1073. RtlCopyMemory((PBYTE)pIconInfo + sizeof(ICONINFO) + Size2Copy,
  1074. pBuffer,
  1075. pIconInfo->icon_Size - Size2Copy);
  1076. BufOffst = pIconInfo->icon_Size - Size2Copy;
  1077. }
  1078. else
  1079. {
  1080. RtlCopyMemory((PBYTE)pIconInfo + sizeof(ICONINFO),
  1081. pBuffer + BufOffst,
  1082. pIconInfo->icon_Size);
  1083. BufOffst += pIconInfo->icon_Size;
  1084. }
  1085. }
  1086. if (Status != AFP_ERR_NONE)
  1087. {
  1088. AfpFreeDesktopTables(pVolDesc);
  1089. desktop_corrupt:
  1090. // We have essentially ignored the existing data in the stream
  1091. // Initialize the header
  1092. pVolDesc->vds_cApplEnts = 0;
  1093. pVolDesc->vds_cIconEnts = 0;
  1094. AfpVolDescToDtHdr(pVolDesc, &Desktop);
  1095. Desktop.dtp_pIconInfo = NULL;
  1096. Desktop.dtp_pApplInfo = NULL;
  1097. AfpIoWrite(pfshDesktop,
  1098. &LIZero,
  1099. sizeof(DESKTOP),
  1100. (PBYTE)&Desktop);
  1101. // Truncate the stream at this point
  1102. AfpIoSetSize(pfshDesktop, sizeof(DESKTOP));
  1103. Status = STATUS_SUCCESS;
  1104. }
  1105. if (pBuffer != NULL)
  1106. AfpFreeMemory(pBuffer);
  1107. return Status;
  1108. }
  1109. /*** AfpInitDesktop
  1110. *
  1111. * This routine initializes the memory image (and all related volume
  1112. * descriptor fields) of the desktop for a newly added volume. If a desktop
  1113. * stream already exists on the disk for the volume root directory, that
  1114. * stream is read in. If this is a newly created volume, the desktop
  1115. * stream is created on the root of the volume. If this is a CD-ROM volume,
  1116. * only the memory image is initialized.
  1117. *
  1118. * No locks are necessary since this routine only operates on volume
  1119. * descriptors which are newly allocated, but not yet linked into the global
  1120. * volume list.
  1121. */
  1122. AFPSTATUS
  1123. AfpInitDesktop(
  1124. IN PVOLDESC pVolDesc,
  1125. OUT BOOLEAN *pfNewVolume
  1126. )
  1127. {
  1128. BOOLEAN InitHeader = True;
  1129. NTSTATUS Status = STATUS_SUCCESS;
  1130. FILESYSHANDLE fshDesktop;
  1131. PAGED_CODE( );
  1132. // for now
  1133. *pfNewVolume = FALSE;
  1134. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_INFO, ("\tInitializing Desktop...\n") );
  1135. AfpSwmrInitSwmr(&(pVolDesc->vds_DtAccessLock));
  1136. // if this is an NTFS volume, attempt to create the desktop stream.
  1137. // If it already exists, open it and read it in.
  1138. if (IS_VOLUME_NTFS(pVolDesc))
  1139. {
  1140. ULONG CreateInfo;
  1141. InitHeader = False;
  1142. Status = AfpIoCreate(&pVolDesc->vds_hRootDir,
  1143. AFP_STREAM_DT,
  1144. &UNullString,
  1145. FILEIO_ACCESS_READWRITE,
  1146. FILEIO_DENY_WRITE,
  1147. FILEIO_OPEN_FILE,
  1148. FILEIO_CREATE_INTERNAL,
  1149. FILE_ATTRIBUTE_NORMAL,
  1150. False,
  1151. NULL,
  1152. &fshDesktop,
  1153. &CreateInfo,
  1154. NULL,
  1155. NULL,
  1156. NULL);
  1157. if (NT_SUCCESS(Status))
  1158. {
  1159. if (CreateInfo == FILE_OPENED)
  1160. {
  1161. Status = afpReadDesktopFromDisk(pVolDesc, &fshDesktop);
  1162. AfpIoClose(&fshDesktop);
  1163. }
  1164. else if (CreateInfo != FILE_CREATED)
  1165. {
  1166. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_ERR,
  1167. ("AfpInitDesktop: Unexpected create action 0x%lx\n", CreateInfo) );
  1168. ASSERT(0); // this should never happen
  1169. Status = STATUS_UNSUCCESSFUL;
  1170. }
  1171. else
  1172. {
  1173. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1174. ("AfpInitDesktop: volume %Z is new\n",&pVolDesc->vds_Name));
  1175. InitHeader = True;
  1176. *pfNewVolume = TRUE;
  1177. }
  1178. }
  1179. else
  1180. {
  1181. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_ERR,
  1182. ("AfpInitDesktop: AfpIoCreate failed %lx\n", Status));
  1183. Status = STATUS_UNSUCCESSFUL;
  1184. }
  1185. }
  1186. if (InitHeader)
  1187. {
  1188. DESKTOP Desktop;
  1189. // Initialize the header
  1190. pVolDesc->vds_cApplEnts = 0;
  1191. pVolDesc->vds_cIconEnts = 0;
  1192. if (IS_VOLUME_NTFS(pVolDesc))
  1193. {
  1194. AfpVolDescToDtHdr(pVolDesc, &Desktop);
  1195. Desktop.dtp_pIconInfo = NULL;
  1196. Desktop.dtp_pApplInfo = NULL;
  1197. AfpIoWrite(&fshDesktop,
  1198. &LIZero,
  1199. sizeof(DESKTOP),
  1200. (PBYTE)&Desktop);
  1201. AfpIoClose(&fshDesktop);
  1202. }
  1203. }
  1204. return Status;
  1205. }
  1206. /*** AfpUpdateDesktop
  1207. *
  1208. * Update the desktop database on the volume root. The swmr access is held
  1209. * for read (by the caller) while the update is in progress. It is already
  1210. * determined by the caller that the volume desktop needs to be updated.
  1211. *
  1212. * LOCKS: vds_DtAccessLock (SWMR, Shared)
  1213. */
  1214. VOID
  1215. AfpUpdateDesktop(
  1216. IN PVOLDESC pVolDesc // Volume Descriptor of the open volume
  1217. )
  1218. {
  1219. AFPSTATUS Status;
  1220. PBYTE pBuffer;
  1221. DWORD Offset = 0, Size;
  1222. LONG i;
  1223. DESKTOP Desktop;
  1224. FORKOFFST ForkOffset;
  1225. FILESYSHANDLE fshDesktop;
  1226. ULONG CreateInfo;
  1227. #ifdef PROFILING
  1228. TIME TimeS, TimeE, TimeD;
  1229. PAGED_CODE( );
  1230. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_DesktopUpdCount);
  1231. AfpGetPerfCounter(&TimeS);
  1232. #endif
  1233. // Take the swmr so that nobody can initiate changes to the desktop
  1234. AfpSwmrAcquireShared(&pVolDesc->vds_DtAccessLock);
  1235. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_INFO,
  1236. ("\tWriting Desktop to disk....\n") );
  1237. do
  1238. {
  1239. fshDesktop.fsh_FileHandle = NULL;
  1240. // Work with one page of memory and do multiple I/Os to the disk.
  1241. if ((pBuffer = AfpAllocPagedMemory(DESKTOPIO_BUFSIZE)) == NULL)
  1242. {
  1243. AFPLOG_ERROR(AFPSRVMSG_WRITE_DESKTOP, STATUS_NO_MEMORY, NULL, 0,
  1244. &pVolDesc->vds_Name);
  1245. break;
  1246. }
  1247. // Open a handle to the desktop stream, denying others read/write
  1248. // access (i.e. backup/restore)
  1249. Status = AfpIoCreate(&pVolDesc->vds_hRootDir,
  1250. AFP_STREAM_DT,
  1251. &UNullString,
  1252. FILEIO_ACCESS_WRITE,
  1253. FILEIO_DENY_ALL,
  1254. FILEIO_OPEN_FILE,
  1255. FILEIO_CREATE_INTERNAL,
  1256. FILE_ATTRIBUTE_NORMAL,
  1257. False,
  1258. NULL,
  1259. &fshDesktop,
  1260. &CreateInfo,
  1261. NULL,
  1262. NULL,
  1263. NULL);
  1264. if (NT_SUCCESS(Status))
  1265. {
  1266. if ((CreateInfo != FILE_OPENED) && (CreateInfo != FILE_CREATED))
  1267. {
  1268. // This should never happen!
  1269. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_WARN,
  1270. ("AfpUpdateDesktop: Unexpected create action 0x%lx\n", CreateInfo) );
  1271. ASSERTMSG("AfpUpdateDesktop: Unexpected create action", 0);
  1272. break;
  1273. }
  1274. }
  1275. else
  1276. {
  1277. AFPLOG_ERROR(AFPSRVMSG_WRITE_DESKTOP, Status, NULL, 0,
  1278. &pVolDesc->vds_Name);
  1279. break;
  1280. }
  1281. // Snapshot the header and write it with an invalid signature. We write
  1282. // the header again later with a valid signature. This protects us from
  1283. // incomplete writes (server crash etc.)
  1284. AfpVolDescToDtHdr(pVolDesc, &Desktop);
  1285. Desktop.dtp_Signature = 0;
  1286. (ULONG_PTR)(Desktop.dtp_pApplInfo) = 0;
  1287. if (Desktop.dtp_cApplEnts > 0)
  1288. (ULONG_PTR)(Desktop.dtp_pApplInfo) = sizeof(DESKTOP);
  1289. (ULONG_PTR)(Desktop.dtp_pIconInfo) = 0;
  1290. if (Desktop.dtp_cIconEnts > 0)
  1291. (ULONG_PTR)(Desktop.dtp_pIconInfo) = sizeof(DESKTOP) +
  1292. sizeof(APPLINFO2)*Desktop.dtp_cApplEnts;
  1293. // Write out the header with invalid signature
  1294. Status = AfpIoWrite(&fshDesktop,
  1295. &LIZero,
  1296. sizeof(DESKTOP),
  1297. (PBYTE)&Desktop);
  1298. Offset = sizeof(DESKTOP);
  1299. Size = 0;
  1300. // First write the APPL Entries
  1301. for (i = 0; (Status == AFP_ERR_NONE) && (i < APPL_BUCKETS); i++)
  1302. {
  1303. PAPPLINFO2 pApplInfo;
  1304. for (pApplInfo = pVolDesc->vds_pApplBuckets[i];
  1305. (Status == AFP_ERR_NONE) && (pApplInfo != NULL);
  1306. pApplInfo = pApplInfo->appl_Next)
  1307. {
  1308. if ((DESKTOPIO_BUFSIZE - Size) < sizeof(APPLINFO2))
  1309. {
  1310. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_INFO,
  1311. ("afpUpdateDesktop: Writing Appl %ld at %ld\n", Size, Offset));
  1312. ForkOffset.QuadPart = Offset;
  1313. Status = AfpIoWrite(&fshDesktop,
  1314. &ForkOffset,
  1315. Size,
  1316. pBuffer);
  1317. Size = 0;
  1318. Offset += Size;
  1319. }
  1320. *(PAPPLINFO2)(pBuffer + Size) = *pApplInfo;
  1321. Size += sizeof(APPLINFO2);
  1322. }
  1323. }
  1324. // And now the ICON entries
  1325. for (i = 0; (Status == AFP_ERR_NONE) && (i < ICON_BUCKETS); i++)
  1326. {
  1327. PICONINFO pIconInfo;
  1328. for (pIconInfo = pVolDesc->vds_pIconBuckets[i];
  1329. (Status == AFP_ERR_NONE) && (pIconInfo != NULL);
  1330. pIconInfo = pIconInfo->icon_Next)
  1331. {
  1332. if ((DESKTOPIO_BUFSIZE - Size) < (sizeof(ICONINFO) + pIconInfo->icon_Size))
  1333. {
  1334. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_INFO,
  1335. ("afpUpdateDesktop: Writing icons %ld at %ld\n", Size, Offset));
  1336. ForkOffset.QuadPart = Offset;
  1337. Status = AfpIoWrite(&fshDesktop,
  1338. &ForkOffset,
  1339. Size,
  1340. pBuffer);
  1341. Offset += Size;
  1342. Size = 0;
  1343. }
  1344. RtlCopyMemory(pBuffer + Size,
  1345. (PBYTE)pIconInfo,
  1346. sizeof(ICONINFO) + pIconInfo->icon_Size);
  1347. Size += sizeof(ICONINFO) + pIconInfo->icon_Size;
  1348. }
  1349. }
  1350. while (Status == AFP_ERR_NONE)
  1351. {
  1352. if (Size > 0)
  1353. {
  1354. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_INFO,
  1355. ("afpUpdateDesktop: Writing at end %ld at %ld\n", Size, Offset));
  1356. ForkOffset.QuadPart = Offset;
  1357. Status = AfpIoWrite(&fshDesktop,
  1358. &ForkOffset,
  1359. Size,
  1360. pBuffer);
  1361. if (Status != AFP_ERR_NONE)
  1362. break;
  1363. }
  1364. DBGPRINT(DBG_COMP_DESKTOP, DBG_LEVEL_INFO,
  1365. ("afpUpdateDesktop: Setting desktop stream size @ %ld\n", Size + Offset));
  1366. // Chop off the stream at this offset.
  1367. Status = AfpIoSetSize(&fshDesktop, Offset + Size);
  1368. ASSERT (Status == AFP_ERR_NONE);
  1369. // Write the correct signature back
  1370. Desktop.dtp_Signature = AFP_SERVER_SIGNATURE;
  1371. Status = AfpIoWrite(&fshDesktop,
  1372. &LIZero,
  1373. sizeof(DESKTOP),
  1374. (PBYTE)&Desktop);
  1375. // Update the count of changes: vds_cChangesDt is protected by the
  1376. // swmr, the scavenger can set this with READ access. All others
  1377. // MUST hold the swmr for WRITE access to increment the cChangesDt.
  1378. // Scavenger is the only consumer of vds_cScvgrDt, so no lock is
  1379. // really needed for it.
  1380. pVolDesc->vds_cScvgrDt = 0;
  1381. break;
  1382. }
  1383. if (Status != AFP_ERR_NONE)
  1384. {
  1385. AFPLOG_ERROR(AFPSRVMSG_WRITE_DESKTOP, Status, NULL, 0,
  1386. &pVolDesc->vds_Name);
  1387. }
  1388. } while (False);
  1389. if (pBuffer != NULL)
  1390. {
  1391. AfpFreeMemory(pBuffer);
  1392. if (fshDesktop.fsh_FileHandle != NULL)
  1393. AfpIoClose(&fshDesktop);
  1394. }
  1395. #ifdef PROFILING
  1396. AfpGetPerfCounter(&TimeE);
  1397. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  1398. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_DesktopUpdTime,
  1399. TimeD,
  1400. &AfpStatisticsLock);
  1401. #endif
  1402. AfpSwmrRelease(&pVolDesc->vds_DtAccessLock);
  1403. }
  1404. /*** AfpFreeDesktopTables
  1405. *
  1406. * Free the allocated memory for the volume desktop tables. The volume is
  1407. * about to be deleted. Ensure that either the volume is non-NTFS or it is
  1408. * clean i.e. the scavenger threads have written it back. No locks are needed
  1409. * as this structure is all by itself.
  1410. */
  1411. VOID
  1412. AfpFreeDesktopTables(
  1413. IN PVOLDESC pVolDesc
  1414. )
  1415. {
  1416. LONG i;
  1417. PAGED_CODE( );
  1418. // This should never happen
  1419. ASSERT (!IS_VOLUME_NTFS(pVolDesc) ||
  1420. (pVolDesc->vds_pOpenForkDesc == NULL));
  1421. // First tackle the ICON list. Traverse each of the hash indices.
  1422. // Note that the icon is allocated as part of the IconInfo structure
  1423. // so free in together.
  1424. for (i = 0; i < ICON_BUCKETS; i++)
  1425. {
  1426. PICONINFO pIconInfo, pFree;
  1427. for (pIconInfo = pVolDesc->vds_pIconBuckets[i]; pIconInfo != NULL; )
  1428. {
  1429. pFree = pIconInfo;
  1430. pIconInfo = pIconInfo->icon_Next;
  1431. AfpFreeMemory(pFree);
  1432. }
  1433. // In case we ever try to free the table again
  1434. pVolDesc->vds_pIconBuckets[i] = NULL;
  1435. }
  1436. // Now tackle the APPL list. Traverse each of the hash indices.
  1437. for (i = 0; i < APPL_BUCKETS; i++)
  1438. {
  1439. PAPPLINFO2 pApplInfo, pFree;
  1440. for (pApplInfo = pVolDesc->vds_pApplBuckets[i]; pApplInfo != NULL; )
  1441. {
  1442. pFree = pApplInfo;
  1443. pApplInfo = pApplInfo->appl_Next;
  1444. AfpFreeMemory(pFree);
  1445. }
  1446. // In case we ever try to free the table again
  1447. pVolDesc->vds_pApplBuckets[i] = NULL;
  1448. }
  1449. }
  1450. 
  1451.