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

1258 lines
30 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. VolInfo.c
  5. Abstract:
  6. This module implements the volume information routines for Fat called by
  7. the dispatch driver.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 12-Apr-1990
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The local debug trace level
  17. //
  18. #define Dbg (DEBUG_TRACE_VOLINFO)
  19. NTSTATUS
  20. FatQueryFsVolumeInfo (
  21. IN PIRP_CONTEXT IrpContext,
  22. IN PVCB Vcb,
  23. IN PFILE_FS_VOLUME_INFORMATION Buffer,
  24. IN OUT PULONG Length
  25. );
  26. NTSTATUS
  27. FatQueryFsSizeInfo (
  28. IN PIRP_CONTEXT IrpContext,
  29. IN PVCB Vcb,
  30. IN PFILE_FS_SIZE_INFORMATION Buffer,
  31. IN OUT PULONG Length
  32. );
  33. NTSTATUS
  34. FatQueryFsDeviceInfo (
  35. IN PIRP_CONTEXT IrpContext,
  36. IN PVCB Vcb,
  37. IN PFILE_FS_DEVICE_INFORMATION Buffer,
  38. IN OUT PULONG Length
  39. );
  40. NTSTATUS
  41. FatQueryFsAttributeInfo (
  42. IN PIRP_CONTEXT IrpContext,
  43. IN PVCB Vcb,
  44. IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
  45. IN OUT PULONG Length
  46. );
  47. NTSTATUS
  48. FatQueryFsFullSizeInfo (
  49. IN PIRP_CONTEXT IrpContext,
  50. IN PVCB Vcb,
  51. IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
  52. IN OUT PULONG Length
  53. );
  54. NTSTATUS
  55. FatSetFsLabelInfo (
  56. IN PIRP_CONTEXT IrpContext,
  57. IN PVCB Vcb,
  58. IN PFILE_FS_LABEL_INFORMATION Buffer
  59. );
  60. #ifdef ALLOC_PRAGMA
  61. #pragma alloc_text(PAGE, FatCommonQueryVolumeInfo)
  62. #pragma alloc_text(PAGE, FatCommonSetVolumeInfo)
  63. #pragma alloc_text(PAGE, FatFsdQueryVolumeInformation)
  64. #pragma alloc_text(PAGE, FatFsdSetVolumeInformation)
  65. #pragma alloc_text(PAGE, FatQueryFsAttributeInfo)
  66. #pragma alloc_text(PAGE, FatQueryFsDeviceInfo)
  67. #pragma alloc_text(PAGE, FatQueryFsSizeInfo)
  68. #pragma alloc_text(PAGE, FatQueryFsVolumeInfo)
  69. #pragma alloc_text(PAGE, FatQueryFsFullSizeInfo)
  70. #pragma alloc_text(PAGE, FatSetFsLabelInfo)
  71. #endif
  72. NTSTATUS
  73. FatFsdQueryVolumeInformation (
  74. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  75. IN PIRP Irp
  76. )
  77. /*++
  78. Routine Description:
  79. This routine implements the Fsd part of the NtQueryVolumeInformation API
  80. call.
  81. Arguments:
  82. VolumeDeviceObject - Supplies the volume device object where the file
  83. being queried exists.
  84. Irp - Supplies the Irp being processed.
  85. Return Value:
  86. NTSTATUS - The FSD status for the Irp.
  87. --*/
  88. {
  89. NTSTATUS Status;
  90. PIRP_CONTEXT IrpContext = NULL;
  91. BOOLEAN TopLevel;
  92. DebugTrace(+1, Dbg, "FatFsdQueryVolumeInformation\n", 0);
  93. //
  94. // Call the common query routine, with blocking allowed if synchronous
  95. //
  96. FsRtlEnterFileSystem();
  97. TopLevel = FatIsIrpTopLevel( Irp );
  98. try {
  99. IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
  100. Status = FatCommonQueryVolumeInfo( IrpContext, Irp );
  101. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  102. //
  103. // We had some trouble trying to perform the requested
  104. // operation, so we'll abort the I/O request with
  105. // the error status that we get back from the
  106. // execption code
  107. //
  108. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  109. }
  110. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  111. FsRtlExitFileSystem();
  112. //
  113. // And return to our caller
  114. //
  115. DebugTrace(-1, Dbg, "FatFsdQueryVolumeInformation -> %08lx\n", Status);
  116. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  117. return Status;
  118. }
  119. NTSTATUS
  120. FatFsdSetVolumeInformation (
  121. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  122. IN PIRP Irp
  123. )
  124. /*++
  125. Routine Description:
  126. This routine implements the FSD part of the NtSetVolumeInformation API
  127. call.
  128. Arguments:
  129. VolumeDeviceObject - Supplies the volume device object where the file
  130. being set exists.
  131. Irp - Supplies the Irp being processed.
  132. Return Value:
  133. NTSTATUS - The FSD status for the Irp.
  134. --*/
  135. {
  136. NTSTATUS Status;
  137. PIRP_CONTEXT IrpContext = NULL;
  138. BOOLEAN TopLevel;
  139. DebugTrace(+1, Dbg, "FatFsdSetVolumeInformation\n", 0);
  140. //
  141. // Call the common set routine
  142. //
  143. FsRtlEnterFileSystem();
  144. TopLevel = FatIsIrpTopLevel( Irp );
  145. try {
  146. IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
  147. Status = FatCommonSetVolumeInfo( IrpContext, Irp );
  148. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  149. //
  150. // We had some trouble trying to perform the requested
  151. // operation, so we'll abort the I/O request with
  152. // the error status that we get back from the
  153. // execption code
  154. //
  155. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  156. }
  157. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  158. FsRtlExitFileSystem();
  159. //
  160. // And return to our caller
  161. //
  162. DebugTrace(-1, Dbg, "FatFsdSetVolumeInformation -> %08lx\n", Status);
  163. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  164. return Status;
  165. }
  166. NTSTATUS
  167. FatCommonQueryVolumeInfo (
  168. IN PIRP_CONTEXT IrpContext,
  169. IN PIRP Irp
  170. )
  171. /*++
  172. Routine Description:
  173. This is the common routine for querying volume information called by both
  174. the fsd and fsp threads.
  175. Arguments:
  176. Irp - Supplies the Irp being processed
  177. Return Value:
  178. NTSTATUS - The return status for the operation
  179. --*/
  180. {
  181. NTSTATUS Status;
  182. PIO_STACK_LOCATION IrpSp;
  183. PVCB Vcb;
  184. PFCB Fcb;
  185. PCCB Ccb;
  186. ULONG Length;
  187. FS_INFORMATION_CLASS FsInformationClass;
  188. PVOID Buffer;
  189. BOOLEAN WeAcquiredVcb = FALSE;
  190. //
  191. // Get the current stack location
  192. //
  193. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  194. DebugTrace(+1, Dbg, "FatCommonQueryVolumeInfo...\n", 0);
  195. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  196. DebugTrace( 0, Dbg, "->Length = %08lx\n", IrpSp->Parameters.QueryVolume.Length);
  197. DebugTrace( 0, Dbg, "->FsInformationClass = %08lx\n", IrpSp->Parameters.QueryVolume.FsInformationClass);
  198. DebugTrace( 0, Dbg, "->Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
  199. //
  200. // Reference our input parameters to make things easier
  201. //
  202. Length = IrpSp->Parameters.QueryVolume.Length;
  203. FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass;
  204. Buffer = Irp->AssociatedIrp.SystemBuffer;
  205. //
  206. // Decode the file object to get the Vcb
  207. //
  208. (VOID) FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
  209. ASSERT( Vcb != NULL );
  210. try {
  211. //
  212. // Make sure the vcb is in a usable condition. This will raise
  213. // and error condition if the volume is unusable
  214. //
  215. // Also verify the Root Dcb since we need info from there.
  216. //
  217. FatVerifyFcb( IrpContext, Vcb->RootDcb );
  218. //
  219. // Based on the information class we'll do different actions. Each
  220. // of the procedures that we're calling fills up the output buffer
  221. // if possible and returns true if it successfully filled the buffer
  222. // and false if it couldn't wait for any I/O to complete.
  223. //
  224. switch (FsInformationClass) {
  225. case FileFsVolumeInformation:
  226. //
  227. // This is the only routine we need the Vcb shared because of
  228. // copying the volume label. All other routines copy fields that
  229. // cannot change or are just manifest constants.
  230. //
  231. if (!FatAcquireSharedVcb( IrpContext, Vcb )) {
  232. DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
  233. Status = FatFsdPostRequest( IrpContext, Irp );
  234. IrpContext = NULL;
  235. Irp = NULL;
  236. } else {
  237. WeAcquiredVcb = TRUE;
  238. Status = FatQueryFsVolumeInfo( IrpContext, Vcb, Buffer, &Length );
  239. }
  240. break;
  241. case FileFsSizeInformation:
  242. Status = FatQueryFsSizeInfo( IrpContext, Vcb, Buffer, &Length );
  243. break;
  244. case FileFsDeviceInformation:
  245. Status = FatQueryFsDeviceInfo( IrpContext, Vcb, Buffer, &Length );
  246. break;
  247. case FileFsAttributeInformation:
  248. Status = FatQueryFsAttributeInfo( IrpContext, Vcb, Buffer, &Length );
  249. break;
  250. case FileFsFullSizeInformation:
  251. Status = FatQueryFsFullSizeInfo( IrpContext, Vcb, Buffer, &Length );
  252. break;
  253. default:
  254. Status = STATUS_INVALID_PARAMETER;
  255. break;
  256. }
  257. //
  258. // Set the information field to the number of bytes actually filled in.
  259. //
  260. if (Irp != NULL) {
  261. Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
  262. }
  263. } finally {
  264. DebugUnwind( FatCommonQueryVolumeInfo );
  265. if ( WeAcquiredVcb ) { FatReleaseVcb( IrpContext, Vcb ); }
  266. if (!AbnormalTermination()) {
  267. FatCompleteRequest( IrpContext, Irp, Status );
  268. }
  269. DebugTrace(-1, Dbg, "FatCommonQueryVolumeInfo -> %08lx\n", Status);
  270. }
  271. return Status;
  272. }
  273. NTSTATUS
  274. FatCommonSetVolumeInfo (
  275. IN PIRP_CONTEXT IrpContext,
  276. IN PIRP Irp
  277. )
  278. /*++
  279. Routine Description:
  280. This is the common routine for setting Volume Information called by both
  281. the fsd and fsp threads.
  282. Arguments:
  283. Irp - Supplies the Irp being processed
  284. Return Value:
  285. NTSTATUS - The return status for the operation
  286. --*/
  287. {
  288. NTSTATUS Status;
  289. PIO_STACK_LOCATION IrpSp;
  290. PVCB Vcb;
  291. PFCB Fcb;
  292. PCCB Ccb;
  293. TYPE_OF_OPEN TypeOfOpen;
  294. ULONG Length;
  295. FS_INFORMATION_CLASS FsInformationClass;
  296. PVOID Buffer;
  297. //
  298. // Get the current stack location
  299. //
  300. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  301. DebugTrace(+1, Dbg, "FatCommonSetVolumeInfo...\n", 0);
  302. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  303. DebugTrace( 0, Dbg, "->Length = %08lx\n", IrpSp->Parameters.SetVolume.Length);
  304. DebugTrace( 0, Dbg, "->FsInformationClass = %08lx\n", IrpSp->Parameters.SetVolume.FsInformationClass);
  305. DebugTrace( 0, Dbg, "->Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
  306. //
  307. // Reference our input parameters to make things easier
  308. //
  309. Length = IrpSp->Parameters.SetVolume.Length;
  310. FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
  311. Buffer = Irp->AssociatedIrp.SystemBuffer;
  312. //
  313. // Decode the file object to get the Vcb
  314. //
  315. TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );
  316. if (TypeOfOpen != UserVolumeOpen) {
  317. FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  318. DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> STATUS_ACCESS_DENIED\n", 0);
  319. return STATUS_ACCESS_DENIED;
  320. }
  321. //
  322. // Acquire exclusive access to the Vcb and enqueue the Irp if we didn't
  323. // get access
  324. //
  325. if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
  326. DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
  327. Status = FatFsdPostRequest( IrpContext, Irp );
  328. DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> %08lx\n", Status );
  329. return Status;
  330. }
  331. try {
  332. //
  333. // Make sure the vcb is in a usable condition. This will raise
  334. // and error condition if the volume is unusable
  335. //
  336. // Also verify the Root Dcb since we need info from there.
  337. //
  338. FatVerifyFcb( IrpContext, Vcb->RootDcb );
  339. //
  340. // Based on the information class we'll do different actions. Each
  341. // of the procedures that we're calling performs the action if
  342. // possible and returns true if it successful and false if it couldn't
  343. // wait for any I/O to complete.
  344. //
  345. switch (FsInformationClass) {
  346. case FileFsLabelInformation:
  347. Status = FatSetFsLabelInfo( IrpContext, Vcb, Buffer );
  348. break;
  349. default:
  350. Status = STATUS_INVALID_PARAMETER;
  351. break;
  352. }
  353. FatUnpinRepinnedBcbs( IrpContext );
  354. } finally {
  355. DebugUnwind( FatCommonSetVolumeInfo );
  356. FatReleaseVcb( IrpContext, Vcb );
  357. if (!AbnormalTermination()) {
  358. FatCompleteRequest( IrpContext, Irp, Status );
  359. }
  360. DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> %08lx\n", Status);
  361. }
  362. return Status;
  363. }
  364. //
  365. // Internal support routine
  366. //
  367. NTSTATUS
  368. FatQueryFsVolumeInfo (
  369. IN PIRP_CONTEXT IrpContext,
  370. IN PVCB Vcb,
  371. IN PFILE_FS_VOLUME_INFORMATION Buffer,
  372. IN OUT PULONG Length
  373. )
  374. /*++
  375. Routine Description:
  376. This routine implements the query volume info call
  377. Arguments:
  378. Vcb - Supplies the Vcb being queried
  379. Buffer - Supplies a pointer to the output buffer where the information
  380. is to be returned
  381. Length - Supplies the length of the buffer in byte. This variable
  382. upon return recieves the remaining bytes free in the buffer
  383. Return Value:
  384. NTSTATUS - Returns the status for the query
  385. --*/
  386. {
  387. ULONG BytesToCopy;
  388. NTSTATUS Status;
  389. DebugTrace(0, Dbg, "FatQueryFsVolumeInfo...\n", 0);
  390. //
  391. // Zero out the buffer, then extract and fill up the non zero fields.
  392. //
  393. RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION) );
  394. Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
  395. Buffer->SupportsObjects = FALSE;
  396. *Length -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);
  397. //
  398. // Check if the buffer we're given is long enough
  399. //
  400. if ( *Length >= (ULONG)Vcb->Vpb->VolumeLabelLength ) {
  401. BytesToCopy = Vcb->Vpb->VolumeLabelLength;
  402. Status = STATUS_SUCCESS;
  403. } else {
  404. BytesToCopy = *Length;
  405. Status = STATUS_BUFFER_OVERFLOW;
  406. }
  407. //
  408. // Copy over what we can of the volume label, and adjust *Length
  409. //
  410. Buffer->VolumeLabelLength = Vcb->Vpb->VolumeLabelLength;
  411. RtlCopyMemory( &Buffer->VolumeLabel[0],
  412. &Vcb->Vpb->VolumeLabel[0],
  413. BytesToCopy );
  414. *Length -= BytesToCopy;
  415. //
  416. // Set our status and return to our caller
  417. //
  418. UNREFERENCED_PARAMETER( IrpContext );
  419. return Status;
  420. }
  421. //
  422. // Internal support routine
  423. //
  424. NTSTATUS
  425. FatQueryFsSizeInfo (
  426. IN PIRP_CONTEXT IrpContext,
  427. IN PVCB Vcb,
  428. IN PFILE_FS_SIZE_INFORMATION Buffer,
  429. IN OUT PULONG Length
  430. )
  431. /*++
  432. Routine Description:
  433. This routine implements the query volume size call
  434. Arguments:
  435. Vcb - Supplies the Vcb being queried
  436. Buffer - Supplies a pointer to the output buffer where the information
  437. is to be returned
  438. Length - Supplies the length of the buffer in byte. This variable
  439. upon return recieves the remaining bytes free in the buffer
  440. Return Value:
  441. Status - Returns the status for the query
  442. --*/
  443. {
  444. DebugTrace(0, Dbg, "FatQueryFsSizeInfo...\n", 0);
  445. RtlZeroMemory( Buffer, sizeof(FILE_FS_SIZE_INFORMATION) );
  446. //
  447. // Set the output buffer.
  448. //
  449. Buffer->TotalAllocationUnits.LowPart =
  450. Vcb->AllocationSupport.NumberOfClusters;
  451. Buffer->AvailableAllocationUnits.LowPart =
  452. Vcb->AllocationSupport.NumberOfFreeClusters;
  453. Buffer->SectorsPerAllocationUnit = Vcb->Bpb.SectorsPerCluster;
  454. Buffer->BytesPerSector = Vcb->Bpb.BytesPerSector;
  455. //
  456. // Adjust the length variable
  457. //
  458. *Length -= sizeof(FILE_FS_SIZE_INFORMATION);
  459. //
  460. // And return success to our caller
  461. //
  462. UNREFERENCED_PARAMETER( IrpContext );
  463. return STATUS_SUCCESS;
  464. }
  465. //
  466. // Internal support routine
  467. //
  468. NTSTATUS
  469. FatQueryFsDeviceInfo (
  470. IN PIRP_CONTEXT IrpContext,
  471. IN PVCB Vcb,
  472. IN PFILE_FS_DEVICE_INFORMATION Buffer,
  473. IN OUT PULONG Length
  474. )
  475. /*++
  476. Routine Description:
  477. This routine implements the query volume device call
  478. Arguments:
  479. Vcb - Supplies the Vcb being queried
  480. Buffer - Supplies a pointer to the output buffer where the information
  481. is to be returned
  482. Length - Supplies the length of the buffer in byte. This variable
  483. upon return recieves the remaining bytes free in the buffer
  484. Return Value:
  485. Status - Returns the status for the query
  486. --*/
  487. {
  488. DebugTrace(0, Dbg, "FatQueryFsDeviceInfo...\n", 0);
  489. RtlZeroMemory( Buffer, sizeof(FILE_FS_DEVICE_INFORMATION) );
  490. //
  491. // Set the output buffer
  492. //
  493. Buffer->DeviceType = FILE_DEVICE_DISK;
  494. Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
  495. //
  496. // Adjust the length variable
  497. //
  498. *Length -= sizeof(FILE_FS_DEVICE_INFORMATION);
  499. //
  500. // And return success to our caller
  501. //
  502. UNREFERENCED_PARAMETER( IrpContext );
  503. return STATUS_SUCCESS;
  504. }
  505. //
  506. // Internal support routine
  507. //
  508. NTSTATUS
  509. FatQueryFsAttributeInfo (
  510. IN PIRP_CONTEXT IrpContext,
  511. IN PVCB Vcb,
  512. IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
  513. IN OUT PULONG Length
  514. )
  515. /*++
  516. Routine Description:
  517. This routine implements the query volume attribute call
  518. Arguments:
  519. Vcb - Supplies the Vcb being queried
  520. Buffer - Supplies a pointer to the output buffer where the information
  521. is to be returned
  522. Length - Supplies the length of the buffer in byte. This variable
  523. upon return recieves the remaining bytes free in the buffer
  524. Return Value:
  525. Status - Returns the status for the query
  526. --*/
  527. {
  528. ULONG BytesToCopy;
  529. NTSTATUS Status;
  530. DebugTrace(0, Dbg, "FatQueryFsAttributeInfo...\n", 0);
  531. //
  532. // Set the output buffer
  533. //
  534. Buffer->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES |
  535. FILE_UNICODE_ON_DISK;
  536. if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED )) {
  537. SetFlag( Buffer->FileSystemAttributes, FILE_READ_ONLY_VOLUME );
  538. }
  539. Buffer->MaximumComponentNameLength = FatData.ChicagoMode ? 255 : 12;
  540. if (FatIsFat32(Vcb)) {
  541. //
  542. // Determine how much of the file system name will fit.
  543. //
  544. if ( (*Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
  545. FileSystemName[0] )) >= 10 ) {
  546. BytesToCopy = 10;
  547. *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
  548. FileSystemName[0] ) + 10;
  549. Status = STATUS_SUCCESS;
  550. } else {
  551. BytesToCopy = *Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
  552. FileSystemName[0]);
  553. *Length = 0;
  554. Status = STATUS_BUFFER_OVERFLOW;
  555. }
  556. RtlCopyMemory( &Buffer->FileSystemName[0], L"FAT32", BytesToCopy );
  557. } else {
  558. //
  559. // Determine how much of the file system name will fit.
  560. //
  561. if ( (*Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
  562. FileSystemName[0] )) >= 6 ) {
  563. BytesToCopy = 6;
  564. *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
  565. FileSystemName[0] ) + 6;
  566. Status = STATUS_SUCCESS;
  567. } else {
  568. BytesToCopy = *Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
  569. FileSystemName[0]);
  570. *Length = 0;
  571. Status = STATUS_BUFFER_OVERFLOW;
  572. }
  573. RtlCopyMemory( &Buffer->FileSystemName[0], L"FAT", BytesToCopy );
  574. }
  575. Buffer->FileSystemNameLength = BytesToCopy;
  576. //
  577. // And return success to our caller
  578. //
  579. UNREFERENCED_PARAMETER( IrpContext );
  580. UNREFERENCED_PARAMETER( Vcb );
  581. return Status;
  582. }
  583. //
  584. // Internal support routine
  585. //
  586. NTSTATUS
  587. FatQueryFsFullSizeInfo (
  588. IN PIRP_CONTEXT IrpContext,
  589. IN PVCB Vcb,
  590. IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
  591. IN OUT PULONG Length
  592. )
  593. /*++
  594. Routine Description:
  595. This routine implements the query volume full size call
  596. Arguments:
  597. Vcb - Supplies the Vcb being queried
  598. Buffer - Supplies a pointer to the output buffer where the information
  599. is to be returned
  600. Length - Supplies the length of the buffer in byte. This variable
  601. upon return recieves the remaining bytes free in the buffer
  602. Return Value:
  603. Status - Returns the status for the query
  604. --*/
  605. {
  606. DebugTrace(0, Dbg, "FatQueryFsSizeInfo...\n", 0);
  607. RtlZeroMemory( Buffer, sizeof(FILE_FS_FULL_SIZE_INFORMATION) );
  608. Buffer->TotalAllocationUnits.LowPart =
  609. Vcb->AllocationSupport.NumberOfClusters;
  610. Buffer->CallerAvailableAllocationUnits.LowPart =
  611. Vcb->AllocationSupport.NumberOfFreeClusters;
  612. Buffer->ActualAvailableAllocationUnits.LowPart =
  613. Buffer->CallerAvailableAllocationUnits.LowPart;
  614. Buffer->SectorsPerAllocationUnit = Vcb->Bpb.SectorsPerCluster;
  615. Buffer->BytesPerSector = Vcb->Bpb.BytesPerSector;
  616. //
  617. // Adjust the length variable
  618. //
  619. *Length -= sizeof(FILE_FS_FULL_SIZE_INFORMATION);
  620. //
  621. // And return success to our caller
  622. //
  623. UNREFERENCED_PARAMETER( IrpContext );
  624. return STATUS_SUCCESS;
  625. }
  626. //
  627. // Internal support routine
  628. //
  629. NTSTATUS
  630. FatSetFsLabelInfo (
  631. IN PIRP_CONTEXT IrpContext,
  632. IN PVCB Vcb,
  633. IN PFILE_FS_LABEL_INFORMATION Buffer
  634. )
  635. /*++
  636. Routine Description:
  637. This routine implements the set volume label call
  638. Arguments:
  639. Vcb - Supplies the Vcb being queried
  640. Buffer - Supplies the input where the information is stored.
  641. Return Value:
  642. NTSTATUS - Returns the status for the operation
  643. --*/
  644. {
  645. NTSTATUS Status;
  646. PDIRENT Dirent;
  647. PBCB DirentBcb = NULL;
  648. ULONG ByteOffset;
  649. WCHAR TmpBuffer[11];
  650. UCHAR OemBuffer[11];
  651. OEM_STRING OemLabel;
  652. UNICODE_STRING UnicodeString;
  653. UNICODE_STRING UpcasedLabel;
  654. DebugTrace(+1, Dbg, "FatSetFsLabelInfo...\n", 0);
  655. //
  656. // Setup our local variable
  657. //
  658. UnicodeString.Length = (USHORT)Buffer->VolumeLabelLength;
  659. UnicodeString.MaximumLength = UnicodeString.Length;
  660. UnicodeString.Buffer = (PWSTR) &Buffer->VolumeLabel[0];
  661. //
  662. // Make sure the name can fit into the stack buffer
  663. //
  664. if ( UnicodeString.Length > 11*sizeof(WCHAR) ) {
  665. return STATUS_INVALID_VOLUME_LABEL;
  666. }
  667. //
  668. // Upcase the name and convert it to the Oem code page.
  669. //
  670. OemLabel.Buffer = &OemBuffer[0];
  671. OemLabel.Length = 0;
  672. OemLabel.MaximumLength = 11;
  673. Status = RtlUpcaseUnicodeStringToCountedOemString( &OemLabel,
  674. &UnicodeString,
  675. FALSE );
  676. //
  677. // Volume label that fits in 11 unicode character length limit
  678. // is not necessary within 11 characters in OEM character set.
  679. //
  680. if (!NT_SUCCESS( Status )) {
  681. DebugTrace(-1, Dbg, "FatSetFsLabelInfo: Label must be too long. %08lx\n", Status );
  682. return STATUS_INVALID_VOLUME_LABEL;
  683. }
  684. //
  685. // Strip spaces off of the label.
  686. //
  687. if (OemLabel.Length > 0) {
  688. USHORT i;
  689. USHORT LastSpaceIndex = MAXUSHORT;
  690. //
  691. // Check the label for illegal characters
  692. //
  693. for ( i = 0; i < (ULONG)OemLabel.Length; i += 1 ) {
  694. if ( FsRtlIsLeadDbcsCharacter( OemLabel.Buffer[i] ) ) {
  695. LastSpaceIndex = MAXUSHORT;
  696. i += 1;
  697. continue;
  698. }
  699. if (!FsRtlIsAnsiCharacterLegalFat(OemLabel.Buffer[i], FALSE) ||
  700. (OemLabel.Buffer[i] == '.')) {
  701. return STATUS_INVALID_VOLUME_LABEL;
  702. }
  703. //
  704. // Watch for the last run of spaces, so we can strip them.
  705. //
  706. if (OemLabel.Buffer[i] == ' ' &&
  707. LastSpaceIndex == MAXUSHORT) {
  708. LastSpaceIndex = i;
  709. } else {
  710. LastSpaceIndex = MAXUSHORT;
  711. }
  712. }
  713. if (LastSpaceIndex != MAXUSHORT) {
  714. OemLabel.Length = LastSpaceIndex;
  715. }
  716. }
  717. //
  718. // Get the Unicode upcased string to store in the VPB.
  719. //
  720. UpcasedLabel.Length = UnicodeString.Length;
  721. UpcasedLabel.MaximumLength = 11*sizeof(WCHAR);
  722. UpcasedLabel.Buffer = &TmpBuffer[0];
  723. Status = RtlOemStringToCountedUnicodeString( &UpcasedLabel,
  724. &OemLabel,
  725. FALSE );
  726. if (!NT_SUCCESS( Status )) {
  727. DebugTrace(-1, Dbg, "FatSetFsLabelInfo: Label must be too long. %08lx\n", Status );
  728. return STATUS_INVALID_VOLUME_LABEL;
  729. }
  730. DirentBcb = NULL;
  731. //
  732. // Make this look like a write through to disk. This is important to
  733. // avoid a unpleasant window where it looks like we have the wrong volume.
  734. //
  735. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
  736. try {
  737. //
  738. // Are we setting or removing the label? Note that shaving spaces could
  739. // make this different than wondering if the input buffer is non-zero length.
  740. //
  741. if (OemLabel.Length > 0) {
  742. //
  743. // Locate the volume label if there already is one
  744. //
  745. FatLocateVolumeLabel( IrpContext,
  746. Vcb,
  747. &Dirent,
  748. &DirentBcb,
  749. &ByteOffset );
  750. //
  751. // Check that we really got one, if not then we need to create
  752. // a new one. The procedure we call will raise an appropriate
  753. // status if we are not able to allocate a new dirent
  754. //
  755. if (Dirent == NULL) {
  756. ByteOffset = FatCreateNewDirent( IrpContext,
  757. Vcb->RootDcb,
  758. 1 );
  759. FatPrepareWriteDirectoryFile( IrpContext,
  760. Vcb->RootDcb,
  761. ByteOffset,
  762. sizeof(DIRENT),
  763. &DirentBcb,
  764. &Dirent,
  765. FALSE,
  766. TRUE,
  767. &Status );
  768. ASSERT( NT_SUCCESS( Status ));
  769. } else {
  770. //
  771. // Just mark this guy dirty now.
  772. //
  773. FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE );
  774. }
  775. //
  776. // Now reconstruct the volume label dirent.
  777. //
  778. FatConstructLabelDirent( IrpContext,
  779. Dirent,
  780. &OemLabel );
  781. //
  782. // Unpin the Bcb here so that we will get any IO errors
  783. // here before changing the VPB label.
  784. //
  785. FatUnpinBcb( IrpContext, DirentBcb );
  786. FatUnpinRepinnedBcbs( IrpContext );
  787. //
  788. // Now set the upcased label in the VPB
  789. //
  790. RtlCopyMemory( &Vcb->Vpb->VolumeLabel[0],
  791. &UpcasedLabel.Buffer[0],
  792. UpcasedLabel.Length );
  793. Vcb->Vpb->VolumeLabelLength = UpcasedLabel.Length;
  794. } else {
  795. //
  796. // Otherwise we're trying to delete the label
  797. // Locate the current volume label if there already is one
  798. //
  799. FatLocateVolumeLabel( IrpContext,
  800. Vcb,
  801. &Dirent,
  802. &DirentBcb,
  803. &ByteOffset );
  804. //
  805. // Check that we really got one
  806. //
  807. if (Dirent == NULL) {
  808. try_return( Status = STATUS_SUCCESS );
  809. }
  810. //
  811. // Now delete the current label.
  812. //
  813. Dirent->FileName[0] = FAT_DIRENT_DELETED;
  814. ASSERT( (Vcb->RootDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) ||
  815. RtlAreBitsSet( &Vcb->RootDcb->Specific.Dcb.FreeDirentBitmap,
  816. ByteOffset / sizeof(DIRENT),
  817. 1 ) );
  818. RtlClearBits( &Vcb->RootDcb->Specific.Dcb.FreeDirentBitmap,
  819. ByteOffset / sizeof(DIRENT),
  820. 1 );
  821. FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE );
  822. //
  823. // Unpin the Bcb here so that we will get any IO errors
  824. // here before changing the VPB label.
  825. //
  826. FatUnpinBcb( IrpContext, DirentBcb );
  827. FatUnpinRepinnedBcbs( IrpContext );
  828. //
  829. // Now set the label in the VPB
  830. //
  831. Vcb->Vpb->VolumeLabelLength = 0;
  832. }
  833. Status = STATUS_SUCCESS;
  834. try_exit: NOTHING;
  835. } finally {
  836. DebugUnwind( FatSetFsALabelInfo );
  837. FatUnpinBcb( IrpContext, DirentBcb );
  838. DebugTrace(-1, Dbg, "FatSetFsALabelInfo -> STATUS_SUCCESS\n", 0);
  839. }
  840. return Status;
  841. }