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.

1286 lines
29 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. fileinfo.c
  5. Abstract:
  6. This module implements the get / set volume information routines for
  7. netware redirector.
  8. Setting volume information is currently unimplemented.
  9. Author:
  10. Manny Weiser (mannyw) 4-Mar-1993
  11. Revision History:
  12. --*/
  13. #include "procs.h"
  14. #define NW_FS_NAME L"NWCompat"
  15. //
  16. // The debug trace level
  17. //
  18. #define Dbg (DEBUG_TRACE_VOLINFO)
  19. //
  20. // Local procedure prototypes.
  21. //
  22. NTSTATUS
  23. NwCommonQueryVolumeInformation (
  24. IN PIRP_CONTEXT pIrpContext
  25. );
  26. NTSTATUS
  27. NwQueryAttributeInfo (
  28. IN PVCB Vcb,
  29. IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
  30. IN ULONG Length,
  31. OUT PULONG BytesWritten
  32. );
  33. NTSTATUS
  34. NwQueryVolumeInfo (
  35. IN PIRP_CONTEXT pIrpContext,
  36. IN PVCB Vcb,
  37. IN PFILE_FS_VOLUME_INFORMATION Buffer,
  38. IN ULONG Length,
  39. OUT PULONG BytesWritten
  40. );
  41. NTSTATUS
  42. NwQueryLabelInfo (
  43. IN PIRP_CONTEXT pIrpContext,
  44. IN PVCB Vcb,
  45. IN PFILE_FS_LABEL_INFORMATION Buffer,
  46. IN ULONG Length,
  47. OUT PULONG BytesWritten
  48. );
  49. NTSTATUS
  50. NwQuerySizeInfo (
  51. IN PIRP_CONTEXT pIrpContext,
  52. IN PVCB Vcb,
  53. IN PFILE_FS_VOLUME_INFORMATION Buffer,
  54. IN ULONG Length
  55. );
  56. NTSTATUS
  57. QueryFsSizeInfoCallback(
  58. IN PIRP_CONTEXT pIrpContext,
  59. IN ULONG BytesAvailable,
  60. IN PUCHAR Response
  61. );
  62. NTSTATUS
  63. QueryFsSizeInfoCallback2(
  64. IN PIRP_CONTEXT pIrpContext,
  65. IN ULONG BytesAvailable,
  66. IN PUCHAR Response
  67. );
  68. NTSTATUS
  69. NwQueryDeviceInfo (
  70. IN PIRP_CONTEXT pIrpContext,
  71. IN PVCB Vcb,
  72. IN PFILE_FS_DEVICE_INFORMATION Buffer,
  73. IN ULONG Length
  74. );
  75. NTSTATUS
  76. NwCommonSetVolumeInformation (
  77. IN PIRP_CONTEXT pIrpContext
  78. );
  79. #ifdef ALLOC_PRAGMA
  80. #pragma alloc_text( PAGE, NwFsdQueryVolumeInformation )
  81. #pragma alloc_text( PAGE, NwCommonQueryVolumeInformation )
  82. #pragma alloc_text( PAGE, NwQueryAttributeInfo )
  83. #pragma alloc_text( PAGE, NwQueryVolumeInfo )
  84. #pragma alloc_text( PAGE, NwQueryLabelInfo )
  85. #pragma alloc_text( PAGE, NwQuerySizeInfo )
  86. #pragma alloc_text( PAGE, NwQueryDeviceInfo )
  87. #pragma alloc_text( PAGE, NwFsdSetVolumeInformation )
  88. #pragma alloc_text( PAGE, NwCommonSetVolumeInformation )
  89. #ifndef QFE_BUILD
  90. #pragma alloc_text( PAGE1, QueryFsSizeInfoCallback )
  91. #pragma alloc_text( PAGE1, QueryFsSizeInfoCallback2 )
  92. #endif
  93. #endif
  94. #if 0 // Not pageable
  95. // see ifndef QFE_BUILD above
  96. #endif
  97. NTSTATUS
  98. NwFsdQueryVolumeInformation (
  99. IN PDEVICE_OBJECT DeviceObject,
  100. IN PIRP Irp
  101. )
  102. /*++
  103. Routine Description:
  104. This routine implements the FSD part of the NtQueryVolumeInformationFile
  105. API calls.
  106. Arguments:
  107. NwfsDeviceObject - Supplies a pointer to the device object to use.
  108. Irp - Supplies a pointer to the Irp to process.
  109. Return Value:
  110. NTSTATUS - The Fsd status for the Irp
  111. --*/
  112. {
  113. NTSTATUS status;
  114. PIRP_CONTEXT pIrpContext = NULL;
  115. BOOLEAN TopLevel;
  116. PAGED_CODE();
  117. DebugTrace(+1, Dbg, "NwFsdQueryVolumeInformation\n", 0);
  118. //
  119. // Call the common query volume information routine.
  120. //
  121. FsRtlEnterFileSystem();
  122. TopLevel = NwIsIrpTopLevel( Irp );
  123. try {
  124. pIrpContext = AllocateIrpContext( Irp );
  125. status = NwCommonQueryVolumeInformation( pIrpContext );
  126. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  127. if ( pIrpContext == NULL ) {
  128. //
  129. // If we couldn't allocate an irp context, just complete
  130. // irp without any fanfare.
  131. //
  132. status = STATUS_INSUFFICIENT_RESOURCES;
  133. Irp->IoStatus.Status = status;
  134. Irp->IoStatus.Information = 0;
  135. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  136. } else {
  137. //
  138. // We had some trouble trying to perform the requested
  139. // operation, so we'll abort the I/O request with
  140. // the error Status that we get back from the
  141. // execption code
  142. //
  143. status = NwProcessException( pIrpContext, GetExceptionCode() );
  144. }
  145. }
  146. if ( pIrpContext ) {
  147. if ( status != STATUS_PENDING ) {
  148. NwDequeueIrpContext( pIrpContext, FALSE );
  149. }
  150. NwCompleteRequest( pIrpContext, status );
  151. }
  152. if ( TopLevel ) {
  153. NwSetTopLevelIrp( NULL );
  154. }
  155. FsRtlExitFileSystem();
  156. //
  157. // Return to the caller.
  158. //
  159. DebugTrace(-1, Dbg, "NwFsdQueryVolumeInformation -> %08lx\n", status );
  160. return status;
  161. }
  162. NTSTATUS
  163. NwCommonQueryVolumeInformation (
  164. IN PIRP_CONTEXT pIrpContext
  165. )
  166. /*++
  167. Routine Description:
  168. This is the common routine for querying volume information.
  169. Arguments:
  170. IrpContext - Supplies the Irp to process
  171. Return Value:
  172. NTSTATUS - the return status for the operation.
  173. --*/
  174. {
  175. PIRP Irp;
  176. PIO_STACK_LOCATION irpSp;
  177. NTSTATUS status;
  178. ULONG length;
  179. ULONG bytesWritten = 0;
  180. FS_INFORMATION_CLASS fsInformationClass;
  181. PVOID buffer;
  182. NODE_TYPE_CODE nodeTypeCode;
  183. PVOID fsContext, fsContext2;
  184. PICB icb = NULL;
  185. PVCB vcb = NULL;
  186. PAGED_CODE();
  187. //
  188. // Get the current stack location.
  189. //
  190. Irp = pIrpContext->pOriginalIrp;
  191. irpSp = IoGetCurrentIrpStackLocation( Irp );
  192. DebugTrace(+1, Dbg, "NwCommonQueryInformation...\n", 0);
  193. DebugTrace( 0, Dbg, " Irp = %08lx\n", (ULONG_PTR)Irp);
  194. DebugTrace( 0, Dbg, " ->Length = %08lx\n", irpSp->Parameters.QueryFile.Length);
  195. DebugTrace( 0, Dbg, " ->FsInformationClass = %08lx\n", irpSp->Parameters.QueryVolume.FsInformationClass);
  196. DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer);
  197. //
  198. // Find out who are.
  199. //
  200. if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  201. &fsContext,
  202. &fsContext2 )) == NTC_UNDEFINED) {
  203. DebugTrace(0, Dbg, "Handle is closing\n", 0);
  204. NwCompleteRequest( pIrpContext, STATUS_INVALID_HANDLE );
  205. status = STATUS_INVALID_HANDLE;
  206. DebugTrace(-1, Dbg, "NwCommonQueryVolumeInformation -> %08lx\n", status );
  207. return status;
  208. }
  209. //
  210. // Decide how to handle this request. A user can query information
  211. // on a VCB only.
  212. //
  213. switch (nodeTypeCode) {
  214. case NW_NTC_RCB:
  215. break;
  216. case NW_NTC_ICB:
  217. icb = (PICB)fsContext2;
  218. //
  219. // Make sure that this ICB is still active.
  220. //
  221. NwVerifyIcb( icb );
  222. vcb = icb->SuperType.Fcb->Vcb;
  223. pIrpContext->pNpScb = icb->SuperType.Fcb->Scb->pNpScb;
  224. break;
  225. default: // This is not a nodetype
  226. DebugTrace(0, Dbg, "Node type code is not incorrect\n", 0);
  227. DebugTrace(-1, Dbg, "NwCommonQueryVolumeInformation -> STATUS_INVALID_PARAMETER\n", 0);
  228. return STATUS_INVALID_PARAMETER;
  229. }
  230. //
  231. // Make local copies of the input parameters.
  232. //
  233. length = irpSp->Parameters.QueryVolume.Length;
  234. fsInformationClass = irpSp->Parameters.QueryVolume.FsInformationClass;
  235. buffer = Irp->AssociatedIrp.SystemBuffer;
  236. //
  237. // It is ok to attempt a reconnect if this request fails with a
  238. // connection error.
  239. //
  240. SetFlag( pIrpContext->Flags, IRP_FLAG_RECONNECTABLE );
  241. try {
  242. //
  243. // Decide how to handle the request.
  244. //
  245. switch (fsInformationClass) {
  246. case FileFsVolumeInformation:
  247. status = NwQueryVolumeInfo( pIrpContext, vcb, buffer, length, &bytesWritten );
  248. break;
  249. case FileFsLabelInformation:
  250. status = NwQueryLabelInfo( pIrpContext, vcb, buffer, length, &bytesWritten );
  251. break;
  252. case FileFsSizeInformation:
  253. if ( vcb != NULL ) {
  254. status = NwQuerySizeInfo( pIrpContext, vcb, buffer, length );
  255. } else {
  256. status = STATUS_INVALID_PARAMETER;
  257. }
  258. break;
  259. case FileFsDeviceInformation:
  260. status = NwQueryDeviceInfo( pIrpContext, vcb, buffer, length );
  261. bytesWritten = sizeof( FILE_FS_DEVICE_INFORMATION );
  262. break;
  263. case FileFsAttributeInformation:
  264. if ( vcb != NULL ) {
  265. status = NwQueryAttributeInfo( vcb, buffer, length, &bytesWritten );
  266. } else {
  267. status = STATUS_INVALID_PARAMETER;
  268. }
  269. break;
  270. default:
  271. status = STATUS_INVALID_PARAMETER;
  272. DebugTrace(0, Dbg, "Unhandled query volume level %d\n", fsInformationClass );
  273. break;
  274. }
  275. //
  276. // Set the information field to the number of bytes actually
  277. // filled in and then complete the request.
  278. //
  279. // If the worker function returned status pending, it's
  280. // callback routine will fill the information field.
  281. //
  282. if ( status != STATUS_PENDING ) {
  283. Irp->IoStatus.Information = bytesWritten;
  284. }
  285. } finally {
  286. DebugTrace(-1, Dbg, "NwCommonQueryVolumeInformation -> %08lx\n", status );
  287. }
  288. return status;
  289. }
  290. NTSTATUS
  291. NwQueryAttributeInfo (
  292. IN PVCB Vcb,
  293. IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
  294. IN ULONG Length,
  295. OUT PULONG BytesWritten
  296. )
  297. /*++
  298. Routine Description:
  299. This routine performs the query fs attribute information operation.
  300. Arguments:
  301. Vcb - Supplies the VCB to query.
  302. Buffer - Supplies a pointer to the buffer where the information is
  303. to be returned.
  304. Length - Supplies the length of the buffer in bytes.
  305. BytesWritten - Returns the number of bytes written to the buffer.
  306. Return Value:
  307. NTSTATUS - The result of this query.
  308. --*/
  309. {
  310. NTSTATUS status;
  311. ULONG bytesToCopy;
  312. PAGED_CODE();
  313. DebugTrace(0, Dbg, "QueryFsAttributeInfo...\n", 0);
  314. //
  315. // See how many bytes of the file system name we can copy.
  316. //
  317. Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0] );
  318. *BytesWritten = FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0] );
  319. if ( Length >= sizeof(NW_FS_NAME) - 2 ) {
  320. status = STATUS_SUCCESS;
  321. *BytesWritten += sizeof(NW_FS_NAME - 2);
  322. bytesToCopy = sizeof( NW_FS_NAME - 2 );
  323. } else {
  324. status = STATUS_BUFFER_OVERFLOW;
  325. *BytesWritten += Length;
  326. bytesToCopy = Length;
  327. }
  328. //
  329. // Fill in the attribute information.
  330. //
  331. Buffer->FileSystemAttributes = 0;
  332. if ( Vcb->Specific.Disk.LongNameSpace == LFN_NO_OS2_NAME_SPACE ) {
  333. Buffer->MaximumComponentNameLength = 12;
  334. } else {
  335. Buffer->MaximumComponentNameLength = NW_MAX_FILENAME_LENGTH;
  336. }
  337. //
  338. // And copy over the file name and its length.
  339. //
  340. RtlMoveMemory( &Buffer->FileSystemName[0],
  341. NW_FS_NAME,
  342. bytesToCopy );
  343. Buffer->FileSystemNameLength = bytesToCopy;
  344. return status;
  345. }
  346. NTSTATUS
  347. NwQueryVolumeInfo (
  348. IN PIRP_CONTEXT pIrpContext,
  349. IN PVCB Vcb,
  350. IN PFILE_FS_VOLUME_INFORMATION Buffer,
  351. IN ULONG Length,
  352. OUT PULONG BytesWritten
  353. )
  354. /*++
  355. Routine Description:
  356. This routine performs the query fs volume information operation.
  357. Arguments:
  358. Vcb - The VCB to query.
  359. Buffer - Supplies a pointer to the buffer where the information is
  360. to be returned.
  361. Length - Supplies the length of the buffer in bytes.
  362. Return Value:
  363. NTSTATUS - The result of this query.
  364. --*/
  365. {
  366. NTSTATUS status;
  367. UNICODE_STRING VolumeName;
  368. PAGED_CODE();
  369. DebugTrace(0, Dbg, "QueryVolumeInfo...\n", 0);
  370. //
  371. // Do the volume request synchronously.
  372. //
  373. if (!Vcb) {
  374. return STATUS_INVALID_PARAMETER;
  375. }
  376. status = ExchangeWithWait(
  377. pIrpContext,
  378. SynchronousResponseCallback,
  379. "Sb",
  380. NCP_DIR_FUNCTION, NCP_GET_VOLUME_STATS,
  381. Vcb->Specific.Disk.Handle );
  382. if ( !NT_SUCCESS( status ) ) {
  383. return status;
  384. }
  385. //
  386. // Get the data from the response.
  387. //
  388. VolumeName.MaximumLength =
  389. (USHORT)(MIN( MAX_VOLUME_NAME_LENGTH * sizeof( WCHAR ),
  390. Length - FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel) ) );
  391. VolumeName.Buffer = Buffer->VolumeLabel;
  392. status = ParseResponse(
  393. pIrpContext,
  394. pIrpContext->rsp,
  395. pIrpContext->ResponseLength,
  396. "N=====R",
  397. &VolumeName,
  398. MAX_VOLUME_NAME_LENGTH );
  399. //
  400. // Fill in the volume information.
  401. //
  402. Buffer->VolumeCreationTime.HighPart = 0;
  403. Buffer->VolumeCreationTime.LowPart = 0;
  404. Buffer->VolumeSerialNumber = 0;
  405. Buffer->VolumeLabelLength = VolumeName.Length;
  406. Buffer->SupportsObjects = FALSE;
  407. pIrpContext->pOriginalIrp->IoStatus.Information =
  408. FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel[0] ) +
  409. VolumeName.Length;
  410. *BytesWritten = (ULONG) pIrpContext->pOriginalIrp->IoStatus.Information;
  411. pIrpContext->pOriginalIrp->IoStatus.Status = status;
  412. //
  413. // If the volume has been unmounted and remounted then we will
  414. // fail this dir but the next one will be fine.
  415. //
  416. if (status == STATUS_UNSUCCESSFUL) {
  417. NwReopenVcbHandle( pIrpContext, Vcb);
  418. }
  419. return status;
  420. }
  421. NTSTATUS
  422. NwQueryLabelInfo (
  423. IN PIRP_CONTEXT pIrpContext,
  424. IN PVCB Vcb,
  425. IN PFILE_FS_LABEL_INFORMATION Buffer,
  426. IN ULONG Length,
  427. OUT PULONG BytesWritten
  428. )
  429. /*++
  430. Routine Description:
  431. This routine performs the query fs label information operation.
  432. Arguments:
  433. Vcb - The VCB to query.
  434. Buffer - Supplies a pointer to the buffer where the information is
  435. to be returned.
  436. Length - Supplies the length of the buffer in bytes.
  437. Return Value:
  438. NTSTATUS - The result of this query.
  439. --*/
  440. {
  441. NTSTATUS status;
  442. UNICODE_STRING VolumeName;
  443. PAGED_CODE();
  444. DebugTrace(0, Dbg, "QueryLabelInfo...\n", 0);
  445. //
  446. // Do the volume query synchronously.
  447. //
  448. status = ExchangeWithWait(
  449. pIrpContext,
  450. SynchronousResponseCallback,
  451. "Sb",
  452. NCP_DIR_FUNCTION, NCP_GET_VOLUME_STATS,
  453. Vcb->Specific.Disk.Handle );
  454. if ( !NT_SUCCESS( status ) ) {
  455. return status;
  456. }
  457. VolumeName.MaximumLength =
  458. (USHORT)(MIN( MAX_VOLUME_NAME_LENGTH * sizeof( WCHAR ),
  459. Length - FIELD_OFFSET(FILE_FS_LABEL_INFORMATION, VolumeLabel) ) );
  460. VolumeName.Buffer = Buffer->VolumeLabel;
  461. status = ParseResponse(
  462. pIrpContext,
  463. pIrpContext->rsp,
  464. pIrpContext->ResponseLength,
  465. "N=====R",
  466. &VolumeName, 12 );
  467. //
  468. // Fill in the label information.
  469. //
  470. Buffer->VolumeLabelLength = VolumeName.Length;
  471. pIrpContext->pOriginalIrp->IoStatus.Information =
  472. FIELD_OFFSET( FILE_FS_LABEL_INFORMATION, VolumeLabel[0] ) +
  473. VolumeName.Length;
  474. *BytesWritten = (ULONG) pIrpContext->pOriginalIrp->IoStatus.Information;
  475. pIrpContext->pOriginalIrp->IoStatus.Status = status;
  476. return status;
  477. }
  478. NTSTATUS
  479. NwQuerySizeInfo (
  480. IN PIRP_CONTEXT pIrpContext,
  481. IN PVCB Vcb,
  482. IN PFILE_FS_VOLUME_INFORMATION Buffer,
  483. IN ULONG Length
  484. )
  485. /*++
  486. Routine Description:
  487. This routine performs the query fs size information operation.
  488. Arguments:
  489. Vcb - The VCB to query.
  490. Buffer - Supplies a pointer to the buffer where the information is
  491. to be returned.
  492. Length - Supplies the length of the buffer in bytes.
  493. Return Value:
  494. NTSTATUS - The result of this query.
  495. --*/
  496. {
  497. NTSTATUS status;
  498. PAGED_CODE();
  499. DebugTrace(0, Dbg, "QueryFsSizeInfo...\n", 0);
  500. //
  501. // Remember where the response goes.
  502. //
  503. pIrpContext->Specific.QueryVolumeInformation.Buffer = Buffer;
  504. pIrpContext->Specific.QueryVolumeInformation.Length = Length;
  505. pIrpContext->Specific.QueryVolumeInformation.VolumeNumber = Vcb->Specific.Disk.VolumeNumber;
  506. //
  507. // Start a Get Size Information NCP
  508. //
  509. status = Exchange(
  510. pIrpContext,
  511. QueryFsSizeInfoCallback,
  512. "Sb",
  513. NCP_DIR_FUNCTION, NCP_GET_VOLUME_STATS,
  514. Vcb->Specific.Disk.Handle );
  515. return( status );
  516. }
  517. NTSTATUS
  518. QueryFsSizeInfoCallback(
  519. IN PIRP_CONTEXT pIrpContext,
  520. IN ULONG BytesAvailable,
  521. IN PUCHAR Response
  522. )
  523. /*++
  524. Routine Description:
  525. This routine receives the query volume size response and generates
  526. a Query Standard Information response.
  527. Arguments:
  528. Return Value:
  529. VOID
  530. --*/
  531. {
  532. PFILE_FS_SIZE_INFORMATION Buffer;
  533. NTSTATUS Status;
  534. DebugTrace(0, Dbg, "QueryFsSizeInfoCallback...\n", 0);
  535. if ( BytesAvailable == 0) {
  536. //
  537. // We're done with this request. Dequeue the IRP context from
  538. // SCB and complete the request.
  539. //
  540. NwDequeueIrpContext( pIrpContext, FALSE );
  541. NwCompleteRequest( pIrpContext, STATUS_REMOTE_NOT_LISTENING );
  542. //
  543. // No response from server. Status is in pIrpContext->
  544. // ResponseParameters.Error
  545. //
  546. DebugTrace( 0, Dbg, "Timeout\n", 0);
  547. return STATUS_REMOTE_NOT_LISTENING;
  548. }
  549. //
  550. // Get the data from the response.
  551. //
  552. Buffer = pIrpContext->Specific.QueryVolumeInformation.Buffer;
  553. RtlZeroMemory( Buffer, sizeof( FILE_FS_SIZE_INFORMATION ) );
  554. Status = ParseResponse(
  555. pIrpContext,
  556. Response,
  557. BytesAvailable,
  558. "Nwww",
  559. &Buffer->SectorsPerAllocationUnit,
  560. &Buffer->TotalAllocationUnits.LowPart,
  561. &Buffer->AvailableAllocationUnits.LowPart );
  562. if ( NT_SUCCESS( Status ) ) {
  563. if (Buffer->TotalAllocationUnits.LowPart == 0xffff) {
  564. //
  565. // The next callback will fill in all the appropriate size info.
  566. //
  567. Status = Exchange(
  568. pIrpContext,
  569. QueryFsSizeInfoCallback2,
  570. "Sb",
  571. NCP_DIR_FUNCTION, NCP_GET_VOLUME_INFO,
  572. pIrpContext->Specific.QueryVolumeInformation.VolumeNumber );
  573. if (Status == STATUS_PENDING) {
  574. return( STATUS_SUCCESS );
  575. }
  576. } else {
  577. //
  578. // Fill in the remaining size information.
  579. //
  580. Buffer->BytesPerSector = 512;
  581. pIrpContext->pOriginalIrp->IoStatus.Information =
  582. sizeof( FILE_FS_SIZE_INFORMATION );
  583. }
  584. }
  585. //
  586. // We're done with this request. Dequeue the IRP context from
  587. // SCB and complete the request.
  588. //
  589. NwDequeueIrpContext( pIrpContext, FALSE );
  590. NwCompleteRequest( pIrpContext, Status );
  591. return STATUS_SUCCESS;
  592. }
  593. NTSTATUS
  594. QueryFsSizeInfoCallback2(
  595. IN PIRP_CONTEXT pIrpContext,
  596. IN ULONG BytesAvailable,
  597. IN PUCHAR Response
  598. )
  599. /*++
  600. Routine Description:
  601. This routine receives the query volume size response and generates
  602. a Query Standard Information response.
  603. Arguments:
  604. Return Value:
  605. VOID
  606. --*/
  607. {
  608. PFILE_FS_SIZE_INFORMATION Buffer;
  609. NTSTATUS Status;
  610. ULONG PurgeableAllocationUnits;
  611. ULONG OriginalFreeSpace, OriginalSectorsPerAllocUnit, OriginalTotalSpace;
  612. ULONG ScaleSectorsPerUnit;
  613. DebugTrace(0, Dbg, "QueryFsSizeInfoCallback2...\n", 0);
  614. if ( BytesAvailable == 0) {
  615. //
  616. // We're done with this request. Dequeue the IRP context from
  617. // SCB and complete the request.
  618. //
  619. NwDequeueIrpContext( pIrpContext, FALSE );
  620. NwCompleteRequest( pIrpContext, STATUS_REMOTE_NOT_LISTENING );
  621. //
  622. // No response from server. Status is in pIrpContext->
  623. // ResponseParameters.Error
  624. //
  625. DebugTrace( 0, Dbg, "Timeout\n", 0);
  626. return STATUS_REMOTE_NOT_LISTENING;
  627. }
  628. //
  629. // Get the data from the response. Save off the data from
  630. // the GET_VOLUME_STATS call to compute the correct sizes.
  631. //
  632. Buffer = pIrpContext->Specific.QueryVolumeInformation.Buffer;
  633. OriginalTotalSpace = Buffer->TotalAllocationUnits.LowPart;
  634. OriginalFreeSpace = Buffer->AvailableAllocationUnits.LowPart;
  635. OriginalSectorsPerAllocUnit = Buffer->SectorsPerAllocationUnit;
  636. RtlZeroMemory( Buffer, sizeof( FILE_FS_SIZE_INFORMATION ) );
  637. Status = ParseResponse(
  638. pIrpContext,
  639. Response,
  640. BytesAvailable,
  641. "Neee_b",
  642. &Buffer->TotalAllocationUnits.LowPart,
  643. &Buffer->AvailableAllocationUnits.LowPart,
  644. &PurgeableAllocationUnits,
  645. 16,
  646. &Buffer->SectorsPerAllocationUnit);
  647. if ( NT_SUCCESS( Status ) ) {
  648. //
  649. // If the original free space was maxed out, just add the
  650. // additionally indicated units. Otherwise, return the
  651. // original free space (which is the correct limit) and
  652. // adjust the sectors per allocation units if necessary.
  653. //
  654. if ( OriginalFreeSpace != 0xffff ) {
  655. Buffer->AvailableAllocationUnits.LowPart = OriginalFreeSpace;
  656. if ( ( Buffer->SectorsPerAllocationUnit != 0 ) &&
  657. ( OriginalSectorsPerAllocUnit != 0 ) ) {
  658. //
  659. // ScaleSectorsPerUnit should always be a whole number.
  660. // There's no floating point here!!
  661. //
  662. if ( (ULONG) Buffer->SectorsPerAllocationUnit <= OriginalSectorsPerAllocUnit ) {
  663. ScaleSectorsPerUnit =
  664. OriginalSectorsPerAllocUnit / Buffer->SectorsPerAllocationUnit;
  665. Buffer->TotalAllocationUnits.LowPart /= ScaleSectorsPerUnit;
  666. } else {
  667. ScaleSectorsPerUnit =
  668. Buffer->SectorsPerAllocationUnit / OriginalSectorsPerAllocUnit;
  669. Buffer->TotalAllocationUnits.LowPart *= ScaleSectorsPerUnit;
  670. }
  671. Buffer->SectorsPerAllocationUnit = OriginalSectorsPerAllocUnit;
  672. }
  673. } else {
  674. Buffer->AvailableAllocationUnits.QuadPart += PurgeableAllocationUnits;
  675. }
  676. } else {
  677. //
  678. // If we didn't succeed the second packet, restore the original values.
  679. //
  680. Buffer->TotalAllocationUnits.LowPart = OriginalTotalSpace;
  681. Buffer->AvailableAllocationUnits.LowPart = OriginalFreeSpace;
  682. Buffer->SectorsPerAllocationUnit = OriginalSectorsPerAllocUnit;
  683. }
  684. //
  685. // Fill in the remaining size information.
  686. //
  687. Buffer->BytesPerSector = 512;
  688. pIrpContext->pOriginalIrp->IoStatus.Information =
  689. sizeof( FILE_FS_SIZE_INFORMATION );
  690. //
  691. // We're done with this request. Dequeue the IRP context from
  692. // SCB and complete the request.
  693. //
  694. NwDequeueIrpContext( pIrpContext, FALSE );
  695. NwCompleteRequest( pIrpContext, Status );
  696. return STATUS_SUCCESS;
  697. }
  698. NTSTATUS
  699. NwQueryDeviceInfo (
  700. IN PIRP_CONTEXT pIrpContext,
  701. IN PVCB Vcb,
  702. IN PFILE_FS_DEVICE_INFORMATION Buffer,
  703. IN ULONG Length
  704. )
  705. /*++
  706. Routine Description:
  707. This routine performs the query fs size information operation.
  708. Arguments:
  709. Vcb - The VCB to query.
  710. Buffer - Supplies a pointer to the buffer where the information is
  711. to be returned.
  712. Length - Supplies the length of the buffer in bytes.
  713. Return Value:
  714. NTSTATUS - The result of this query.
  715. --*/
  716. {
  717. PAGED_CODE();
  718. DebugTrace(0, Dbg, "QueryFsDeviceInfo...\n", 0);
  719. //- Multi-user code merge --
  720. // Citrix bug fix.
  721. //
  722. if (Vcb && FlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE)) {
  723. Buffer->DeviceType = FILE_DEVICE_PRINTER;
  724. } else {
  725. Buffer->DeviceType = FILE_DEVICE_DISK;
  726. }
  727. Buffer->Characteristics = FILE_REMOTE_DEVICE;
  728. return( STATUS_SUCCESS );
  729. }
  730. NTSTATUS
  731. NwFsdSetVolumeInformation (
  732. IN PDEVICE_OBJECT DeviceObject,
  733. IN PIRP Irp
  734. )
  735. /*++
  736. Routine Description:
  737. This routine implements the FSD part of the NtSetVolumeInformationFile
  738. API calls.
  739. Arguments:
  740. NwfsDeviceObject - Supplies a pointer to the device object to use.
  741. Irp - Supplies a pointer to the Irp to process.
  742. Return Value:
  743. NTSTATUS - The Fsd status for the Irp
  744. --*/
  745. {
  746. NTSTATUS status;
  747. PIRP_CONTEXT pIrpContext = NULL;
  748. BOOLEAN TopLevel;
  749. PAGED_CODE();
  750. DebugTrace(+1, Dbg, "NwFsdSetVolumeInformation\n", 0);
  751. //
  752. // Call the common query volume information routine.
  753. //
  754. FsRtlEnterFileSystem();
  755. TopLevel = NwIsIrpTopLevel( Irp );
  756. try {
  757. pIrpContext = AllocateIrpContext( Irp );
  758. status = NwCommonSetVolumeInformation( pIrpContext );
  759. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  760. if ( pIrpContext == NULL ) {
  761. //
  762. // If we couldn't allocate an irp context, just complete
  763. // irp without any fanfare.
  764. //
  765. status = STATUS_INSUFFICIENT_RESOURCES;
  766. Irp->IoStatus.Status = status;
  767. Irp->IoStatus.Information = 0;
  768. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  769. } else {
  770. //
  771. // We had some trouble trying to perform the requested
  772. // operation, so we'll abort the I/O request with
  773. // the error Status that we get back from the
  774. // execption code
  775. //
  776. status = NwProcessException( pIrpContext, GetExceptionCode() );
  777. }
  778. }
  779. if ( pIrpContext ) {
  780. if ( status != STATUS_PENDING ) {
  781. NwDequeueIrpContext( pIrpContext, FALSE );
  782. }
  783. NwCompleteRequest( pIrpContext, status );
  784. }
  785. if ( TopLevel ) {
  786. NwSetTopLevelIrp( NULL );
  787. }
  788. FsRtlExitFileSystem();
  789. //
  790. // Return to the caller.
  791. //
  792. DebugTrace(-1, Dbg, "NwFsdSetVolumeInformation -> %08lx\n", status );
  793. return status;
  794. }
  795. NTSTATUS
  796. NwCommonSetVolumeInformation (
  797. IN PIRP_CONTEXT pIrpContext
  798. )
  799. /*++
  800. Routine Description:
  801. This is the common routine for setting volume information.
  802. Arguments:
  803. IrpContext - Supplies the Irp context to process
  804. Return Value:
  805. NTSTATUS - the return status for the operation.
  806. --*/
  807. {
  808. PIRP Irp;
  809. PIO_STACK_LOCATION irpSp;
  810. NTSTATUS status;
  811. FS_INFORMATION_CLASS fsInformationClass;
  812. NODE_TYPE_CODE nodeTypeCode;
  813. PVOID fsContext, fsContext2;
  814. PICB icb = NULL;
  815. PVCB vcb = NULL;
  816. PAGED_CODE();
  817. //
  818. // Get the current stack location.
  819. //
  820. Irp = pIrpContext->pOriginalIrp;
  821. irpSp = IoGetCurrentIrpStackLocation( Irp );
  822. DebugTrace(+1, Dbg, "NwCommonSetVolumeInformation...\n", 0);
  823. DebugTrace( 0, Dbg, " Irp = %08lx\n", (ULONG_PTR)Irp);
  824. DebugTrace( 0, Dbg, " ->Length = %08lx\n", irpSp->Parameters.QueryFile.Length);
  825. DebugTrace( 0, Dbg, " ->FsInformationClass = %08lx\n", irpSp->Parameters.QueryVolume.FsInformationClass);
  826. DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer);
  827. //
  828. // Find out who are.
  829. //
  830. if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  831. &fsContext,
  832. &fsContext2 )) == NTC_UNDEFINED) {
  833. DebugTrace(0, Dbg, "Handle is closing\n", 0);
  834. NwCompleteRequest( pIrpContext, STATUS_INVALID_HANDLE );
  835. status = STATUS_INVALID_HANDLE;
  836. DebugTrace(-1, Dbg, "NwCommonSetVolumeInformation -> %08lx\n", status );
  837. return status;
  838. }
  839. //
  840. // Decide how to handle this request. A user can set information
  841. // on a VCB only.
  842. //
  843. switch (nodeTypeCode) {
  844. case NW_NTC_RCB:
  845. break;
  846. case NW_NTC_ICB:
  847. icb = (PICB)fsContext2;
  848. //
  849. // Make sure that this ICB is still active.
  850. //
  851. NwVerifyIcb( icb );
  852. vcb = icb->SuperType.Fcb->Vcb;
  853. pIrpContext->pNpScb = icb->SuperType.Fcb->Scb->pNpScb;
  854. break;
  855. default: // This is not a nodetype
  856. DebugTrace(0, Dbg, "Node type code is not incorrect\n", 0);
  857. DebugTrace(-1, Dbg, "NwCommonSetVolumeInformation -> STATUS_INVALID_PARAMETER\n", 0);
  858. return STATUS_INVALID_PARAMETER;
  859. }
  860. fsInformationClass = irpSp->Parameters.SetVolume.FsInformationClass;
  861. try {
  862. //
  863. // Decide how to handle the request.
  864. //
  865. switch (fsInformationClass) {
  866. case FileFsLabelInformation:
  867. //
  868. // We're not allowed to set the label on a Netware volume.
  869. //
  870. status = STATUS_ACCESS_DENIED;
  871. break;
  872. default:
  873. status = STATUS_INVALID_PARAMETER;
  874. DebugTrace(0, Dbg, "Unhandled set volume level %d\n", fsInformationClass );
  875. break;
  876. }
  877. //
  878. // Set the information field to the number of bytes actually
  879. // filled in and then complete the request.
  880. //
  881. // If the worker function returned status pending, it's
  882. // callback routine will fill the information field.
  883. //
  884. if ( status != STATUS_PENDING ) {
  885. Irp->IoStatus.Information = 0;
  886. }
  887. } finally {
  888. DebugTrace(-1, Dbg, "NwCommonSetVolumeInformation -> %08lx\n", status );
  889. }
  890. return status;
  891. }