Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3294 lines
93 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: LOCALVOL.C
  6. //
  7. // Contents: This module implements the routines associated with
  8. // managing local volumes. These are generally external
  9. // interfaces which are called via NtFsControlFile.
  10. //
  11. // Functions: DfsFsctrlGetLocalVolumeEntry -
  12. // DfsFsctrlCreateLocalPartition -
  13. // DfsFsctrlDeleteLocalPartition -
  14. // DfsFsctrlCreateExitPoint -
  15. // DfsFsctrlDeleteExitPoint -
  16. // BuildLocalVolPath - build the path to a file on a local volume
  17. // DfsCreateExitPath -
  18. // DfsDeleteExitPath -
  19. // DfsGetPrincipalName -
  20. // DfsFileOnExitPath -
  21. // DfsStorageIdLegal -
  22. //
  23. // History: 28 May 1992 Peterco Created.
  24. // 22 Jul 1992 Alanw Extended DfsFsctrlInitLocalPartitions
  25. // SudK Creating/DeletingLocal Knowledge
  26. // SudK Adding Aging PKT entries.
  27. // 12 Jul 1993 Alanw Removed fsctrls for manipulating PKT.
  28. //
  29. //-----------------------------------------------------------------------------
  30. #include "dfsprocs.h"
  31. #include <align.h>
  32. #include <stdlib.h>
  33. #include <dfserr.h>
  34. #include <netevent.h>
  35. #include "fsctrl.h"
  36. #include "registry.h"
  37. #include "regkeys.h"
  38. #include "log.h"
  39. #include "know.h"
  40. #include "lvolinit.h"
  41. #include "attach.h"
  42. #include "dfswml.h"
  43. //
  44. // The local debug trace level
  45. //
  46. #define Dbg (DEBUG_TRACE_LOCALVOL)
  47. BOOLEAN
  48. DfsDeleteDirectoryCheck(
  49. UCHAR *Buffer);
  50. ULONG
  51. DfsGetDirectoriesToDelete(
  52. PUNICODE_STRING pExitPtName,
  53. PUNICODE_STRING pShareName);
  54. NTSTATUS
  55. DfsCreateExitPath(
  56. IN PDFS_SERVICE pService,
  57. IN PUNICODE_STRING pRemPath,
  58. IN ULONG Disposition);
  59. NTSTATUS
  60. BuildShortPrefix(
  61. IN PUNICODE_STRING pRemPath,
  62. IN PDFS_SERVICE pService,
  63. IN PDFS_PKT_ENTRY_ID PeidParent,
  64. IN OUT PDFS_PKT_ENTRY_ID Peid);
  65. VOID
  66. StripLastComponent(PUNICODE_STRING pustr);
  67. VOID
  68. AddLastComponent(PUNICODE_STRING pustr);
  69. #ifdef ALLOC_PRAGMA
  70. #pragma alloc_text( PAGE, DfsFsctrlGetLocalVolumeEntry )
  71. #pragma alloc_text( PAGE, DfsFsctrlGetEntryType )
  72. #pragma alloc_text( PAGE, DfsFsctrlGetChildVolumes )
  73. #pragma alloc_text( PAGE, BuildLocalVolPath )
  74. #pragma alloc_text( PAGE, DfsRegModifyLocalVolume )
  75. #pragma alloc_text( PAGE, DfsFsctrlCreateLocalPartition )
  76. #pragma alloc_text( PAGE, DfsInternalDeleteLocalVolume )
  77. #pragma alloc_text( PAGE, DfsFsctrlDeleteLocalPartition )
  78. #pragma alloc_text( PAGE, DfsCreateExitPath )
  79. #pragma alloc_text( PAGE, DfsDeleteExitPath )
  80. #pragma alloc_text( PAGE, DfsInternalModifyPrefix )
  81. #pragma alloc_text( PAGE, DfsFsctrlModifyLocalVolPrefix )
  82. #pragma alloc_text( PAGE, DfsInternalCreateExitPoint )
  83. #pragma alloc_text( PAGE, DfsFsctrlCreateExitPoint )
  84. #pragma alloc_text( PAGE, DfsInternalDeleteExitPoint )
  85. #pragma alloc_text( PAGE, DfsFsctrlDeleteExitPoint )
  86. #pragma alloc_text( PAGE, DfsGetPrincipalName )
  87. #pragma alloc_text( PAGE, DfsFileOnExitPath )
  88. #pragma alloc_text( PAGE, DfsStorageIdLegal )
  89. #pragma alloc_text( PAGE, DfsExitPtLegal )
  90. #pragma alloc_text( PAGE, BuildShortPrefix)
  91. #pragma alloc_text( PAGE, StripLastComponent)
  92. #pragma alloc_text( PAGE, AddLastComponent)
  93. #pragma alloc_text( PAGE, DfsDeleteDirectoryCheck)
  94. #pragma alloc_text( PAGE, DfsGetDirectoriesToDelete)
  95. #endif // ALLOC_PRAGMA
  96. //+----------------------------------------------------------------------------
  97. //
  98. // Function: DfspBringVolumeOnline
  99. //
  100. // Synopsis: Brings an offline volume online
  101. //
  102. // Arguments: [pkt] -- The pkt and pktEntry identify the local volume to
  103. // [pktEntry] -- bring online
  104. //
  105. // Returns:
  106. //
  107. //-----------------------------------------------------------------------------
  108. NTSTATUS
  109. DfspBringVolumeOnline(
  110. IN PDFS_PKT pkt,
  111. IN PDFS_PKT_ENTRY pktEntry)
  112. {
  113. NTSTATUS status;
  114. UNICODE_STRING shareName, localVolAddress;
  115. PDEVICE_OBJECT targetVdo;
  116. PDFS_VOLUME_OBJECT dfsVdo;
  117. ULONG volNameLen;
  118. BOOLEAN fCreated;
  119. //
  120. // Construct the full share name.
  121. //
  122. ASSERT(pktEntry->LocalService != NULL );
  123. shareName = pktEntry->LocalService->Address;
  124. status = DfsGetAttachName( &shareName, &localVolAddress );
  125. if (NT_SUCCESS(status)) {
  126. status = DfsAttachVolume(
  127. &shareName,
  128. &pktEntry->LocalService->pProvider);
  129. if (NT_SUCCESS(status)) {
  130. pktEntry->LocalService->Type &= ~DFS_SERVICE_TYPE_OFFLINE;
  131. RtlMoveMemory(
  132. (PVOID) pktEntry->LocalService->Address.Buffer,
  133. (PVOID) localVolAddress.Buffer,
  134. localVolAddress.Length);
  135. pktEntry->LocalService->Address.Length = localVolAddress.Length;
  136. }
  137. } else {
  138. status = STATUS_INSUFFICIENT_RESOURCES;
  139. }
  140. return( status );
  141. }
  142. //+----------------------------------------------------------------------------
  143. //
  144. // Function: DfspTakeVolumeOffline
  145. //
  146. // Synopsis: Takes an online volume offline
  147. //
  148. // Arguments: [pkt] -- The pkt and pktEntry identify the local volume to be
  149. // [pktEntry] -- taken off line.
  150. //
  151. // Returns: [STATUS_SUCCESS] -- The volume was sucessfully taken offline.
  152. //
  153. // [STATUS_FILES_OPEN] -- The volume could not be taken offline
  154. // because it has open files.
  155. //
  156. // Notes: Assumes that the pkt has been acquired exclusive.
  157. //
  158. //-----------------------------------------------------------------------------
  159. NTSTATUS
  160. DfspTakeVolumeOffline(
  161. IN PDFS_PKT pkt,
  162. IN PDFS_PKT_ENTRY pktEntry)
  163. {
  164. NTSTATUS status;
  165. if (pktEntry->FileOpenCount > 0) {
  166. DebugTrace(0, Dbg, "Volume has %d open files\n", ULongToPtr( pktEntry->FileOpenCount ));
  167. status = STATUS_FILES_OPEN;
  168. } else {
  169. UNICODE_STRING shareName, remPath;
  170. DebugTrace(0, Dbg, "Volume has no files open!\n", 0);
  171. //
  172. // Detach the device object from the volume
  173. //
  174. remPath.Length = 0;
  175. remPath.MaximumLength = 0;
  176. remPath.Buffer = NULL;
  177. status = BuildLocalVolPath(&shareName, pktEntry->LocalService, &remPath);
  178. if (NT_SUCCESS(status)) {
  179. DebugTrace(0, Dbg, "Detaching device object %wZ\n", &shareName);
  180. if (!(pktEntry->Type & PKT_ENTRY_TYPE_LEAFONLY) &&
  181. !(pktEntry->LocalService->pProvider->fProvCapability & PROV_UNAVAILABLE)) {
  182. DfsDetachVolume( &shareName );
  183. }
  184. ASSERT( pktEntry->LocalService != NULL );
  185. pktEntry->LocalService->Type |= DFS_SERVICE_TYPE_OFFLINE;
  186. //
  187. // At this point, the LocalService->Address field has the name
  188. // relative to the device name. If we later try to bring this
  189. // volume online, we'll need the full name, including the device.
  190. // So, we'll junk the LocalService->Address field and copy the
  191. // full name there, just in case we need to bring it online again.
  192. //
  193. ExFreePool( pktEntry->LocalService->Address.Buffer );
  194. pktEntry->LocalService->Address = shareName;
  195. } else {
  196. DebugTrace(0, Dbg, "Unable to allocate share name %08lx\n", ULongToPtr( status ));
  197. }
  198. }
  199. return( status );
  200. }
  201. //+----------------------------------------------------------------------------
  202. //
  203. // Function: DfsFsctrlSetVolumeState
  204. //
  205. // Synopsis: Sets the volume on or off line.
  206. //
  207. // Arguments:
  208. //
  209. // Returns: [STATUS_SUCCESS] -- The volume state was successfully set
  210. // to the requested mode.
  211. //
  212. // [STATUS_FILES_OPEN] -- The volume has open files.
  213. //
  214. // [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- The volume is not local
  215. //
  216. // [STATUS_INSUFFICIENT_RESOURCES] -- Unable to unmarshal
  217. // arguments or allocate memory to complete operations
  218. //
  219. //-----------------------------------------------------------------------------
  220. NTSTATUS
  221. DfsFsctrlSetVolumeState(
  222. IN PIRP Irp,
  223. IN PVOID InputBuffer,
  224. IN ULONG InputBufferLength)
  225. {
  226. NTSTATUS status;
  227. PDFS_SET_LOCAL_VOLUME_STATE_ARG setArg;
  228. PDFS_PKT pkt;
  229. DFS_PKT_ENTRY_ID EntryId;
  230. PDFS_PKT_ENTRY pktEntry;
  231. STD_FSCTRL_PROLOGUE(DfsFsctrlSetVolumeState, TRUE, FALSE);
  232. if (InputBufferLength < sizeof(*setArg)+sizeof(UNICODE_NULL)) {
  233. status = STATUS_INVALID_PARAMETER;
  234. goto exit_with_status;
  235. }
  236. //
  237. // Unmarshal the name of the volume and the requested state.
  238. //
  239. setArg = (PDFS_SET_LOCAL_VOLUME_STATE_ARG) InputBuffer;
  240. OFFSET_TO_POINTER( setArg->Prefix, setArg );
  241. if (!DfspStringInBuffer(setArg->Prefix, InputBuffer, InputBufferLength)) {
  242. status = STATUS_INVALID_PARAMETER;
  243. goto exit_with_status;
  244. }
  245. EntryId.Uid = setArg->Uid;
  246. RtlInitUnicodeString( &EntryId.Prefix, setArg->Prefix );
  247. pkt = _GetPkt();
  248. PktAcquireExclusive( pkt, TRUE );
  249. DebugTrace(0, Dbg, "Setting state for [%wZ]\n", &EntryId.Prefix );
  250. DebugTrace(0, Dbg, "Requested state is %d\n", ULongToPtr( setArg->State ));
  251. pktEntry = PktLookupEntryById( pkt, &EntryId );
  252. if (pktEntry == NULL ) {
  253. DebugTrace(0, Dbg, "Unable to locate Pkt Entry!\n", 0);
  254. status = DFS_STATUS_NOSUCH_LOCAL_VOLUME;
  255. } else {
  256. if (!(pktEntry->Type & PKT_ENTRY_TYPE_LOCAL)) {
  257. DebugTrace(0, Dbg, "Entry %wZ is not a local volume!\n",
  258. &EntryId.Prefix);
  259. status = DFS_STATUS_BAD_EXIT_POINT;
  260. } else {
  261. status = STATUS_SUCCESS;
  262. }
  263. }
  264. if (NT_SUCCESS(status)) {
  265. ASSERT( pktEntry != NULL );
  266. //
  267. // See if the state bit is already as desired; if not, then do
  268. // the needful.
  269. //
  270. if (((pktEntry->LocalService->Type & DFS_SERVICE_TYPE_OFFLINE)
  271. ^ setArg->State) != 0) {
  272. //
  273. // Volume is not in requested state - try to switch it.
  274. //
  275. if (setArg->State == DFS_SERVICE_TYPE_OFFLINE) {
  276. status = DfspTakeVolumeOffline( pkt, pktEntry );
  277. } else {
  278. status = DfspBringVolumeOnline( pkt, pktEntry );
  279. }
  280. //
  281. // If successful, update our persistent knowledge in the registry
  282. //
  283. if (NT_SUCCESS(status)) {
  284. status = DfsChangeLvolInfoServiceType(
  285. &pktEntry->Id.Uid,
  286. pktEntry->LocalService->Type);
  287. if (!NT_SUCCESS(status)) {
  288. NTSTATUS statusRecover;
  289. DebugTrace(
  290. 0,
  291. Dbg,
  292. "DfsFsctrlSetVolumeState: Unable to update "
  293. "registry %08lx!\n",
  294. ULongToPtr( status ));
  295. if (setArg->State == DFS_SERVICE_TYPE_OFFLINE) {
  296. statusRecover = DfspBringVolumeOnline(pkt, pktEntry);
  297. } else {
  298. statusRecover = DfspTakeVolumeOffline(pkt, pktEntry);
  299. }
  300. if (!NT_SUCCESS(statusRecover)) {
  301. DebugTrace(
  302. 0,
  303. Dbg,
  304. "DfsFsctrlSetVolumeState: Unable to recover "
  305. "%08lx!\n",
  306. ULongToPtr( statusRecover ));
  307. }
  308. }
  309. }
  310. } else {
  311. //
  312. // Volume is already in the requested state - return!
  313. //
  314. NOTHING;
  315. }
  316. }
  317. PktRelease( pkt );
  318. exit_with_status:
  319. DebugTrace(-1, Dbg, "DfsFsctrlSetVolumeState: Returning %08lx\n", ULongToPtr( status ));
  320. DfsCompleteRequest( Irp, status );
  321. return( status );
  322. }
  323. //+----------------------------------------------------------------------------
  324. //
  325. // Function: DfsFsctrlGetEntryType
  326. //
  327. // Synopsis: Looks-up and retrieves the type of the Pkt Entry for the input
  328. // prefix. If there is no exact match for the input prefix,
  329. // this function fails with STATUS_OBJECT_NAME_NOT_FOUND
  330. //
  331. // Arguments:
  332. //
  333. // Returns: [STATUS_SUCCESS] -- Entry is in output buffer.
  334. //
  335. // [STATUS_BUFFER_TOO_SMALL] -- The OutputBuffer was less than
  336. // 4 bytes, so can't return the type.
  337. //
  338. // [STATUS_OBJECT_NAME_NOT_FOUND] -- The input prefix is not
  339. // in the local pkt.
  340. //
  341. //-----------------------------------------------------------------------------
  342. NTSTATUS
  343. DfsFsctrlGetEntryType(
  344. IN PIRP Irp,
  345. IN PVOID InputBuffer,
  346. IN ULONG InputBufferLength,
  347. IN PVOID OutputBuffer,
  348. IN ULONG OutputBufferLength)
  349. {
  350. NTSTATUS Status = STATUS_SUCCESS;
  351. UNICODE_STRING prefix, remPath;
  352. MARSHAL_BUFFER marshalBuffer;
  353. PDFS_PKT pkt;
  354. PDFS_PKT_ENTRY pktEntry;
  355. STD_FSCTRL_PROLOGUE(DfsFsctrlGetEntryType, TRUE, TRUE);
  356. //
  357. // must be multiple of two
  358. //
  359. if ((InputBufferLength % sizeof(WCHAR)) != 0) {
  360. Status = STATUS_INVALID_PARAMETER;
  361. goto exit_with_status;
  362. }
  363. pkt = _GetPkt();
  364. PktAcquireShared(pkt, (BOOLEAN)TRUE);
  365. prefix.MaximumLength = prefix.Length = (USHORT) InputBufferLength;
  366. prefix.Buffer = (PWCHAR) InputBuffer;
  367. DebugTrace(0, Dbg, "Getting Entry for [%wZ]\n", &prefix);
  368. pktEntry = PktLookupEntryByPrefix( pkt, &prefix, &remPath );
  369. if (pktEntry == NULL) {
  370. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  371. }
  372. if (NT_SUCCESS(Status) && remPath.Length != 0) {
  373. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  374. }
  375. if (NT_SUCCESS(Status)) {
  376. DebugTrace(0, Dbg, "Found Pkt Entry @%08lx\n", pktEntry );
  377. if (sizeof(ULONG) > OutputBufferLength) {
  378. Status = STATUS_BUFFER_TOO_SMALL;
  379. }
  380. }
  381. if (NT_SUCCESS(Status)) {
  382. _PutULong( ((PUCHAR) OutputBuffer), pktEntry->Type );
  383. Irp->IoStatus.Information = sizeof(ULONG);
  384. }
  385. PktRelease( pkt );
  386. exit_with_status:
  387. DebugTrace(-1, Dbg, "DfsFsctrlGetPktEntry returning %08lx\n", ULongToPtr( Status ));
  388. DfsCompleteRequest( Irp, Status );
  389. return( Status );
  390. }
  391. //+-------------------------------------------------------------------------
  392. //
  393. // Function: BuildLocalVolPath, local
  394. //
  395. // Synopsis: This function creates the path to a file on a local volume.
  396. //
  397. // Arguments: [pFullName] -- On return, the full path name to the file
  398. // [pService] -- The Local Service which has storageId in it.
  399. // [RemPath] -- The remaining path relative to storageId.
  400. //
  401. // Returns: [STATUS_SUCCESS] --
  402. //
  403. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory
  404. //
  405. // History: 05-Apr-93 Alanw Created.
  406. //
  407. //--------------------------------------------------------------------------
  408. NTSTATUS
  409. BuildLocalVolPath(
  410. OUT PUNICODE_STRING pFullName,
  411. IN PDFS_SERVICE pService,
  412. IN PUNICODE_STRING pRemPath
  413. ) {
  414. //
  415. // We figure out the FullName from the StorageId in the Service
  416. // structure passed in and the remaining path passed in.
  417. // The devicename and address are preceeded by path separators,
  418. // so we don't need to add those in.
  419. //
  420. if (pService->pProvider != NULL) {
  421. pFullName->MaximumLength = pService->pProvider->DeviceName.Length;
  422. } else {
  423. pFullName->MaximumLength = 0;
  424. }
  425. pFullName->MaximumLength += pService->Address.Length +
  426. sizeof(WCHAR) + //For PATHSEP
  427. pRemPath->Length +
  428. sizeof(WCHAR); //For UNICODE_NULL.
  429. pFullName->Buffer = ExAllocatePoolWithTag(PagedPool, pFullName->MaximumLength, ' sfD');
  430. if (pFullName->Buffer==NULL) {
  431. pFullName->Length = pFullName->MaximumLength = 0;
  432. return(STATUS_INSUFFICIENT_RESOURCES);
  433. }
  434. if (pService->pProvider != NULL) {
  435. pFullName->Length = pService->pProvider->DeviceName.Length;
  436. RtlMoveMemory( pFullName->Buffer,
  437. pService->pProvider->DeviceName.Buffer,
  438. pService->pProvider->DeviceName.Length
  439. );
  440. } else {
  441. pFullName->Length = 0;
  442. }
  443. DfsConcatenateFilePath(pFullName,
  444. (PWCHAR)pService->Address.Buffer,
  445. pService->Address.Length
  446. );
  447. if (pRemPath->Length > 0)
  448. DfsConcatenateFilePath(pFullName,
  449. pRemPath->Buffer,
  450. pRemPath->Length
  451. );
  452. pFullName->Buffer[pFullName->Length/sizeof(WCHAR)] = UNICODE_NULL;
  453. return STATUS_SUCCESS;
  454. }
  455. //+----------------------------------------------------------------------
  456. //
  457. // Function: DfsStorageIdLocal
  458. //
  459. // Synopsis: This function determines if a given storage Id is local or not.
  460. //
  461. // Arguments: [StorageId] -- UnicodeString which represents the StorageId.
  462. // [RemovableableMedia] -- On return, if the storage Id represents
  463. // removable media.
  464. //
  465. // Returns: TRUE if it is Local else FALSE.
  466. //
  467. // Note: This function can also return FALSE if it cannot find the
  468. // drive at all as well.
  469. //
  470. // History: 10-10-1994 SudK Created.
  471. //
  472. //-----------------------------------------------------------------------
  473. BOOLEAN
  474. DfsStorageIdLocal(
  475. IN PUNICODE_STRING StorageId,
  476. OUT BOOLEAN *RemovableMedia
  477. )
  478. {
  479. UNICODE_STRING DriveStgId;
  480. OBJECT_ATTRIBUTES objectAttributes;
  481. HANDLE handle;
  482. IO_STATUS_BLOCK ioStatus;
  483. NTSTATUS status;
  484. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  485. if (StorageId->Length == 0)
  486. return(FALSE);
  487. //
  488. // Should we verify that the storage id is of \?? form.
  489. //
  490. DriveStgId.Buffer = L"\\??\\C:\\";
  491. DriveStgId.Length = wcslen(L"\\??\\C:\\")*sizeof(WCHAR);
  492. DriveStgId.MaximumLength = DriveStgId.Length + sizeof(WCHAR);
  493. DriveStgId.Buffer[DriveStgId.Length/sizeof(WCHAR)-3] =
  494. StorageId->Buffer[DriveStgId.Length/sizeof(WCHAR)-3];
  495. InitializeObjectAttributes(
  496. &objectAttributes,
  497. &DriveStgId,
  498. OBJ_CASE_INSENSITIVE,
  499. NULL,
  500. NULL);
  501. status = ZwCreateFile(
  502. &handle,
  503. FILE_READ_ATTRIBUTES,
  504. &objectAttributes,
  505. &ioStatus,
  506. NULL,
  507. FILE_ATTRIBUTE_NORMAL,
  508. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  509. FILE_OPEN,
  510. FILE_SYNCHRONOUS_IO_NONALERT,
  511. NULL,
  512. 0);
  513. if (!NT_SUCCESS(status)) {
  514. if (status == STATUS_NO_MEDIA_IN_DEVICE) {
  515. *RemovableMedia = TRUE;
  516. return( TRUE );
  517. } else {
  518. return( FALSE );
  519. }
  520. }
  521. //
  522. // So we now have a open handle to the file
  523. //
  524. status = ZwQueryVolumeInformationFile(
  525. handle,
  526. &ioStatus,
  527. &DeviceInfo,
  528. sizeof(FILE_FS_DEVICE_INFORMATION),
  529. FileFsDeviceInformation
  530. );
  531. ZwClose(handle);
  532. if (!NT_SUCCESS(status)) {
  533. DebugTrace(0, Dbg, "ZwQueryStdInformation failed %08lx\n", ULongToPtr( status ));
  534. return(FALSE);
  535. }
  536. if (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE) {
  537. DebugTrace(0, Dbg, "Remote StgId passed in %wZ\n", StorageId);
  538. return(FALSE);
  539. }
  540. switch (DeviceInfo.DeviceType) {
  541. case FILE_DEVICE_NETWORK:
  542. case FILE_DEVICE_NETWORK_FILE_SYSTEM:
  543. case FILE_DEVICE_VIRTUAL_DISK:
  544. DebugTrace(0, Dbg, "Remote StgId passed in %wZ\n", StorageId);
  545. return(FALSE);
  546. break;
  547. case FILE_DEVICE_CD_ROM:
  548. case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
  549. *RemovableMedia = TRUE;
  550. return(TRUE);
  551. break;
  552. case FILE_DEVICE_DISK:
  553. case FILE_DEVICE_DISK_FILE_SYSTEM:
  554. if (DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA) {
  555. *RemovableMedia = TRUE;
  556. } else {
  557. *RemovableMedia = FALSE;
  558. }
  559. return(TRUE);
  560. break;
  561. default:
  562. DebugTrace(0, Dbg, "Unknown type StgId passed in %wZ\n", StorageId);
  563. return(FALSE);
  564. break;
  565. }
  566. }
  567. //+----------------------------------------------------------------------------
  568. //
  569. // Function: DfsInternalCreateLocalPartition, public
  570. //
  571. // Synopsis: This routine does all the server-side work required to share
  572. // some local storage under Dfs. This includes:
  573. //
  574. // Verifying the storage id is legal
  575. // Updating the registry
  576. // Creating the local partition info in the Pkt.
  577. //
  578. // Arguments: [StgId] -- The storage id to be shared under Dfs.
  579. //
  580. // [CreateStorage] -- TRUE if you want Dfs to create the storage
  581. // if it does not exist.
  582. //
  583. // [pInfo] -- The DFS_LOCAL_VOLUME_CONFIG structure describing the
  584. // local volume.
  585. //
  586. //
  587. //
  588. // Returns: [STATUS_SUCCESS] -- Local volume was successfully creaeted.
  589. //
  590. // [DFS_STATUS_BAD_STORAGEID] -- The storage id is not a local
  591. // storage, or does not exist and CreateStorage flag
  592. // was not TRUE in the, or is a badly formatted string
  593. //
  594. // [DFS_STATUS_STORAGEID_ALREADY_INUSE] -- Some parent or child
  595. // of this storage id is already in the dfs namespace.
  596. //
  597. // [DFS_STATUS_LOCAL_ENTRY] -- There is already a local volume
  598. // with the same prefix as the input.
  599. //
  600. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory
  601. //
  602. //-----------------------------------------------------------------------------
  603. NTSTATUS
  604. DfsInternalCreateLocalPartition(
  605. IN PUNICODE_STRING StgId,
  606. IN BOOLEAN CreateStorage,
  607. IN OUT PDFS_LOCAL_VOLUME_CONFIG pConfigInfo)
  608. {
  609. NTSTATUS status = STATUS_SUCCESS;
  610. PDFS_PKT pkt;
  611. BOOLEAN fPreviousErrorMode, removableMedia = FALSE;
  612. NTSTATUS DeleteStatus;
  613. //
  614. // Set this in case we are going to create a volume on removable
  615. // media which has no media in it
  616. //
  617. fPreviousErrorMode = IoSetThreadHardErrorMode( FALSE );
  618. if (!DfsStorageIdLocal(StgId, &removableMedia)) {
  619. status = DFS_STATUS_BAD_STORAGEID;
  620. }
  621. if (NT_SUCCESS(status) && !DfsStorageIdLegal(StgId)) {
  622. DebugTrace(0, Dbg,
  623. "DfsFsctlCreateLPartition illegal stgid %wZ\n", StgId);
  624. status = DFS_STATUS_STORAGEID_ALREADY_INUSE;
  625. }
  626. if (removableMedia) {
  627. pConfigInfo->EntryType |= PKT_ENTRY_TYPE_LEAFONLY;
  628. }
  629. if (NT_SUCCESS(status)) {
  630. pkt = _GetPkt();
  631. PktAcquireExclusive(pkt, TRUE);
  632. if (!DfsStorageIdExists(*StgId, CreateStorage) ) {
  633. status = DFS_STATUS_BAD_STORAGEID;
  634. } else {
  635. status = DfsStoreLvolInfo(pConfigInfo, StgId);
  636. //
  637. // Now we need to initialize the PKT with this new partition info.
  638. //
  639. if (NT_SUCCESS(status)) {
  640. //
  641. // We'll initialize the local partition with no exit points.
  642. // Then, if the local partition is initialized successfully,
  643. // we'll try to create all the exit points with individual
  644. // calls to DfsInternalCreateExitPoint
  645. //
  646. DFS_LOCAL_VOLUME_CONFIG configInfo;
  647. UNICODE_STRING unusedShortPrefix;
  648. ULONG i;
  649. configInfo = *pConfigInfo;
  650. configInfo.RelationInfo.SubordinateIdCount = 0;
  651. status = PktInitializeLocalPartition( pkt, StgId, &configInfo);
  652. if (NT_SUCCESS(status)) {
  653. for (i = 0;
  654. (i < pConfigInfo->RelationInfo.SubordinateIdCount)
  655. && NT_SUCCESS(status);
  656. i++ ) {
  657. RtlInitUnicodeString(&unusedShortPrefix,NULL);
  658. status = DfsInternalCreateExitPoint(
  659. &pConfigInfo->RelationInfo.SubordinateIdList[i],
  660. PKT_ENTRY_TYPE_LOCAL_XPOINT,
  661. FILE_OPEN,
  662. &unusedShortPrefix);
  663. if (NT_SUCCESS(status) && unusedShortPrefix.Buffer != NULL) {
  664. ExFreePool(unusedShortPrefix.Buffer);
  665. }
  666. }
  667. //
  668. // If creating one of the junction points failed, we need
  669. // to cleanup the the ones we created
  670. //
  671. if (!NT_SUCCESS(status)) {
  672. for (i--; i > 0; i--) {
  673. (void) DfsInternalDeleteExitPoint(
  674. &pConfigInfo->RelationInfo.SubordinateIdList[i],
  675. PKT_ENTRY_TYPE_LOCAL_XPOINT);
  676. }
  677. //
  678. // We also need to "uninitialize" the local partition
  679. // we just initialized
  680. //
  681. (void) DfsInternalDeleteLocalVolume(
  682. &pConfigInfo->RelationInfo.EntryId);
  683. DeleteStatus = DfsDeleteLvolInfo(
  684. &pConfigInfo->RelationInfo.EntryId.Uid);
  685. if (!NT_SUCCESS(DeleteStatus)) {
  686. DebugTrace(
  687. 0, Dbg,
  688. "Error %08lx deleting registry info after "
  689. "failed create partition!\n",
  690. ULongToPtr( DeleteStatus ));
  691. }
  692. }
  693. } else {
  694. DeleteStatus = DfsDeleteLvolInfo(
  695. &pConfigInfo->RelationInfo.EntryId.Uid);
  696. if (!NT_SUCCESS(DeleteStatus)) {
  697. DebugTrace(
  698. 0, Dbg,
  699. "Error %08lx deleting registry info after "
  700. "failed create partition!\n",
  701. ULongToPtr( DeleteStatus ));
  702. }
  703. }
  704. } else {
  705. DebugTrace(0, Dbg, "Error %08lx storing info in registry\n", ULongToPtr( status ));
  706. }
  707. }
  708. //
  709. // Release the PKT.
  710. //
  711. PktRelease(pkt);
  712. }
  713. IoSetThreadHardErrorMode( fPreviousErrorMode );
  714. return( status );
  715. }
  716. //+-------------------------------------------------------------------------
  717. //
  718. // Function: DfsFsctrlCreateLocalPartition, public
  719. //
  720. // Synopsis:
  721. //
  722. // Arguments:
  723. //
  724. // Returns:
  725. //
  726. // Notes: We only process this FSCTRL from the file system process,
  727. // never from the driver.
  728. //
  729. //--------------------------------------------------------------------------
  730. NTSTATUS
  731. DfsFsctrlCreateLocalPartition(
  732. IN PIRP Irp,
  733. IN PVOID InputBuffer,
  734. IN ULONG InputBufferLength
  735. )
  736. {
  737. NTSTATUS status = STATUS_SUCCESS;
  738. MARSHAL_BUFFER marshalBuffer;
  739. PDFS_CREATE_LOCAL_PARTITION_ARG arg;
  740. PDFS_LOCAL_VOLUME_CONFIG configInfo;
  741. UNICODE_STRING sharePath;
  742. ULONG i;
  743. STD_FSCTRL_PROLOGUE(DfsFsctrlCreateLocalPartition, TRUE, FALSE);
  744. if (InputBufferLength < sizeof(*arg)) {
  745. status = STATUS_INVALID_PARAMETER;
  746. goto exit_with_status;
  747. }
  748. //
  749. // unmarshal the arguments...
  750. //
  751. arg = (PDFS_CREATE_LOCAL_PARTITION_ARG) InputBuffer;
  752. OFFSET_TO_POINTER(arg->ShareName, arg);
  753. OFFSET_TO_POINTER(arg->SharePath, arg);
  754. OFFSET_TO_POINTER(arg->EntryPrefix, arg);
  755. OFFSET_TO_POINTER(arg->ShortName, arg);
  756. OFFSET_TO_POINTER(arg->RelationInfo, arg);
  757. if (
  758. !DfspStringInBuffer(arg->ShareName, InputBuffer, InputBufferLength) ||
  759. !DfspStringInBuffer(arg->SharePath, InputBuffer, InputBufferLength) ||
  760. !DfspStringInBuffer(arg->EntryPrefix, InputBuffer, InputBufferLength) ||
  761. !DfspStringInBuffer(arg->ShortName, InputBuffer, InputBufferLength) ||
  762. !POINTER_IS_VALID(arg->RelationInfo, InputBuffer, InputBufferLength)
  763. ) {
  764. status = STATUS_INVALID_PARAMETER;
  765. goto exit_with_status;
  766. }
  767. if (!POINTER_IN_BUFFER(
  768. &arg->RelationInfo->Buffer,
  769. sizeof(arg->RelationInfo->Buffer),
  770. InputBuffer,
  771. InputBufferLength)) {
  772. status = STATUS_INVALID_PARAMETER;
  773. goto exit_with_status;
  774. }
  775. OFFSET_TO_POINTER( arg->RelationInfo->Buffer, arg );
  776. if (!POINTER_IS_VALID(arg->RelationInfo->Buffer, InputBuffer, InputBufferLength)) {
  777. status = STATUS_INVALID_PARAMETER;
  778. goto exit_with_status;
  779. }
  780. for (i = 0; i < arg->RelationInfo->Count; i++) {
  781. if (!POINTER_IN_BUFFER(
  782. &arg->RelationInfo->Buffer[i].Prefix,
  783. sizeof(arg->RelationInfo->Buffer[i].Prefix),
  784. InputBuffer,
  785. InputBufferLength)) {
  786. status = STATUS_INVALID_PARAMETER;
  787. goto exit_with_status;
  788. }
  789. OFFSET_TO_POINTER( arg->RelationInfo->Buffer[i].Prefix, arg );
  790. if (!DfspStringInBuffer(
  791. arg->RelationInfo->Buffer[i].Prefix,
  792. InputBuffer,
  793. InputBufferLength)) {
  794. status = STATUS_INVALID_PARAMETER;
  795. goto exit_with_status;
  796. }
  797. }
  798. RtlInitUnicodeString( &sharePath, arg->SharePath );
  799. configInfo = DfsNetInfoToConfigInfo(
  800. PKT_ENTRY_TYPE_CAIRO,
  801. DFS_SERVICE_TYPE_MASTER,
  802. arg->SharePath,
  803. arg->ShareName,
  804. &arg->EntryUid,
  805. arg->EntryPrefix,
  806. arg->ShortName,
  807. arg->RelationInfo );
  808. if (configInfo == NULL) {
  809. status = STATUS_INSUFFICIENT_RESOURCES;
  810. }
  811. if (NT_SUCCESS(status)) {
  812. status = DfsInternalCreateLocalPartition(
  813. &sharePath,
  814. FALSE,
  815. configInfo);
  816. //
  817. // need to deallocate the config info...
  818. //
  819. LocalVolumeConfigInfoDestroy( configInfo, TRUE );
  820. } else {
  821. DebugTrace(0, Dbg, "DfsFsctrlCreateLPart Unmarshal Err %08lx\n", ULongToPtr( status ));
  822. }
  823. exit_with_status:
  824. DfsCompleteRequest( Irp, status );
  825. DebugTrace(-1, Dbg,
  826. "DfsFsctrlCreateLocalPartition: Exit -> %08lx\n", ULongToPtr( status ));
  827. return status;
  828. }
  829. //+-------------------------------------------------------------------------
  830. //
  831. // function: DfsInternalDeleteLocalVolume, public
  832. //
  833. // Synopsis: This function deletes a local volume knowledge given the
  834. // EntryId describing the local volume.
  835. //
  836. // Arguments: [localEntryId] -- The entryId describing the local volume.
  837. //
  838. // Returns: [SUCCESS_SUCCESS] -- If all went well.
  839. //
  840. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory.
  841. //
  842. // [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- Couldn't find pkt entry
  843. // in Pkt.
  844. //
  845. // This routine can also return error codes returned by
  846. // NT Registry calls.
  847. //
  848. // Notes: This function will attempt to acquire Exclusive Locks on PKT.
  849. //
  850. // History: 31 March 1993 Created SudK from
  851. // DfsFsctrlDeleteLocalPartition.
  852. //
  853. //--------------------------------------------------------------------------
  854. NTSTATUS
  855. DfsInternalDeleteLocalVolume(
  856. IN PDFS_PKT_ENTRY_ID localEntryId)
  857. {
  858. NTSTATUS status = STATUS_SUCCESS;
  859. DebugTrace(+1, Dbg, "DfsInternalDeleteLocalVolume: Entered\n", 0);
  860. ASSERT(ARGUMENT_PRESENT(localEntryId));
  861. if (NT_SUCCESS(status)) {
  862. PDFS_PKT pkt;
  863. PDFS_PKT_ENTRY localEntry;
  864. //
  865. // Find the local entry...and make sure that its local...
  866. //
  867. pkt = _GetPkt();
  868. PktAcquireExclusive(pkt, TRUE);
  869. localEntry = PktLookupEntryById(pkt, localEntryId);
  870. if ((localEntry != NULL) &&
  871. (localEntry->Type & PKT_ENTRY_TYPE_LOCAL)) {
  872. PDFS_SERVICE service;
  873. status = DfsDeleteLvolInfo(&localEntryId->Uid);
  874. //
  875. // We don't want to invalidate this entry unless everything
  876. // else (deletion of the registry info) went well.
  877. //
  878. if (NT_SUCCESS(status)) {
  879. UNICODE_STRING ShareName = {0, 0, NULL};
  880. UNICODE_STRING RemPath = {0, 0, NULL};
  881. //
  882. // First, we delete the local DFS_SERVICE associated with
  883. // the Pkt Entry
  884. //
  885. if (! (localEntry->LocalService->Type &
  886. DFS_SERVICE_TYPE_OFFLINE)) {
  887. status = BuildLocalVolPath(&ShareName, localEntry->LocalService, &RemPath);
  888. if (NT_SUCCESS(status)) {
  889. DebugTrace(0, Dbg, "Trying to remove local service %wZ\n", &ShareName);
  890. PktEntryRemoveLocalService(pkt, localEntry, &ShareName);
  891. }
  892. } else {
  893. PktServiceDestroy(localEntry->LocalService, (BOOLEAN)TRUE);
  894. localEntry->LocalService = NULL;
  895. }
  896. //
  897. // Next, we delete the Pkt Entry if it is only a local
  898. // volume. If it is also an exit point, then we want to
  899. // keep the entry.
  900. //
  901. if (NT_SUCCESS(status)) {
  902. localEntry->Type &= ~PKT_ENTRY_TYPE_LOCAL;
  903. if (! (localEntry->Type & PKT_ENTRY_TYPE_LOCAL_XPOINT)) {
  904. status = PktInvalidateEntry(pkt, localEntry);
  905. ASSERT( status == STATUS_SUCCESS );
  906. }
  907. if (ShareName.Buffer) {
  908. ExFreePool(ShareName.Buffer);
  909. }
  910. } else {
  911. DebugTrace(0, Dbg, "Unable to allocate share name %08lx\n", ULongToPtr( status ));
  912. }
  913. } else {
  914. DebugTrace(0, Dbg, "Error %08lx deleting registry info\n", ULongToPtr( status ));
  915. }
  916. } else {
  917. //
  918. // We did not find a local entry that matches the Prefix that
  919. // has been requested to be deleted. We have to return an
  920. // error code here.
  921. //
  922. status = DFS_STATUS_NOSUCH_LOCAL_VOLUME;
  923. }
  924. //
  925. // We can release the Pkt now...
  926. //
  927. PktRelease(pkt);
  928. }
  929. DebugTrace(-1, Dbg, "DfsInternalDeleteLocalVolume: Exit -> %08lx\n", ULongToPtr( status ));
  930. return status;
  931. }
  932. //+-------------------------------------------------------------------------
  933. //
  934. // Function: DfsFsctrlDeleteLocalPartition, public
  935. //
  936. // Synopsis: This function services an FSCTRL which the DC can make to
  937. // delete knowledge of a local partition in the PKT.
  938. //
  939. // Arguments:
  940. //
  941. // Returns:
  942. //
  943. // History: March 31 1993 Modified to use DfsInternalDelete by SudK
  944. //
  945. //--------------------------------------------------------------------------
  946. NTSTATUS
  947. DfsFsctrlDeleteLocalPartition(
  948. IN PIRP Irp,
  949. IN PVOID InputBuffer,
  950. IN ULONG InputBufferLength
  951. )
  952. {
  953. NTSTATUS status = STATUS_SUCCESS;
  954. DFS_PKT_ENTRY_ID localEntryId;
  955. PDFS_DELETE_LOCAL_PARTITION_ARG arg;
  956. STD_FSCTRL_PROLOGUE(DfsFsctrlDeleteLocalPartition, TRUE, FALSE);
  957. if (InputBufferLength < sizeof(*arg)+sizeof(UNICODE_NULL)) {
  958. status = STATUS_INVALID_PARAMETER;
  959. goto exit_with_status;
  960. }
  961. //
  962. // Unmarshal the argument...
  963. //
  964. arg = (PDFS_DELETE_LOCAL_PARTITION_ARG) InputBuffer;
  965. OFFSET_TO_POINTER( arg->Prefix, arg );
  966. if (!DfspStringInBuffer(arg->Prefix, InputBuffer, InputBufferLength)) {
  967. status = STATUS_INVALID_PARAMETER;
  968. goto exit_with_status;
  969. }
  970. localEntryId.Uid = arg->Uid;
  971. RtlInitUnicodeString( &localEntryId.Prefix, arg->Prefix );
  972. DebugTrace(0, Dbg, "Deleting [%wZ]", &localEntryId.Prefix );
  973. status = DfsInternalDeleteLocalVolume(&localEntryId);
  974. exit_with_status:
  975. DfsCompleteRequest( Irp, status );
  976. DebugTrace(-1, Dbg, "DfsFsctrlDeleteLocalPartition: Exit -> %08lx\n", ULongToPtr( status ));
  977. return status;
  978. }
  979. //+-------------------------------------------------------------------------
  980. //
  981. // Function: DfsCreateExitPath, local
  982. //
  983. // Synopsis: This function creates the exit point on the disk.
  984. //
  985. // Arguments: [pService] -- The Local Service which has storageId in it.
  986. // [pRemPath] -- The remaining path relative to storageId.
  987. // [Disposition] -- If this is set to FILE_OPEN_IF, success
  988. // is returned if the exit path already exists on disk.
  989. // If it is set to FILE_CREATE, then an error is
  990. // returned if the exit path exists.
  991. // [pExitPointHandle] -- On successful return, handle to the
  992. // newly create exit point is returned here.
  993. //
  994. // Returns: [STATUS_SUCCESS] -- If everything succeeds.
  995. //
  996. // [DFS_STATUS_BAD_EXIT_POINT] -- If any error was encountered
  997. // during the creation of the exit path.
  998. //
  999. // [STATUS_INSUFFICIENT_RESOURCES] -- If unable to allocate
  1000. // memory for the Device Path form of the exit
  1001. // path.
  1002. //
  1003. // History: 02-Feb-93 SudK Created.
  1004. //
  1005. //--------------------------------------------------------------------------
  1006. NTSTATUS
  1007. DfsCreateExitPath(
  1008. PDFS_SERVICE pService,
  1009. PUNICODE_STRING pRemPath,
  1010. ULONG Disposition)
  1011. {
  1012. HANDLE exitPtHandle;
  1013. UNICODE_STRING exitPtName;
  1014. UNICODE_STRING exitPtPath;
  1015. OBJECT_ATTRIBUTES objectAttributes;
  1016. IO_STATUS_BLOCK ioStatus;
  1017. NTSTATUS status;
  1018. BOOLEAN fDoingParents = TRUE;
  1019. DebugTrace(+1, Dbg, "DfsCreateExitPath()\n", 0 );
  1020. //
  1021. // Get the full name of the exit point.
  1022. //
  1023. status = BuildLocalVolPath(&exitPtName, pService, pRemPath);
  1024. if (! NT_SUCCESS(status)) {
  1025. return status;
  1026. }
  1027. //
  1028. // Now we have the Full Path of the ExitPoint. Let's go create it.
  1029. //
  1030. InitializeObjectAttributes(
  1031. &objectAttributes,
  1032. &exitPtName,
  1033. OBJ_CASE_INSENSITIVE,
  1034. NULL,
  1035. NULL);
  1036. //
  1037. // Bug fix: 431227. Attempt to create the dir if it doesn't already
  1038. // exist. Instead of always deleting the directory and then recreating
  1039. // it, since that causes FRS headaches.
  1040. status = ZwCreateFile(
  1041. &exitPtHandle,
  1042. DELETE | FILE_READ_ATTRIBUTES,
  1043. &objectAttributes,
  1044. &ioStatus,
  1045. NULL,
  1046. FILE_ATTRIBUTE_NORMAL,
  1047. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1048. FILE_OPEN_IF,
  1049. FILE_DIRECTORY_FILE |
  1050. FILE_SYNCHRONOUS_IO_NONALERT,
  1051. NULL,
  1052. 0);
  1053. DFS_TRACE_ERROR_HIGH(status,ALL_ERROR, DfsCreateExitPath_Error_ZwCreateFile,
  1054. LOGSTATUS(status)
  1055. LOGUSTR(*pRemPath));
  1056. if (!NT_SUCCESS(status)) {
  1057. (void) ZwDeleteFile(&objectAttributes);
  1058. } else {
  1059. ZwClose( exitPtHandle );
  1060. goto done;
  1061. }
  1062. exitPtPath = exitPtName;
  1063. exitPtPath.MaximumLength = exitPtPath.Length;
  1064. do {
  1065. DebugTrace( 0, Dbg, "exitPtPath=%wZ\n", &exitPtPath);
  1066. status = ZwCreateFile(
  1067. &exitPtHandle,
  1068. DELETE | FILE_READ_ATTRIBUTES,
  1069. &objectAttributes,
  1070. &ioStatus,
  1071. NULL,
  1072. FILE_ATTRIBUTE_NORMAL,
  1073. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1074. Disposition,
  1075. FILE_DIRECTORY_FILE |
  1076. FILE_SYNCHRONOUS_IO_NONALERT,
  1077. NULL,
  1078. 0);
  1079. DFS_TRACE_ERROR_HIGH(status,ALL_ERROR, DfsCreateExitPath_Error_ZwCreateFile2,
  1080. LOGSTATUS(status)
  1081. LOGUSTR(*pRemPath));
  1082. if (!NT_SUCCESS(status)) {
  1083. StripLastComponent(&exitPtPath);
  1084. InitializeObjectAttributes(
  1085. &objectAttributes,
  1086. &exitPtPath,
  1087. OBJ_CASE_INSENSITIVE,
  1088. NULL,
  1089. NULL);
  1090. } else {
  1091. ZwClose( exitPtHandle );
  1092. }
  1093. } while (!NT_SUCCESS(status) && exitPtPath.Length > (7 * sizeof(WCHAR)));
  1094. if (NT_SUCCESS(status)) {
  1095. while (exitPtPath.Length < exitPtPath.MaximumLength) {
  1096. AddLastComponent(&exitPtPath);
  1097. InitializeObjectAttributes(
  1098. &objectAttributes,
  1099. &exitPtPath,
  1100. OBJ_CASE_INSENSITIVE,
  1101. NULL,
  1102. NULL);
  1103. DebugTrace( 0, Dbg, "exitPtPath=%wZ\n", &exitPtPath);
  1104. status = ZwCreateFile(
  1105. &exitPtHandle,
  1106. DELETE | FILE_READ_ATTRIBUTES,
  1107. &objectAttributes,
  1108. &ioStatus,
  1109. NULL,
  1110. FILE_ATTRIBUTE_NORMAL,
  1111. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1112. Disposition,
  1113. FILE_DIRECTORY_FILE |
  1114. FILE_SYNCHRONOUS_IO_NONALERT,
  1115. NULL,
  1116. 0);
  1117. DFS_TRACE_ERROR_HIGH(status,ALL_ERROR, DfsCreateExitPath_Error_ZwCreateFile3,
  1118. LOGSTATUS(status)
  1119. LOGUSTR(*pRemPath));
  1120. if (!NT_SUCCESS(status)) {
  1121. break;
  1122. }
  1123. ZwClose( exitPtHandle );
  1124. }
  1125. }
  1126. done:
  1127. if (!NT_SUCCESS(status)) {
  1128. status = DFS_STATUS_BAD_EXIT_POINT;
  1129. }
  1130. if (exitPtName.Buffer != NULL) {
  1131. ExFreePool(exitPtName.Buffer);
  1132. }
  1133. DebugTrace(-1, Dbg, "DfsCreateExitPath: Exit -> %08lx\n", ULongToPtr( status ));
  1134. return(status);
  1135. }
  1136. //+-------------------------------------------------------------------------
  1137. //
  1138. // Function: DfsDeleteExitPath, local
  1139. //
  1140. // Synopsis: This function deletes the exit point on the disk.
  1141. //
  1142. // Arguments: [pService] -- The Local Service which has storageId in it.
  1143. // [pRemPath] -- The remaining path relative to storageId.
  1144. //
  1145. // Returns: [STATUS_INSUFFICIENT_RESOURCES] -- If unable to build a
  1146. // local path.
  1147. //
  1148. // [STATUS_DEVICE_OFF_LINE] -- If the local volume on which the
  1149. // exit path resides is offline.
  1150. //
  1151. // NTSTATUS from the ZwCreateFile call to delete the exit path.
  1152. //
  1153. // History: 02-Feb-93 SudK Created.
  1154. //
  1155. //--------------------------------------------------------------------------
  1156. NTSTATUS
  1157. DfsDeleteExitPath(PDFS_SERVICE pService, PUNICODE_STRING pRemPath)
  1158. {
  1159. UNICODE_STRING ExitPtName, ExitPtPath;
  1160. OBJECT_ATTRIBUTES objectAttributes;
  1161. HANDLE exitPtHandle;
  1162. IO_STATUS_BLOCK ioStatus;
  1163. NTSTATUS status;
  1164. FILE_DISPOSITION_INFORMATION FileDispInfo;
  1165. UNICODE_STRING ShareRemPath = {0, 0, NULL};
  1166. UNICODE_STRING ShareName = {0, 0, NULL};
  1167. ULONG Deletes;
  1168. ULONG i;
  1169. //
  1170. // See if the local volume from which the exit point has to be deleted
  1171. // is offline.
  1172. //
  1173. if (pService->Type & DFS_SERVICE_TYPE_OFFLINE) {
  1174. return( STATUS_DEVICE_OFF_LINE );
  1175. }
  1176. //
  1177. // Get the name of the Share (this is NOT the full name of exit point).
  1178. // The sharename is that specified in the pservice.
  1179. //
  1180. status = BuildLocalVolPath(&ShareName, pService, &ShareRemPath);
  1181. if (! NT_SUCCESS(status)) {
  1182. return status;
  1183. }
  1184. //
  1185. // Get the full name of the exit point.
  1186. //
  1187. status = BuildLocalVolPath(&ExitPtName, pService, pRemPath);
  1188. if (! NT_SUCCESS(status)) {
  1189. return status;
  1190. }
  1191. Deletes = DfsGetDirectoriesToDelete(&ExitPtName, &ShareName);
  1192. ExitPtPath = ExitPtName;
  1193. //
  1194. // Now we have the Full Path of the ExitPoint. Let's go delete it.
  1195. //
  1196. for (i = 0; (i < Deletes) && (NT_SUCCESS(status)); i++) {
  1197. InitializeObjectAttributes(
  1198. &objectAttributes,
  1199. &ExitPtPath,
  1200. OBJ_CASE_INSENSITIVE,
  1201. NULL,
  1202. NULL);
  1203. status = ZwOpenFile(
  1204. &exitPtHandle,
  1205. DELETE,
  1206. &objectAttributes,
  1207. &ioStatus,
  1208. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1209. FILE_DIRECTORY_FILE);
  1210. DFS_TRACE_ERROR_HIGH(status,ALL_ERROR, DfsDeleteExitPath_Error_ZwOpenFile,
  1211. LOGSTATUS(status)
  1212. LOGUSTR(*pRemPath));
  1213. if (NT_SUCCESS(status)) {
  1214. FILE_DISPOSITION_INFORMATION disposition;
  1215. disposition.DeleteFile = TRUE;
  1216. status = ZwSetInformationFile(
  1217. exitPtHandle,
  1218. &ioStatus,
  1219. &disposition,
  1220. sizeof(disposition),
  1221. FileDispositionInformation);
  1222. DFS_TRACE_ERROR_HIGH(status,ALL_ERROR, DfsDeleteExitPath_Error_ZwSetInformationFile,
  1223. LOGSTATUS(status)
  1224. LOGUSTR(*pRemPath));
  1225. ZwClose(exitPtHandle);
  1226. StripLastComponent(&ExitPtPath);
  1227. }
  1228. }
  1229. if (ExitPtName.Buffer != NULL) {
  1230. ExFreePool(ExitPtName.Buffer);
  1231. }
  1232. return(status);
  1233. }
  1234. //+------------------------------------------------------------------------
  1235. //
  1236. // Function: DfsInternalModifyPrefix, private
  1237. //
  1238. // Synopsis: This function fixes the entrypath of the volume whose EntryId
  1239. // is passed to it.
  1240. //
  1241. // Arguments: [peid] -- The PktEntryId of vol to be fixed. The GUID is
  1242. // used to look up the volume.
  1243. //
  1244. // Returns: [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- If no pkt entry with the
  1245. // GUID in peid is found.
  1246. //
  1247. // [DFS_STATUS_BAD_EXIT_POINT] -- If the new prefix could not
  1248. // be inserted in the Prefix Table (because
  1249. // of a conflicting entry already in the Pkt)
  1250. //
  1251. // [STATUS_INSUFFICIENT_RESOURCES] -- If room for the new
  1252. // prefix could not be allocated.
  1253. //
  1254. // [STATUS_SUCCESS] -- If everything succeeds
  1255. //
  1256. // History: 24 Oct 1993 SudK Created.
  1257. //
  1258. //-------------------------------------------------------------------------
  1259. NTSTATUS
  1260. DfsInternalModifyPrefix(
  1261. IN PDFS_PKT_ENTRY_ID peid
  1262. )
  1263. {
  1264. PDFS_PKT pkt;
  1265. PDFS_PKT_ENTRY localEntry;
  1266. NTSTATUS status = STATUS_SUCCESS;
  1267. UNICODE_STRING oldPrefix;
  1268. DebugTrace(+1, Dbg, "DfsInternalModifyPrefix: Entered\n", 0);
  1269. memset(&oldPrefix, 0, sizeof(UNICODE_STRING));
  1270. pkt = _GetPkt();
  1271. PktAcquireExclusive(pkt, TRUE);
  1272. localEntry = PktLookupEntryByUid(pkt, &peid->Uid);
  1273. if ((localEntry != NULL) &&
  1274. (localEntry->Type & PKT_ENTRY_TYPE_LOCAL)) {
  1275. ASSERT(localEntry->LocalService != NULL);
  1276. //
  1277. // We now need to save the old prefix first.
  1278. //
  1279. oldPrefix = localEntry->Id.Prefix;
  1280. oldPrefix.Buffer = ExAllocatePoolWithTag(PagedPool, oldPrefix.MaximumLength, ' sfD');
  1281. if (oldPrefix.Buffer != NULL) {
  1282. RtlMoveMemory( oldPrefix.Buffer,
  1283. localEntry->Id.Prefix.Buffer,
  1284. oldPrefix.MaximumLength);
  1285. status = PktEntryModifyPrefix(pkt, &peid->Prefix, localEntry);
  1286. } else {
  1287. status = STATUS_INSUFFICIENT_RESOURCES;
  1288. }
  1289. } else {
  1290. //
  1291. // The best match with the ExitPath was not a local volume.
  1292. // Hence we cannot create this exit point. There might be some
  1293. // knowledge discrepancy here.
  1294. //
  1295. DebugTrace(0, Dbg, "Did Not Find Entry to ModifyPrefix %ws\n",
  1296. peid->Prefix.Buffer);
  1297. status = DFS_STATUS_NOSUCH_LOCAL_VOLUME;
  1298. }
  1299. //
  1300. // OK we took care of the PKT. We still need to take care of the
  1301. // info in the registry.
  1302. //
  1303. if (NT_SUCCESS(status)) {
  1304. status = DfsChangeLvolInfoEntryPath(&localEntry->Id.Uid,
  1305. &peid->Prefix);
  1306. if (!NT_SUCCESS(status)) {
  1307. status = PktEntryModifyPrefix(pkt, &oldPrefix, localEntry);
  1308. }
  1309. }
  1310. //
  1311. // We can release the Pkt now...
  1312. //
  1313. if (oldPrefix.Buffer != NULL)
  1314. ExFreePool(oldPrefix.Buffer);
  1315. PktRelease(pkt);
  1316. DebugTrace(-1, Dbg, "DfsInternalModifyPrefix: Exit -> %08lx\n", ULongToPtr( status ));
  1317. return(status);
  1318. }
  1319. //+----------------------------------------------------------------------
  1320. //
  1321. // Function: DfsFsctrlModifyLocalVolPrefix
  1322. //
  1323. // Synopsis: This function is called on a client/server by the DC during
  1324. // knowledge synchronisation to fix a bad prefix match.
  1325. //
  1326. // Arguments: The PktEntryID.
  1327. //
  1328. // Returns: [STATUS_DATA_ERROR] -- If the input buffer is not formatted
  1329. // correctly.
  1330. //
  1331. // [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- If no pkt entry with the
  1332. // GUID in peid is found.
  1333. //
  1334. // [DFS_STATUS_BAD_EXIT_POINT] -- If the new prefix could not
  1335. // be inserted in the Prefix Table (because
  1336. // of a conflicting entry already in the Pkt)
  1337. //
  1338. // [STATUS_INSUFFICIENT_RESOURCES] -- If memory could not be
  1339. // allocated.
  1340. //
  1341. // [STATUS_SUCCESS] -- If everything succeeds
  1342. //
  1343. //-----------------------------------------------------------------------
  1344. NTSTATUS
  1345. DfsFsctrlModifyLocalVolPrefix(
  1346. IN PIRP Irp,
  1347. IN PVOID InputBuffer,
  1348. IN ULONG InputBufferLength
  1349. )
  1350. {
  1351. NTSTATUS status = STATUS_SUCCESS;
  1352. DFS_PKT_ENTRY_ID ExitPtId;
  1353. MARSHAL_BUFFER marshalBuffer;
  1354. STD_FSCTRL_PROLOGUE(DfsFsctrlModifyLocalVolPrefix, TRUE, FALSE);
  1355. //
  1356. // Unmarshal the argument...
  1357. //
  1358. MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
  1359. status = DfsRtlGet(&marshalBuffer, &MiPktEntryId, &ExitPtId);
  1360. if (NT_SUCCESS(status)) {
  1361. status = DfsInternalModifyPrefix(&ExitPtId);
  1362. //
  1363. // Need to deallocate the entry Id...
  1364. //
  1365. PktEntryIdDestroy(&ExitPtId, FALSE);
  1366. } else
  1367. DebugTrace(0, Dbg,
  1368. "DfsFsctrlModifyLocalVolPrefix: Unmarshalling Error!\n", 0);
  1369. DfsCompleteRequest( Irp, status );
  1370. DebugTrace(-1, Dbg, "DfsFsctrlModifyLocalVolPrefix: Exit -> %08lx\n", ULongToPtr( status ));
  1371. return status;
  1372. }
  1373. //+-------------------------------------------------------------------------
  1374. //
  1375. // Function: DfsInternalCreateExitPoint, private
  1376. //
  1377. // Synopsis: This is the same as the function DfsFsctrlCreateExitPoint
  1378. // except that it expects to be called after args are unmarshaled.
  1379. //
  1380. // Arguments: [peid] -- ExitPt to create.
  1381. // [Type] -- The type of exit point. For now only
  1382. // PKT_ENTRY_TYPE_MACHINE is relevant - if the type is
  1383. // PKT_ENTRY_TYPE_MACHINE, no attempt is made to create
  1384. // the on-disk exit point.
  1385. // [Disposition] -- What to do if the on-disk exit point already
  1386. // exists. If Disposition == FILE_OPEN, a success is
  1387. // returned if the exit point already exits on disk.
  1388. // [ShortPrefix] -- On successful return, the short prefix
  1389. // of the exit point that was created. Caller must free
  1390. // the buffer of this variable.
  1391. //
  1392. // Returns: [STATUS_INVALID_DEVICE_REQUEST] -- If the local volume is
  1393. // leafonly (removable media)
  1394. //
  1395. // [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- If there is no appropriate
  1396. // local volume to create the exit pt under.
  1397. //
  1398. // [DFS_STATUS_LOCAL_ENTRY] - creation of the subordinate entry
  1399. // would have required that a local entry or exit point
  1400. // be invalidated.
  1401. //
  1402. // [DFS_STATUS_INCONSISTENT] - an inconsistency in the PKT
  1403. // has been discovered.
  1404. //
  1405. // [STATUS_DEVICE_OFF_LINE] -- The local volume on which the
  1406. // exit point has to be created is currently offline.
  1407. //
  1408. // [STATUS_INVALID_PARAMETER] - the Id specified for the
  1409. // subordinate is invalid.
  1410. //
  1411. // [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was
  1412. // available to complete the operation.
  1413. //
  1414. // History: 24 Oct 1993 SudK Created.
  1415. //
  1416. //--------------------------------------------------------------------------
  1417. NTSTATUS
  1418. DfsInternalCreateExitPoint(
  1419. PDFS_PKT_ENTRY_ID peid,
  1420. ULONG Type,
  1421. ULONG Disposition,
  1422. PUNICODE_STRING ShortPrefix
  1423. )
  1424. {
  1425. PDFS_PKT pkt;
  1426. PDFS_PKT_ENTRY localEntry;
  1427. UNICODE_STRING RemainingPath;
  1428. NTSTATUS status = STATUS_SUCCESS;
  1429. BOOLEAN ExitPtCreated = FALSE;
  1430. BOOLEAN PktEntryCreated = FALSE;
  1431. PDFS_SERVICE service;
  1432. PDFS_PKT_ENTRY pSubEntry;
  1433. UNICODE_STRING ustrPrefix;
  1434. DebugTrace(+1, Dbg, "DfsInternalCreateExitPoint: Entered\n",0 );
  1435. //
  1436. // Find the local entry in which the exit point needs to be created
  1437. // and make sure that its local...
  1438. //
  1439. pkt = _GetPkt();
  1440. PktAcquireExclusive(pkt, TRUE);
  1441. RtlInitUnicodeString(&ustrPrefix, NULL);
  1442. localEntry = PktLookupEntryByPrefix(
  1443. pkt,
  1444. &peid->Prefix,
  1445. &RemainingPath);
  1446. if ((localEntry != NULL) &&
  1447. (localEntry->Type & PKT_ENTRY_TYPE_LEAFONLY)) {
  1448. status = STATUS_INVALID_DEVICE_REQUEST;
  1449. }
  1450. if (NT_SUCCESS(status) &&
  1451. (localEntry != NULL) &&
  1452. (localEntry->Type & PKT_ENTRY_TYPE_LOCAL)) {
  1453. ASSERT(localEntry->LocalService != NULL);
  1454. if (localEntry->LocalService->Type & DFS_SERVICE_TYPE_OFFLINE) {
  1455. //
  1456. // This volume is offline, can't create exit point.
  1457. //
  1458. status = STATUS_DEVICE_OFF_LINE;
  1459. } else if (DfsExitPtLegal(pkt, localEntry, &RemainingPath)) {
  1460. //
  1461. // Now we first want to create the exit point since we now
  1462. // know that there is an appropriate place to create it.
  1463. //
  1464. service = localEntry->LocalService;
  1465. status = STATUS_SUCCESS;
  1466. //
  1467. // Only if this is not an exit point leading to a machine volume
  1468. // will we create the physical exit path on disk.
  1469. //
  1470. if (!(Type & PKT_ENTRY_TYPE_MACHINE)) {
  1471. status = DfsCreateExitPath(
  1472. service,
  1473. &RemainingPath,
  1474. Disposition);
  1475. if (NT_SUCCESS(status)) {
  1476. ExitPtCreated = TRUE;
  1477. status = BuildShortPrefix(
  1478. &RemainingPath,
  1479. service,
  1480. &localEntry->Id,
  1481. peid);
  1482. }
  1483. } else {
  1484. status = DFS_STATUS_BAD_EXIT_POINT;
  1485. }
  1486. //
  1487. // Only if we succeeded in Creating ExitPoint will we get here.
  1488. //
  1489. if (NT_SUCCESS(status)) {
  1490. //
  1491. // We now merely need to update the PKT.
  1492. // This should create no problems in general.
  1493. //
  1494. status = PktCreateSubordinateEntry(
  1495. pkt,
  1496. localEntry,
  1497. PKT_ENTRY_TYPE_LOCAL_XPOINT |
  1498. PKT_ENTRY_TYPE_PERMANENT,
  1499. peid,
  1500. NULL,
  1501. PKT_ENTRY_SUPERSEDE,
  1502. &pSubEntry
  1503. );
  1504. }
  1505. if (NT_SUCCESS(status)) {
  1506. //
  1507. // Now that we have created the exit pt on disk, let us
  1508. // update our knowledge in the registry.
  1509. //
  1510. PktEntryCreated = TRUE;
  1511. ustrPrefix = pSubEntry->Id.ShortPrefix;
  1512. ustrPrefix.Buffer = ExAllocatePoolWithTag(
  1513. PagedPool,
  1514. pSubEntry->Id.ShortPrefix.Length,
  1515. ' fsD');
  1516. if (ustrPrefix.Buffer != NULL) {
  1517. RtlCopyMemory(ustrPrefix.Buffer,
  1518. pSubEntry->Id.ShortPrefix.Buffer,
  1519. pSubEntry->Id.ShortPrefix.Length);
  1520. status = DfsCreateExitPointInfo(
  1521. &localEntry->Id.Uid,
  1522. &pSubEntry->Id);
  1523. } else {
  1524. ustrPrefix.Length = ustrPrefix.MaximumLength = 0;
  1525. status = STATUS_INSUFFICIENT_RESOURCES;
  1526. }
  1527. }
  1528. //
  1529. // Now we check for an error. If we do have an error then we
  1530. // need to back out all the operations that we did so far.
  1531. //
  1532. if (!NT_SUCCESS(status)) {
  1533. if (PktEntryCreated == TRUE) {
  1534. //
  1535. // What do we do with an error in this case.
  1536. //
  1537. pSubEntry->Type &= ~(PKT_ENTRY_TYPE_LOCAL_XPOINT);
  1538. PktEntryDestroy(pSubEntry, pkt, TRUE);
  1539. }
  1540. if ((ExitPtCreated == TRUE)&&!( Type & PKT_ENTRY_TYPE_MACHINE)) {
  1541. //
  1542. // What do we do with an error in this case.
  1543. //
  1544. status = DfsDeleteExitPath(service, &RemainingPath);
  1545. }
  1546. }
  1547. } else {
  1548. DebugTrace(0, Dbg, "Illegal exit pt passed in %wZ\n",
  1549. &peid->Prefix);
  1550. status = DFS_STATUS_NOSUCH_LOCAL_VOLUME;
  1551. }
  1552. } else {
  1553. //
  1554. // The best match with the ExitPath was not a local volume.
  1555. // Hence we cannot create this exit point. There might be some
  1556. // knowledge discrepancy here.
  1557. //
  1558. status = DFS_STATUS_NOSUCH_LOCAL_VOLUME;
  1559. }
  1560. //
  1561. // We can release the Pkt now...
  1562. //
  1563. PktRelease(pkt);
  1564. //
  1565. // Either return the ShortPrefix with the allocated buffer or destroy it, depending on the
  1566. // status returned.
  1567. //
  1568. if (NT_SUCCESS(status)) {
  1569. *ShortPrefix = ustrPrefix;
  1570. } else if (ustrPrefix.Buffer != NULL) {
  1571. ExFreePool(ustrPrefix.Buffer);
  1572. }
  1573. DebugTrace(-1, Dbg, "DfsInternalCreateExitPoint: Exit -> %08lx\n", ULongToPtr( status ));
  1574. return(status);
  1575. }
  1576. //+-------------------------------------------------------------------------
  1577. //
  1578. // Function: DfsFsctrlCreateExitPoint, public
  1579. //
  1580. // Synopsis: This method creates an exit point on disk, creates a DFS.CFG
  1581. // file and updates the PKT with the new exit point information.
  1582. // This method of course checks to make sure that it makes sense
  1583. // to create such an exit point. i.e. there is a local volume
  1584. // under which this exit point can be created. Also if any of the
  1585. // operations above fail then it backs out the entire operation.
  1586. // If no system failures occur during this function, then it will
  1587. // behave in an atomic fashion.
  1588. //
  1589. // Arguments:
  1590. //
  1591. // Returns: [SUCCESS_SUCCESS] -- If all went well.
  1592. //
  1593. // [STATUS_DATA_ERROR] -- If unable to unmarshal the input
  1594. // buffer.
  1595. //
  1596. // [DFS_STATUS_BAD_EXIT_POINT] -- If cannot create exit point.
  1597. //
  1598. // History: 02-Feb-93 SudK Created.
  1599. //
  1600. //--------------------------------------------------------------------------
  1601. NTSTATUS
  1602. DfsFsctrlCreateExitPoint(
  1603. IN PIRP Irp,
  1604. IN PVOID InputBuffer,
  1605. IN ULONG InputBufferLength,
  1606. OUT PVOID OutputBuffer,
  1607. IN ULONG OutputBufferLength
  1608. )
  1609. {
  1610. NTSTATUS status = STATUS_SUCCESS;
  1611. DFS_PKT_ENTRY_ID ExitPtId;
  1612. PDFS_CREATE_EXIT_POINT_ARG arg;
  1613. ULONG Type;
  1614. UNICODE_STRING ShortPrefix;
  1615. WCHAR *wcp;
  1616. PCHAR BufferEnd;
  1617. STD_FSCTRL_PROLOGUE(DfsFsctrlCreateExitPoint, TRUE, FALSE);
  1618. if (InputBufferLength < sizeof(*arg)+sizeof(UNICODE_NULL) ||
  1619. OutputBufferLength < sizeof(UNICODE_NULL)) {
  1620. status = STATUS_INVALID_PARAMETER;
  1621. DfsCompleteRequest( Irp, status );
  1622. DebugTrace(-1, Dbg, "DfsFsctrlCreateExitPoint: Exit -> %08lx\n", ULongToPtr( status ));
  1623. return( status );
  1624. }
  1625. //
  1626. // Unmarshal the argument...
  1627. //
  1628. arg = (PDFS_CREATE_EXIT_POINT_ARG) InputBuffer;
  1629. OFFSET_TO_POINTER( arg->Prefix, arg );
  1630. if (!DfspStringInBuffer(arg->Prefix, InputBuffer, InputBufferLength)) {
  1631. status = STATUS_INVALID_PARAMETER;
  1632. DfsCompleteRequest( Irp, status );
  1633. DebugTrace(-1, Dbg, "DfsFsctrlCreateExitPoint: Exit -> %08lx\n", ULongToPtr( status ));
  1634. return( status );
  1635. }
  1636. RtlInitUnicodeString(&ShortPrefix,NULL);
  1637. DFS_DUPLICATE_STRING(ExitPtId.Prefix, arg->Prefix, status);
  1638. if (!NT_SUCCESS(status)) {
  1639. DfsCompleteRequest( Irp, status );
  1640. DebugTrace(-1, Dbg, "DfsFsctrlCreateExitPoint: Exit -> %08lx\n", ULongToPtr( status ));
  1641. return( status );
  1642. }
  1643. ExitPtId.ShortPrefix.Length = ExitPtId.ShortPrefix.MaximumLength = 0;
  1644. ExitPtId.ShortPrefix.Buffer = NULL;
  1645. ExitPtId.Uid = arg->Uid;
  1646. Type = arg->Type;
  1647. if (NT_SUCCESS(status)) {
  1648. DebugTrace(0, Dbg, "Creating Exit Point [%wZ]\n", &ExitPtId.Prefix );
  1649. DebugTrace(0, Dbg, "Type == %d\n", ULongToPtr( Type ) );
  1650. status = DfsInternalCreateExitPoint(&ExitPtId, Type, FILE_CREATE, &ShortPrefix);
  1651. PktEntryIdDestroy(&ExitPtId, FALSE);
  1652. if (NT_SUCCESS(status)) {
  1653. if (OutputBufferLength >= (ShortPrefix.Length + sizeof(WCHAR))) {
  1654. RtlCopyMemory(
  1655. OutputBuffer,
  1656. ShortPrefix.Buffer,
  1657. ShortPrefix.Length);
  1658. ((PWCHAR) OutputBuffer)[ShortPrefix.Length/sizeof(WCHAR)] = UNICODE_NULL;
  1659. OutputBufferLength = ShortPrefix.Length + sizeof(WCHAR);
  1660. } else {
  1661. RtlZeroMemory(OutputBuffer, OutputBufferLength);
  1662. }
  1663. Irp->IoStatus.Information = OutputBufferLength;
  1664. }
  1665. }
  1666. if (ShortPrefix.Buffer != NULL) {
  1667. ExFreePool(ShortPrefix.Buffer);
  1668. }
  1669. DfsCompleteRequest( Irp, status );
  1670. DebugTrace(-1, Dbg, "DfsFsctrlCreateExitPoint: Exit -> %08lx\n", ULongToPtr( status ) );
  1671. return status;
  1672. }
  1673. //+-------------------------------------------------------------------------
  1674. //
  1675. // Function: DfsInternalDeleteExitPoint, public
  1676. //
  1677. // Synopsis: This method deletes an exit point on disk, updates the local
  1678. // volume info in the registry and updates the PKT wrt
  1679. // exit point information.
  1680. //
  1681. // Arguments: [ExitPtId] -- THis is the exitPath and GUID.
  1682. // [Type] -- The kind of ExitPt (Machine/Cairo/NonCairo)
  1683. //
  1684. // Returns: [SUCCESS_SUCCESS] -- If all went well.
  1685. //
  1686. // [DFS_STATUS_BAD_EXIT_POINT] -- If cannot find exit point.
  1687. //
  1688. // [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- Unable to find a local
  1689. // service for the volume on which the exit pt is.
  1690. //
  1691. // This routine can return errors from the NT Registry API.
  1692. //
  1693. // Note:
  1694. //
  1695. // History: March 31 1993 SudK Created from DfsFstrlDeleteExitPoint.
  1696. //
  1697. //--------------------------------------------------------------------------
  1698. NTSTATUS
  1699. DfsInternalDeleteExitPoint(
  1700. IN PDFS_PKT_ENTRY_ID ExitPtId,
  1701. IN ULONG Type)
  1702. {
  1703. NTSTATUS status = STATUS_SUCCESS;
  1704. PDFS_PKT pkt = _GetPkt();
  1705. PWCHAR pwch;
  1706. PDFS_PKT_ENTRY localEntry;
  1707. UNICODE_STRING RemainingPath;
  1708. PDFS_SERVICE service;
  1709. DFS_LOCAL_VOLUME_CONFIG ConfigInfo;
  1710. BOOLEAN PktUpdated = FALSE;
  1711. BOOLEAN ExitPtDeleted = FALSE;
  1712. UNICODE_STRING ParentPrefix;
  1713. DebugTrace(+1, Dbg, "DfsInternalDeleteExitPoint: Entered\n", 0);
  1714. ASSERT(ARGUMENT_PRESENT(ExitPtId));
  1715. memset(&ConfigInfo, 0, sizeof(DFS_LOCAL_VOLUME_CONFIG));
  1716. //
  1717. // Find the local entry in which the exit point needs to be created
  1718. // and make sure that it's local...
  1719. //
  1720. PktAcquireExclusive(pkt, TRUE);
  1721. localEntry = PktLookupEntryByPrefix(
  1722. pkt,
  1723. &ExitPtId->Prefix,
  1724. &RemainingPath);
  1725. if ((localEntry == NULL) ||
  1726. (RemainingPath.Length != 0) ||
  1727. !(localEntry->Type & PKT_ENTRY_TYPE_LOCAL_XPOINT)) {
  1728. //
  1729. // We don't have a perfect match or if we do, it is not
  1730. // a local exit point.
  1731. //
  1732. status = DFS_STATUS_BAD_EXIT_POINT;
  1733. }
  1734. //
  1735. // We go in here only if we found the exit pt in the PKT.
  1736. //
  1737. if ((RemainingPath.Length == 0) && (NT_SUCCESS(status))) {
  1738. //
  1739. // We first delete the exit Point info from the PKT. Else we
  1740. // will not be able to delete the exit point??
  1741. //
  1742. if (localEntry->LocalService != NULL) {
  1743. //
  1744. // In this case we should only turn off the exit point
  1745. // bit and leave the entry intact.
  1746. //
  1747. PktEntryUnlinkSubordinate((localEntry->Superior), localEntry);
  1748. localEntry->Type &= ~PKT_ENTRY_TYPE_LOCAL_XPOINT;
  1749. } else {
  1750. PktEntryDestroy(localEntry, pkt, TRUE);
  1751. }
  1752. PktUpdated = TRUE;
  1753. }
  1754. //
  1755. // We will attempt to delete the exit point on disk irrespective of
  1756. // whether we found it in the PKT.
  1757. //
  1758. // We will remove the last component of the exit path in order to find
  1759. // the PKT entry for the local volume on which the exit point exists.
  1760. //
  1761. ASSERT(ExitPtId->Prefix.Length >= 2*sizeof(WCHAR));
  1762. pwch = ExitPtId->Prefix.Buffer;
  1763. pwch = pwch + ExitPtId->Prefix.Length/sizeof(WCHAR) - 1;
  1764. while ((pwch >= ExitPtId->Prefix.Buffer) && (*pwch != L'\\')) {
  1765. pwch--;
  1766. }
  1767. ASSERT((pwch > ExitPtId->Prefix.Buffer) ||
  1768. ((pwch == ExitPtId->Prefix.Buffer) && (*pwch == L'\\')));
  1769. if (pwch > ExitPtId->Prefix.Buffer) {
  1770. //
  1771. // Save original length before we update.
  1772. //
  1773. ParentPrefix = ExitPtId->Prefix;
  1774. ParentPrefix.Length = (USHORT)((pwch-ExitPtId->Prefix.Buffer))*sizeof(WCHAR);
  1775. } else if (pwch == ExitPtId->Prefix.Buffer) {
  1776. //
  1777. // This means that we have an exit point off of O:
  1778. //
  1779. ParentPrefix = ExitPtId->Prefix;
  1780. ParentPrefix.Length = sizeof(WCHAR);
  1781. } else {
  1782. //
  1783. // This should never happen because of above asserts
  1784. //
  1785. DebugTrace(0, 1,
  1786. "DFS: Got a Bad ExitPt for deletion: %wZ\n", &ExitPtId->Prefix);
  1787. return(DFS_STATUS_BAD_EXIT_POINT);
  1788. }
  1789. localEntry = PktLookupEntryByPrefix(
  1790. pkt,
  1791. &ParentPrefix,
  1792. &RemainingPath);
  1793. if (localEntry && localEntry->LocalService) {
  1794. service = localEntry->LocalService;
  1795. //
  1796. // Adjust the remaining path to take account of the path name
  1797. // component we removed above.
  1798. //
  1799. if (RemainingPath.Buffer == NULL) {
  1800. RemainingPath.Buffer = pwch + 1;
  1801. RemainingPath.Length =
  1802. ExitPtId->Prefix.Length - ParentPrefix.Length;
  1803. if (pwch != ExitPtId->Prefix.Buffer) {
  1804. RemainingPath.Length -= sizeof(WCHAR);
  1805. }
  1806. RemainingPath.MaximumLength = RemainingPath.Length + sizeof(WCHAR);
  1807. } else {
  1808. //
  1809. // Here we include the leading Path separator before last component
  1810. // in length field whereas in the Previous case we do not
  1811. //
  1812. RemainingPath.Length += ExitPtId->Prefix.Length-ParentPrefix.Length;
  1813. RemainingPath.MaximumLength = RemainingPath.Length + sizeof(WCHAR);
  1814. }
  1815. //
  1816. // We attempt to delete the exit path. But we ignore all
  1817. // errors here and continue on. We delete exit path only if we
  1818. // are not dealing with an exit point leading to a machine volume.
  1819. //
  1820. if (!(Type & PKT_ENTRY_TYPE_MACHINE)) {
  1821. status = DfsDeleteExitPath(service, &RemainingPath);
  1822. if (NT_SUCCESS(status)) {
  1823. ExitPtDeleted = TRUE;
  1824. }
  1825. }
  1826. //
  1827. // Now that we have deleted the exit pt on disk, let us
  1828. // update our knowledge in the registry.
  1829. //
  1830. if (NT_SUCCESS(status)) {
  1831. status = DfsDeleteExitPointInfo(
  1832. &localEntry->Id.Uid,
  1833. &ExitPtId->Uid);
  1834. }
  1835. } else {
  1836. DebugTrace(0, 1,
  1837. "DFS: Could not find a LocalEntry To Delete ExitPt %ws\n",
  1838. ExitPtId->Prefix.Buffer);
  1839. status = DFS_STATUS_NOSUCH_LOCAL_VOLUME;
  1840. }
  1841. //
  1842. // We go in here only if we managed to Update the PKT and at the
  1843. // same time also managed to delete the ExitPt from the Disk, but
  1844. // failed to update the DFS.CFG file.
  1845. //
  1846. if (!NT_SUCCESS(status)) {
  1847. //
  1848. // If we got here. We definitely did not update the registry config
  1849. // info with changes. We might have updated the PKT and
  1850. // also deleted the exit point.
  1851. //
  1852. if (ExitPtDeleted == TRUE) {
  1853. // RAID 455283: What do we do here? Should we attempt to
  1854. // recreate the exitPt?
  1855. }
  1856. if (PktUpdated == TRUE) {
  1857. // RAID 455283: What do we do here? Should we update
  1858. // the Pkt with the exit pt info again?
  1859. }
  1860. }
  1861. //
  1862. // We can release the Pkt now...
  1863. //
  1864. PktRelease(pkt);
  1865. DebugTrace(-1, Dbg, "DfsInternalDeleteExitPoint: Exit -> %08lx\n", ULongToPtr( status ));
  1866. return status;
  1867. }
  1868. //+-------------------------------------------------------------------------
  1869. //
  1870. // Function: DfsFsctrlDeleteExitPoint, public
  1871. //
  1872. // Synopsis: This method deletes an exit point on disk, updates a DFS.CFG
  1873. // file and updates the PKT without the exit point information.
  1874. // What should this method do if there are errors along the way
  1875. // during any of its 3 steps described above. RAID 455283
  1876. //
  1877. // Arguments:
  1878. //
  1879. // Returns: STATUS_SUCCESS -- If all went well.
  1880. //
  1881. // DFS_STATUS_BAD_EXIT_POINT -- If cannot find exit point.
  1882. //
  1883. // Note:
  1884. //
  1885. // History: 02-Feb-93 SudK Created.
  1886. //
  1887. //--------------------------------------------------------------------------
  1888. NTSTATUS
  1889. DfsFsctrlDeleteExitPoint(
  1890. IN PIRP Irp,
  1891. IN PVOID InputBuffer,
  1892. IN ULONG InputBufferLength
  1893. )
  1894. {
  1895. NTSTATUS status = STATUS_SUCCESS;
  1896. PDFS_DELETE_EXIT_POINT_ARG arg;
  1897. DFS_PKT_ENTRY_ID ExitPtId;
  1898. ULONG Type;
  1899. STD_FSCTRL_PROLOGUE(DfsFsctrlDeleteExitPoint, TRUE, FALSE);
  1900. if (InputBufferLength < sizeof(*arg)+sizeof(UNICODE_NULL)) {
  1901. status = STATUS_INVALID_PARAMETER;
  1902. goto exit_with_status;
  1903. }
  1904. //
  1905. // Unmarshal the argument...
  1906. //
  1907. arg = (PDFS_DELETE_EXIT_POINT_ARG) InputBuffer;
  1908. OFFSET_TO_POINTER( arg->Prefix, arg );
  1909. if (!DfspStringInBuffer(arg->Prefix, InputBuffer, InputBufferLength)) {
  1910. status = STATUS_INVALID_PARAMETER;
  1911. goto exit_with_status;
  1912. }
  1913. ExitPtId.Uid = arg->Uid;
  1914. RtlInitUnicodeString( &ExitPtId.Prefix, arg->Prefix );
  1915. Type = arg->Type;
  1916. DebugTrace(0, Dbg, "Deleting Exit Point [%wZ]\n", &ExitPtId.Prefix );
  1917. DebugTrace(0, Dbg, "Type == %d\n", ULongToPtr( Type ));
  1918. status = DfsInternalDeleteExitPoint(&ExitPtId, Type);
  1919. exit_with_status:
  1920. DfsCompleteRequest( Irp, status );
  1921. DebugTrace(-1, Dbg, "DfsFsctrlDeleteExitPoint: Exit -> %08lx\n", ULongToPtr( status ) );
  1922. return status;
  1923. }
  1924. //+---------------------------------------------------------------------
  1925. //
  1926. // Function: DfsGetPrincipalName, public
  1927. //
  1928. // Synopsis: Gets the principal name of this machine either from the
  1929. // DfsData structure or creates a new one by looking at Registry
  1930. // and domain service.
  1931. //
  1932. // Arguments: [pustrName] -- The Service Name is to be filled in here.
  1933. //
  1934. // Returns: STATUS_SUCCESS -- If all went well.
  1935. //
  1936. // History: 30 May 1993 SudK Created.
  1937. //
  1938. //----------------------------------------------------------------------
  1939. NTSTATUS
  1940. DfsGetPrincipalName(PUNICODE_STRING pustrName)
  1941. {
  1942. NTSTATUS status;
  1943. ASSERT(ARGUMENT_PRESENT(pustrName));
  1944. //
  1945. // We first need to acquire DfsData resource.
  1946. //
  1947. ExAcquireResourceSharedLite(&DfsData.Resource, TRUE);
  1948. ASSERT(DfsData.PrincipalName.Length != 0);
  1949. if (DfsData.PrincipalName.Length != 0) {
  1950. *pustrName = DfsData.PrincipalName;
  1951. status = STATUS_SUCCESS;
  1952. } else {
  1953. status = STATUS_OBJECT_NAME_NOT_FOUND;
  1954. }
  1955. ExReleaseResourceLite(&DfsData.Resource);
  1956. return(status);
  1957. }
  1958. //+----------------------------------------------------------------------
  1959. //
  1960. // Function: DfsFileOnExitPath,
  1961. //
  1962. // Synopsis: This function figures out if the given path lies along an
  1963. // exit path on the local machine.
  1964. //
  1965. // Arguments: [Pkt] -- Shared access is sufficient.
  1966. // [StorageId] -- The FilePath which we need to test for.
  1967. //
  1968. // Returns: TRUE if FilePath is a prefix of some exit path.
  1969. // Also if FilePath matches a StorageId then we return TRUE.
  1970. // ELSE we return FALSE.
  1971. //-----------------------------------------------------------------------
  1972. BOOLEAN
  1973. DfsFileOnExitPath(
  1974. PDFS_PKT Pkt,
  1975. PUNICODE_STRING StorageId
  1976. )
  1977. {
  1978. PDFS_LOCAL_VOL_ENTRY lv;
  1979. UNICODE_STRING RemStgId;
  1980. lv = PktEntryLookupLocalService(Pkt, StorageId, &RemStgId);
  1981. if ((lv != NULL) && (RemStgId.Length == 0)) {
  1982. //
  1983. // If we did find a perfect match, return TRUE
  1984. // from this perfect match.
  1985. //
  1986. return(TRUE);
  1987. } else if (lv != NULL) {
  1988. //
  1989. // We did not have a perfect match. We now need to look for exit pts
  1990. // crossing into this StorageId from the match that we found.
  1991. //
  1992. PDFS_PKT_ENTRY pktEntry, pktExitEntry;
  1993. USHORT prefixLength;
  1994. UNICODE_STRING RemExitPt;
  1995. pktEntry = lv->PktEntry;
  1996. pktExitEntry = PktEntryFirstSubordinate(pktEntry);
  1997. //
  1998. // As long as there are more exit points see if that exit point crosses
  1999. // into the new storage Id.
  2000. //
  2001. while (pktExitEntry != NULL) {
  2002. PUNICODE_STRING ExitPrefix;
  2003. ExitPrefix = &pktExitEntry->Id.Prefix;
  2004. prefixLength = pktEntry->Id.Prefix.Length;
  2005. if (ExitPrefix->Buffer[prefixLength/sizeof(WCHAR)] == UNICODE_PATH_SEP)
  2006. prefixLength += sizeof(WCHAR);
  2007. RemExitPt.Length = pktExitEntry->Id.Prefix.Length - prefixLength;
  2008. RemExitPt.MaximumLength = RemExitPt.Length + 1;
  2009. RemExitPt.Buffer = &ExitPrefix->Buffer[prefixLength/sizeof(WCHAR)];
  2010. //
  2011. // Only if the ExitPt has the potential of crossing over into the
  2012. // storageId do we do this.
  2013. //
  2014. if (DfsRtlPrefixPath(&RemStgId, &RemExitPt, TRUE)) {
  2015. return(TRUE);
  2016. }
  2017. pktExitEntry = PktEntryNextSubordinate(pktEntry, pktExitEntry);
  2018. } //while exit pt exists
  2019. } // lv != NULL
  2020. return(FALSE);
  2021. }
  2022. //+----------------------------------------------------------------------
  2023. //
  2024. // Function: DfsStorageIdLegal
  2025. //
  2026. // Synopsis: This function determines if a given storage Id can be used
  2027. // to support a new part of the namespace without violating any
  2028. // of the DFS rules as specified below.
  2029. //
  2030. // Arguments: [StorageId] -- UnicodeString which represents the StorageId.
  2031. //
  2032. // Returns: TRUE if it is Legal else FALSE.
  2033. //
  2034. // History: 8th Dec. 1993 SudK Created.
  2035. //
  2036. //-----------------------------------------------------------------------
  2037. BOOLEAN
  2038. DfsStorageIdLegal(
  2039. PUNICODE_STRING StorageId
  2040. )
  2041. {
  2042. PDFS_PKT Pkt;
  2043. PDFS_LOCAL_VOL_ENTRY lv;
  2044. PUNICODE_PREFIX_TABLE_ENTRY lvpfx;
  2045. BOOLEAN conflictFound = FALSE;
  2046. if (StorageId->Length == 0)
  2047. return(FALSE);
  2048. //
  2049. // We need Read access to the Pkt.
  2050. //
  2051. Pkt = _GetPkt();
  2052. PktAcquireShared(Pkt, TRUE);
  2053. lvpfx = DfsNextUnicodePrefix(&Pkt->LocalVolTable, TRUE);
  2054. while (lvpfx != NULL && !conflictFound) {
  2055. lv = CONTAINING_RECORD(lvpfx, DFS_LOCAL_VOL_ENTRY, PrefixTableEntry);
  2056. if (lv->LocalPath.Length > StorageId->Length) {
  2057. if (RtlPrefixUnicodeString(StorageId, &lv->LocalPath, TRUE)) {
  2058. //
  2059. // StorageId scopes over a directory which is in Dfs - this is
  2060. // not allowed.
  2061. //
  2062. conflictFound = TRUE;
  2063. }
  2064. }
  2065. if (lv->LocalPath.Length <= StorageId->Length) {
  2066. if (RtlPrefixUnicodeString(&lv->LocalPath, StorageId, TRUE)) {
  2067. //
  2068. // StorageId is a child of a Dfs volume - this is not allowed
  2069. // either.
  2070. //
  2071. conflictFound = TRUE;
  2072. }
  2073. }
  2074. lvpfx = DfsNextUnicodePrefix(&Pkt->LocalVolTable, FALSE);
  2075. }
  2076. //
  2077. // If we got here the StorageId was perfectly legal.
  2078. //
  2079. PktRelease(Pkt);
  2080. return( !conflictFound );
  2081. }
  2082. //+-------------------------------------------------------------------------
  2083. //
  2084. // Function: DfsExitPtLegal
  2085. //
  2086. // Synopsis: This function checks to see whether a given exit point is legal
  2087. //
  2088. // Arguments: [localEntry] -- The Local Entry where exit pt is to be created.
  2089. // [Remaining] -- Remaining Path on local Stg Id to be created.
  2090. //
  2091. // History: 8th Dec. 1993 SudK Created.
  2092. //
  2093. //--------------------------------------------------------------------------
  2094. BOOLEAN
  2095. DfsExitPtLegal(
  2096. IN PDFS_PKT Pkt,
  2097. IN PDFS_PKT_ENTRY localEntry,
  2098. IN PUNICODE_STRING Remaining
  2099. )
  2100. {
  2101. NTSTATUS status;
  2102. UNICODE_STRING LocalExitPt;
  2103. PDFS_LOCAL_VOL_ENTRY lv;
  2104. UNICODE_STRING RemExitPt;
  2105. PWCHAR pwsz;
  2106. BOOLEAN retCode;
  2107. USHORT index;
  2108. DebugTrace(+1, Dbg, "DfsExitPtLegal Entered : %wZ\n", Remaining);
  2109. ASSERT(localEntry != NULL);
  2110. //
  2111. // We first compose the local path to the exit pt.
  2112. //
  2113. status = BuildLocalVolPath(&LocalExitPt,
  2114. localEntry->LocalService,
  2115. Remaining);
  2116. //
  2117. // If for some reason (Mem Failure) we fail above, then we will just make
  2118. // the exit pt to be illegal. That should be an OK restrictions since the
  2119. // only reason the above would fail is due to memory failure.
  2120. //
  2121. if (!NT_SUCCESS(status)) {
  2122. DebugTrace(-1, Dbg, "DfsExitPtLegal Exited %08lx\n", ULongToPtr( status ));
  2123. return(FALSE);
  2124. }
  2125. lv = PktEntryLookupLocalService(Pkt, &LocalExitPt, &RemExitPt);
  2126. //
  2127. // There is atleast the stg id in the local entry so we better getback a
  2128. // Non Null value here.
  2129. //
  2130. ASSERT(lv != NULL);
  2131. if (lv != NULL) {
  2132. ASSERT(RemExitPt.Length <= Remaining->Length);
  2133. //
  2134. // If we the remaining path is less than original remaining exit path
  2135. // the we definitely hit a different and longer storage Id. So the
  2136. // exit pt is illegal since it would cross over into a new storageId.
  2137. //
  2138. if (RemExitPt.Length < Remaining->Length) {
  2139. DebugTrace(-1, Dbg, "Illegal exit pt creation attempted %wZ\n",
  2140. &LocalExitPt);
  2141. ExFreePool(LocalExitPt.Buffer);
  2142. return(FALSE);
  2143. }
  2144. }
  2145. else {
  2146. DebugTrace(-1, Dbg, "InternalData structures seem to be corrupt\n",0);
  2147. ExFreePool(LocalExitPt.Buffer);
  2148. return(FALSE); // We should never get here.
  2149. }
  2150. //
  2151. // Now we need to see if there is an encompassing and shorter StorageId.
  2152. // If so we wont allow this exit pt to be created.
  2153. //
  2154. LocalExitPt.Length = LocalExitPt.Length - Remaining->Length - sizeof(WCHAR);
  2155. index = LocalExitPt.Length/sizeof(WCHAR) - 1;
  2156. pwsz = &LocalExitPt.Buffer[index];
  2157. while ((*pwsz != UNICODE_PATH_SEP) && (index > 0)) {
  2158. pwsz--;
  2159. index--;
  2160. }
  2161. if (index == 0) {
  2162. ExFreePool(LocalExitPt.Buffer);
  2163. return(TRUE); // When would this happen at all.
  2164. }
  2165. else {
  2166. *pwsz = UNICODE_NULL;
  2167. LocalExitPt.Length = index*sizeof(WCHAR);
  2168. //
  2169. // Now we have the StorageId with the last component of StorageId in
  2170. // the current local service removed. Lets do a lookup for a shorter
  2171. // StgId now.
  2172. //
  2173. lv = PktEntryLookupLocalService(Pkt, &LocalExitPt, &RemExitPt);
  2174. if (lv == NULL) {
  2175. retCode = TRUE;
  2176. }
  2177. else {
  2178. DebugTrace(0, Dbg,
  2179. "Found shorter StgId %wZ which makes ExitPt illegal\n",
  2180. &lv->LocalPath);
  2181. retCode = FALSE;
  2182. }
  2183. }
  2184. ExFreePool(LocalExitPt.Buffer);
  2185. DebugTrace(-1, Dbg, "DfsExitPtLegal Exited\n", 0);
  2186. return(retCode);
  2187. }
  2188. //+----------------------------------------------------------------------------
  2189. //
  2190. // Function: BuildShortPrefix
  2191. //
  2192. // Synopsis: Given the name of an exit path relative to some local volume,
  2193. // and the Dfs prefix of the local volume, this routine computes
  2194. // the short prefix of the exit path.
  2195. //
  2196. // Arguments: [pRemPath] -- Exit path relative to local volume
  2197. // [pService] -- DFS_SERVICE describing local volume
  2198. // [PeidParent] -- Entry path of the local volume
  2199. // [Peid] -- EntryID of the volume for which this exit point
  2200. // was created.
  2201. //
  2202. // Returns: [STATUS_SUCCESS] -- Successfully return short prefix in
  2203. // Peid->ShortPrefix.
  2204. //
  2205. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory
  2206. //
  2207. //-----------------------------------------------------------------------------
  2208. NTSTATUS
  2209. BuildShortPrefix(
  2210. PUNICODE_STRING pRemPath,
  2211. PDFS_SERVICE pService,
  2212. PDFS_PKT_ENTRY_ID PeidParent,
  2213. PDFS_PKT_ENTRY_ID Peid)
  2214. {
  2215. NTSTATUS status;
  2216. UNICODE_STRING exitPath, exitPathComponent, shortPrefix;
  2217. DebugTrace(+1, Dbg, "BuildShortPrefix - Entered\n", 0);
  2218. status = BuildLocalVolPath( &exitPath, pService, pRemPath);
  2219. if (!NT_SUCCESS(status)) {
  2220. ASSERT(status == STATUS_INSUFFICIENT_RESOURCES );
  2221. return( status );
  2222. }
  2223. DebugTrace(0, Dbg, "Exit Path = [%wZ]\n", &exitPath);
  2224. //
  2225. // We now have the exit path name, which looks like
  2226. // \Device\Harddisk0\Partition1\a\b\c\rem-path
  2227. // The short prefix we are after looks like
  2228. // \PeidParent.ShortPrefix\8.3-form-of-pRemPath
  2229. //
  2230. //
  2231. // First, allocate room for the short prefix
  2232. //
  2233. shortPrefix.MaximumLength = PeidParent->ShortPrefix.Length +
  2234. exitPath.Length +
  2235. sizeof(FILE_NAME_INFORMATION);
  2236. shortPrefix.MaximumLength = (USHORT) ROUND_UP_COUNT(
  2237. shortPrefix.MaximumLength,
  2238. 4);
  2239. shortPrefix.Buffer = ExAllocatePoolWithTag(PagedPool, shortPrefix.MaximumLength, ' sfD');
  2240. if (shortPrefix.Buffer == NULL) {
  2241. ExFreePool( exitPath.Buffer );
  2242. return( STATUS_INSUFFICIENT_RESOURCES );
  2243. }
  2244. //
  2245. // Copy the parent's short prefix first
  2246. //
  2247. shortPrefix.Length = PeidParent->ShortPrefix.Length;
  2248. RtlCopyMemory(
  2249. shortPrefix.Buffer,
  2250. PeidParent->ShortPrefix.Buffer,
  2251. PeidParent->ShortPrefix.Length);
  2252. //
  2253. // Now, for each component of pRemPath, figure out its 8.3 form, and
  2254. // append it to the short prefix we are constructing.
  2255. //
  2256. exitPathComponent = exitPath;
  2257. exitPathComponent.Length -= pRemPath->Length;
  2258. do {
  2259. ULONG n, lastIndex;
  2260. HANDLE componentHandle;
  2261. OBJECT_ATTRIBUTES objectAttributes;
  2262. IO_STATUS_BLOCK ioStatus;
  2263. PFILE_NAME_INFORMATION shortNameInfo;
  2264. if (exitPathComponent.Buffer[
  2265. exitPathComponent.Length/sizeof(WCHAR)] ==
  2266. UNICODE_PATH_SEP) {
  2267. exitPathComponent.Length += sizeof(WCHAR);
  2268. }
  2269. for (n = exitPathComponent.Length / sizeof(WCHAR),
  2270. lastIndex = exitPath.Length / sizeof(WCHAR);
  2271. n < lastIndex &&
  2272. exitPathComponent.Buffer[n] != UNICODE_PATH_SEP;
  2273. n++,
  2274. exitPathComponent.Length += sizeof(WCHAR)) {
  2275. NOTHING;
  2276. }
  2277. DebugTrace(0, Dbg, "ExitPathComponent: [%wZ]\n", &exitPathComponent);
  2278. InitializeObjectAttributes(
  2279. &objectAttributes,
  2280. &exitPathComponent,
  2281. OBJ_CASE_INSENSITIVE,
  2282. NULL,
  2283. NULL);
  2284. status = ZwOpenFile(
  2285. &componentHandle,
  2286. FILE_READ_ATTRIBUTES,
  2287. &objectAttributes,
  2288. &ioStatus,
  2289. FILE_SHARE_VALID_FLAGS,
  2290. FILE_DIRECTORY_FILE);
  2291. if (NT_SUCCESS(status)) {
  2292. shortNameInfo = (PFILE_NAME_INFORMATION)
  2293. &shortPrefix.Buffer[
  2294. shortPrefix.Length/sizeof(WCHAR)];
  2295. shortNameInfo = ROUND_UP_POINTER(shortNameInfo, 4);
  2296. status = ZwQueryInformationFile(
  2297. componentHandle,
  2298. &ioStatus,
  2299. shortNameInfo,
  2300. shortPrefix.MaximumLength - shortPrefix.Length,
  2301. FileAlternateNameInformation);
  2302. ZwClose( componentHandle );
  2303. }
  2304. if (NT_SUCCESS(status)) {
  2305. ULONG componentLength;
  2306. componentLength = shortNameInfo->FileNameLength;
  2307. shortPrefix.Buffer[ shortPrefix.Length/sizeof(WCHAR) ] =
  2308. UNICODE_PATH_SEP;
  2309. shortPrefix.Length += sizeof(WCHAR);
  2310. RtlMoveMemory(
  2311. &shortPrefix.Buffer[ shortPrefix.Length/sizeof(WCHAR) ],
  2312. shortNameInfo->FileName,
  2313. componentLength);
  2314. shortPrefix.Length += (USHORT) componentLength;
  2315. }
  2316. DebugTrace(0, Dbg, "ShortPrefix: [%wZ]\n", &shortPrefix);
  2317. } while ( NT_SUCCESS(status) &&
  2318. exitPathComponent.Length < exitPath.Length );
  2319. if (!NT_SUCCESS(status)) {
  2320. //
  2321. // We failed to compute the short prefix. So, we'll just use the
  2322. // prefix as our short prefix.
  2323. //
  2324. shortPrefix.Length = PeidParent->Prefix.Length;
  2325. RtlCopyMemory(
  2326. &shortPrefix.Buffer[ shortPrefix.Length/sizeof(WCHAR) ],
  2327. &Peid->Prefix.Buffer[ PeidParent->Prefix.Length/sizeof(WCHAR) ],
  2328. Peid->Prefix.Length - PeidParent->Prefix.Length);
  2329. }
  2330. Peid->ShortPrefix = shortPrefix;
  2331. ExFreePool( exitPath.Buffer );
  2332. DebugTrace(-1, Dbg, "BuildShortPrefix: Exiting [%wZ]\n", &shortPrefix);
  2333. return( STATUS_SUCCESS );
  2334. }
  2335. //+----------------------------------------------------------------------------
  2336. //
  2337. // Function: StripLastComponent, private
  2338. //
  2339. // Synopsis: Strip the trailing backslash and path from a name. Adjusts
  2340. // the Length field, leaves the MaximumLength field alone.
  2341. //
  2342. // Arguments: [pustr] -- pointer to unicode string
  2343. //
  2344. // Returns: nothing
  2345. //
  2346. //-----------------------------------------------------------------------------
  2347. VOID
  2348. StripLastComponent(PUNICODE_STRING pustr)
  2349. {
  2350. PWCHAR pwch;
  2351. USHORT i = 0;
  2352. pwch = pustr->Buffer;
  2353. pwch += (pustr->Length/sizeof(WCHAR)) - 1;
  2354. while ((*pwch != UNICODE_PATH_SEP) && (pwch != pustr->Buffer)) {
  2355. i += sizeof(WCHAR);
  2356. pwch--;
  2357. }
  2358. if ((*pwch == UNICODE_PATH_SEP) && (pwch != pustr->Buffer)) {
  2359. i += sizeof(WCHAR);
  2360. pwch--;
  2361. }
  2362. pustr->Length -= i;
  2363. }
  2364. //+----------------------------------------------------------------------------
  2365. //
  2366. // Function: AddLastComponent, private
  2367. //
  2368. // Synopsis: Restore the trailing backslash and path from a name. Adjusts
  2369. // the Length field, leaves the MaximumLength field alone. Assumes
  2370. // that MaximumLength is the 'real' length of the string.
  2371. //
  2372. // Arguments: [pustr] -- pointer to unicode string
  2373. //
  2374. // Returns: nothing
  2375. //
  2376. //-----------------------------------------------------------------------------
  2377. VOID
  2378. AddLastComponent(PUNICODE_STRING pustr)
  2379. {
  2380. PWCHAR pwch;
  2381. PWCHAR pend;
  2382. USHORT i = 0;
  2383. pwch = pustr->Buffer;
  2384. pwch += (pustr->Length/sizeof(WCHAR)) - 1;
  2385. pend = &pustr->Buffer[pustr->MaximumLength/sizeof(WCHAR) - 1];
  2386. if (pwch != pend) {
  2387. i += sizeof(WCHAR);
  2388. pwch++;
  2389. }
  2390. if ((*pwch == UNICODE_PATH_SEP) && (pwch != pend)) {
  2391. i += sizeof(WCHAR);
  2392. pwch++;
  2393. }
  2394. while ((*pwch != UNICODE_PATH_SEP) && (pwch != pend)) {
  2395. i += sizeof(WCHAR);
  2396. pwch++;
  2397. }
  2398. if ((*pwch == UNICODE_PATH_SEP) && (pwch != pend)) {
  2399. i -= sizeof(WCHAR);
  2400. pwch--;
  2401. }
  2402. pustr->Length += i;
  2403. }
  2404. #define DFS_DIRECTORY_INFO_BUFFER_SIZE 1024
  2405. #define DFS_MAX_DELETE_FILES_IN_DIRECTORY 3
  2406. //+----------------------------------------------------------------------------
  2407. //
  2408. // Function: DfsDeleteDirectoryCheck, private
  2409. //
  2410. // Synopsis: Given a buffer of FILE_NAMES_INFORMATION, this will indicate
  2411. // if the given directory can be deleted.
  2412. //
  2413. // Arguments: [buffer] -- buffer containing info
  2414. //
  2415. // Returns: TRUE if directory can be deleted.
  2416. //
  2417. //-----------------------------------------------------------------------------
  2418. BOOLEAN
  2419. DfsDeleteDirectoryCheck(
  2420. UCHAR *Buffer)
  2421. {
  2422. FILE_NAMES_INFORMATION *buf;
  2423. ULONG numFiles = 1;
  2424. BOOLEAN DeleteOk = TRUE;
  2425. buf = (FILE_NAMES_INFORMATION *)Buffer;
  2426. while (buf->NextEntryOffset) {
  2427. numFiles++;
  2428. if (numFiles > DFS_MAX_DELETE_FILES_IN_DIRECTORY) {
  2429. DeleteOk = FALSE;
  2430. break;
  2431. }
  2432. buf = (FILE_NAMES_INFORMATION *)((UCHAR *)(buf) + buf->NextEntryOffset);
  2433. }
  2434. return DeleteOk;
  2435. }
  2436. //+----------------------------------------------------------------------------
  2437. //
  2438. // Function: DfsGetDirectoriesToDelete, private
  2439. //
  2440. // Synopsis: Walk the pathnames all the way up to the sharename, and
  2441. // and return a count of number of levels that can be deleted.
  2442. // NOTE: This is not atomic! (If someone creates a directory or
  2443. // file AFTER this check, they are hosed since we will mark the
  2444. // directory for delete)
  2445. //
  2446. // Arguments: pExitPtName : name of exit point
  2447. // pShareName : name of the share.
  2448. //
  2449. // Returns: count of number of levels that can be deleted.
  2450. //
  2451. //-----------------------------------------------------------------------------
  2452. ULONG
  2453. DfsGetDirectoriesToDelete(
  2454. PUNICODE_STRING pExitPtName,
  2455. PUNICODE_STRING pShareName)
  2456. {
  2457. PUCHAR Buffer;
  2458. ULONG Deletes = 0;
  2459. OBJECT_ATTRIBUTES objectAttributes;
  2460. HANDLE exitPtHandle;
  2461. IO_STATUS_BLOCK ioStatus;
  2462. NTSTATUS status, CloseStatus;
  2463. UNICODE_STRING ExitPtName;
  2464. ExitPtName = *pExitPtName;
  2465. Buffer = ExAllocatePoolWithTag(PagedPool,
  2466. DFS_DIRECTORY_INFO_BUFFER_SIZE,
  2467. ' sfD');
  2468. if (Buffer == NULL)
  2469. return ++Deletes;
  2470. do {
  2471. InitializeObjectAttributes(
  2472. &objectAttributes,
  2473. &ExitPtName,
  2474. OBJ_CASE_INSENSITIVE,
  2475. NULL,
  2476. NULL);
  2477. status = ZwOpenFile(
  2478. &exitPtHandle,
  2479. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  2480. &objectAttributes,
  2481. &ioStatus,
  2482. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2483. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
  2484. if (NT_SUCCESS(status)) {
  2485. status = ZwQueryDirectoryFile(
  2486. exitPtHandle,
  2487. NULL, NULL, NULL,
  2488. &ioStatus,
  2489. Buffer,
  2490. DFS_DIRECTORY_INFO_BUFFER_SIZE,
  2491. FileNamesInformation,
  2492. FALSE,
  2493. NULL,
  2494. TRUE);
  2495. CloseStatus = ZwClose( exitPtHandle );
  2496. }
  2497. if (!NT_SUCCESS(status) ||
  2498. (DfsDeleteDirectoryCheck(Buffer) == FALSE)) {
  2499. break;
  2500. }
  2501. Deletes++;
  2502. StripLastComponent(&ExitPtName);
  2503. } while (!RtlEqualUnicodeString(&ExitPtName, pShareName, TRUE));
  2504. if (Buffer)
  2505. ExFreePool(Buffer);
  2506. return Deletes;
  2507. }