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.

4045 lines
113 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. volume.c
  5. Abstract:
  6. This module contains the volume list manipulation routines and worker
  7. routines for some afp volume apis.
  8. Author:
  9. Jameel Hyder (microsoft!jameelh)
  10. Revision History:
  11. 25 Apr 1992 Initial Version
  12. Notes: Tab stop: 4
  13. Volumes are represented by two distinct data structures VolDesc and ConnDesc
  14. VolDesc:This structure represents a configured volume. The information in
  15. this descriptor consists of static configuration information like
  16. the name of the volume and its path, reconfigurable information like
  17. the volume password and volume options and dynamic information like
  18. the open desktop, id database, open forks etc.
  19. The list of VolDesc structures orignate from AfpVolumeList and is
  20. protected by AfpVolumeListLock . The Volume descriptor fields are
  21. protected by vds_VolLock.
  22. A volume descriptor has a UseCount field which specifies how many
  23. clients have this volume open. The reference count specifies the
  24. number of references to this volume. A volume descriptor can be
  25. unlinked from the AfpVolumeList ONLY if the UseCount is ZERO. It
  26. can be freed only when the reference count is ZERO. The reference
  27. count can NEVER be less than the use count.
  28. ConnDesc:This is created for every instance of a volume opened by a client.
  29. This structure is mostly used in the context of the client. This
  30. is also used by the admin connection apis. The ConnDesc list is
  31. linked to its owning VolDesc, its owning SDA and AfpConnList. The
  32. list orignating from the SDA is protected by sda_Lock. The list
  33. orignating from AfpConnList is protected by AfpConnLock and the
  34. list orignating from the VolDesc is protected by vds_VolLock.
  35. The order in which the locks are acquired is as follows:
  36. 1. AfpConnLock
  37. 2. cds_ConnLock
  38. 3. vds_VolLock
  39. --*/
  40. #define FILENUM FILE_VOLUME
  41. #define VOLUME_LOCALS
  42. #include <afp.h>
  43. #include <fdparm.h>
  44. #include <scavengr.h>
  45. #include <nwtrash.h>
  46. #include <pathmap.h>
  47. #include <afpinfo.h>
  48. #include <forkio.h>
  49. #ifdef ALLOC_PRAGMA
  50. #pragma alloc_text( INIT, AfpVolumeInit)
  51. #pragma alloc_text( PAGE, AfpAdmWVolumeAdd)
  52. #pragma alloc_text( PAGE, AfpVolumePostChangeNotify)
  53. #pragma alloc_text( PAGE, afpVolumeChangeNotifyComplete)
  54. #pragma alloc_text( PAGE, afpVolumeCloseHandleAndFreeDesc)
  55. #pragma alloc_text( PAGE, afpNudgeCdfsVolume)
  56. #pragma alloc_text( PAGE, AfpVolumeUpdateIdDbAndDesktop)
  57. #pragma alloc_text( PAGE_AFP, AfpVolumeReferenceByUpCaseName)
  58. #pragma alloc_text( PAGE_AFP, AfpVolumeReferenceByPath)
  59. #pragma alloc_text( PAGE_AFP, afpConnectionReferenceById)
  60. #pragma alloc_text( PAGE_AFP, afpVolumeAdd)
  61. #pragma alloc_text( PAGE_AFP, afpVolumeCheckForDuplicate)
  62. #pragma alloc_text( PAGE_AFP, AfpAdmWVolumeDelete)
  63. #pragma alloc_text( PAGE_AFP, AfpAdmWConnectionClose)
  64. #pragma alloc_text( PAGE_AFP, afpVolumeGetNewIdAndLinkToList)
  65. #pragma alloc_text( PAGE_AFP, AfpVolumeStopAllVolumes)
  66. #pragma alloc_text(PAGE, afpAllocNotify)
  67. #pragma alloc_text(PAGE, afpFreeNotify)
  68. #pragma alloc_text(PAGE, afpNotifyBlockAge)
  69. #pragma alloc_text(PAGE, afpFreeNotifyBlockMemory)
  70. #endif
  71. /*** AfpVolumeInit
  72. *
  73. * Initialize Volume Data structures. Called at init time.
  74. */
  75. NTSTATUS
  76. AfpVolumeInit(
  77. VOID
  78. )
  79. {
  80. LONG i;
  81. INITIALIZE_SPIN_LOCK(&AfpConnLock);
  82. INITIALIZE_SPIN_LOCK(&AfpVolumeListLock);
  83. AfpSwmrInitSwmr(&afpNotifyBlockLock);
  84. AfpSwmrInitSwmr(&AfpVolumeListSwmr);
  85. for (i = 0; i < NUM_NOTIFY_QUEUES; i++)
  86. {
  87. InitializeListHead(&AfpVolumeNotifyList[i]);
  88. InitializeListHead(&AfpVirtualMemVolumeNotifyList[i]);
  89. AfpNotifyListCount[i] = 0;
  90. AfpNotifyQueueCount[i] = 0;
  91. }
  92. // Age out Notify Blocks
  93. AfpScavengerScheduleEvent(afpNotifyBlockAge,
  94. afpDirNotifyFreeBlockHead,
  95. NOTIFY_DIR_BLOCK_AGE_TIME,
  96. True);
  97. return STATUS_SUCCESS;
  98. }
  99. /*** AfpVolumeReference
  100. *
  101. * Mark the volume descriptor as being referenced.
  102. *
  103. * LOCKS: vds_VolLock (SPIN)
  104. *
  105. * Callable from DISPATCH_LEVEL.
  106. */
  107. BOOLEAN FASTCALL
  108. AfpVolumeReference(
  109. IN PVOLDESC pVolDesc
  110. )
  111. {
  112. KIRQL OldIrql;
  113. BOOLEAN RetCode = False;
  114. ASSERT (VALID_VOLDESC(pVolDesc));
  115. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  116. // NOTE: in order for ChangeNotify code to reference volume
  117. // before it is officially not INTRANSITION, we must allow
  118. // a reference before INTRANSITION
  119. if (!(pVolDesc->vds_Flags & (VOLUME_DELETED | VOLUME_STOPPED)))
  120. {
  121. ASSERT (pVolDesc->vds_RefCount >= pVolDesc->vds_UseCount);
  122. pVolDesc->vds_RefCount++;
  123. RetCode = True;
  124. }
  125. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  126. return RetCode;
  127. }
  128. /*** AfpVolumeReferenceByUpCaseName
  129. *
  130. * Reference the volume in AfpVolumeList with the same vds_UpCaseName as
  131. * pTargetName. Since we are holding the AfpVolumeListLock (SpinLock)
  132. * and are at DPC level, our string comparison must be case sensitive, because
  133. * the codepage used to do case insensitive compares is in paged memory, and
  134. * we cannot take a pagefault at DPC level.
  135. *
  136. * If we find the volume we are looking for, it will be referenced. THE
  137. * CALLER IS THEN RESPONSIBLE FOR DEREFERENCING THE VOLUME!!!
  138. *
  139. * LOCKS: vds_VolLock (SPIN), AfpVolumeListLock (SPIN)
  140. * LOCK_ORDER: vds_VolLock after AfpVolumeListLock
  141. *
  142. */
  143. PVOLDESC FASTCALL
  144. AfpVolumeReferenceByUpCaseName(
  145. IN PUNICODE_STRING pTargetName
  146. )
  147. {
  148. PVOLDESC pVolDesc;
  149. KIRQL OldIrql;
  150. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  151. for (pVolDesc = AfpVolumeList;
  152. pVolDesc != NULL;
  153. pVolDesc = pVolDesc->vds_Next)
  154. {
  155. BOOLEAN Found;
  156. Found = False;
  157. ACQUIRE_SPIN_LOCK_AT_DPC(&pVolDesc->vds_VolLock);
  158. if ((pVolDesc->vds_Flags & (VOLUME_DELETED |
  159. VOLUME_STOPPED |
  160. VOLUME_INTRANSITION)) == 0)
  161. {
  162. if (AfpEqualUnicodeString(pTargetName,
  163. &pVolDesc->vds_UpCaseName))
  164. {
  165. pVolDesc->vds_RefCount ++;
  166. Found = True;
  167. }
  168. }
  169. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  170. if (Found)
  171. break;
  172. }
  173. RELEASE_SPIN_LOCK(&AfpVolumeListLock,OldIrql);
  174. return pVolDesc;
  175. }
  176. /*** AfpVolumeReferenceByPath
  177. *
  178. * Reference the volume by a path into the volume. We ignore volumes which are
  179. * marked as in-transition, stopped or deleted. Also this is only supported for
  180. * NTFS volumes since thats what these are used for.
  181. *
  182. * LOCKS: AfpVolumeListLock (SPIN), vds_VolLock (SPIN)
  183. * LOCK_ORDER: vds_VolLock after AfpVolumeListLock
  184. *
  185. */
  186. AFPSTATUS FASTCALL
  187. AfpVolumeReferenceByPath(
  188. IN PUNICODE_STRING pFDPath,
  189. OUT PVOLDESC * ppVolDesc
  190. )
  191. {
  192. UNICODE_STRING UpCasedVolPath;
  193. KIRQL OldIrql;
  194. PVOLDESC pVolDesc;
  195. AFPSTATUS Status = AFPERR_DirectoryNotInVolume;
  196. // Allocate a buffer for upcasing the path. Tag on a trailing '\' at the
  197. // end. Then uppercase the volume path
  198. *ppVolDesc = NULL;
  199. UpCasedVolPath.MaximumLength = pFDPath->Length + 2*sizeof(WCHAR);
  200. if ((UpCasedVolPath.Buffer = (LPWSTR)
  201. AfpAllocNonPagedMemory(UpCasedVolPath.MaximumLength)) == NULL)
  202. {
  203. return STATUS_INSUFFICIENT_RESOURCES;
  204. }
  205. RtlUpcaseUnicodeString(&UpCasedVolPath, pFDPath, False);
  206. UpCasedVolPath.Buffer[UpCasedVolPath.Length/sizeof(WCHAR)] = L'\\';
  207. UpCasedVolPath.Length += sizeof(WCHAR);
  208. // Scan the volume list and map the path to a volume descriptor
  209. // If we get a match, reference the volume
  210. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  211. for (pVolDesc = AfpVolumeList;
  212. pVolDesc != NULL;
  213. pVolDesc = pVolDesc->vds_Next)
  214. {
  215. BOOLEAN Found;
  216. Found = False;
  217. ACQUIRE_SPIN_LOCK_AT_DPC(&pVolDesc->vds_VolLock);
  218. if ((pVolDesc->vds_Flags & (VOLUME_INTRANSITION | VOLUME_STOPPED | VOLUME_DELETED)) == 0)
  219. {
  220. if (AfpPrefixUnicodeString(&pVolDesc->vds_Path, &UpCasedVolPath))
  221. {
  222. Found = True;
  223. // Share out NTFS, CD and CD-HFS
  224. if (IS_VOLUME_NTFS(pVolDesc) || IS_VOLUME_RO(pVolDesc))
  225. // if (IS_VOLUME_NTFS(pVolDesc))
  226. {
  227. pVolDesc->vds_RefCount ++;
  228. Status = STATUS_SUCCESS;
  229. *ppVolDesc = pVolDesc;
  230. }
  231. else
  232. {
  233. Status = AFPERR_UnsupportedFS;
  234. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  235. ("AfpVolumeReferenceByPath: *** AFPERR_UnsupportedFS**" ));
  236. }
  237. }
  238. }
  239. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  240. if (Found)
  241. break;
  242. }
  243. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  244. AfpFreeMemory(UpCasedVolPath.Buffer);
  245. return Status;
  246. }
  247. /*** afpUnlinkVolume
  248. *
  249. * Unlink the volume from the free list
  250. *
  251. * LOCKS: AfpVolumeListLock (SPIN)
  252. */
  253. LOCAL VOID FASTCALL
  254. afpUnlinkVolume(
  255. IN PVOLDESC pVolDesc
  256. )
  257. {
  258. PVOLDESC * ppVolDesc;
  259. KIRQL OldIrql;
  260. // It is now safe for a new volume to be added using the same root
  261. // directory that this volume had used. Unlink this volume from the
  262. // global volume list.
  263. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  264. for (ppVolDesc = &AfpVolumeList;
  265. *ppVolDesc != NULL;
  266. ppVolDesc = &(*ppVolDesc)->vds_Next)
  267. {
  268. if (*ppVolDesc == pVolDesc)
  269. break; // found it
  270. }
  271. ASSERT (*ppVolDesc != NULL);
  272. // Adjust the count of configured volumes
  273. AfpVolCount --;
  274. // Unlink it now
  275. *ppVolDesc = pVolDesc->vds_Next;
  276. // Is this the smallest recyclable Volid ?
  277. if (pVolDesc->vds_VolId < afpSmallestFreeVolId)
  278. afpSmallestFreeVolId = pVolDesc->vds_VolId;
  279. // if the volume with largest id so far is going away, update our value for largest id
  280. if (pVolDesc->vds_VolId == afpLargestVolIdInUse)
  281. {
  282. afpLargestVolIdInUse = 0;
  283. for (ppVolDesc = &AfpVolumeList;
  284. *ppVolDesc != NULL;
  285. ppVolDesc = &((*ppVolDesc)->vds_Next))
  286. {
  287. if ((*ppVolDesc)->vds_VolId > afpLargestVolIdInUse)
  288. afpLargestVolIdInUse = (*ppVolDesc)->vds_VolId;
  289. }
  290. }
  291. // If the server is stopping and the count of sessions has gone to zero
  292. // clear the termination confirmation event to unblock the admin thread
  293. if (((AfpServerState == AFP_STATE_STOP_PENDING) ||
  294. (AfpServerState == AFP_STATE_SHUTTINGDOWN)) &&
  295. (AfpVolCount == 0))
  296. {
  297. DBGPRINT(DBG_COMP_ADMINAPI, DBG_LEVEL_WARN,
  298. ("afpVolumeCloseHandleAndFreeDesc: Unblocking server stop\n"));
  299. KeSetEvent(&AfpStopConfirmEvent, IO_NETWORK_INCREMENT, False);
  300. }
  301. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  302. }
  303. /*** afpVolumeCloseHandleAndFreeDesc
  304. *
  305. * If the last entity to dereference the volume is at DPC level, this is run
  306. * by the scavenger thread to perform the last rites for a volume descriptor.
  307. * Otherwise, the last entity to dereference the deleted volume will call
  308. * this routine directly. The reason this is done here is because the last
  309. * dereference may happen at DPC level and we cannot do this at DPC level.
  310. *
  311. * The VolDesc is marked DELETED or STOPPED and as such, anyone looking at the
  312. * VolDesc in the volume list will treat it as though it is non-existant.
  313. * The one exception to this is the volume add code which must look at the
  314. * volume root path in order to prohibit anyone from adding a new volume
  315. * which points to the same path until we have actually done the final
  316. * cleanup on the directory tree, such as deleting the network trash, deleting
  317. * the various streams, etc. In effect, the VOLUME_DELETED or VOLUME_STOPPED
  318. * flags act as a lock for the volume, so that during this routine no locks are
  319. * needed.
  320. *
  321. */
  322. LOCAL AFPSTATUS FASTCALL
  323. afpVolumeCloseHandleAndFreeDesc(
  324. IN PVOLDESC pVolDesc
  325. )
  326. {
  327. int id;
  328. FILESYSHANDLE streamhandle;
  329. PLIST_ENTRY pList;
  330. int i;
  331. PDELAYED_NOTIFY pDelayedNotify;
  332. PAGED_CODE( );
  333. ASSERT(VALID_VOLDESC(pVolDesc));
  334. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_WARN,
  335. ("afpVolumeCloseHandleAndFreeDesc: Shutting Down volume %d\n",
  336. pVolDesc->vds_VolId));
  337. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_WARN,
  338. ("afpVolumeCloseHandleAndFreeDesc: Freeing up desktop tables\n"));
  339. // Free the volume desktop
  340. AfpFreeDesktopTables(pVolDesc);
  341. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_WARN,
  342. ("afpVolumeCloseHandleAndFreeDesc: Freeing up iddb tables\n"));
  343. // Free the id index tables
  344. AfpFreeIdIndexTables(pVolDesc);
  345. // Delete the Network Trash Folder and the Afp_IdIndex, AFP_DeskTop,
  346. // and AFP_AfpInfo streams from volume root directory (the streams
  347. // are removed only if the volume is being deleted. NetworkTrash is
  348. // removed whenever the volume stops/gets deleted)
  349. if (IS_VOLUME_NTFS(pVolDesc))
  350. {
  351. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_WARN,
  352. ("afpVolumeCloseHandleAndFreeDesc: Deleting the Network trash tree\n"));
  353. AfpDeleteNetworkTrash(pVolDesc, False);
  354. if (!(pVolDesc->vds_Flags & (VOLUME_INTRANSITION | VOLUME_STOPPED)))
  355. {
  356. WCHAR wchVolIcon[AFPSERVER_VOLUME_ICON_FILE_SIZE] = AFPSERVER_VOLUME_ICON_FILE;
  357. UNICODE_STRING UIconName;
  358. for (id = AFP_STREAM_IDDB;id < AFP_STREAM_COMM; id++)
  359. {
  360. if (NT_SUCCESS(AfpIoOpen(&pVolDesc->vds_hRootDir,
  361. id,
  362. FILEIO_OPEN_FILE,
  363. &UNullString,
  364. FILEIO_ACCESS_DELETE,
  365. FILEIO_DENY_NONE,
  366. False,
  367. &streamhandle)))
  368. {
  369. AfpIoMarkFileForDelete(&streamhandle, NULL, NULL, NULL);
  370. AfpIoClose(&streamhandle);
  371. }
  372. }
  373. UIconName.Buffer = wchVolIcon;
  374. UIconName.Length = UIconName.MaximumLength =
  375. (AFPSERVER_VOLUME_ICON_FILE_SIZE - 1) * sizeof(WCHAR);
  376. // Delete the hidden volume Icon file
  377. if (NT_SUCCESS(AfpIoOpen(&pVolDesc->vds_hRootDir,
  378. AFP_STREAM_DATA,
  379. FILEIO_OPEN_FILE,
  380. &UIconName,
  381. FILEIO_ACCESS_DELETE,
  382. FILEIO_DENY_NONE,
  383. False,
  384. &streamhandle)))
  385. {
  386. AfpIoMarkFileForDelete(&streamhandle, NULL, NULL, NULL);
  387. AfpIoClose(&streamhandle);
  388. }
  389. }
  390. }
  391. // Flush out any queued 'our changes' on this volume
  392. for (i = 0; i < NUM_AFP_CHANGE_ACTION_LISTS; i++)
  393. {
  394. POUR_CHANGE pChange;
  395. ASSERTMSG("afpVolumeCloseHandleAndFreeDesc: vds_OurChangeList not empty\n",
  396. IsListEmpty(&pVolDesc->vds_OurChangeList[i]));
  397. while (!IsListEmpty(&pVolDesc->vds_OurChangeList[i]))
  398. {
  399. pList = RemoveHeadList(&pVolDesc->vds_OurChangeList[i]);
  400. pChange = CONTAINING_RECORD(pList, OUR_CHANGE, oc_Link);
  401. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  402. ("afpVolumeCloseHandleAndFreeDesc: Manually freeing list for Action %x, Pathname %Z\n",
  403. i, &pChange->oc_Path));
  404. AfpFreeMemory(pChange);
  405. }
  406. }
  407. afpUnlinkVolume(pVolDesc);
  408. // Close the volume handle
  409. AfpIoClose(&pVolDesc->vds_hRootDir);
  410. if (pVolDesc->vds_EnumBuffer != NULL)
  411. {
  412. AfpFreePANonPagedMemory(pVolDesc->vds_EnumBuffer, AFP_ENUMBUF_SIZE);
  413. }
  414. if (pVolDesc->vds_pDfeDirBucketStart)
  415. {
  416. AfpFreeMemory(pVolDesc->vds_pDfeDirBucketStart);
  417. }
  418. if (pVolDesc->vds_pDfeFileBucketStart)
  419. {
  420. AfpFreeMemory(pVolDesc->vds_pDfeFileBucketStart);
  421. }
  422. pList = pVolDesc->vds_DelayedNotifyList.Flink;
  423. while (pList != &pVolDesc->vds_DelayedNotifyList)
  424. {
  425. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  426. ("afpVolumeCloseHandleAndFreeDesc: freeing delayed notify buf %lx\n",pDelayedNotify));
  427. pDelayedNotify = CONTAINING_RECORD (pList, DELAYED_NOTIFY, dn_List);
  428. pList = pList->Flink;
  429. RemoveEntryList(&pDelayedNotify->dn_List);
  430. AfpFreeMemory(pDelayedNotify->filename.Buffer);
  431. AfpFreeMemory(pDelayedNotify);
  432. }
  433. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  434. ("afpVolumeCloseHandleAndFreeDesc: freeing %lx for vol %Z\n",
  435. pVolDesc,&pVolDesc->vds_Name));
  436. AfpFreeMemory(pVolDesc);
  437. return AFP_ERR_NONE;
  438. }
  439. /*** AfpVolumeDereference
  440. *
  441. * Dereference the volume descriptor. If it is marked to be deleted then
  442. * also perform its last rites. Note that updates to the databases need
  443. * to happen at a lower irql than DISPATCH_LEVEL. For this reason these
  444. * activities have to be queued up for the scavenger to handle.
  445. *
  446. * LOCKS: vds_VolLock (SPIN)
  447. *
  448. * Callable from DISPATCH_LEVEL.
  449. *
  450. * NOTE: This should be re-entrant.
  451. */
  452. VOID FASTCALL
  453. AfpVolumeDereference(
  454. IN PVOLDESC pVolDesc
  455. )
  456. {
  457. KIRQL OldIrql;
  458. BOOLEAN Cleanup = False;
  459. ASSERT (pVolDesc != NULL);
  460. ASSERT (VALID_VOLDESC(pVolDesc));
  461. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  462. ASSERT (pVolDesc->vds_RefCount >= pVolDesc->vds_UseCount);
  463. pVolDesc->vds_RefCount --;
  464. if ((pVolDesc->vds_RefCount == 0) &&
  465. (pVolDesc->vds_Flags & (VOLUME_DELETED | VOLUME_STOPPED)))
  466. Cleanup = True;
  467. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  468. if (Cleanup)
  469. {
  470. if ((pVolDesc->vds_Flags & VOLUME_INITIAL_CACHE) &&
  471. !(pVolDesc->vds_Flags & VOLUME_INTRANSITION))
  472. {
  473. // set this so we don't reset the Indexing global flag again!
  474. pVolDesc->vds_Flags |= VOLUME_INTRANSITION;
  475. }
  476. ASSERT((pVolDesc->vds_UseCount == 0) &&
  477. (pVolDesc->vds_pOpenForkDesc == NULL));
  478. // We have to defer the actual close of the volume root handle to the
  479. // scavenger, if we are at DISPATCH_LEVEL.
  480. if (OldIrql == DISPATCH_LEVEL)
  481. {
  482. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  483. ("AfpVolumeDereference: Queuing Close&Free to Scavenger\n"));
  484. AfpScavengerScheduleEvent(afpVolumeCloseHandleAndFreeDesc,
  485. pVolDesc,
  486. 0,
  487. True);
  488. }
  489. else
  490. {
  491. afpVolumeCloseHandleAndFreeDesc(pVolDesc);
  492. }
  493. }
  494. }
  495. /*** AfpVolumeMarkDt
  496. *
  497. * Set the ConnDesc for this volume to indicate that the desktop is
  498. * opened/closed.
  499. *
  500. * LOCKS: cds_ConnLock (SPIN)
  501. *
  502. * Callable from DISPATCH_LEVEL.
  503. */
  504. BOOLEAN
  505. AfpVolumeMarkDt(
  506. IN PSDA pSda,
  507. IN PCONNDESC pConnDesc,
  508. IN DWORD OpenState
  509. )
  510. {
  511. BOOLEAN Success = True;
  512. ACQUIRE_SPIN_LOCK_AT_DPC(&pConnDesc->cds_ConnLock);
  513. if (OpenState)
  514. {
  515. pConnDesc->cds_Flags |= CONN_DESKTOP_OPENED;
  516. }
  517. else if (pConnDesc->cds_Flags & CONN_DESKTOP_OPENED)
  518. {
  519. pConnDesc->cds_Flags &= ~CONN_DESKTOP_OPENED;
  520. }
  521. else
  522. {
  523. Success = False;
  524. }
  525. RELEASE_SPIN_LOCK_FROM_DPC(&pConnDesc->cds_ConnLock);
  526. return Success;
  527. }
  528. /*** AfpVolumeSetModifiedTime
  529. *
  530. * Set the Volume Modified time for this volume to the current time.
  531. *
  532. * Callable from DISPATCH_LEVEL.
  533. *
  534. * LOCKS: vds_VolLock (SPIN)
  535. */
  536. VOID FASTCALL
  537. AfpVolumeSetModifiedTime(
  538. IN PVOLDESC pVolDesc
  539. )
  540. {
  541. KIRQL OldIrql;
  542. AFPTIME OriginalTime;
  543. DWORD dwSchedDelay;
  544. BOOLEAN fSendNotification=FALSE;
  545. // ASSERT (IS_VOLUME_NTFS(pVolDesc));
  546. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  547. OriginalTime = pVolDesc->vds_ModifiedTime;
  548. AfpGetCurrentTimeInMacFormat(&pVolDesc->vds_ModifiedTime);
  549. pVolDesc->vds_Flags |= VOLUME_IDDBHDR_DIRTY;
  550. //
  551. // volume was modified: need to inform all the Afp22 clients
  552. //
  553. if ((pVolDesc->vds_ModifiedTime > OriginalTime) &&
  554. ((pVolDesc->vds_Flags & (VOLUME_DELETED |
  555. VOLUME_STOPPED |
  556. VOLUME_INTRANSITION )) == 0))
  557. {
  558. fSendNotification = TRUE;
  559. // put SendNotif refcount
  560. pVolDesc->vds_RefCount++;
  561. //
  562. // if we don't have a notification pending, reset our MustSend clock!
  563. // (idea here is that if there are too many notifications happening withing
  564. // a very short time, we don't want to send a notification for every change,
  565. // but at the same time, don't want to wait beyond AFP_MAX_SRVR_NOTIF_INTERVAL
  566. // to send a notification).
  567. //
  568. if (!(pVolDesc->vds_Flags & VOLUME_SRVR_NOTIF_PENDING))
  569. {
  570. dwSchedDelay = AFP_MIN_SRVR_NOTIF_INTERVAL;
  571. pVolDesc->vds_TimeToSendNotify =
  572. AfpSecondsSinceEpoch + AFP_MIN_SRVR_NOTIF_INTERVAL;
  573. pVolDesc->vds_TimeMustSendNotify =
  574. AfpSecondsSinceEpoch + AFP_MAX_SRVR_NOTIF_INTERVAL;
  575. pVolDesc->vds_Flags |= VOLUME_SRVR_NOTIF_PENDING;
  576. }
  577. // advance the next send time by a second
  578. else
  579. {
  580. if (pVolDesc->vds_TimeToSendNotify >= AfpSecondsSinceEpoch)
  581. {
  582. pVolDesc->vds_TimeToSendNotify = pVolDesc->vds_TimeToSendNotify + 1;
  583. }
  584. else
  585. {
  586. pVolDesc->vds_TimeToSendNotify = AfpSecondsSinceEpoch + 1;
  587. }
  588. dwSchedDelay = (pVolDesc->vds_TimeToSendNotify - AfpSecondsSinceEpoch);
  589. }
  590. }
  591. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  592. // if necessary, tell those AFP22 clients that volume mod time changed
  593. if (fSendNotification)
  594. {
  595. AfpScavengerScheduleEvent(AfpSendServerNotification,
  596. pVolDesc,
  597. dwSchedDelay,
  598. True);
  599. }
  600. }
  601. AFPSTATUS FASTCALL
  602. AfpSendServerNotification(
  603. IN PVOLDESC pVolDesc
  604. )
  605. {
  606. KIRQL OldIrql;
  607. PSDA pSda;
  608. PSDA pSdaNext;
  609. PCONNDESC pConnDesc;
  610. BOOLEAN fSendOnThisSda;
  611. BOOLEAN fMustSend=FALSE;
  612. ASSERT (VALID_VOLDESC(pVolDesc));
  613. // ASSERT (IS_VOLUME_NTFS(pVolDesc));
  614. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  615. // is the volume shutting down? if so, don't do anything
  616. if (pVolDesc->vds_Flags & (VOLUME_DELETED |
  617. VOLUME_STOPPED |
  618. VOLUME_INTRANSITION))
  619. {
  620. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  621. // remove the SendNotif refcount
  622. AfpVolumeDereference(pVolDesc);
  623. return(AFP_ERR_NONE);
  624. }
  625. // is it time to send the notify?
  626. if (AfpSecondsSinceEpoch >= pVolDesc->vds_TimeToSendNotify)
  627. {
  628. fMustSend = TRUE;
  629. }
  630. //
  631. // has it been a while since we sent a notify? This would happen if a there is
  632. // a big tree copy going on the server which keeps pushing vds_TimeToSendNotify
  633. // forward, so AfpSecondsSinceEpoch is never less or equal to it.
  634. //
  635. else if (AfpSecondsSinceEpoch >= pVolDesc->vds_TimeMustSendNotify)
  636. {
  637. fMustSend = TRUE;
  638. }
  639. if (fMustSend)
  640. {
  641. pVolDesc->vds_Flags &= ~VOLUME_SRVR_NOTIF_PENDING;
  642. pVolDesc->vds_TimeMustSendNotify = AfpSecondsSinceEpoch;
  643. }
  644. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  645. if (!fMustSend)
  646. {
  647. // remove the SendNotif refcount
  648. AfpVolumeDereference(pVolDesc);
  649. return(AFP_ERR_NONE);
  650. }
  651. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  652. for (pSda = AfpSessionList; pSda != NULL; pSda = pSdaNext)
  653. {
  654. pSdaNext = pSda->sda_Next;
  655. ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
  656. //
  657. // if the sda is closing, or if the client is older than version AFP2.2 or if
  658. // we have just sent the notify to the client, skip this sda
  659. //
  660. if ((pSda->sda_Flags & (SDA_CLOSING | SDA_SESSION_CLOSED | SDA_CLIENT_CLOSE)) ||
  661. (pSda->sda_ClientVersion < AFP_VER_22) ||
  662. (pSda->sda_Flags & SDA_SESSION_NOTIFY_SENT))
  663. {
  664. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  665. continue;
  666. }
  667. //
  668. // find out if this session has mounted this volume. Only if it is, we
  669. // send notification to this session
  670. //
  671. fSendOnThisSda = FALSE;
  672. pConnDesc = pSda->sda_pConnDesc;
  673. while (pConnDesc != NULL)
  674. {
  675. ASSERT(VALID_CONNDESC(pConnDesc));
  676. if (pConnDesc->cds_pVolDesc == pVolDesc)
  677. {
  678. fSendOnThisSda = TRUE;
  679. pSda->sda_RefCount ++;
  680. break;
  681. }
  682. pConnDesc = pConnDesc->cds_Next;
  683. }
  684. pSda->sda_Flags |= SDA_SESSION_NOTIFY_SENT;
  685. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  686. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  687. if (fSendOnThisSda)
  688. {
  689. AfpSpSendAttention(pSda, ATTN_SERVER_NOTIFY, False);
  690. AfpSdaDereferenceSession(pSda);
  691. }
  692. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  693. pSdaNext = AfpSessionList;
  694. }
  695. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  696. //
  697. // now, go back and reset that flag
  698. //
  699. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  700. for (pSda = AfpSessionList; pSda != NULL; pSda = pSda->sda_Next)
  701. {
  702. pSdaNext = pSda->sda_Next;
  703. ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
  704. pSda->sda_Flags &= ~SDA_SESSION_NOTIFY_SENT;
  705. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  706. }
  707. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  708. // remove the SendNotif refcount
  709. AfpVolumeDereference(pVolDesc);
  710. return(AFP_ERR_NONE);
  711. }
  712. /*** AfpConnectionReference
  713. *
  714. * Map the volume id to a pointer to the connection descriptor. Traverse the
  715. * list starting from the Sda. Since the open volume can be reference from
  716. * both the session using it as well as the worker serving admin requests,
  717. * we need a lock.
  718. *
  719. * LOCKS: AfpConnLock, vds_VolLock (SPIN), cds_ConnLock (SPIN).
  720. *
  721. * LOCK_ORDER: vds_VolLock after cds_ConnLock. (via AfpVolumeReference)
  722. *
  723. * Callable from DISPATCH_LEVEL.
  724. */
  725. PCONNDESC FASTCALL
  726. AfpConnectionReference(
  727. IN PSDA pSda,
  728. IN LONG VolId
  729. )
  730. {
  731. PCONNDESC pConnDesc;
  732. KIRQL OldIrql;
  733. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  734. pConnDesc = AfpConnectionReferenceAtDpc(pSda, VolId);
  735. KeLowerIrql(OldIrql);
  736. return pConnDesc;
  737. }
  738. /*** AfpConnectionReferenceAtDpc
  739. *
  740. * Map the volume id to a pointer to the connection descriptor. Traverse the
  741. * list starting from the Sda. Since the open volume can be reference from
  742. * both the session using it as well as the worker serving admin requests,
  743. * we need a lock.
  744. *
  745. * LOCKS: AfpConnLock, vds_VolLock (SPIN), cds_ConnLock (SPIN).
  746. *
  747. * LOCK_ORDER: vds_VolLock after cds_ConnLock. (via AfpVolumeReference)
  748. *
  749. * Callable from DISPATCH_LEVEL ONLY
  750. */
  751. PCONNDESC FASTCALL
  752. AfpConnectionReferenceAtDpc(
  753. IN PSDA pSda,
  754. IN LONG VolId
  755. )
  756. {
  757. PCONNDESC pConnDesc, pCD = NULL;
  758. PVOLDESC pVolDesc;
  759. ASSERT (VALID_SDA(pSda) && (VolId != 0));
  760. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  761. ACQUIRE_SPIN_LOCK_AT_DPC(&AfpConnLock);
  762. for (pConnDesc = pSda->sda_pConnDesc;
  763. pConnDesc != NULL;
  764. pConnDesc = pConnDesc->cds_Next)
  765. {
  766. if (pConnDesc->cds_pVolDesc->vds_VolId == VolId)
  767. break;
  768. }
  769. RELEASE_SPIN_LOCK_FROM_DPC(&AfpConnLock);
  770. if (pConnDesc != NULL)
  771. {
  772. ASSERT(VALID_CONNDESC(pConnDesc));
  773. pVolDesc = pConnDesc->cds_pVolDesc;
  774. ASSERT(VALID_VOLDESC(pVolDesc));
  775. ACQUIRE_SPIN_LOCK_AT_DPC(&pConnDesc->cds_ConnLock);
  776. if ((pConnDesc->cds_Flags & CONN_CLOSING) == 0)
  777. {
  778. pCD = pConnDesc;
  779. pConnDesc->cds_RefCount ++;
  780. }
  781. RELEASE_SPIN_LOCK_FROM_DPC(&pConnDesc->cds_ConnLock);
  782. }
  783. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  784. ("AfpConnectionReferenence: VolId %d, pConnDesc %lx\n", VolId, pConnDesc));
  785. return pCD;
  786. }
  787. /*** AfpConnectionReferenceByPointer
  788. *
  789. * Reference the Connection descriptor. This is used by the admin APIs.
  790. *
  791. * LOCKS: vds_VolLock (SPIN), cds_ConnLock (SPIN).
  792. *
  793. * LOCK_ORDER: vds_VolLock after cds_ConnLock. (via AfpVolumeReference)
  794. *
  795. * Callable from DISPATCH_LEVEL.
  796. */
  797. PCONNDESC FASTCALL
  798. AfpConnectionReferenceByPointer(
  799. IN PCONNDESC pConnDesc
  800. )
  801. {
  802. PCONNDESC pCD = NULL;
  803. PVOLDESC pVolDesc;
  804. KIRQL OldIrql;
  805. ASSERT (VALID_CONNDESC(pConnDesc));
  806. pVolDesc = pConnDesc->cds_pVolDesc;
  807. ASSERT(VALID_VOLDESC(pVolDesc));
  808. ACQUIRE_SPIN_LOCK(&pConnDesc->cds_ConnLock, &OldIrql);
  809. if ((pConnDesc->cds_Flags & CONN_CLOSING) == 0)
  810. {
  811. pConnDesc->cds_RefCount ++;
  812. pCD = pConnDesc;
  813. }
  814. RELEASE_SPIN_LOCK(&pConnDesc->cds_ConnLock, OldIrql);
  815. return pCD;
  816. }
  817. /*** afpConnectionReferenceById
  818. *
  819. * Map the Connection id to a pointer to the connection descriptor.
  820. * Traverse the list starting from the AfpConnList. This is called by
  821. * the Admin CloseConnection API.
  822. *
  823. * LOCKS: AfpConnLock, cds_ConnLock (SPIN).
  824. *
  825. * LOCK_ORDER: vds_VolLock after cds_ConnLock. (via AfpVolumeReference)
  826. *
  827. * Callable from DISPATCH_LEVEL.
  828. */
  829. LOCAL PCONNDESC FASTCALL
  830. afpConnectionReferenceById(
  831. IN DWORD ConnId
  832. )
  833. {
  834. PCONNDESC pConnDesc;
  835. PCONNDESC pRetConnDesc=NULL;
  836. PVOLDESC pVolDesc;
  837. KIRQL OldIrql;
  838. ASSERT (ConnId != 0);
  839. ACQUIRE_SPIN_LOCK(&AfpConnLock, &OldIrql);
  840. for (pConnDesc = AfpConnList;
  841. pConnDesc != NULL;
  842. pConnDesc = pConnDesc->cds_NextGlobal)
  843. {
  844. if (pConnDesc->cds_ConnId == ConnId)
  845. break;
  846. }
  847. if (pConnDesc != NULL)
  848. {
  849. ASSERT(VALID_CONNDESC(pConnDesc));
  850. #if DBG
  851. pVolDesc = pConnDesc->cds_pVolDesc;
  852. ASSERT(VALID_VOLDESC(pVolDesc));
  853. #endif
  854. ACQUIRE_SPIN_LOCK_AT_DPC(&pConnDesc->cds_ConnLock);
  855. if ((pConnDesc->cds_Flags & CONN_CLOSING) == 0)
  856. {
  857. pConnDesc->cds_RefCount ++;
  858. pRetConnDesc = pConnDesc;
  859. }
  860. RELEASE_SPIN_LOCK_FROM_DPC(&pConnDesc->cds_ConnLock);
  861. }
  862. RELEASE_SPIN_LOCK(&AfpConnLock, OldIrql);
  863. return pRetConnDesc;
  864. }
  865. /*** AfpConnectionDereference
  866. *
  867. * Dereference the open volume. If this is the last reference to it and the
  868. * connection is marked to shut down, perform its last rites.
  869. *
  870. * LOCKS: vds_VolLock (SPIN), cds_ConnLock (SPIN), AfpConnLock (SPIN)
  871. *
  872. * LOCK_ORDER: vds_VolLock after cds_ConnLock
  873. *
  874. * Callable from DISPATCH_LEVEL.
  875. */
  876. VOID FASTCALL
  877. AfpConnectionDereference(
  878. IN PCONNDESC pConnDesc
  879. )
  880. {
  881. PCONNDESC * ppConnDesc;
  882. KIRQL OldIrql;
  883. PSDA pSda;
  884. PVOLDESC pVolDesc;
  885. BOOLEAN Cleanup;
  886. ASSERT (VALID_CONNDESC(pConnDesc) && (pConnDesc->cds_pVolDesc != NULL));
  887. ASSERT (pConnDesc->cds_RefCount > 0);
  888. ACQUIRE_SPIN_LOCK(&pConnDesc->cds_ConnLock, &OldIrql);
  889. Cleanup = (--(pConnDesc->cds_RefCount) == 0);
  890. RELEASE_SPIN_LOCK(&pConnDesc->cds_ConnLock, OldIrql);
  891. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  892. ("AfpConnectionDereferenence: pConnDesc %lx %s\n", pConnDesc,
  893. Cleanup ? "cleanup" : "normal"));
  894. if (!Cleanup)
  895. {
  896. return;
  897. }
  898. ASSERT(pConnDesc->cds_Flags & CONN_CLOSING);
  899. // Unlink this from the global list
  900. ACQUIRE_SPIN_LOCK(&AfpConnLock, &OldIrql);
  901. for (ppConnDesc = &AfpConnList;
  902. *ppConnDesc != NULL;
  903. ppConnDesc = &(*ppConnDesc)->cds_NextGlobal)
  904. {
  905. if (pConnDesc == *ppConnDesc)
  906. break;
  907. }
  908. ASSERT (*ppConnDesc != NULL);
  909. *ppConnDesc = pConnDesc->cds_NextGlobal;
  910. pVolDesc = pConnDesc->cds_pVolDesc;
  911. RELEASE_SPIN_LOCK(&AfpConnLock, OldIrql);
  912. INTERLOCKED_ADD_ULONG(&pVolDesc->vds_UseCount,
  913. (DWORD)-1,
  914. &pVolDesc->vds_VolLock);
  915. ACQUIRE_SPIN_LOCK(&pConnDesc->cds_ConnLock, &OldIrql);
  916. // Now unlink it from the Sda.
  917. pSda = pConnDesc->cds_pSda;
  918. for (ppConnDesc = &pSda->sda_pConnDesc;
  919. *ppConnDesc != NULL;
  920. ppConnDesc = &(*ppConnDesc)->cds_Next)
  921. {
  922. if (pConnDesc == *ppConnDesc)
  923. break;
  924. }
  925. ASSERT (*ppConnDesc != NULL);
  926. *ppConnDesc = pConnDesc->cds_Next;
  927. // Even though the connection is now history we need to release this
  928. // lock to get the right IRQL back.
  929. RELEASE_SPIN_LOCK(&pConnDesc->cds_ConnLock, OldIrql);
  930. INTERLOCKED_ADD_ULONG(&pSda->sda_cOpenVolumes,
  931. (ULONG)-1,
  932. &pSda->sda_Lock);
  933. // De-reference the volume descriptor and free the connection descriptor
  934. AfpVolumeDereference(pConnDesc->cds_pVolDesc);
  935. if (pConnDesc->cds_pEnumDir != NULL)
  936. AfpFreeMemory(pConnDesc->cds_pEnumDir);
  937. // Finally free the connection descriptor
  938. AfpFreeMemory(pConnDesc);
  939. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  940. ("AfpConnectionDereferenence: pConnDesc %lx is history\n", pConnDesc));
  941. }
  942. /*** AfpConnectionOpen
  943. *
  944. * Open the specified volume. If the volume is already open this translates
  945. * to a NOP. If the volume has a password, then it is checked.
  946. *
  947. * The volume list lock is obtained for the duration of the processing.
  948. *
  949. * Callable from DISPATCH_LEVEL.
  950. *
  951. * LOCKS: AfpVolumeListLock (SPIN), vds_VolLock (SPIN)
  952. *
  953. * LOCK_ORDER: vds_VolLock after AfpVolumeListLock
  954. */
  955. AFPSTATUS
  956. AfpConnectionOpen(
  957. IN PSDA pSda,
  958. IN PANSI_STRING pVolName,
  959. IN PANSI_STRING pVolPass,
  960. IN DWORD Bitmap,
  961. OUT PBYTE pVolParms
  962. )
  963. {
  964. PVOLDESC pVolDesc;
  965. PCONNDESC pConnDesc;
  966. AFPSTATUS Status = AFP_ERR_NONE;
  967. KIRQL OldIrql;
  968. BOOLEAN VolFound = False;
  969. // First find the volume descriptor for this volume
  970. if (KeGetCurrentIrql() == DISPATCH_LEVEL)
  971. {
  972. ACQUIRE_SPIN_LOCK_AT_DPC(&AfpVolumeListLock);
  973. for (pVolDesc = AfpVolumeList;
  974. pVolDesc != NULL;
  975. pVolDesc = pVolDesc->vds_Next)
  976. {
  977. // Ignore volumes that are in the process of being added but
  978. // the operation has not completed yet.
  979. ACQUIRE_SPIN_LOCK_AT_DPC(&pVolDesc->vds_VolLock);
  980. if ((pVolDesc->vds_Flags & (VOLUME_CDFS_INVALID |
  981. VOLUME_INTRANSITION |
  982. VOLUME_INITIAL_CACHE |
  983. VOLUME_DELETED |
  984. VOLUME_STOPPED)) == 0)
  985. {
  986. // The compare is case sensitive here
  987. if (EQUAL_STRING(&pVolDesc->vds_MacName, pVolName, False))
  988. {
  989. //
  990. // if DiskQuota is enabled, we need to first find out the
  991. // quota for this user which we cannot do at dpc: so come
  992. // back at task time
  993. //
  994. if (pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
  995. {
  996. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  997. ("AfpConnectionOpen: %lx disk-quota on, queuing\n",pVolDesc));
  998. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  999. RELEASE_SPIN_LOCK_FROM_DPC(&AfpVolumeListLock);
  1000. return AFP_ERR_QUEUE;
  1001. }
  1002. else // DiskQuota is not enabled: go ahead and process at DPC
  1003. {
  1004. pVolDesc->vds_RefCount ++;
  1005. pVolDesc->vds_UseCount ++;
  1006. VolFound = True;
  1007. }
  1008. }
  1009. }
  1010. #if DBG
  1011. else if (pVolDesc->vds_Flags & VOLUME_CDFS_INVALID)
  1012. ASSERT (!IS_VOLUME_NTFS(pVolDesc));
  1013. #endif
  1014. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1015. if (VolFound)
  1016. break;
  1017. }
  1018. RELEASE_SPIN_LOCK_FROM_DPC(&AfpVolumeListLock);
  1019. if (pVolDesc == NULL)
  1020. {
  1021. return AFP_ERR_QUEUE;
  1022. }
  1023. }
  1024. else
  1025. {
  1026. // We are here because we did not find the volume at DISPATCH_LEVEL and
  1027. // possibly the volume has been specified with a different case. Catch
  1028. // this
  1029. WCHAR VolNameBuf[AFP_VOLNAME_LEN + 1];
  1030. WCHAR UpCasedNameBuffer[AFP_VOLNAME_LEN + 1];
  1031. UNICODE_STRING UpCasedVolName;
  1032. UNICODE_STRING UVolName;
  1033. pVolDesc = NULL;
  1034. AfpSetEmptyUnicodeString(&UVolName, sizeof(VolNameBuf), VolNameBuf);
  1035. AfpSetEmptyUnicodeString(&UpCasedVolName, sizeof(UpCasedNameBuffer), UpCasedNameBuffer);
  1036. Status = AfpConvertStringToUnicode(pVolName, &UVolName);
  1037. ASSERT (NT_SUCCESS(Status));
  1038. Status = RtlUpcaseUnicodeString(&UpCasedVolName, &UVolName, False);
  1039. if (!NT_SUCCESS(Status))
  1040. {
  1041. return(AFP_ERR_PARAM);
  1042. }
  1043. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  1044. for (pVolDesc = AfpVolumeList;
  1045. pVolDesc != NULL;
  1046. pVolDesc = pVolDesc->vds_Next)
  1047. {
  1048. // Ignore volumes that are in the process of being added but
  1049. // the operation has not completed yet.
  1050. ACQUIRE_SPIN_LOCK_AT_DPC(&pVolDesc->vds_VolLock);
  1051. if ((pVolDesc->vds_Flags & (VOLUME_CDFS_INVALID |
  1052. VOLUME_INTRANSITION |
  1053. VOLUME_INITIAL_CACHE |
  1054. VOLUME_DELETED |
  1055. VOLUME_STOPPED)) == 0)
  1056. {
  1057. if (AfpEqualUnicodeString(&pVolDesc->vds_UpCaseName,
  1058. &UpCasedVolName))
  1059. {
  1060. pVolDesc->vds_RefCount ++;
  1061. pVolDesc->vds_UseCount ++;
  1062. VolFound = True;
  1063. }
  1064. }
  1065. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1066. if (VolFound)
  1067. break;
  1068. }
  1069. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  1070. if (pVolDesc == NULL)
  1071. {
  1072. return AFP_ERR_PARAM;
  1073. }
  1074. }
  1075. ASSERT (pVolDesc != NULL);
  1076. do
  1077. {
  1078. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  1079. // Check for volume password, if one exists. Volume password is
  1080. // case sensitive.
  1081. if ((pVolDesc->vds_Flags & AFP_VOLUME_HASPASSWORD) &&
  1082. ((pVolPass->Buffer == NULL) ||
  1083. (!EQUAL_STRING(pVolPass, &pVolDesc->vds_MacPassword, False))))
  1084. {
  1085. Status = AFP_ERR_ACCESS_DENIED;
  1086. break;
  1087. }
  1088. // Check if the volume is already open
  1089. for (pConnDesc = pSda->sda_pConnDesc;
  1090. pConnDesc != NULL;
  1091. pConnDesc = pConnDesc->cds_Next)
  1092. {
  1093. if (pConnDesc->cds_pVolDesc == pVolDesc)
  1094. {
  1095. if (pConnDesc->cds_Flags & CONN_CLOSING)
  1096. continue;
  1097. // Dereference the volume since we already have it open
  1098. pVolDesc->vds_RefCount --;
  1099. pVolDesc->vds_UseCount --;
  1100. break;
  1101. }
  1102. }
  1103. // This volume is already open. Unlock the volume.
  1104. if (pConnDesc != NULL)
  1105. {
  1106. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  1107. break;
  1108. }
  1109. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  1110. ("AfpConnectionOpen: Opening a fresh connection volid=%d\n",
  1111. pVolDesc->vds_VolId));
  1112. // This is a fresh open. Check if we have access to it and if we satisfy
  1113. // the MAXUSES. If not dereference the volume before we quit
  1114. if ((pVolDesc->vds_UseCount > pVolDesc->vds_MaxUses) ||
  1115. (!(pVolDesc->vds_Flags & AFP_VOLUME_GUESTACCESS) &&
  1116. (pSda->sda_ClientType == SDA_CLIENT_GUEST)))
  1117. {
  1118. Status = AFP_ERR_TOO_MANY_FILES_OPEN;
  1119. break;
  1120. }
  1121. // All is hunky-dory. Go ahead with the open
  1122. pConnDesc = (PCONNDESC)AfpAllocZeroedNonPagedMemory(sizeof(CONNDESC));
  1123. if (pConnDesc == NULL)
  1124. {
  1125. Status = AFP_ERR_MISC;
  1126. break;
  1127. }
  1128. ASSERT ((pVolDesc->vds_Flags & (VOLUME_DELETED | VOLUME_STOPPED)) == 0);
  1129. // Now release the vds_VolLock before we acquire the link it into
  1130. // the global list since we acquire the AfpConnLock then.
  1131. // Re-acquire it when we are done. We are safe since the VolDesc has
  1132. // been referenced
  1133. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  1134. // Initialize the connection structure fields
  1135. #if DBG
  1136. pConnDesc->Signature = CONNDESC_SIGNATURE;
  1137. #endif
  1138. pConnDesc->cds_pSda = pSda;
  1139. pConnDesc->cds_pVolDesc = pVolDesc;
  1140. pConnDesc->cds_RefCount = 1; // Creation reference
  1141. AfpGetCurrentTimeInMacFormat(&pConnDesc->cds_TimeOpened);
  1142. INITIALIZE_SPIN_LOCK(&pConnDesc->cds_ConnLock);
  1143. // Assign a new connection id and link it in the global connection list.
  1144. afpConnectionGetNewIdAndLinkToList(pConnDesc);
  1145. // Link the new ConnDesc into the sda.
  1146. pConnDesc->cds_Next = pSda->sda_pConnDesc;
  1147. pSda->sda_pConnDesc = pConnDesc;
  1148. pSda->sda_cOpenVolumes ++;
  1149. } while (False);
  1150. // We are holding the vds_VolLock if an error occured. The volume has a
  1151. // usecount and reference count which we need to get rid of.
  1152. if (!NT_SUCCESS(Status))
  1153. {
  1154. pVolDesc->vds_RefCount --;
  1155. pVolDesc->vds_UseCount --;
  1156. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  1157. }
  1158. else
  1159. {
  1160. //
  1161. // if disk-quota is enabled on this volume, get this user's quota info
  1162. //
  1163. if (pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
  1164. {
  1165. ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
  1166. // up the refcount (this can't fail: we just created the thing!)
  1167. AfpConnectionReferenceByPointer(pConnDesc);
  1168. afpUpdateDiskQuotaInfo(pConnDesc);
  1169. }
  1170. else
  1171. {
  1172. // initialize these to something meaningful for now
  1173. pConnDesc->cds_QuotaLimit = pVolDesc->vds_VolumeSize;
  1174. pConnDesc->cds_QuotaAvl = pVolDesc->vds_FreeBytes;
  1175. }
  1176. AfpVolumePackParms(pSda, pVolDesc, Bitmap, pVolParms);
  1177. }
  1178. return Status;
  1179. }
  1180. /*** AfpConnectionClose
  1181. *
  1182. * Close the connection - this represents an open volume.
  1183. */
  1184. VOID FASTCALL
  1185. AfpConnectionClose(
  1186. IN PCONNDESC pConnDesc
  1187. )
  1188. {
  1189. KIRQL OldIrql;
  1190. ASSERT (VALID_CONNDESC(pConnDesc));
  1191. ASSERT (pConnDesc->cds_RefCount > 1);
  1192. ASSERT ((pConnDesc->cds_Flags & CONN_CLOSING) == 0);
  1193. ACQUIRE_SPIN_LOCK(&pConnDesc->cds_ConnLock, &OldIrql);
  1194. pConnDesc->cds_Flags |= CONN_CLOSING;
  1195. RELEASE_SPIN_LOCK(&pConnDesc->cds_ConnLock, OldIrql);
  1196. // Take away the creation reference.
  1197. AfpConnectionDereference(pConnDesc);
  1198. }
  1199. /*** AfpVolumeGetParmsReplyLength
  1200. *
  1201. * Compute the size of buffer required to copy the volume parameters based
  1202. * on the bitmap.
  1203. */
  1204. USHORT FASTCALL
  1205. AfpVolumeGetParmsReplyLength(
  1206. IN DWORD Bitmap,
  1207. IN USHORT NameLen
  1208. )
  1209. {
  1210. LONG i;
  1211. USHORT Size = sizeof(USHORT); // to accomodate a copy of the bitmap
  1212. static BYTE Bitmap2Size[12] =
  1213. {
  1214. sizeof(USHORT), // Attributes
  1215. sizeof(USHORT), // Signature
  1216. sizeof(DWORD), // Creation date
  1217. sizeof(DWORD), // Mod date
  1218. sizeof(DWORD), // Backup date
  1219. sizeof(USHORT), // Volume Id
  1220. sizeof(DWORD), // Bytes Free
  1221. sizeof(DWORD), // Bytes total
  1222. sizeof(USHORT) + sizeof(BYTE), // Volume name
  1223. sizeof(DWORD) + sizeof(DWORD), // Extended Bytes Free
  1224. sizeof(DWORD) + sizeof(DWORD), // Extended Bytes Total
  1225. sizeof(DWORD) // Allocation Block size
  1226. };
  1227. ASSERT ((Bitmap & ~VOL_BITMAP_MASK) == 0);
  1228. if (Bitmap & VOL_BITMAP_VOLUMENAME)
  1229. Size += NameLen;
  1230. for (i = 0; Bitmap; i++)
  1231. {
  1232. if (Bitmap & 1)
  1233. Size += (USHORT)Bitmap2Size[i];
  1234. Bitmap >>= 1;
  1235. }
  1236. return Size;
  1237. }
  1238. /*** AfpVolumePackParms
  1239. *
  1240. * Pack the volume parameters in the reply buffer. The AfpVolumeListLock is taken
  1241. * before the volume parameters are accessed. The parameters are copied in
  1242. * the on-the-wire format.
  1243. *
  1244. * LOCKS: vds_VolLock (SPIN)
  1245. */
  1246. VOID
  1247. AfpVolumePackParms(
  1248. IN PSDA pSda,
  1249. IN PVOLDESC pVolDesc,
  1250. IN DWORD Bitmap,
  1251. OUT PBYTE pReplyBuf
  1252. )
  1253. {
  1254. int Offset = sizeof(USHORT);
  1255. KIRQL OldIrql;
  1256. DWORD Attr;
  1257. PCONNDESC pConnDesc;
  1258. PBYTE pVolNamePtr;
  1259. LARGE_INTEGER QuotaAvailable={0};
  1260. LARGE_INTEGER QuotaLimit={0};
  1261. // older Macs have problems with 2 or 4Gig volumes
  1262. LARGE_INTEGER TwoGig = { 0x7E200000, 0 };
  1263. LARGE_INTEGER FourGig = { 0xFFFFFFFF, 0 };
  1264. LARGE_INTEGER Limit;
  1265. BOOLEAN fAfp21OrOlderClient=TRUE;
  1266. //
  1267. // get this info out before we grab the pVolDesc lock
  1268. //
  1269. if (Bitmap & (VOL_BITMAP_BYTESFREE | VOL_BITMAP_VOLUMESIZE |
  1270. VOL_BITMAP_EXTBYTESFREE | VOL_BITMAP_EXTBYTESTOTAL))
  1271. {
  1272. QuotaLimit = pVolDesc->vds_VolumeSize;
  1273. QuotaAvailable = pVolDesc->vds_FreeBytes;
  1274. if (pSda->sda_ClientVersion >= AFP_VER_22)
  1275. {
  1276. fAfp21OrOlderClient = FALSE;
  1277. }
  1278. if (pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
  1279. {
  1280. pConnDesc = AfpConnectionReference(pSda, pVolDesc->vds_VolId);
  1281. if (pConnDesc)
  1282. {
  1283. ACQUIRE_SPIN_LOCK(&pConnDesc->cds_ConnLock, &OldIrql);
  1284. QuotaLimit = pConnDesc->cds_QuotaLimit;
  1285. // if user's available quota shows 10MB, but space left on the
  1286. // disk shows 3MB, we need to return 3MB (smaller of the two)
  1287. //
  1288. if (QuotaAvailable.QuadPart > pConnDesc->cds_QuotaAvl.QuadPart)
  1289. {
  1290. QuotaAvailable = pConnDesc->cds_QuotaAvl;
  1291. }
  1292. RELEASE_SPIN_LOCK(&pConnDesc->cds_ConnLock, OldIrql);
  1293. AfpConnectionDereference(pConnDesc);
  1294. }
  1295. }
  1296. //
  1297. // AFP2.1 and older clients can't handle more than 4GB (2GB if so configured)
  1298. // Lie to the client so it survives
  1299. //
  1300. if (fAfp21OrOlderClient)
  1301. {
  1302. Limit = ((AfpServerOptions & AFP_SRVROPT_4GB_VOLUMES) ||
  1303. (pVolDesc->vds_Flags & AFP_VOLUME_4GB)) ? FourGig : TwoGig;
  1304. if (QuotaLimit.QuadPart > Limit.QuadPart)
  1305. {
  1306. QuotaLimit = Limit;
  1307. }
  1308. if (QuotaAvailable.QuadPart > Limit.QuadPart)
  1309. {
  1310. QuotaAvailable = Limit;
  1311. }
  1312. }
  1313. else
  1314. {
  1315. Limit = FourGig;
  1316. }
  1317. }
  1318. // First copy the bitmap
  1319. PUTDWORD2SHORT(pReplyBuf, Bitmap);
  1320. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  1321. if (Bitmap & VOL_BITMAP_ATTR)
  1322. {
  1323. Attr = pVolDesc->vds_Flags & AFP_VOLUME_MASK_AFP;
  1324. if (pSda->sda_ClientVersion < AFP_VER_21)
  1325. Attr &= AFP_VOLUME_READONLY; // Do not give Afp 2.0 any more bits
  1326. PUTDWORD2SHORT(pReplyBuf + Offset, Attr);
  1327. Offset += sizeof(USHORT);
  1328. }
  1329. if (Bitmap & VOL_BITMAP_SIGNATURE)
  1330. {
  1331. PUTSHORT2SHORT(pReplyBuf + Offset, AFP_VOLUME_FIXED_DIR);
  1332. Offset += sizeof(USHORT);
  1333. }
  1334. if (Bitmap & VOL_BITMAP_CREATETIME)
  1335. {
  1336. PUTDWORD2DWORD(pReplyBuf + Offset, pVolDesc->vds_CreateTime);
  1337. Offset += sizeof(DWORD);
  1338. }
  1339. if (Bitmap & VOL_BITMAP_MODIFIEDTIME)
  1340. {
  1341. PUTDWORD2DWORD(pReplyBuf + Offset, pVolDesc->vds_ModifiedTime);
  1342. Offset += sizeof(DWORD);
  1343. }
  1344. if (Bitmap & VOL_BITMAP_BACKUPTIME)
  1345. {
  1346. PUTDWORD2DWORD(pReplyBuf + Offset, pVolDesc->vds_BackupTime);
  1347. Offset += sizeof(DWORD);
  1348. }
  1349. if (Bitmap & VOL_BITMAP_VOLUMEID)
  1350. {
  1351. PUTSHORT2SHORT(pReplyBuf + Offset, pVolDesc->vds_VolId);
  1352. Offset += sizeof(USHORT);
  1353. }
  1354. if (Bitmap & VOL_BITMAP_BYTESFREE)
  1355. {
  1356. //
  1357. // if this is a huge volume (and we are talking to an AFP2.2 or later client)
  1358. // we need to fill 4GB in this field
  1359. //
  1360. if (QuotaAvailable.QuadPart > Limit.QuadPart)
  1361. {
  1362. PUTDWORD2DWORD(pReplyBuf + Offset, Limit.LowPart);
  1363. Offset += sizeof(DWORD);
  1364. }
  1365. else
  1366. {
  1367. PUTDWORD2DWORD(pReplyBuf + Offset, QuotaAvailable.LowPart);
  1368. Offset += sizeof(DWORD);
  1369. }
  1370. }
  1371. if (Bitmap & VOL_BITMAP_VOLUMESIZE)
  1372. {
  1373. //
  1374. // if this is a huge volume (and we are talking to an AFP2.2 or later client)
  1375. // we need to fill 4GB in this field
  1376. //
  1377. if (QuotaLimit.QuadPart > Limit.QuadPart)
  1378. {
  1379. PUTDWORD2DWORD(pReplyBuf + Offset, Limit.LowPart);
  1380. Offset += sizeof(DWORD);
  1381. }
  1382. else
  1383. {
  1384. PUTDWORD2DWORD(pReplyBuf + Offset, QuotaLimit.LowPart);
  1385. Offset += sizeof(DWORD);
  1386. }
  1387. }
  1388. // save pointer to where we need to write the offset: we'll write at the
  1389. // end after we figure out where the name goes
  1390. if (Bitmap & VOL_BITMAP_VOLUMENAME)
  1391. {
  1392. pVolNamePtr = pReplyBuf + Offset;
  1393. Offset += sizeof(USHORT);
  1394. }
  1395. //
  1396. // 8-bytes to say how many free bytes there are
  1397. //
  1398. if (Bitmap & VOL_BITMAP_EXTBYTESFREE)
  1399. {
  1400. PUTDWORD2DWORD(pReplyBuf + Offset, QuotaAvailable.HighPart);
  1401. Offset += sizeof(DWORD);
  1402. PUTDWORD2DWORD(pReplyBuf + Offset, QuotaAvailable.LowPart);
  1403. Offset += sizeof(DWORD);
  1404. }
  1405. //
  1406. // 8-bytes to say how many bytes there are on the volume
  1407. //
  1408. if (Bitmap & VOL_BITMAP_EXTBYTESTOTAL)
  1409. {
  1410. PUTDWORD2DWORD(pReplyBuf + Offset, QuotaLimit.HighPart);
  1411. Offset += sizeof(DWORD);
  1412. PUTDWORD2DWORD(pReplyBuf + Offset, QuotaLimit.LowPart);
  1413. Offset += sizeof(DWORD);
  1414. }
  1415. //
  1416. // 4-bytes to say what is the block allocation size
  1417. //
  1418. if (Bitmap & VOL_BITMAP_ALLOCBLKSIZE)
  1419. {
  1420. PUTDWORD2DWORD(pReplyBuf + Offset, pVolDesc->vds_AllocationBlockSize);
  1421. Offset += sizeof(DWORD);
  1422. }
  1423. // now, write the volume name (if asked for), after writing the offset, now
  1424. // that we know it (subtract 2: we measure from parms, not Bitmap field)
  1425. if (Bitmap & VOL_BITMAP_VOLUMENAME)
  1426. {
  1427. PUTSHORT2SHORT(pVolNamePtr, (Offset - sizeof(USHORT)));
  1428. PUTSHORT2BYTE(pReplyBuf + Offset, pVolDesc->vds_MacName.Length);
  1429. Offset += sizeof(BYTE);
  1430. RtlCopyMemory(pReplyBuf + Offset,
  1431. pVolDesc->vds_MacName.Buffer,
  1432. pVolDesc->vds_MacName.Length);
  1433. }
  1434. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  1435. }
  1436. /*** AfpVolumeStopAllVolumes
  1437. *
  1438. * This is called at service stop time. All configured volumes are asked to
  1439. * stop. Wait for the actual stop to happen before returning.
  1440. *
  1441. * LOCKS: AfpVolumeListLock (SPIN), vds_VolLock
  1442. * LOCK_ORDER: vds_VolLock after AfpVolumeListLock
  1443. */
  1444. VOID
  1445. AfpVolumeStopAllVolumes(
  1446. VOID
  1447. )
  1448. {
  1449. KIRQL OldIrql;
  1450. PVOLDESC pVolDesc, pVolDescx = NULL;
  1451. BOOLEAN Wait, CancelNotify = False;
  1452. NTSTATUS Status;
  1453. pVolDesc = AfpVolumeList;
  1454. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  1455. if (Wait = (AfpVolCount > 0))
  1456. {
  1457. KeClearEvent(&AfpStopConfirmEvent);
  1458. for (NOTHING; pVolDesc != NULL; pVolDesc = pVolDesc->vds_Next)
  1459. {
  1460. if ((pVolDesc == pVolDescx) ||
  1461. (pVolDesc->vds_Flags & (VOLUME_STOPPED | VOLUME_DELETED)))
  1462. continue;
  1463. pVolDescx = pVolDesc;
  1464. ACQUIRE_SPIN_LOCK_AT_DPC(&pVolDesc->vds_VolLock);
  1465. // Cancel posted change notify
  1466. pVolDesc->vds_Flags |= VOLUME_STOPPED;
  1467. if (pVolDesc->vds_Flags & VOLUME_NOTIFY_POSTED)
  1468. {
  1469. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  1470. ("AfpStopAllVolumes: Cancel notify on volume %ld\n",
  1471. pVolDesc->vds_VolId));
  1472. // ASSERT (IS_VOLUME_NTFS(pVolDesc));
  1473. ASSERT (pVolDesc->vds_pIrp != NULL);
  1474. CancelNotify = True;
  1475. // Cancel after releasing the volume lock since the completion
  1476. // routine acquires it and it could be called in the context
  1477. // of IoCancelIrp(). Also Cancel uses paged resource and so
  1478. // must be called w/o holding any spin locks.
  1479. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1480. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  1481. IoCancelIrp(pVolDesc->vds_pIrp);
  1482. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  1483. }
  1484. else RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1485. // Remove the creation reference
  1486. AfpVolumeDereference(pVolDesc);
  1487. }
  1488. }
  1489. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  1490. if (CancelNotify)
  1491. {
  1492. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  1493. ("AfpStopAllVolumes: Waiting on all notify to complete\n"));
  1494. do
  1495. {
  1496. Status = AfpIoWait(&AfpStopConfirmEvent, &FiveSecTimeOut);
  1497. if (Status == STATUS_TIMEOUT)
  1498. {
  1499. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1500. ("AfpVolumeStopAllVolumes: Timeout Waiting for cancel notify, re-waiting\n"));
  1501. }
  1502. } while (Status == STATUS_TIMEOUT);
  1503. }
  1504. if (Wait)
  1505. {
  1506. KeClearEvent(&AfpStopConfirmEvent);
  1507. AfpScavengerFlushAndStop();
  1508. if (AfpVolCount > 0)
  1509. AfpIoWait(&AfpStopConfirmEvent, NULL);
  1510. }
  1511. else
  1512. {
  1513. AfpScavengerFlushAndStop();
  1514. }
  1515. }
  1516. /*** afpConnectionGetNewIdAndLinkToList
  1517. *
  1518. * Get a new connection id for a volume that is being opened. A connection
  1519. * id ranges from 1 to MAXULONG. If it wraps, then the entire connection
  1520. * list is scanned to get a free one.
  1521. *
  1522. * LOCKS: AfpConnectionLock (SPIN)
  1523. */
  1524. LOCAL VOID FASTCALL
  1525. afpConnectionGetNewIdAndLinkToList(
  1526. IN PCONNDESC pConnDesc
  1527. )
  1528. {
  1529. KIRQL OldIrql;
  1530. PCONNDESC * ppConnDesc;
  1531. ACQUIRE_SPIN_LOCK(&AfpConnLock, &OldIrql);
  1532. pConnDesc->cds_ConnId = afpNextConnId++;
  1533. for (ppConnDesc = &AfpConnList;
  1534. *ppConnDesc != NULL;
  1535. ppConnDesc = &(*ppConnDesc)->cds_NextGlobal)
  1536. {
  1537. if ((*ppConnDesc)->cds_ConnId < pConnDesc->cds_ConnId)
  1538. break;
  1539. }
  1540. pConnDesc->cds_NextGlobal = *ppConnDesc;
  1541. *ppConnDesc = pConnDesc;
  1542. RELEASE_SPIN_LOCK(&AfpConnLock, OldIrql);
  1543. }
  1544. /*** AfpVolumeUpdateIdDbAndDesktop
  1545. *
  1546. * Called by the volume scavenger to write either the IdDb header and/or the
  1547. * dektop to disk.
  1548. */
  1549. VOID
  1550. AfpVolumeUpdateIdDbAndDesktop(
  1551. IN PVOLDESC pVolDesc,
  1552. IN BOOLEAN WriteDt,
  1553. IN BOOLEAN WriteIdDb,
  1554. IN PIDDBHDR pIdDbHdr OPTIONAL
  1555. )
  1556. {
  1557. FILESYSHANDLE fshIdDb;
  1558. NTSTATUS Status;
  1559. BOOLEAN WriteBackROAttr = False;
  1560. TIME ModTime;
  1561. NTSTATUS ModStatus=AFP_ERR_MISC;
  1562. PAGED_CODE();
  1563. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1564. ("AfpVolumeUpdateIdDbAndDesktop: Called by volume scavenger\n") );
  1565. ModStatus = AfpIoRestoreTimeStamp(&pVolDesc->vds_hRootDir,
  1566. &ModTime,
  1567. AFP_RETRIEVE_MODTIME);
  1568. // If we need to update the IdIndex or Desktop streams, make sure
  1569. // the ReadOnly bit is not set on the volume root directory
  1570. AfpExamineAndClearROAttr(&pVolDesc->vds_hRootDir, &WriteBackROAttr, NULL, NULL);
  1571. // Update the disk image of the IdDb header and/or the whole database if it is dirty
  1572. if (WriteIdDb || ARGUMENT_PRESENT(pIdDbHdr))
  1573. {
  1574. if (NT_SUCCESS(Status = AfpIoOpen(&pVolDesc->vds_hRootDir,
  1575. AFP_STREAM_IDDB,
  1576. WriteIdDb ?
  1577. FILEIO_OPEN_FILE_SEQ : FILEIO_OPEN_FILE,
  1578. &UNullString,
  1579. FILEIO_ACCESS_WRITE,
  1580. FILEIO_DENY_WRITE,
  1581. False,
  1582. &fshIdDb)))
  1583. {
  1584. if (ARGUMENT_PRESENT(pIdDbHdr))
  1585. {
  1586. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1587. ("AfpVolumeUpdateIdDbAndDesktop: Writing IdDb Header...\n") );
  1588. if (!fAfpServerShutdownEvent)
  1589. {
  1590. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1591. ("AfpVolumeUpdateIdDbAndDesktop: Corrupting IDDB header\n"));
  1592. pIdDbHdr->idh_Signature = AFP_SERVER_SIGNATURE_INITIDDB;
  1593. }
  1594. if (!NT_SUCCESS(Status = AfpIoWrite(&fshIdDb,
  1595. &LIZero,
  1596. sizeof(IDDBHDR),
  1597. (PBYTE)pIdDbHdr)))
  1598. {
  1599. // Write failed, put back the dirty bit.
  1600. AfpInterlockedSetDword(&pVolDesc->vds_Flags,
  1601. VOLUME_IDDBHDR_DIRTY,
  1602. &pVolDesc->vds_VolLock);
  1603. AFPLOG_ERROR(AFPSRVMSG_WRITE_IDDB,
  1604. Status,
  1605. NULL,
  1606. 0,
  1607. &pVolDesc->vds_Name);
  1608. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1609. ("AfpVolumeUpdateIdDbAndDesktop: Error writing IdDb Header %lx\n",
  1610. Status));
  1611. }
  1612. }
  1613. if (WriteIdDb)
  1614. {
  1615. AfpFlushIdDb(pVolDesc, &fshIdDb);
  1616. }
  1617. AfpIoClose(&fshIdDb);
  1618. }
  1619. else
  1620. {
  1621. // Open failed, put back the dirty bit
  1622. AfpInterlockedSetDword(&pVolDesc->vds_Flags,
  1623. VOLUME_IDDBHDR_DIRTY,
  1624. &pVolDesc->vds_VolLock);
  1625. AFPLOG_ERROR(AFPSRVMSG_WRITE_IDDB,
  1626. Status,
  1627. NULL,
  1628. 0,
  1629. &pVolDesc->vds_Name);
  1630. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1631. ("AfpVolumeUpdateIdDbAndDesktop: Error opening IdDb Header %lx\n",
  1632. Status));
  1633. }
  1634. }
  1635. if (WriteDt)
  1636. {
  1637. AfpUpdateDesktop(pVolDesc);
  1638. }
  1639. AfpPutBackROAttr(&pVolDesc->vds_hRootDir, WriteBackROAttr);
  1640. if (ModStatus == AFP_ERR_NONE)
  1641. {
  1642. ModStatus = AfpIoRestoreTimeStamp(&pVolDesc->vds_hRootDir,
  1643. &ModTime,
  1644. AFP_RESTORE_MODTIME);
  1645. }
  1646. }
  1647. /*** afpNudgeCdfsVolume
  1648. *
  1649. * Called from within the volume scavenger to verify if either a CD which we
  1650. * believe to be valid is still so or one we believe to be invalid has become
  1651. * valid again.
  1652. */
  1653. LOCAL VOID FASTCALL
  1654. afpNudgeCdfsVolume(
  1655. IN PVOLDESC pVolDesc
  1656. )
  1657. {
  1658. PFILE_FS_VOLUME_INFORMATION pVolumeInfo;
  1659. LONGLONG VolumeBuf[(sizeof(FILE_FS_VOLUME_INFORMATION) + 128)/sizeof(LONGLONG) + 1];
  1660. IO_STATUS_BLOCK IoStsBlk;
  1661. NTSTATUS Status;
  1662. PAGED_CODE();
  1663. // Just nudge the CD volume handle to see if this is valid, if
  1664. // not mark the volume as invalid.
  1665. pVolumeInfo = (PFILE_FS_VOLUME_INFORMATION)VolumeBuf;
  1666. Status = NtQueryVolumeInformationFile(pVolDesc->vds_hRootDir.fsh_FileHandle,
  1667. &IoStsBlk,
  1668. (PVOID)pVolumeInfo,
  1669. sizeof(VolumeBuf),
  1670. FileFsVolumeInformation);
  1671. if (NT_SUCCESS(Status))
  1672. {
  1673. if (pVolDesc->vds_Flags & VOLUME_CDFS_INVALID)
  1674. {
  1675. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1676. ("afpNudgeCdfsVolume: Volume %d online again !!!\n",
  1677. pVolDesc->vds_VolId));
  1678. AfpInterlockedClearDword(&pVolDesc->vds_Flags,
  1679. VOLUME_CDFS_INVALID,
  1680. &pVolDesc->vds_VolLock);
  1681. AfpVolumeSetModifiedTime(pVolDesc);
  1682. }
  1683. }
  1684. else if ((Status == STATUS_WRONG_VOLUME) ||
  1685. (Status == STATUS_INVALID_VOLUME_LABEL)||
  1686. (Status == STATUS_NO_MEDIA_IN_DEVICE) ||
  1687. (Status == STATUS_UNRECOGNIZED_VOLUME))
  1688. {
  1689. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  1690. ("afpNudgeCdfsVolume: Volume %d error %lx, marking volume invalid\n",
  1691. pVolDesc->vds_VolId, Status));
  1692. if (!(pVolDesc->vds_Flags & VOLUME_CDFS_INVALID))
  1693. {
  1694. // AFP_LOGERR();
  1695. }
  1696. AfpInterlockedSetDword(&pVolDesc->vds_Flags,
  1697. VOLUME_CDFS_INVALID,
  1698. &pVolDesc->vds_VolLock);
  1699. AfpVolumeSetModifiedTime(pVolDesc);
  1700. }
  1701. }
  1702. /*** AfpUpdateVolFreeSpaceAndModTime
  1703. *
  1704. * Update free space on a volume and other volumes on the same physical drive. Update
  1705. * volume modified time on the volume as well.
  1706. *
  1707. * LOCKS: AfpVolumeListLock (SPIN)
  1708. */
  1709. VOID FASTCALL
  1710. AfpUpdateVolFreeSpaceAndModTime(
  1711. IN PVOLDESC pVolDesc,
  1712. IN BOOLEAN fUpdateModTime
  1713. )
  1714. {
  1715. PVOLDESC pVds;
  1716. KIRQL OldIrql, OldIrql1;
  1717. NTSTATUS Status;
  1718. WCHAR DriveLetter;
  1719. LARGE_INTEGER FreeSpace;
  1720. AFPTIME ModifiedTime;
  1721. ASSERT (VALID_VOLDESC(pVolDesc));
  1722. // Get new values for Free space on disk
  1723. Status = AfpIoQueryVolumeSize(pVolDesc, &FreeSpace, NULL);
  1724. if (!NT_SUCCESS(Status))
  1725. {
  1726. return;
  1727. }
  1728. // Update the free space on all volumes on the same physical ntfs partition
  1729. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  1730. DriveLetter = pVolDesc->vds_Path.Buffer[0];
  1731. AfpGetCurrentTimeInMacFormat(&ModifiedTime);
  1732. for (pVds = AfpVolumeList; pVds != NULL; pVds = pVds->vds_Next)
  1733. {
  1734. if (pVds->vds_Path.Buffer[0] == DriveLetter)
  1735. {
  1736. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  1737. ("AfpUpdateVolFreeSpace: Updating free space for volume %Z\n",
  1738. &pVds->vds_Path));
  1739. ACQUIRE_SPIN_LOCK_AT_DPC(&pVolDesc->vds_VolLock);
  1740. pVds->vds_FreeBytes = FreeSpace;
  1741. // have we been asked to update volume mod time?
  1742. if (fUpdateModTime)
  1743. {
  1744. pVolDesc->vds_ModifiedTime = ModifiedTime;
  1745. pVolDesc->vds_Flags |= VOLUME_IDDBHDR_DIRTY;
  1746. }
  1747. RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
  1748. }
  1749. }
  1750. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  1751. }
  1752. /*** AfpVolumeScavenger
  1753. *
  1754. * This is invoked by the scavenger periodically. It initiates the updates to
  1755. * the id index stream and the desktop stream. If the volume is marked for
  1756. * shutdown (STOPPED), then do one final flush to disk if needed. This will
  1757. * guarantee that any remaining changes get flushed before stopping.
  1758. * If the volume is marked to either shutdown or delete, then it dereferences
  1759. * the volume and does not reschedule itself.
  1760. *
  1761. * For CD volumes, we want to try to check if the CD is still valid, if not we
  1762. * want to mark the volume appropritely - basically update the modified date
  1763. * on the volume - this will cause the clients to come in to refresh and we'll
  1764. * take care of it then.
  1765. *
  1766. * LOCKS: vds_VolLock(SPIN),vds_idDbAccessLock(SWMR, Shared),vds_DtAccessLock(SWMR, Shared)
  1767. */
  1768. AFPSTATUS FASTCALL
  1769. AfpVolumeScavenger(
  1770. IN PVOLDESC pVolDesc
  1771. )
  1772. {
  1773. KIRQL OldIrql;
  1774. IDDBHDR IdDbHdr;
  1775. BOOLEAN WriteHdr = False, WriteIdDb = False, DerefVol = False;
  1776. BOOLEAN WriteDt = False, AgeDfes = False;
  1777. BOOLEAN MacLimitExceeded = False;
  1778. AFPSTATUS RequeueStatus = AFP_ERR_REQUEUE;
  1779. ASSERT(VALID_VOLDESC(pVolDesc) && (pVolDesc->vds_RefCount > 0));
  1780. // Determine if any updates needs to happen. Lock down the volume first
  1781. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  1782. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  1783. ("AfpVolumeScavenger: Volume %ld Scavenger entered @ %s_LEVEL\n",
  1784. pVolDesc->vds_VolId,
  1785. (OldIrql == DISPATCH_LEVEL) ? "DISPATCH" : "LOW"));
  1786. if (pVolDesc->vds_Flags & (VOLUME_DELETED | VOLUME_STOPPED))
  1787. {
  1788. if (IS_VOLUME_NTFS(pVolDesc))
  1789. {
  1790. pVolDesc->vds_cScvgrIdDb = 1;
  1791. pVolDesc->vds_cScvgrDt = 1;
  1792. }
  1793. DerefVol = True;
  1794. }
  1795. if (IS_VOLUME_NTFS(pVolDesc))
  1796. {
  1797. AFPTIME CurTime;
  1798. #ifdef AGE_DFES
  1799. if (OldIrql == DISPATCH_LEVEL)
  1800. {
  1801. pVolDesc->vds_ScavengerInvocationCnt ++;
  1802. }
  1803. #endif
  1804. if (DerefVol && pVolDesc->vds_Flags & VOLUME_IDDBHDR_DIRTY)
  1805. {
  1806. WriteHdr = True;
  1807. }
  1808. if (pVolDesc->vds_cScvgrIdDb > 0)
  1809. {
  1810. WriteIdDb = True;
  1811. WriteHdr = False; // We will always write the header with the iddb
  1812. }
  1813. if (pVolDesc->vds_cScvgrDt > 0)
  1814. {
  1815. WriteDt = True;
  1816. }
  1817. }
  1818. #ifdef AGE_DFES
  1819. else // Not NTFS
  1820. {
  1821. pVolDesc->vds_ScavengerInvocationCnt ++;
  1822. }
  1823. if (IS_VOLUME_AGING_DFES(pVolDesc) &&
  1824. ((pVolDesc->vds_ScavengerInvocationCnt % VOLUME_IDDB_AGE_GRANULARITY) == 0))
  1825. {
  1826. AgeDfes = True;
  1827. }
  1828. #endif
  1829. // if we are at DPC, return (we will come back at non-dpc)
  1830. if (OldIrql == DISPATCH_LEVEL)
  1831. {
  1832. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  1833. return AFP_ERR_QUEUE;
  1834. }
  1835. // check to see if we have exceeded Mac limits (4GB vol size, 65535 file/folders)
  1836. // if we know we have exceeded the limit, we have already logged an event. Don't even
  1837. // bother checking in that case.
  1838. if (!pVolDesc->MacLimitExceeded)
  1839. {
  1840. DWORD dwNumDirs = pVolDesc->vds_NumDirDfEntries;
  1841. DWORD dwNumFiles = pVolDesc->vds_NumFileDfEntries;
  1842. if ( (dwNumDirs > APLIMIT_MAX_FOLDERS) ||
  1843. (dwNumFiles > APLIMIT_MAX_FOLDERS) ||
  1844. (dwNumDirs+dwNumFiles > APLIMIT_MAX_FOLDERS) )
  1845. {
  1846. MacLimitExceeded = True;
  1847. pVolDesc->MacLimitExceeded = TRUE;
  1848. }
  1849. }
  1850. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  1851. // update the disk space, but don't update timestamp
  1852. AfpUpdateVolFreeSpaceAndModTime(pVolDesc, FALSE);
  1853. if (MacLimitExceeded)
  1854. {
  1855. AFPLOG_INFO( AFPSRVMSG_TOO_MANY_FOLDERS,
  1856. 0,
  1857. NULL,
  1858. 0,
  1859. &pVolDesc->vds_Name);
  1860. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_ERR,
  1861. ("AfpVolumeScavenger: more than 65535 files+folders on volume %lx\n", pVolDesc) );
  1862. }
  1863. // The following is intentionally bit-wise or instead of logical or
  1864. // The result is same except that this is more efficient
  1865. if (WriteHdr | WriteIdDb | WriteDt)
  1866. {
  1867. ASSERT (IS_VOLUME_NTFS(pVolDesc));
  1868. // Snapshot the IdDbHdr for updating to the disk if it is dirty
  1869. if (WriteHdr)
  1870. {
  1871. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  1872. AfpVolDescToIdDbHdr(pVolDesc, &IdDbHdr);
  1873. // Clear the dirty bit
  1874. pVolDesc->vds_Flags &= ~VOLUME_IDDBHDR_DIRTY;
  1875. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  1876. }
  1877. AfpVolumeUpdateIdDbAndDesktop(pVolDesc,
  1878. WriteDt,
  1879. WriteIdDb,
  1880. WriteHdr ? &IdDbHdr : NULL);
  1881. }
  1882. if (!DerefVol)
  1883. {
  1884. if (!IS_VOLUME_NTFS(pVolDesc))
  1885. {
  1886. afpNudgeCdfsVolume(pVolDesc);
  1887. }
  1888. #ifdef AGE_DFES
  1889. if (AgeDfes)
  1890. {
  1891. AfpAgeDfEntries(pVolDesc);
  1892. }
  1893. #endif
  1894. }
  1895. else
  1896. {
  1897. AfpInterlockedClearDword(&pVolDesc->vds_Flags,
  1898. VOLUME_SCAVENGER_RUNNING,
  1899. &pVolDesc->vds_VolLock);
  1900. AfpVolumeDereference(pVolDesc);
  1901. RequeueStatus = AFP_ERR_NONE;
  1902. }
  1903. return RequeueStatus;
  1904. }
  1905. /*** afpVolumeAdd
  1906. *
  1907. * Add a newly created volume to the server volume list. At this point,
  1908. * at least the volume names, volume path and volume spinlock fields must be
  1909. * initialized in the volume descriptor.
  1910. *
  1911. * LOCKS: AfpVolumeListLock (SPIN)
  1912. */
  1913. LOCAL AFPSTATUS FASTCALL
  1914. afpVolumeAdd(
  1915. IN PVOLDESC pVolDesc
  1916. )
  1917. {
  1918. KIRQL OldIrql;
  1919. AFPSTATUS rc;
  1920. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  1921. ("afpVolumeAdd entered\n"));
  1922. // acquire the lock for server global volume list
  1923. ACQUIRE_SPIN_LOCK(&AfpVolumeListLock, &OldIrql);
  1924. // make sure a volume by that name does not already exist, and
  1925. // make sure a volume doesn't already point to the same volume root dir
  1926. // or to an ancestor or descendent directory of the root dir
  1927. rc = afpVolumeCheckForDuplicate(pVolDesc);
  1928. if (!NT_SUCCESS(rc))
  1929. {
  1930. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  1931. return rc;
  1932. }
  1933. // Assign a new volume id and link in the new volume
  1934. afpVolumeGetNewIdAndLinkToList(pVolDesc);
  1935. // release the server global volume list lock
  1936. RELEASE_SPIN_LOCK(&AfpVolumeListLock, OldIrql);
  1937. return STATUS_SUCCESS;
  1938. }
  1939. /*** afpCheckForDuplicateVolume
  1940. *
  1941. * Check for new volume that a volume by the same name does not
  1942. * already exist, and that the volume root does not point to an ancestor,
  1943. * descendent or same directory of an existing volume. Note that each volume
  1944. * in the volume list is checked *regardless* of whether or not it is marked
  1945. * IN_TRANSITION or DELETED.
  1946. *
  1947. * LOCKS_ASSUMED: AfpVolumeListLock (SPIN)
  1948. */
  1949. LOCAL AFPSTATUS FASTCALL
  1950. afpVolumeCheckForDuplicate(
  1951. IN PVOLDESC Newvol
  1952. )
  1953. {
  1954. PVOLDESC pVolDesc;
  1955. AFPSTATUS Status = AFP_ERR_NONE;
  1956. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  1957. ("afpCheckForDuplicateVolume entered\n"));
  1958. do
  1959. {
  1960. for (pVolDesc = AfpVolumeList;
  1961. pVolDesc != NULL;
  1962. pVolDesc = pVolDesc->vds_Next)
  1963. {
  1964. // We do not take vds_VolLock for each volume since even if a
  1965. // volume is in transition, its names and path are at least
  1966. // initialized, and cannot change. We do not reference each
  1967. // volume since in order for to delete or stop a volume, the
  1968. // AfpVolListLock must be taken to unlink it from the list,
  1969. // and whoever called us owns that lock. These are special
  1970. // exceptions ONLY allowed for the volume add code. Also ignore
  1971. // the volumes that are on their way out. We do not want to punt
  1972. // cases where somebody does a delete followed by an add.
  1973. if (pVolDesc->vds_Flags & (VOLUME_DELETED | VOLUME_STOPPED))
  1974. continue;
  1975. if (AfpEqualUnicodeString(&pVolDesc->vds_UpCaseName,
  1976. &Newvol->vds_UpCaseName))
  1977. {
  1978. Status = AFPERR_DuplicateVolume;
  1979. break;
  1980. }
  1981. // volume paths are stored as uppercase since we cannot do a case
  1982. // insensitive compare while holding a spinlock (DPC level)
  1983. if (AfpPrefixUnicodeString(&pVolDesc->vds_Path, &Newvol->vds_Path) ||
  1984. AfpPrefixUnicodeString(&Newvol->vds_Path, &pVolDesc->vds_Path))
  1985. {
  1986. Status = AFPERR_NestedVolume;
  1987. break;
  1988. }
  1989. }
  1990. } while (False);
  1991. return Status;
  1992. }
  1993. /*** afpVolumeGetNewIdAndLinkToList
  1994. *
  1995. * Assign a new volume id to a volume that is being added. The volume is also
  1996. * inserted into the list but marked as "in transition". This should be cleared
  1997. * when the volume is 'ready to be mounted'.
  1998. * The volume ids are recycled. A volume id also cannot be 0 and cannot
  1999. * exceed MAXSHORT.
  2000. *
  2001. * We always assign the lowest free id that is not in use. For example if
  2002. * there are currently N volumes with ids 1, 2, 4, 5 ... N then the newly
  2003. * created volume will be id 3.
  2004. *
  2005. * LOCKS_ASSUMED: AfpVolumeListLock (SPIN)
  2006. */
  2007. LOCAL VOID FASTCALL
  2008. afpVolumeGetNewIdAndLinkToList(
  2009. IN PVOLDESC pVolDesc
  2010. )
  2011. {
  2012. PVOLDESC *ppVolDesc;
  2013. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  2014. ("afpGetNewVolIdAndLinkToList entered\n"));
  2015. pVolDesc->vds_Flags |= (VOLUME_INTRANSITION | VOLUME_INITIAL_CACHE);
  2016. AfpVolCount ++; // Up the count of volumes.
  2017. pVolDesc->vds_VolId = afpSmallestFreeVolId++;
  2018. // This will always be valid
  2019. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  2020. ("afpGetNewVolIdAndLinkToList: using volID %d\n",
  2021. pVolDesc->vds_VolId));
  2022. // See if we need to do anything to make the above True next time around
  2023. if (afpSmallestFreeVolId <= AfpVolCount)
  2024. {
  2025. // What this means is that we have some holes. Figure out the first
  2026. // free id that can be used.
  2027. for (ppVolDesc = &AfpVolumeList;
  2028. *ppVolDesc != NULL;
  2029. ppVolDesc = &((*ppVolDesc)->vds_Next))
  2030. {
  2031. if ((*ppVolDesc)->vds_VolId < afpSmallestFreeVolId)
  2032. continue;
  2033. else if ((*ppVolDesc)->vds_VolId == afpSmallestFreeVolId)
  2034. afpSmallestFreeVolId++;
  2035. else
  2036. break;
  2037. }
  2038. }
  2039. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  2040. ("afpGetNewVolIdAndLinkToList: next free volID is %d\n",
  2041. afpSmallestFreeVolId));
  2042. // make sure our LargestVolIdInUse value is accurate
  2043. //
  2044. if (afpLargestVolIdInUse < pVolDesc->vds_VolId )
  2045. afpLargestVolIdInUse = pVolDesc->vds_VolId;
  2046. // Now link the descriptor in the list.
  2047. for (ppVolDesc = &AfpVolumeList;
  2048. *ppVolDesc != NULL;
  2049. ppVolDesc = &((*ppVolDesc)->vds_Next))
  2050. {
  2051. ASSERT (pVolDesc->vds_VolId != (*ppVolDesc)->vds_VolId);
  2052. if (pVolDesc->vds_VolId < (*ppVolDesc)->vds_VolId)
  2053. break;
  2054. }
  2055. pVolDesc->vds_Next = *ppVolDesc;
  2056. *ppVolDesc = pVolDesc;
  2057. }
  2058. /*** AfpAdmWVolumeAdd
  2059. *
  2060. * This routine adds a volume to the server global list of volumes headed by
  2061. * AfpVolumeList. The volume descriptor is created and initialized. The ID
  2062. * index is read in (or created). The same is true with the desktop.
  2063. *
  2064. * This routine will be queued to the worker thread.
  2065. *
  2066. */
  2067. AFPSTATUS
  2068. AfpAdmWVolumeAdd(
  2069. IN OUT PVOID Inbuf OPTIONAL,
  2070. IN LONG OutBufLen OPTIONAL,
  2071. OUT PVOID Outbuf OPTIONAL
  2072. )
  2073. {
  2074. PVOLDESC pVolDesc = NULL;
  2075. UNICODE_STRING RootName;
  2076. FILESYSHANDLE hVolRoot;
  2077. DWORD tempflags;
  2078. DWORD memsize;
  2079. USHORT ansivolnamelen, devpathlen;
  2080. PBYTE tempptr;
  2081. UNICODE_STRING uname, upwd, upath, udevpath;
  2082. AFPSTATUS status = STATUS_SUCCESS;
  2083. PAFP_VOLUME_INFO pVolInfo = (PAFP_VOLUME_INFO)Inbuf;
  2084. BOOLEAN WriteBackROAttr = False, RefForNotify = False;
  2085. BOOLEAN VolLinked = False;
  2086. BOOLEAN fNewVolume;
  2087. BOOLEAN fVerifyIndex = FALSE;
  2088. DWORD dwDirHashSz;
  2089. DWORD dwFileHashSz;
  2090. int i;
  2091. PAGED_CODE( );
  2092. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  2093. ("AfpAdmWVolumeAdd entered\n"));
  2094. do
  2095. {
  2096. if (pVolInfo->afpvol_props_mask & AFP_VOLUME_DISALLOW_CATSRCH)
  2097. {
  2098. pVolInfo->afpvol_props_mask &= ~AFP_VOLUME_DISALLOW_CATSRCH;
  2099. tempflags = AFP_VOLUME_SUPPORTS_FILEID;
  2100. }
  2101. else
  2102. {
  2103. tempflags = AFP_VOLUME_SUPPORTS_FILEID | AFP_VOLUME_SUPPORTS_CATSRCH;
  2104. }
  2105. RtlInitUnicodeString(&uname,pVolInfo->afpvol_name);
  2106. RtlInitUnicodeString(&upwd,pVolInfo->afpvol_password);
  2107. RtlInitUnicodeString(&upath,pVolInfo->afpvol_path);
  2108. hVolRoot.fsh_FileHandle = NULL;
  2109. // need to prepend "\DOSDEVICES\" to the path of volume root
  2110. devpathlen = upath.MaximumLength + DosDevices.MaximumLength;
  2111. if ((udevpath.Buffer = (PWSTR)AfpAllocNonPagedMemory(devpathlen)) == NULL)
  2112. {
  2113. status = STATUS_INSUFFICIENT_RESOURCES;
  2114. break;
  2115. }
  2116. udevpath.Length = 0;
  2117. udevpath.MaximumLength = devpathlen;
  2118. AfpCopyUnicodeString(&udevpath,&DosDevices);
  2119. RtlAppendUnicodeStringToString(&udevpath,&upath);
  2120. // open a handle to the volume root
  2121. status = AfpIoOpen(NULL,
  2122. AFP_STREAM_DATA,
  2123. FILEIO_OPEN_DIR,
  2124. &udevpath,
  2125. FILEIO_ACCESS_NONE,
  2126. FILEIO_DENY_NONE,
  2127. False,
  2128. &hVolRoot);
  2129. AfpFreeMemory(udevpath.Buffer);
  2130. if (!NT_SUCCESS(status))
  2131. {
  2132. break;
  2133. }
  2134. if (!AfpIoIsSupportedDevice(&hVolRoot, &tempflags))
  2135. {
  2136. status = AFPERR_UnsupportedFS;
  2137. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_ERR,
  2138. ("AfpAdmWVolumeAdd: AFPERR_UnsupportedFS\n"));
  2139. break;
  2140. }
  2141. // allocate a new volume descriptor -- allocate ALL required memory in
  2142. // one fell swoop. That is, we will just tack all the required string
  2143. // pointers onto the end of the memory chunk that we allocate for the
  2144. // volume descriptor. In this way, we don't have to deal with checking
  2145. // error codes in a million different places for memory routines and
  2146. // have to clean up a million different pointers if one allocation should
  2147. // fail.
  2148. // NOTE: when deleting a volume, don't free all the individual strings
  2149. // withing the voldesc, just free the one chunk of memory
  2150. memsize = sizeof(VOLDESC) + // volume descriptor
  2151. // mac ansi volume name
  2152. (ansivolnamelen = (USHORT)RtlUnicodeStringToAnsiSize(&uname)) +
  2153. uname.MaximumLength * 2 + // unicode volume names (orginial
  2154. // and uppercase version)
  2155. AFP_VOLPASS_LEN+1 + // mac ansi password
  2156. upath.MaximumLength + // unicode root path
  2157. sizeof(WCHAR); // need to append '\' to root path
  2158. if ((pVolDesc = (PVOLDESC)AfpAllocZeroedNonPagedMemory(memsize)) == NULL)
  2159. {
  2160. status = STATUS_INSUFFICIENT_RESOURCES;
  2161. break;
  2162. }
  2163. #if DBG
  2164. pVolDesc->Signature = VOLDESC_SIGNATURE;
  2165. #endif
  2166. // the volume lock MUST be initialized prior to linking into global
  2167. // volume list
  2168. INITIALIZE_SPIN_LOCK(&pVolDesc->vds_VolLock);
  2169. AfpSwmrInitSwmr(&pVolDesc->vds_IdDbAccessLock);
  2170. AfpSwmrInitSwmr(&pVolDesc->vds_ExchangeFilesLock);
  2171. for (i = 0; i < NUM_AFP_CHANGE_ACTION_LISTS; i++)
  2172. {
  2173. InitializeListHead(&pVolDesc->vds_OurChangeList[i]);
  2174. }
  2175. InitializeListHead(&pVolDesc->vds_ChangeNotifyLookAhead);
  2176. InitializeListHead(&pVolDesc->vds_DelayedNotifyList);
  2177. // calculate pointer for the unicode path string
  2178. tempptr = (PBYTE)pVolDesc + sizeof(VOLDESC);
  2179. // initialize unicode path string
  2180. AfpSetEmptyUnicodeString(&(pVolDesc->vds_Path),
  2181. upath.MaximumLength + sizeof(WCHAR),tempptr);
  2182. // This must be stored as uppercase since we cannot do case insensitive
  2183. // string compares at DPC level (holding the volume spinlock) to
  2184. // detect nested volumes
  2185. RtlUpcaseUnicodeString(&(pVolDesc->vds_Path), &upath, False);
  2186. // Does the path already contain a trailing backslash?
  2187. if (pVolDesc->vds_Path.Buffer[(pVolDesc->vds_Path.Length/sizeof(WCHAR))-1] != L'\\')
  2188. {
  2189. // append a backslash to simplify search for nested volumes
  2190. RtlCopyMemory(tempptr + upath.Length, L"\\", sizeof(WCHAR));
  2191. pVolDesc->vds_Path.Length += sizeof(WCHAR);
  2192. RtlCopyMemory(tempptr + upath.Length + sizeof(WCHAR), L"",
  2193. sizeof(UNICODE_NULL));
  2194. }
  2195. // calculate pointer for the unicode volume name
  2196. tempptr += upath.MaximumLength + sizeof(WCHAR);
  2197. // initialize the unicode volume name
  2198. AfpSetEmptyUnicodeString(&(pVolDesc->vds_Name),uname.MaximumLength,tempptr);
  2199. AfpCopyUnicodeString(&(pVolDesc->vds_Name),&uname);
  2200. RtlCopyMemory(tempptr + uname.Length,L"",sizeof(UNICODE_NULL));
  2201. // calculate pointer for the UPPER CASE unicode volume name
  2202. tempptr += uname.MaximumLength;
  2203. // initialize the UPPER CASE unicode volume name
  2204. AfpSetEmptyUnicodeString(&(pVolDesc->vds_UpCaseName),uname.MaximumLength,tempptr);
  2205. RtlUpcaseUnicodeString(&(pVolDesc->vds_UpCaseName), &uname, False);
  2206. RtlCopyMemory(tempptr + uname.Length,L"",sizeof(UNICODE_NULL));
  2207. // calculate pointer for the mac ansi volume name
  2208. tempptr += uname.MaximumLength;
  2209. // initialize the mac ansi volume name
  2210. AfpSetEmptyAnsiString(&(pVolDesc->vds_MacName),ansivolnamelen,tempptr);
  2211. status = AfpConvertStringToAnsi(&uname, &(pVolDesc->vds_MacName));
  2212. if (!NT_SUCCESS(status))
  2213. {
  2214. status = AFPERR_InvalidVolumeName;
  2215. break;
  2216. }
  2217. // calculate pointer for the mac ansi password
  2218. tempptr += ansivolnamelen;
  2219. // initialize the mac ansi password
  2220. AfpSetEmptyAnsiString(&pVolDesc->vds_MacPassword, AFP_VOLPASS_LEN+1, tempptr);
  2221. if (pVolInfo->afpvol_props_mask & AFP_VOLUME_HASPASSWORD)
  2222. {
  2223. status = AfpConvertStringToAnsi(&upwd, &pVolDesc->vds_MacPassword);
  2224. if (!NT_SUCCESS(status))
  2225. {
  2226. status = AFPERR_InvalidPassword;
  2227. break;
  2228. }
  2229. pVolDesc->vds_MacPassword.Length = AFP_VOLPASS_LEN;
  2230. }
  2231. pVolDesc->vds_Flags = 0;
  2232. // Add a creation reference and one for this routine itself.
  2233. pVolDesc->vds_RefCount = 2;
  2234. // add the volume to the global volume list - but mark it as 'add pending'
  2235. status = afpVolumeAdd(pVolDesc);
  2236. if (!NT_SUCCESS(status))
  2237. {
  2238. break;
  2239. }
  2240. VolLinked = True;
  2241. // set miscellaneous fields in volume descriptor
  2242. pVolDesc->vds_hRootDir = hVolRoot;
  2243. pVolDesc->vds_hNWT.fsh_FileHandle = NULL;
  2244. pVolDesc->vds_MaxUses = pVolInfo->afpvol_max_uses;
  2245. pVolDesc->vds_Flags |= (pVolInfo->afpvol_props_mask | tempflags);
  2246. pVolDesc->vds_UseCount = 0;
  2247. pVolDesc->vds_pOpenForkDesc = NULL;
  2248. #ifdef BLOCK_MACS_DURING_NOTIFYPROC
  2249. pVolDesc->vds_QueuedNotifyCount = 0;
  2250. #endif
  2251. if (pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
  2252. {
  2253. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2254. ("AfpAdmWVolumeAdd: DiskQuota is enabled on volume %Z\n",&pVolDesc->vds_Name));
  2255. }
  2256. AfpGetDirFileHashSizes(pVolDesc, &dwDirHashSz, &dwFileHashSz);
  2257. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2258. ("AfpAdmWVolumeAdd: DirHash = %d, FileHash = %d, VolSize = %d for vol %Z\n",
  2259. dwDirHashSz,dwFileHashSz,
  2260. (memsize + (sizeof(struct _DirFileEntry *) * (dwDirHashSz+dwFileHashSz))),
  2261. &pVolDesc->vds_Name));
  2262. pVolDesc->vds_DirHashTableSize = dwDirHashSz;
  2263. pVolDesc->vds_FileHashTableSize = dwFileHashSz;
  2264. pVolDesc->vds_pDfeDirBucketStart = (struct _DirFileEntry **)
  2265. AfpAllocZeroedNonPagedMemory(sizeof(struct _DirFileEntry *) * dwDirHashSz);
  2266. if (pVolDesc->vds_pDfeDirBucketStart == NULL)
  2267. {
  2268. status = STATUS_INSUFFICIENT_RESOURCES;
  2269. break;
  2270. }
  2271. pVolDesc->vds_pDfeFileBucketStart = (struct _DirFileEntry **)
  2272. AfpAllocZeroedNonPagedMemory(sizeof(struct _DirFileEntry *) * dwFileHashSz);
  2273. if (pVolDesc->vds_pDfeFileBucketStart == NULL)
  2274. {
  2275. status = STATUS_INSUFFICIENT_RESOURCES;
  2276. break;
  2277. }
  2278. // snapshot the disk space information
  2279. status = AfpIoQueryVolumeSize(pVolDesc,
  2280. &pVolDesc->vds_FreeBytes,
  2281. &pVolDesc->vds_VolumeSize);
  2282. if (!NT_SUCCESS(status))
  2283. {
  2284. break;
  2285. }
  2286. if (IS_VOLUME_NTFS(pVolDesc))
  2287. {
  2288. // In order to create IdIndex, AfpInfo and Desktop, the volume
  2289. // root directory cannot be marked read only
  2290. AfpExamineAndClearROAttr(&hVolRoot, &WriteBackROAttr, NULL, NULL);
  2291. // Get rid of the NetworkTrash directory if it exists
  2292. status = AfpDeleteNetworkTrash(pVolDesc, True);
  2293. if (!NT_SUCCESS(status))
  2294. {
  2295. break;
  2296. }
  2297. }
  2298. // initialize the desktop
  2299. status = AfpInitDesktop(pVolDesc, &fNewVolume);
  2300. if (!NT_SUCCESS(status))
  2301. {
  2302. break;
  2303. }
  2304. // if we just created the index database stream, this must be a new
  2305. // volume. Also, this is the first pass. Note these facts
  2306. if (fNewVolume)
  2307. {
  2308. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2309. ("AfpAdmWVolumeAdd: AfpInitDesktop says volume %Z is new\n",
  2310. &pVolDesc->vds_Name));
  2311. pVolDesc->vds_Flags |= VOLUME_NEW_FIRST_PASS;
  2312. }
  2313. // initialize the ID index database.
  2314. status = AfpInitIdDb(pVolDesc, &fNewVolume, &fVerifyIndex);
  2315. if (!NT_SUCCESS(status))
  2316. {
  2317. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2318. ("AfpAdmWVolumeAdd: AfpInitIdDb failed %lx on volume %Z\n",
  2319. status,&pVolDesc->vds_Name));
  2320. break;
  2321. }
  2322. if (fNewVolume)
  2323. {
  2324. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2325. ("AfpAdmWVolumeAdd: AfpInitIdDb says volume %Z is new\n",
  2326. &pVolDesc->vds_Name));
  2327. pVolDesc->vds_Flags |= VOLUME_NEW_FIRST_PASS;
  2328. }
  2329. if (IS_VOLUME_NTFS(pVolDesc))
  2330. {
  2331. // Create the network trash if this is not a CDFS volume;
  2332. // a volume can be changed to/from readonly on the fly, so by putting
  2333. // the network trash even on a readonly NTFS volume, we avoid a lot
  2334. // of painful extra work. This must be done AFTER initializing
  2335. // the ID index database since we add the DFE for nwtrash. We do
  2336. // it here BEFORE posting the change notify since if an error
  2337. // occurs, we don't have to clean up the posted notify.
  2338. status = AfpCreateNetworkTrash(pVolDesc);
  2339. if (!NT_SUCCESS(status))
  2340. {
  2341. break;
  2342. }
  2343. //
  2344. // if it's a volume that was created earlier, and if this is not
  2345. // an exclusive volume, post the chgntfy irp
  2346. //
  2347. if (!fNewVolume && !EXCLUSIVE_VOLUME(pVolDesc))
  2348. {
  2349. // Begin monitoring changes to the tree. Even though we may
  2350. // start processing PC changes before we have finished
  2351. // enumerating the tree, if we get notified of part of the
  2352. // tree we have yet to cache (and therefore can't find it's
  2353. // path in our database its ok, since we will end up
  2354. // picking up the change when we enumerate that branch. Also,
  2355. // by posting this before starting to cache the tree instead
  2356. // of after, we will pick up any changes that are made to parts
  2357. // of the tree we have already seen, otherwise we would miss
  2358. // those.
  2359. // Explicitly reference this volume for ChangeNotifies and post it
  2360. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  2361. if (AfpVolumeReference(pVolDesc))
  2362. {
  2363. RefForNotify = True;
  2364. pVolDesc->vds_RequiredNotifyBufLen = AFP_VOLUME_NOTIFY_STARTING_BUFSIZE;
  2365. status = AfpVolumePostChangeNotify(pVolDesc);
  2366. if (!NT_SUCCESS(status))
  2367. {
  2368. AfpVolumeDereference(pVolDesc);
  2369. RefForNotify = False;
  2370. break;
  2371. }
  2372. status = STATUS_SUCCESS;
  2373. }
  2374. else
  2375. {
  2376. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2377. ("AfpAdmWVolumeAdd: couldn't reference volume %Z!!\n",
  2378. &pVolDesc->vds_Name));
  2379. RefForNotify = False;
  2380. status = STATUS_UNSUCCESSFUL;
  2381. }
  2382. }
  2383. else
  2384. {
  2385. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2386. ("AfpAdmWVolumeAdd: postponing chg-notify irp for %Z\n",&pVolDesc->vds_Name));
  2387. }
  2388. }
  2389. } while (False);
  2390. AfpPutBackROAttr(&hVolRoot, WriteBackROAttr);
  2391. if (WriteBackROAttr && NT_SUCCESS(status))
  2392. {
  2393. pVolDesc->vds_pDfeRoot->dfe_NtAttr |= FILE_ATTRIBUTE_READONLY;
  2394. }
  2395. if (NT_SUCCESS(status))
  2396. {
  2397. if (fNewVolume || fVerifyIndex)
  2398. {
  2399. // put Indexing refcount, removed when we begin indexing
  2400. pVolDesc->vds_RefCount++;
  2401. AfpScavengerScheduleEvent(AfpVolumeBeginIndexing,
  2402. pVolDesc,
  2403. 0,
  2404. True);
  2405. }
  2406. else
  2407. {
  2408. // mark the volume as 'officially' added.
  2409. AfpInterlockedClearDword(&pVolDesc->vds_Flags,
  2410. VOLUME_INTRANSITION,
  2411. &pVolDesc->vds_VolLock);
  2412. // activate the volume if IDDB was read correctly from the file
  2413. afpActivateVolume(pVolDesc);
  2414. }
  2415. }
  2416. else
  2417. {
  2418. #if DBG
  2419. if (pVolDesc)
  2420. {
  2421. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2422. ("AfpAdmWVolumeAdd: Failed to add volume %Z %lx\n",&pVolDesc->vds_Name,status));
  2423. }
  2424. else
  2425. {
  2426. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  2427. ("AfpAdmWVolumeAdd: Failed to add volume %lx\n",status));
  2428. }
  2429. #endif
  2430. if ((hVolRoot.fsh_FileHandle != NULL) && !VolLinked)
  2431. {
  2432. AfpIoClose(&hVolRoot);
  2433. }
  2434. if (VolLinked)
  2435. {
  2436. // don't clear the VOLUME_INTRANSITION bit since this bit along
  2437. // with VOLUME_DELETED bit signify the special case of an
  2438. // error occurrence during volume add.
  2439. pVolDesc->vds_Flags |= VOLUME_DELETED;
  2440. // Remove the creation reference
  2441. AfpVolumeDereference(pVolDesc);
  2442. // if a Notify was posted, we need to cancel it here. By
  2443. // deleting the network trash we trigger the notify to complete.
  2444. // This is safer than trying to cancel the irp since there are
  2445. // windows where the vds_VolLock is not held between 2 threads
  2446. // checking/setting vds_Flags. (Notify complete and repost).
  2447. // The spin lock cannot be held while cancelling the Irp.
  2448. //
  2449. // Do this after marking the volume as DELETED since when the
  2450. // notify completion sees the volume is being deleted it will
  2451. // not repost (and will clean up the Irp, etc.).
  2452. if (RefForNotify)
  2453. {
  2454. // Note at this point we are guaranteed there is a trash
  2455. // directory since if creating the trash had failed, we
  2456. // would have failed the volume add before posting the
  2457. // change notify.
  2458. AfpDeleteNetworkTrash(pVolDesc, False);
  2459. }
  2460. }
  2461. else if (pVolDesc != NULL)
  2462. {
  2463. if (pVolDesc->vds_pDfeDirBucketStart)
  2464. {
  2465. AfpFreeMemory(pVolDesc->vds_pDfeDirBucketStart);
  2466. }
  2467. if (pVolDesc->vds_pDfeFileBucketStart)
  2468. {
  2469. AfpFreeMemory(pVolDesc->vds_pDfeFileBucketStart);
  2470. }
  2471. AfpFreeMemory(pVolDesc);
  2472. }
  2473. }
  2474. // Dereferencing the volume here takes care of any necessary error cleanup work
  2475. if (VolLinked)
  2476. {
  2477. AfpVolumeDereference(pVolDesc);
  2478. }
  2479. return status;
  2480. }
  2481. /*** AfpAdmWVolumeDelete
  2482. *
  2483. * This routine deletes a volume from the server global list of volumes
  2484. * headed by AfpVolumeList and recycles its volid. A volume with active
  2485. * connections cannot be deleted.
  2486. *
  2487. * LOCKS: AfpVolumeListLock (SPIN), vds_VolLock (SPIN)
  2488. * LOCK_ORDER: vds_VolLock (SPIN) after AfpVolumeListLock (SPIN)
  2489. *
  2490. */
  2491. AFPSTATUS
  2492. AfpAdmWVolumeDelete(
  2493. IN OUT PVOID Inbuf OPTIONAL,
  2494. IN LONG OutBufLen OPTIONAL,
  2495. OUT PVOID Outbuf OPTIONAL
  2496. )
  2497. {
  2498. WCHAR wcbuf[AFP_VOLNAME_LEN + 1];
  2499. UNICODE_STRING uvolname, upcasename;
  2500. KIRQL OldIrql;
  2501. PVOLDESC pVolDesc;
  2502. AFPSTATUS Status = STATUS_SUCCESS;
  2503. DBGPRINT(DBG_COMP_ADMINAPI_VOL, DBG_LEVEL_INFO,
  2504. ("AfpAdmWVolumeDelete entered\n"));
  2505. RtlInitUnicodeString(&uvolname, ((PAFP_VOLUME_INFO)Inbuf)->afpvol_name);
  2506. AfpSetEmptyUnicodeString(&upcasename, sizeof(wcbuf), wcbuf);
  2507. Status = RtlUpcaseUnicodeString(&upcasename, &uvolname, False);
  2508. ASSERT(NT_SUCCESS(Status));
  2509. do
  2510. {
  2511. // Reference the volume while we clean-up
  2512. pVolDesc = AfpVolumeReferenceByUpCaseName(&upcasename);
  2513. if (pVolDesc == NULL)
  2514. {
  2515. Status = AFPERR_VolumeNonExist;
  2516. break;
  2517. }
  2518. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  2519. // make sure there are no AFP clients using the volume
  2520. if (pVolDesc->vds_UseCount != 0)
  2521. {
  2522. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  2523. Status = AFPERR_VolumeBusy;
  2524. AfpVolumeDereference(pVolDesc);
  2525. break;
  2526. }
  2527. // if this volume is in the process of being stopped or deleted,
  2528. // in effect it should be 'invisible' to the caller.
  2529. if (pVolDesc->vds_Flags & (VOLUME_STOPPED | VOLUME_DELETED))
  2530. {
  2531. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  2532. Status = AFPERR_VolumeNonExist;
  2533. AfpVolumeDereference(pVolDesc);
  2534. break;
  2535. }
  2536. if ((pVolDesc->vds_Flags & VOLUME_INITIAL_CACHE) &&
  2537. !(pVolDesc->vds_Flags & VOLUME_INTRANSITION))
  2538. {
  2539. // set this so we don't reset the Indexing global flag again!
  2540. pVolDesc->vds_Flags |= VOLUME_INTRANSITION;
  2541. }
  2542. pVolDesc->vds_Flags |= VOLUME_DELETED;
  2543. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  2544. // Remove the creation reference
  2545. AfpVolumeDereference(pVolDesc);
  2546. // Cancel posted change notify
  2547. if (pVolDesc->vds_Flags & VOLUME_NOTIFY_POSTED)
  2548. {
  2549. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  2550. ("AfpAdmWVolumeDelete: Cancel notify on volume %ld\n",
  2551. pVolDesc->vds_VolId));
  2552. ASSERT (pVolDesc->vds_pIrp != NULL);
  2553. // Cancel after releasing the volume lock since the completion
  2554. // routine acquires it and it could be called in the context
  2555. // of IoCancelIrp(). Also Cancel uses paged resource and so
  2556. // must be called w/o holding any spin locks.
  2557. IoCancelIrp(pVolDesc->vds_pIrp);
  2558. }
  2559. // We have a reference to the volume from AfpFindVolumeByUpcaseName
  2560. ASSERT(pVolDesc->vds_RefCount >= 1);
  2561. // Cancel the OurChange scavenger for this volume.
  2562. if (AfpScavengerKillEvent(AfpOurChangeScavenger, pVolDesc))
  2563. {
  2564. // If it was deleted from scavenger list, run it one last time
  2565. AfpOurChangeScavenger(pVolDesc);
  2566. }
  2567. // Cancel the volume scavenger and call it ourselves to avoid the delay
  2568. if (AfpScavengerKillEvent(AfpVolumeScavenger, pVolDesc))
  2569. {
  2570. // This will do the dereference for the scavenger reference
  2571. // Take away our reference before calling the volume scavenger
  2572. AfpVolumeDereference(pVolDesc);
  2573. AfpVolumeScavenger(pVolDesc);
  2574. }
  2575. else
  2576. {
  2577. AfpVolumeDereference(pVolDesc);
  2578. }
  2579. } while (False);
  2580. return Status;
  2581. }
  2582. /*** AfpAdmWConnectionClose
  2583. *
  2584. * Close a connection forcibly. This is an admin operation and must be queued
  2585. * up since this can potentially cause filesystem operations that are valid
  2586. * only in the system process context.
  2587. *
  2588. * LOCKS: AfpConnLock (SPIN), cds_ConnLock (SPIN)
  2589. * LOCK_ORDER: cds_ConnLock (SPIN) after AfpConnLock (SPIN)
  2590. */
  2591. AFPSTATUS
  2592. AfpAdmWConnectionClose(
  2593. IN OUT PVOID InBuf OPTIONAL,
  2594. IN LONG OutBufLen OPTIONAL,
  2595. OUT PVOID OutBuf OPTIONAL
  2596. )
  2597. {
  2598. AFPSTATUS Status = AFPERR_InvalidId;
  2599. PCONNDESC pConnDesc;
  2600. DWORD ConnId;
  2601. PAFP_CONNECTION_INFO pConnInfo = (PAFP_CONNECTION_INFO)InBuf;
  2602. AFP_SESSION_INFO SessInfo;
  2603. BOOLEAN KillSessionToo;
  2604. if ((ConnId = pConnInfo->afpconn_id) != 0)
  2605. {
  2606. if ((pConnDesc = afpConnectionReferenceById(ConnId)) != NULL)
  2607. {
  2608. SessInfo.afpsess_id = pConnDesc->cds_pSda->sda_SessionId;
  2609. KillSessionToo = (pConnDesc->cds_pSda->sda_cOpenVolumes == 1) ?
  2610. True : False;
  2611. AfpConnectionClose(pConnDesc);
  2612. AfpConnectionDereference(pConnDesc);
  2613. if (KillSessionToo)
  2614. {
  2615. AfpAdmWSessionClose(&SessInfo, 0, NULL);
  2616. }
  2617. Status = AFP_ERR_NONE;
  2618. }
  2619. }
  2620. else
  2621. {
  2622. DWORD ConnId = MAXULONG;
  2623. KIRQL OldIrql;
  2624. BOOLEAN Shoot;
  2625. Status = AFP_ERR_NONE;
  2626. while (True)
  2627. {
  2628. ACQUIRE_SPIN_LOCK(&AfpConnLock, &OldIrql);
  2629. for (pConnDesc = AfpConnList;
  2630. pConnDesc != NULL;
  2631. pConnDesc = pConnDesc->cds_NextGlobal)
  2632. {
  2633. if (pConnDesc->cds_ConnId > ConnId)
  2634. continue;
  2635. ACQUIRE_SPIN_LOCK_AT_DPC(&pConnDesc->cds_ConnLock);
  2636. ConnId = pConnDesc->cds_ConnId;
  2637. Shoot = False;
  2638. if (!(pConnDesc->cds_Flags & CONN_CLOSING))
  2639. {
  2640. pConnDesc->cds_RefCount ++;
  2641. Shoot = True;
  2642. SessInfo.afpsess_id = pConnDesc->cds_pSda->sda_SessionId;
  2643. KillSessionToo = (pConnDesc->cds_pSda->sda_cOpenVolumes == 1) ?
  2644. True : False;
  2645. }
  2646. RELEASE_SPIN_LOCK_FROM_DPC(&pConnDesc->cds_ConnLock);
  2647. if (Shoot)
  2648. {
  2649. RELEASE_SPIN_LOCK(&AfpConnLock, OldIrql);
  2650. AfpConnectionClose(pConnDesc);
  2651. AfpConnectionDereference(pConnDesc);
  2652. if (KillSessionToo)
  2653. {
  2654. AfpAdmWSessionClose(&SessInfo, 0, NULL);
  2655. }
  2656. break;
  2657. }
  2658. }
  2659. if (pConnDesc == NULL)
  2660. {
  2661. RELEASE_SPIN_LOCK(&AfpConnLock, OldIrql);
  2662. break;
  2663. }
  2664. }
  2665. }
  2666. return Status;
  2667. }
  2668. /*** AfpVolumeBeginIndexing
  2669. *
  2670. * Check if another volume is doing it's indexing: if yes, put it back on the
  2671. * queue and try later. If no one else is indexing, start indexing this volume
  2672. *
  2673. */
  2674. AFPSTATUS FASTCALL
  2675. AfpVolumeBeginIndexing(
  2676. IN PVOLDESC pVolDesc
  2677. )
  2678. {
  2679. KIRQL OldIrql;
  2680. UNICODE_STRING RootName;
  2681. BOOLEAN fVolumeStopped=FALSE;
  2682. LARGE_INTEGER IndexStartTime;
  2683. // is the volume stopped or deleted? ignore this then
  2684. ACQUIRE_SPIN_LOCK(&pVolDesc->vds_VolLock, &OldIrql);
  2685. if (pVolDesc->vds_Flags & (VOLUME_DELETED | VOLUME_STOPPED))
  2686. {
  2687. DBGPRINT(DBG_COMP_CHGNOTIFY, DBG_LEVEL_ERR,
  2688. ("AfpVolumeBeginIndexing: volume %Z stopping, cancelling indexing\n",&pVolDesc->vds_Name));
  2689. fVolumeStopped = TRUE;
  2690. }
  2691. RELEASE_SPIN_LOCK(&pVolDesc->vds_VolLock, OldIrql);
  2692. if (fVolumeStopped)
  2693. {
  2694. // Remove the Indexing reference
  2695. AfpVolumeDereference(pVolDesc);
  2696. return(AFP_ERR_NONE);
  2697. }
  2698. KeQuerySystemTime (&IndexStartTime);
  2699. pVolDesc->vds_IndxStTime = IndexStartTime;
  2700. DBGPRINT(DBG_COMP_CHGNOTIFY, DBG_LEVEL_ERR,
  2701. ("AfpVolumeBeginIndexing: indexing volume %Z at %8lx%08lx\n",&pVolDesc->vds_Name,
  2702. 0xffffffff*IndexStartTime.HighPart,
  2703. 0xffffffff*IndexStartTime.LowPart));
  2704. // scan the entire directory tree and sync disk with iddb. Must be
  2705. // done AFTER initializing the Desktop since we may add APPL mappings
  2706. // while enumerating the disk. Also we need to know if we read an
  2707. // old style desktop off the disk, and if so, need to rebuild all the
  2708. // APPL mappings so they have the parentID.
  2709. AfpSetEmptyUnicodeString(&RootName, 0, NULL);
  2710. AfpQueuePrivateChangeNotify(pVolDesc,
  2711. &RootName,
  2712. &RootName,
  2713. AFP_ID_ROOT);
  2714. // mark the volume as 'officially' added.
  2715. AfpInterlockedClearDword(&pVolDesc->vds_Flags,
  2716. VOLUME_INTRANSITION,
  2717. &pVolDesc->vds_VolLock);
  2718. // Remove the Indexing reference
  2719. AfpVolumeDereference(pVolDesc);
  2720. return(AFP_ERR_NONE);
  2721. }
  2722. /*** AfpVolumePostChangeNotify
  2723. *
  2724. * Post a change notify on the root of the volume. If the current size of
  2725. * the notify buffer for this volume is not large enough to accomodate a path
  2726. * containing n+1 macintosh filename components, (where n is the maximum
  2727. * depth of the directory tree and a component is a maximum of 31 unicode
  2728. * chars plus 1 char path separator), then the buffer is reallocated.
  2729. * The notify buffer does not ever shrink in size since we cannot keep track
  2730. * of the maximum depth of each branch of the directory tree whenever a
  2731. * directory is deleted.
  2732. *
  2733. * Note that the initial size of the notify buffer is
  2734. * AFP_VOLUME_NOTIFY_STARTING_BUFSIZE. When a volume is added, the change
  2735. * notify is posted *before* the Id Index database is constructed so we do
  2736. * not know what the maximum depth of the tree is yet. In most cases this
  2737. * buffer length is sufficient and will probably never get reallocated unless
  2738. * some sadistic test is running that creates very deep directories. Note
  2739. * that since the maximum path in win32 is 260 chars, the initial buffer
  2740. * size is adequate to handle any changes notified from PC side.
  2741. *
  2742. */
  2743. NTSTATUS FASTCALL
  2744. AfpVolumePostChangeNotify(
  2745. IN PVOLDESC pVolDesc
  2746. )
  2747. {
  2748. PIRP pIrp = NULL;
  2749. PMDL pMdl = NULL;
  2750. PBYTE pNotifyBuf = NULL;
  2751. DWORD NotifyBufSize = 0;
  2752. NTSTATUS Status = STATUS_SUCCESS;
  2753. PDEVICE_OBJECT pDeviceObject;
  2754. PIO_STACK_LOCATION pIrpSp;
  2755. PAGED_CODE ();
  2756. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  2757. ASSERT(pVolDesc->vds_pFileObject != NULL);
  2758. do
  2759. {
  2760. // Get the address of the target device object.
  2761. pDeviceObject = IoGetRelatedDeviceObject(AfpGetRealFileObject(pVolDesc->vds_pFileObject));
  2762. // free that irp: we need to allocate a new one, in case some
  2763. // filter driver chained itself in
  2764. if ((pIrp = pVolDesc->vds_pIrp) != NULL)
  2765. {
  2766. if (pIrp->MdlAddress != NULL)
  2767. {
  2768. pNotifyBuf = MmGetSystemAddressForMdlSafe(
  2769. pIrp->MdlAddress,
  2770. NormalPagePriority);
  2771. AfpFreeMdl(pIrp->MdlAddress);
  2772. if (pNotifyBuf != NULL)
  2773. {
  2774. AfpFreeMemory(pNotifyBuf);
  2775. pNotifyBuf = NULL;
  2776. }
  2777. }
  2778. pVolDesc->vds_pIrp = NULL;
  2779. AfpFreeIrp(pIrp);
  2780. }
  2781. // Allocate and initialize the IRP for this operation, if we do not already
  2782. // have an Irp allocated for this volume.
  2783. if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
  2784. {
  2785. Status = STATUS_INSUFFICIENT_RESOURCES;
  2786. break;
  2787. }
  2788. pVolDesc->vds_pIrp = pIrp;
  2789. // Re-initialize the stack location.
  2790. pIrp->CurrentLocation = (CCHAR)(pIrp->StackCount + 1);
  2791. pIrp->Tail.Overlay.CurrentStackLocation =
  2792. ((PIO_STACK_LOCATION)((UCHAR *)(pIrp) +
  2793. sizeof(IRP) +
  2794. ((pDeviceObject->StackSize) * sizeof(IO_STACK_LOCATION))));
  2795. //
  2796. // If we aren't going to resue the buffer and the mdl, allocate a buffer for
  2797. // Notify information and create an Mdl for it.
  2798. //
  2799. if (pNotifyBuf == NULL)
  2800. {
  2801. NotifyBufSize = pVolDesc->vds_RequiredNotifyBufLen;
  2802. if (((pNotifyBuf = AfpAllocNonPagedMemory(NotifyBufSize)) == NULL) ||
  2803. ((pMdl = AfpAllocMdl(pNotifyBuf, NotifyBufSize, pIrp)) == NULL))
  2804. {
  2805. Status = STATUS_INSUFFICIENT_RESOURCES;
  2806. break;
  2807. }
  2808. }
  2809. else
  2810. {
  2811. ASSERT(pMdl != NULL);
  2812. pIrp->MdlAddress = pMdl;
  2813. }
  2814. ASSERT(NotifyBufSize > 0);
  2815. // Set up the completion routine.
  2816. IoSetCompletionRoutine( pIrp,
  2817. afpVolumeChangeNotifyComplete,
  2818. pVolDesc,
  2819. True,
  2820. True,
  2821. True);
  2822. pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pVolDesc->vds_pFileObject);
  2823. pIrp->Tail.Overlay.Thread = AfpThread;
  2824. pIrp->RequestorMode = KernelMode;
  2825. // Get a pointer to the stack location for the first driver. This will be
  2826. // used to pass the original function codes and the parameters.
  2827. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  2828. pIrpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
  2829. pIrpSp->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
  2830. pIrpSp->FileObject = AfpGetRealFileObject(pVolDesc->vds_pFileObject);
  2831. pIrpSp->DeviceObject = pDeviceObject;
  2832. // Copy the parameters to the service-specific portion of the IRP.
  2833. pIrpSp->Parameters.NotifyDirectory.Length = NotifyBufSize;
  2834. // We do not try to catch FILE_NOTIFY_CHANGE_SECURITY since it will
  2835. // complete with FILE_ACTION_MODIFIED, and we can't tell that it was
  2836. // actually security that changed. A change in security will update
  2837. // the last ChangeTime, but we can't pick this up for every
  2838. // FILE_ACTION_MODIFIED that comes in! So the result will be that
  2839. // if PC changes security, we will not update the modified time on
  2840. // a directory (nor the VolumeModified time so that mac would
  2841. // reenumerate any open windows to display the change in security).
  2842. pIrpSp->Parameters.NotifyDirectory.CompletionFilter =
  2843. FILE_NOTIFY_CHANGE_NAME |
  2844. FILE_NOTIFY_CHANGE_ATTRIBUTES |
  2845. FILE_NOTIFY_CHANGE_SIZE |
  2846. FILE_NOTIFY_CHANGE_CREATION |
  2847. FILE_NOTIFY_CHANGE_STREAM_SIZE |
  2848. FILE_NOTIFY_CHANGE_LAST_WRITE;
  2849. pIrpSp->Flags = SL_WATCH_TREE;
  2850. ASSERT(!(pVolDesc->vds_Flags & VOLUME_DELETED));
  2851. INTERLOCKED_INCREMENT_LONG( &afpNumPostedNotifies );
  2852. AfpInterlockedSetDword( &pVolDesc->vds_Flags,
  2853. VOLUME_NOTIFY_POSTED,
  2854. &pVolDesc->vds_VolLock);
  2855. Status = IoCallDriver(pDeviceObject, pIrp);
  2856. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  2857. ("AfpVolumePostChangeNotify: Posted ChangeNotify on %Z (status 0x%lx)\n",
  2858. &pVolDesc->vds_Name, Status));
  2859. } while (False);
  2860. ASSERTMSG("Post of Volume change notify failed!", NT_SUCCESS(Status));
  2861. if (Status == STATUS_INSUFFICIENT_RESOURCES)
  2862. {
  2863. AFPLOG_DDERROR( AFPSRVMSG_NONPAGED_POOL,
  2864. STATUS_NO_MEMORY,
  2865. NULL,
  2866. 0,
  2867. NULL);
  2868. if (pNotifyBuf != NULL)
  2869. AfpFreeMemory(pNotifyBuf);
  2870. if (pIrp != NULL)
  2871. AfpFreeIrp(pIrp);
  2872. if (pMdl != NULL)
  2873. AfpFreeMdl(pMdl);
  2874. }
  2875. return Status;
  2876. }
  2877. /*** afpVolumeChangeNotifyComplete
  2878. *
  2879. * This is the completion routine for a posted change notify request. Queue
  2880. * this Volume for ChangeNotify processing. No items should be processed
  2881. * until the volume is marked as started because the volume may be in the
  2882. * middle of its initial sync with disk of the entire tree, and we don't
  2883. * want to 'discover' a part of the tree that we may not have seen yet but
  2884. * that somebody just changed.
  2885. *
  2886. * LOCKS: AfpServerGlobalLock (SPIN), vds_VolLock (SPIN)
  2887. */
  2888. NTSTATUS
  2889. afpVolumeChangeNotifyComplete(
  2890. IN PDEVICE_OBJECT pDeviceObject,
  2891. IN PIRP pIrp,
  2892. IN PVOLDESC pVolDesc
  2893. )
  2894. {
  2895. PVOL_NOTIFY pVolNotify = NULL;
  2896. PBYTE pBuf;
  2897. NTSTATUS status = STATUS_SUCCESS;
  2898. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  2899. ASSERT(VALID_VOLDESC(pVolDesc));
  2900. ASSERT(pIrp == pVolDesc->vds_pIrp);
  2901. ASSERT(pIrp->MdlAddress != NULL);
  2902. pBuf = MmGetSystemAddressForMdlSafe(
  2903. pIrp->MdlAddress,
  2904. NormalPagePriority);
  2905. AfpInterlockedClearDword(&pVolDesc->vds_Flags,
  2906. VOLUME_NOTIFY_POSTED,
  2907. &pVolDesc->vds_VolLock);
  2908. INTERLOCKED_DECREMENT_LONG(&afpNumPostedNotifies);
  2909. if (((AfpServerState == AFP_STATE_SHUTTINGDOWN) ||
  2910. (AfpServerState == AFP_STATE_STOP_PENDING)) &&
  2911. (afpNumPostedNotifies == 0))
  2912. {
  2913. // If we are getting out, unblock the the admin thread
  2914. KeSetEvent(&AfpStopConfirmEvent, IO_NETWORK_INCREMENT, False);
  2915. }
  2916. if (((pIrp->IoStatus.Status != STATUS_CANCELLED) &&
  2917. ((pVolDesc->vds_Flags & (VOLUME_STOPPED | VOLUME_DELETED)) == 0)) &&
  2918. (pBuf != NULL)
  2919. )
  2920. {
  2921. if ((NT_SUCCESS(pIrp->IoStatus.Status)) &&
  2922. (pIrp->IoStatus.Information > 0))
  2923. {
  2924. // Allocate a notify structure and copy the data into it.
  2925. // Post another notify before we process this one
  2926. pVolNotify = (PVOL_NOTIFY)AfpAllocNonPagedMemory(sizeof(VOL_NOTIFY) +
  2927. (ULONG)(pIrp->IoStatus.Information) +
  2928. (AFP_LONGNAME_LEN + 1)*sizeof(WCHAR));
  2929. if (pVolNotify != NULL)
  2930. {
  2931. AfpGetCurrentTimeInMacFormat(&pVolNotify->vn_TimeStamp);
  2932. pVolNotify->vn_pVolDesc = pVolDesc;
  2933. pVolNotify->vn_Processor = AfpProcessChangeNotify;
  2934. RtlCopyMemory((PCHAR)pVolNotify + sizeof(VOL_NOTIFY),
  2935. pBuf,
  2936. pIrp->IoStatus.Information);
  2937. }
  2938. else
  2939. {
  2940. DBGPRINT(DBG_COMP_CHGNOTIFY, DBG_LEVEL_ERR,("Out of memory!!\n"));
  2941. ASSERT(0);
  2942. status = STATUS_INSUFFICIENT_RESOURCES;
  2943. }
  2944. }
  2945. else
  2946. {
  2947. if (pIrp->IoStatus.Status == STATUS_NOTIFY_ENUM_DIR)
  2948. {
  2949. pVolDesc->vds_RequiredNotifyBufLen *= 2;
  2950. if (pVolDesc->vds_RequiredNotifyBufLen > AFP_VOLUME_NOTIFY_MAX_BUFSIZE)
  2951. {
  2952. DBGPRINT(DBG_COMP_CHGNOTIFY, DBG_LEVEL_ERR,
  2953. ("afpVolumeChangeNotifyComplete: even %d isn't enough (%d,%lx)??\n",
  2954. AFP_VOLUME_NOTIFY_MAX_BUFSIZE,pVolDesc->vds_RequiredNotifyBufLen,pBuf));
  2955. ASSERT(0);
  2956. pVolDesc->vds_RequiredNotifyBufLen = AFP_VOLUME_NOTIFY_MAX_BUFSIZE;
  2957. }
  2958. }
  2959. else
  2960. {
  2961. DBGPRINT(DBG_COMP_CHGNOTIFY, DBG_LEVEL_ERR,
  2962. ("afpVolumeChangeNotifyComplete: Status %lx, Info %d\n",
  2963. pIrp->IoStatus.Status,pIrp->IoStatus.Information));
  2964. ASSERT(0);
  2965. }
  2966. status = pIrp->IoStatus.Status;
  2967. }
  2968. // Repost our ChangeNotify request if the last one completed
  2969. // without an error
  2970. if (NT_SUCCESS(pIrp->IoStatus.Status))
  2971. {
  2972. AfpVolumePostChangeNotify(pVolDesc);
  2973. }
  2974. else
  2975. {
  2976. // If this notify completed with an error, we cannot recursively
  2977. // repost another one, since it will just keep completing with
  2978. // the same error and we will run out of stack space recursing.
  2979. // We will have to queue up a work item so that the
  2980. // change notify request will get reposted for this volume.
  2981. // Note that in the time it takes to do this, many changes could
  2982. // pile up so the next completion would have multiple entries
  2983. // returned in the list.
  2984. AfpScavengerScheduleEvent(AfpVolumePostChangeNotify,
  2985. (PVOID)pVolDesc,
  2986. 0,
  2987. True);
  2988. }
  2989. if (pVolNotify != NULL)
  2990. {
  2991. if (AfpShouldWeIgnoreThisNotification(pVolNotify))
  2992. {
  2993. AfpFreeMemory(pVolNotify);
  2994. }
  2995. else
  2996. {
  2997. PFILE_NOTIFY_INFORMATION pFNInfo;
  2998. // Reference the volume for Notify processing
  2999. if (AfpVolumeReference(pVolDesc))
  3000. {
  3001. AfpVolumeInsertChangeNotifyList(pVolNotify, pVolDesc);
  3002. pFNInfo = (PFILE_NOTIFY_INFORMATION)(pVolNotify + 1);
  3003. if ((pFNInfo->Action == FILE_ACTION_REMOVED) ||
  3004. (pFNInfo->Action == FILE_ACTION_RENAMED_OLD_NAME))
  3005. {
  3006. // Chain all the rename and delete changes off of the
  3007. // volume descriptor in case we ever need to lookahead
  3008. // for one. We only look at the first change in each
  3009. // FILE_NOTIFY_INFORMATION since normally there will only
  3010. // be one entry per buffer since we repost our changenotify
  3011. // within our completion routine.
  3012. ExInterlockedInsertTailList(&pVolDesc->vds_ChangeNotifyLookAhead,
  3013. &pVolNotify->vn_DelRenLink,
  3014. &(pVolDesc->vds_VolLock.SpinLock));
  3015. }
  3016. else
  3017. {
  3018. // Just set links to initialized state. These will never be looked at.
  3019. InitializeListHead(&pVolNotify->vn_DelRenLink);
  3020. }
  3021. }
  3022. else
  3023. {
  3024. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_ERR,
  3025. ("afpVolumeChangeNotifyComplete: couldn't reference volume %Z!!\n",
  3026. &pVolDesc->vds_Name));
  3027. AfpFreeMemory(pVolNotify);
  3028. }
  3029. }
  3030. }
  3031. else
  3032. {
  3033. AFPLOG_ERROR(AFPSRVMSG_MISSED_NOTIFY,
  3034. status,
  3035. NULL,
  3036. 0,
  3037. &pVolDesc->vds_Name);
  3038. }
  3039. }
  3040. else
  3041. {
  3042. // Free the resources and get out
  3043. AfpFreeMdl(pIrp->MdlAddress);
  3044. if (pBuf != NULL)
  3045. AfpFreeMemory(pBuf);
  3046. AfpFreeIrp(pIrp);
  3047. pVolDesc->vds_pIrp = NULL;
  3048. AfpVolumeDereference(pVolDesc);
  3049. }
  3050. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  3051. // will stop working on the IRP.
  3052. return STATUS_MORE_PROCESSING_REQUIRED;
  3053. }
  3054. /*** afpAllocNotify
  3055. *
  3056. * Allocate a Notify from the Notify Blocks. The Notify's are allocated
  3057. * in 4K chunks and internally managed. The idea is primarily to reduce
  3058. * the dependency we may have on non-paged/paged memory during posting
  3059. * private notify code.
  3060. *
  3061. * The Notify's are allocated out of virtual memory.
  3062. *
  3063. * LOCKS: afpNotifyBlockLock (SWMR, Exclusive)
  3064. *
  3065. */
  3066. PVOL_NOTIFY
  3067. afpAllocNotify(
  3068. IN LONG Index,
  3069. IN BOOLEAN fDir
  3070. )
  3071. {
  3072. PVOL_NOTIFY_BLOCK pDfb;
  3073. PVOL_NOTIFY pVolNotify = NULL;
  3074. PAGED_CODE( );
  3075. ASSERT ((Index >= 0) && (Index < NOTIFY_MAX_BLOCK_TYPE));
  3076. AfpSwmrAcquireExclusive(&afpNotifyBlockLock);
  3077. // If the block head has no free entries then there are none !!
  3078. // Pick the right block based on whether it is file or dir
  3079. pDfb = afpDirNotifyPartialBlockHead[Index];
  3080. if (pDfb == NULL)
  3081. {
  3082. // Currently we will directly allocate it instead of managing
  3083. // the free list and assigning out of it
  3084. //
  3085. // There are no partial blocks. Check if there any free ones
  3086. // and if there move them to partial
  3087. // since we about to allocate from them
  3088. //
  3089. pDfb = afpDirNotifyFreeBlockHead[Index];
  3090. if (pDfb != NULL)
  3091. {
  3092. AfpUnlinkDouble(pDfb, dfb_Next, dfb_Prev);
  3093. AfpLinkDoubleAtHead(afpDirNotifyPartialBlockHead[Index],
  3094. pDfb,
  3095. dfb_Next,
  3096. dfb_Prev);
  3097. }
  3098. }
  3099. if (pDfb != NULL)
  3100. {
  3101. ASSERT(VALID_NOTIFY_BLOCK(pDfb));
  3102. ASSERT((pDfb->dfb_NumFree <= afpNotifyNumDirBlocks[Index]));
  3103. ASSERT (pDfb->dfb_NumFree != 0);
  3104. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_INFO,
  3105. ("afpAllocDfe: Found space in Block %lx\n", pDfb));
  3106. }
  3107. if (pDfb == NULL)
  3108. {
  3109. if ((pDfb = (PVOL_NOTIFY_BLOCK)AfpAllocateVirtualMemoryPage()) != NULL)
  3110. {
  3111. USHORT i;
  3112. USHORT MaxDfes, NotifySize;
  3113. afpNotifyBlockAllocCount ++;
  3114. // update max notify block alloc count
  3115. if (afpNotifyBlockAllocCount > afpMaxNotifyBlockAllocCount)
  3116. {
  3117. afpMaxNotifyBlockAllocCount = afpNotifyBlockAllocCount;
  3118. }
  3119. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  3120. ("afpAllocNotify: No free blocks. Allocated a new block %lx , count=%ld\n",
  3121. pDfb, afpNotifyBlockAllocCount));
  3122. //
  3123. // Link it in the partial list as we are about to
  3124. // allocate one block out of it anyway.
  3125. //
  3126. AfpLinkDoubleAtHead(afpDirNotifyPartialBlockHead[Index],
  3127. pDfb,
  3128. dfb_Next,
  3129. dfb_Prev);
  3130. NotifySize = afpNotifyDirBlockSize[Index];
  3131. pDfb->dfb_NumFree = MaxDfes = afpNotifyNumDirBlocks[Index];
  3132. ASSERT(QUAD_SIZED(NotifySize));
  3133. pDfb->dfb_Age = 0;
  3134. // Initialize the list of free notify entries
  3135. for (i = 0, pVolNotify = pDfb->dfb_FreeHead = (PVOL_NOTIFY)((PBYTE)pDfb + sizeof(VOL_NOTIFY_BLOCK));
  3136. i < MaxDfes;
  3137. i++, pVolNotify = pVolNotify->Notify_NextFree)
  3138. {
  3139. pVolNotify->Notify_NextFree = (i == (MaxDfes - 1)) ?
  3140. NULL :
  3141. (PVOL_NOTIFY)((PBYTE)pVolNotify + NotifySize);
  3142. }
  3143. }
  3144. else
  3145. {
  3146. DBGPRINT(DBG_COMP_CHGNOTIFY, DBG_LEVEL_ERR,
  3147. ("afpAllocDfe: AfpAllocateVirtualMemoryPage failed\n"));
  3148. AFPLOG_ERROR(AFPSRVMSG_VIRTMEM_ALLOC_FAILED,
  3149. STATUS_INSUFFICIENT_RESOURCES,
  3150. NULL,
  3151. 0,
  3152. NULL);
  3153. }
  3154. }
  3155. if (pDfb != NULL)
  3156. {
  3157. PVOL_NOTIFY_BLOCK pTmp;
  3158. ASSERT(VALID_NOTIFY_BLOCK(pDfb));
  3159. pVolNotify = pDfb->dfb_FreeHead;
  3160. afpNotifyAllocCount ++;
  3161. pDfb->dfb_FreeHead = pVolNotify->Notify_NextFree;
  3162. pDfb->dfb_NumFree --;
  3163. //
  3164. // If the block is now empty (completely used), unlink it
  3165. // from here and move it to the Used list.
  3166. //
  3167. if (pDfb->dfb_NumFree == 0)
  3168. {
  3169. AfpUnlinkDouble(pDfb, dfb_Next, dfb_Prev);
  3170. AfpLinkDoubleAtHead(afpDirNotifyUsedBlockHead[Index],
  3171. pDfb,
  3172. dfb_Next,
  3173. dfb_Prev);
  3174. }
  3175. }
  3176. AfpSwmrRelease(&afpNotifyBlockLock);
  3177. return pVolNotify;
  3178. }
  3179. /*** afpFreeNotify
  3180. *
  3181. * Return a Notify to the allocation block.
  3182. *
  3183. * LOCKS: afpNotifyBlockLock (SWMR, Exclusive)
  3184. */
  3185. VOID
  3186. afpFreeNotify(
  3187. IN PVOL_NOTIFY pVolNotify
  3188. )
  3189. {
  3190. PVOL_NOTIFY_BLOCK pDfb;
  3191. ULONG NumBlks, index;
  3192. PAGED_CODE( );
  3193. // NOTE: The following code *depends* on the fact that we allocate DFBs as
  3194. // 64K blocks and also that these are allocated *at* 64K boundaries
  3195. // This lets us *cheaply* get to the owning DFB from the DFE.
  3196. pDfb = (PVOL_NOTIFY_BLOCK)((ULONG_PTR)pVolNotify & ~(PAGE_SIZE-1));
  3197. ASSERT(VALID_NOTIFY_BLOCK(pDfb));
  3198. AfpSwmrAcquireExclusive(&afpNotifyBlockLock);
  3199. afpNotifyAllocCount --;
  3200. index = NOTIFY_USIZE_TO_INDEX(pVolNotify->vn_VariableLength);
  3201. NumBlks = afpNotifyNumDirBlocks[index];
  3202. ASSERT(pDfb->dfb_NumFree < NumBlks);
  3203. #if DBG
  3204. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  3205. ("AfpFreeDfe: Returning Notify %lx to Block %lx, index=%ld, dfb=%ld, alloc=%ld\n",
  3206. pVolNotify, pDfb, index, pDfb->dfb_NumFree+1, afpNotifyAllocCount));
  3207. #endif
  3208. pDfb->dfb_NumFree ++;
  3209. pVolNotify->Notify_NextFree = pDfb->dfb_FreeHead;
  3210. pDfb->dfb_FreeHead = pVolNotify;
  3211. if (pDfb->dfb_NumFree == 1)
  3212. {
  3213. ULONG Index;
  3214. //
  3215. // The block is now partially free (it used to be completely used). move it to the partial list.
  3216. //
  3217. Index = NOTIFY_USIZE_TO_INDEX(pVolNotify->vn_VariableLength);
  3218. AfpUnlinkDouble(pDfb, dfb_Next, dfb_Prev);
  3219. AfpLinkDoubleAtHead(afpDirNotifyPartialBlockHead[Index],
  3220. pDfb,
  3221. dfb_Next,
  3222. dfb_Prev);
  3223. }
  3224. else if (pDfb->dfb_NumFree == NumBlks)
  3225. {
  3226. ULONG Index;
  3227. //
  3228. // The block is now completely free (used to be partially used). move it to the free list
  3229. //
  3230. Index = NOTIFY_USIZE_TO_INDEX(pVolNotify->vn_VariableLength);
  3231. pDfb->dfb_Age = 0;
  3232. AfpUnlinkDouble(pDfb, dfb_Next, dfb_Prev);
  3233. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  3234. ("afpFreeDfe: Freeing Block %lx, Index=%ld\n", pDfb, Index));
  3235. AfpLinkDoubleAtHead(afpDirNotifyFreeBlockHead[Index],
  3236. pDfb,
  3237. dfb_Next,
  3238. dfb_Prev);
  3239. }
  3240. AfpSwmrRelease(&afpNotifyBlockLock);
  3241. }
  3242. /*** afpNotifyBlockAge
  3243. *
  3244. * Age out Notify Blocks
  3245. *
  3246. * LOCKS: afpNotifyBlockLock (SWMR, Exclusive)
  3247. */
  3248. AFPSTATUS FASTCALL
  3249. afpNotifyBlockAge(
  3250. IN PPVOL_NOTIFY_BLOCK ppBlockHead
  3251. )
  3252. {
  3253. int index, MaxDfes;
  3254. PVOL_NOTIFY_BLOCK pDfb;
  3255. PAGED_CODE( );
  3256. AfpSwmrAcquireExclusive(&afpNotifyBlockLock);
  3257. for (index = 0; index < NOTIFY_MAX_BLOCK_TYPE; index++)
  3258. {
  3259. pDfb = ppBlockHead[index];
  3260. if (pDfb != NULL)
  3261. {
  3262. MaxDfes = afpNotifyNumDirBlocks[index];
  3263. }
  3264. while (pDfb != NULL)
  3265. {
  3266. PVOL_NOTIFY_BLOCK pFree;
  3267. ASSERT(VALID_NOTIFY_BLOCK(pDfb));
  3268. pFree = pDfb;
  3269. pDfb = pDfb->dfb_Next;
  3270. ASSERT (pFree->dfb_NumFree == MaxDfes);
  3271. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  3272. ("afpNotifyBlockAge: Aging Block %lx, Size %d\n", pFree,
  3273. afpNotifyDirBlockSize[index]));
  3274. if (++(pFree->dfb_Age) >= NOTIFY_MAX_BLOCK_AGE)
  3275. {
  3276. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  3277. ("afpNotifyBlockAge: Freeing Block %lx, Size %d\n", pFree,
  3278. afpNotifyDirBlockSize[index]));
  3279. AfpUnlinkDouble(pFree, dfb_Next, dfb_Prev);
  3280. AfpFreeVirtualMemoryPage(pFree);
  3281. afpNotifyBlockAllocCount--;
  3282. }
  3283. }
  3284. }
  3285. AfpSwmrRelease(&afpNotifyBlockLock);
  3286. return AFP_ERR_REQUEUE;
  3287. }
  3288. /*** afpFreeNotifyBlockMemory
  3289. *
  3290. * Forced Freeing of Notify Blocks
  3291. *
  3292. * LOCKS: afpNotifyBlockLock (SWMR, Exclusive)
  3293. */
  3294. VOID afpFreeNotifyBlockMemory (
  3295. )
  3296. {
  3297. int index, MaxDfes;
  3298. PVOL_NOTIFY_BLOCK pDfb;
  3299. PAGED_CODE( );
  3300. AfpSwmrAcquireExclusive(&afpNotifyBlockLock);
  3301. for (index = 0; index < NOTIFY_MAX_BLOCK_TYPE; index++)
  3302. {
  3303. pDfb = afpDirNotifyFreeBlockHead[index];
  3304. if (pDfb != NULL)
  3305. {
  3306. MaxDfes = afpNotifyNumDirBlocks[index];
  3307. }
  3308. while (pDfb != NULL)
  3309. {
  3310. PVOL_NOTIFY_BLOCK pFree;
  3311. ASSERT(VALID_NOTIFY_BLOCK(pDfb));
  3312. pFree = pDfb;
  3313. pDfb = pDfb->dfb_Next;
  3314. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  3315. ("afpFreeNotifyBlockMemory: Cleaningup Free Block %lx, Size %d\n",
  3316. pFree, afpNotifyDirBlockSize[index]));
  3317. AfpUnlinkDouble(pFree, dfb_Next, dfb_Prev);
  3318. AfpFreeVirtualMemoryPage(pFree);
  3319. afpNotifyBlockAllocCount--;
  3320. }
  3321. pDfb = afpDirNotifyPartialBlockHead[index];
  3322. while (pDfb != NULL)
  3323. {
  3324. PVOL_NOTIFY_BLOCK pFree;
  3325. ASSERT(VALID_NOTIFY_BLOCK(pDfb));
  3326. pFree = pDfb;
  3327. pDfb = pDfb->dfb_Next;
  3328. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  3329. ("afpFreeNotifyBlockMemory: Cleaningup Partial Block %lx, Size %d\n",
  3330. pFree, afpNotifyDirBlockSize[index]));
  3331. AfpUnlinkDouble(pFree, dfb_Next, dfb_Prev);
  3332. AfpFreeVirtualMemoryPage(pFree);
  3333. afpNotifyBlockAllocCount--;
  3334. }
  3335. pDfb = afpDirNotifyUsedBlockHead[index];
  3336. while (pDfb != NULL)
  3337. {
  3338. PVOL_NOTIFY_BLOCK pFree;
  3339. ASSERT(VALID_NOTIFY_BLOCK(pDfb));
  3340. pFree = pDfb;
  3341. pDfb = pDfb->dfb_Next;
  3342. DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_WARN,
  3343. ("afpFreeNotifyBlockMemory: Cleaningup Used Block %lx, Size %d\n",
  3344. pFree, afpNotifyDirBlockSize[index]));
  3345. AfpUnlinkDouble(pFree, dfb_Next, dfb_Prev);
  3346. AfpFreeVirtualMemoryPage(pFree);
  3347. afpNotifyBlockAllocCount--;
  3348. }
  3349. }
  3350. AfpSwmrRelease(&afpNotifyBlockLock);
  3351. }