1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*++
7 
8 Module Name:
9 
10     VolInfo.cpp
11 
12 Abstract:
13 
14     This module implements the volume information routines for UDF called by
15     the dispatch driver.
16 
17 --*/
18 
19 #include            "udffs.h"
20 
21 // define the file specific bug-check id
22 #define         UDF_BUG_CHECK_ID                UDF_FILE_VOL_INFORMATION
23 
24 //  Local support routines
25 NTSTATUS
26 UDFQueryFsVolumeInfo (
27     IN PtrUDFIrpContext PtrIrpContext,
28     IN PVCB Vcb,
29     IN PFILE_FS_VOLUME_INFORMATION Buffer,
30     IN OUT PULONG Length
31     );
32 
33 NTSTATUS
34 UDFQueryFsSizeInfo (
35     IN PtrUDFIrpContext PtrIrpContext,
36     IN PVCB Vcb,
37     IN PFILE_FS_SIZE_INFORMATION Buffer,
38     IN OUT PULONG Length
39     );
40 
41 NTSTATUS
42 UDFQueryFsFullSizeInfo (
43     IN PtrUDFIrpContext PtrIrpContext,
44     IN PVCB Vcb,
45     IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
46     IN OUT PULONG Length
47     );
48 
49 NTSTATUS
50 UDFQueryFsDeviceInfo (
51     IN PtrUDFIrpContext PtrIrpContext,
52     IN PVCB Vcb,
53     IN PFILE_FS_DEVICE_INFORMATION Buffer,
54     IN OUT PULONG Length
55     );
56 
57 NTSTATUS
58 UDFQueryFsAttributeInfo (
59     IN PtrUDFIrpContext PtrIrpContext,
60     IN PVCB Vcb,
61     IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
62     IN OUT PULONG Length
63     );
64 
65 NTSTATUS
66 UDFSetLabelInfo (
67     IN PtrUDFIrpContext PtrIrpContext,
68     IN PVCB Vcb,
69     IN PFILE_FS_LABEL_INFORMATION Buffer,
70     IN OUT PULONG Length);
71 
72 /*
73     This is the routine for querying volume information
74 
75 Arguments:
76 
77     Irp - Supplies the Irp being processed
78 
79 Return Value:
80 
81     NTSTATUS - The return status for the operation
82 
83  */
84 NTSTATUS
85 NTAPI
86 UDFQueryVolInfo(
87     PDEVICE_OBJECT      DeviceObject,       // the logical volume device object
88     PIRP                Irp                 // I/O Request Packet
89     )
90 {
91     NTSTATUS            RC = STATUS_SUCCESS;
92     PtrUDFIrpContext    PtrIrpContext = NULL;
93     BOOLEAN             AreWeTopLevel = FALSE;
94 
95     UDFPrint(("UDFQueryVolInfo: \n"));
96 
97     FsRtlEnterFileSystem();
98     ASSERT(DeviceObject);
99     ASSERT(Irp);
100 
101     // set the top level context
102     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
103     ASSERT(!UDFIsFSDevObj(DeviceObject));
104 
105     _SEH2_TRY {
106 
107         // get an IRP context structure and issue the request
108         PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
109         if(PtrIrpContext) {
110             RC = UDFCommonQueryVolInfo(PtrIrpContext, Irp);
111         } else {
112             RC = STATUS_INSUFFICIENT_RESOURCES;
113             Irp->IoStatus.Status = RC;
114             Irp->IoStatus.Information = 0;
115             // complete the IRP
116             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
117         }
118 
119     } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
120 
121         RC = UDFExceptionHandler(PtrIrpContext, Irp);
122 
123         UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
124     } _SEH2_END;
125 
126     if (AreWeTopLevel) {
127         IoSetTopLevelIrp(NULL);
128     }
129 
130     FsRtlExitFileSystem();
131 
132     return(RC);
133 } // end UDFQueryVolInfo()
134 
135 /*
136     This is the common routine for querying volume information called by both
137     the fsd and fsp threads.
138 
139 Arguments:
140 
141     Irp - Supplies the Irp being processed
142 
143 Return Value:
144 
145     NTSTATUS - The return status for the operation
146 
147  */
148 NTSTATUS
149 UDFCommonQueryVolInfo(
150     PtrUDFIrpContext PtrIrpContext,
151     PIRP             Irp
152     )
153 {
154     NTSTATUS RC = STATUS_INVALID_PARAMETER;
155     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
156     ULONG Length;
157     BOOLEAN CanWait = FALSE;
158     PVCB Vcb;
159     BOOLEAN PostRequest = FALSE;
160     BOOLEAN AcquiredVCB = FALSE;
161     PFILE_OBJECT            FileObject = NULL;
162 //    PtrUDFFCB               Fcb = NULL;
163     PtrUDFCCB               Ccb = NULL;
164 
165     _SEH2_TRY {
166 
167         UDFPrint(("UDFCommonQueryVolInfo: \n"));
168 
169         ASSERT(PtrIrpContext);
170         ASSERT(Irp);
171 
172         PAGED_CODE();
173 
174         FileObject = IrpSp->FileObject;
175         ASSERT(FileObject);
176 
177         // Get the FCB and CCB pointers.
178         Ccb = (PtrUDFCCB)(FileObject->FsContext2);
179         ASSERT(Ccb);
180 
181         Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension);
182         ASSERT(Vcb);
183         //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
184         //  Reference our input parameters to make things easier
185         Length = IrpSp->Parameters.QueryVolume.Length;
186         //  Acquire the Vcb for this volume.
187         CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
188 #ifdef UDF_ENABLE_SECURITY
189         RC = IoCheckFunctionAccess(
190             Ccb->PreviouslyGrantedAccess,
191             PtrIrpContext->MajorFunction,
192             PtrIrpContext->MinorFunction,
193             0,
194             NULL,
195             &(IrpSp->Parameters.QueryVolume.FsInformationClass));
196         if(!NT_SUCCESS(RC)) {
197             try_return(RC);
198         }
199 #endif //UDF_ENABLE_SECURITY
200 
201         RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, Length);
202 
203         switch (IrpSp->Parameters.QueryVolume.FsInformationClass) {
204 
205         case FileFsVolumeInformation:
206 
207             //  This is the only routine we need the Vcb shared because of
208             //  copying the volume label.  All other routines copy fields that
209             //  cannot change or are just manifest constants.
210             UDFFlushTryBreak(Vcb);
211             if (!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) {
212                 PostRequest = TRUE;
213                 try_return (RC = STATUS_PENDING);
214             }
215             AcquiredVCB = TRUE;
216 
217             RC = UDFQueryFsVolumeInfo( PtrIrpContext, Vcb, (PFILE_FS_VOLUME_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length );
218             break;
219 
220         case FileFsSizeInformation:
221 
222             RC = UDFQueryFsSizeInfo( PtrIrpContext, Vcb, (PFILE_FS_SIZE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length );
223             break;
224 
225         case FileFsDeviceInformation:
226 
227             RC = UDFQueryFsDeviceInfo( PtrIrpContext, Vcb, (PFILE_FS_DEVICE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length );
228             break;
229 
230         case FileFsAttributeInformation:
231 
232             RC = UDFQueryFsAttributeInfo( PtrIrpContext, Vcb, (PFILE_FS_ATTRIBUTE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length );
233             break;
234 
235         case FileFsFullSizeInformation:
236 
237             RC = UDFQueryFsFullSizeInfo( PtrIrpContext, Vcb, (PFILE_FS_FULL_SIZE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length );
238             break;
239 
240         default:
241 
242             RC = STATUS_INVALID_DEVICE_REQUEST;
243             Irp->IoStatus.Information = 0;
244             break;
245 
246         }
247 
248         //  Set the information field to the number of bytes actually filled in
249         Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
250 
251 try_exit:   NOTHING;
252 
253     } _SEH2_FINALLY {
254 
255         if (AcquiredVCB) {
256             UDFReleaseResource(&(Vcb->VCBResource));
257             AcquiredVCB = FALSE;
258         }
259 
260         // Post IRP if required
261         if (PostRequest) {
262 
263             // Since, the I/O Manager gave us a system buffer, we do not
264             // need to "lock" anything.
265 
266             // Perform the post operation which will mark the IRP pending
267             // and will return STATUS_PENDING back to us
268             RC = UDFPostRequest(PtrIrpContext, Irp);
269 
270         } else
271         if(!_SEH2_AbnormalTermination()) {
272 
273             Irp->IoStatus.Status = RC;
274             // Free up the Irp Context
275             UDFReleaseIrpContext(PtrIrpContext);
276             // complete the IRP
277             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
278         } // can we complete the IRP ?
279 
280     } _SEH2_END;
281 
282     return RC;
283 } // end UDFCommonQueryVolInfo()
284 
285 
286 //  Local support routine
287 
288 /*
289     This routine implements the query volume info call
290 
291 Arguments:
292 
293     Vcb    - Vcb for this volume.
294     Buffer - Supplies a pointer to the output buffer where the information
295              is to be returned
296     Length - Supplies the length of the buffer in byte.  This variable
297              upon return recieves the remaining bytes free in the buffer
298  */
299 NTSTATUS
300 UDFQueryFsVolumeInfo(
301     IN PtrUDFIrpContext PtrIrpContext,
302     IN PVCB Vcb,
303     IN PFILE_FS_VOLUME_INFORMATION Buffer,
304     IN OUT PULONG Length
305     )
306 {
307     ULONG BytesToCopy;
308     NTSTATUS Status;
309 
310     PAGED_CODE();
311 
312     UDFPrint(("  UDFQueryFsVolumeInfo: \n"));
313     //  Fill in the data from the Vcb.
314     Buffer->VolumeCreationTime.QuadPart = Vcb->VolCreationTime;
315     Buffer->VolumeSerialNumber = Vcb->PhSerialNumber;
316     UDFPrint(("  SN %x\n", Vcb->PhSerialNumber));
317 
318     Buffer->SupportsObjects = FALSE;
319 
320     *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel[0] );
321 
322     //  Check if the buffer we're given is long enough
323     if (*Length >= (ULONG) Vcb->VolIdent.Length) {
324         BytesToCopy = Vcb->VolIdent.Length;
325         Status = STATUS_SUCCESS;
326     } else {
327         BytesToCopy = *Length;
328         Status = STATUS_BUFFER_OVERFLOW;
329     }
330     //  Copy over what we can of the volume label, and adjust *Length
331     Buffer->VolumeLabelLength = BytesToCopy;
332 
333     if (BytesToCopy)
334         RtlCopyMemory( &(Buffer->VolumeLabel[0]), Vcb->VolIdent.Buffer, BytesToCopy );
335     *Length -= BytesToCopy;
336 
337     return Status;
338 } // end UDFQueryFsVolumeInfo()
339 
340 /*
341     This routine implements the query volume size call.
342 
343 Arguments:
344 
345     Vcb    - Vcb for this volume.
346     Buffer - Supplies a pointer to the output buffer where the information
347              is to be returned
348     Length - Supplies the length of the buffer in byte.  This variable
349              upon return recieves the remaining bytes free in the buffer
350  */
351 NTSTATUS
352 UDFQueryFsSizeInfo(
353     IN PtrUDFIrpContext PtrIrpContext,
354     IN PVCB Vcb,
355     IN PFILE_FS_SIZE_INFORMATION Buffer,
356     IN OUT PULONG Length
357     )
358 {
359     PAGED_CODE();
360 
361     UDFPrint(("  UDFQueryFsSizeInfo: \n"));
362     //  Fill in the output buffer.
363     if(Vcb->BitmapModified) {
364         Vcb->TotalAllocUnits =
365         Buffer->TotalAllocationUnits.QuadPart = UDFGetTotalSpace(Vcb);
366         Vcb->FreeAllocUnits =
367         Buffer->AvailableAllocationUnits.QuadPart = UDFGetFreeSpace(Vcb);
368         Vcb->BitmapModified = FALSE;
369     } else {
370         Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalAllocUnits;
371         Buffer->AvailableAllocationUnits.QuadPart = Vcb->FreeAllocUnits;
372     }
373     Vcb->LowFreeSpace = (Vcb->FreeAllocUnits < max(Vcb->FECharge,UDF_DEFAULT_FE_CHARGE)*128);
374     if(!Buffer->TotalAllocationUnits.QuadPart)
375         Buffer->TotalAllocationUnits.QuadPart = max(1, Vcb->LastPossibleLBA);
376     Buffer->SectorsPerAllocationUnit = Vcb->LBlockSize / Vcb->BlockSize;
377     if(!Buffer->SectorsPerAllocationUnit)
378         Buffer->SectorsPerAllocationUnit = 1;
379     Buffer->BytesPerSector = Vcb->BlockSize;
380     if(!Buffer->BytesPerSector)
381         Buffer->BytesPerSector = 2048;
382 
383     UDFPrint(("  Space: Total %I64x, Free %I64x\n",
384         Buffer->TotalAllocationUnits.QuadPart,
385         Buffer->AvailableAllocationUnits.QuadPart));
386 
387     //  Adjust the length variable
388     *Length -= sizeof( FILE_FS_SIZE_INFORMATION );
389     return STATUS_SUCCESS;
390 } // UDFQueryFsSizeInfo()
391 
392 /*
393     This routine implements the query volume full size call.
394 
395 Arguments:
396 
397     Vcb    - Vcb for this volume.
398     Buffer - Supplies a pointer to the output buffer where the information
399              is to be returned
400     Length - Supplies the length of the buffer in byte.  This variable
401              upon return recieves the remaining bytes free in the buffer
402  */
403 NTSTATUS
404 UDFQueryFsFullSizeInfo(
405     IN PtrUDFIrpContext PtrIrpContext,
406     IN PVCB Vcb,
407     IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
408     IN OUT PULONG Length
409     )
410 {
411     PAGED_CODE();
412 
413     UDFPrint(("  UDFQueryFsFullSizeInfo: \n"));
414     //  Fill in the output buffer.
415     if(Vcb->BitmapModified) {
416         Vcb->TotalAllocUnits =
417         Buffer->TotalAllocationUnits.QuadPart = UDFGetTotalSpace(Vcb);
418         Vcb->FreeAllocUnits =
419         Buffer->CallerAvailableAllocationUnits.QuadPart =
420         Buffer->ActualAvailableAllocationUnits.QuadPart = UDFGetFreeSpace(Vcb);
421         Vcb->BitmapModified = FALSE;
422     } else {
423         Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalAllocUnits;
424         Buffer->CallerAvailableAllocationUnits.QuadPart =
425         Buffer->ActualAvailableAllocationUnits.QuadPart = Vcb->FreeAllocUnits;
426     }
427     if(!Buffer->TotalAllocationUnits.QuadPart)
428         Buffer->TotalAllocationUnits.QuadPart = max(1, Vcb->LastPossibleLBA);
429     Buffer->SectorsPerAllocationUnit = Vcb->LBlockSize / Vcb->BlockSize;
430     if(!Buffer->SectorsPerAllocationUnit)
431         Buffer->SectorsPerAllocationUnit = 1;
432     Buffer->BytesPerSector = Vcb->BlockSize;
433     if(!Buffer->BytesPerSector)
434         Buffer->BytesPerSector = 2048;
435 
436     UDFPrint(("  Space: Total %I64x, Free %I64x\n",
437         Buffer->TotalAllocationUnits.QuadPart,
438         Buffer->ActualAvailableAllocationUnits.QuadPart));
439 
440     //  Adjust the length variable
441     *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION );
442     return STATUS_SUCCESS;
443 } // UDFQueryFsSizeInfo()
444 
445 /*
446     This routine implements the query volume device call.
447 
448 Arguments:
449 
450     Vcb    - Vcb for this volume.
451     Buffer - Supplies a pointer to the output buffer where the information
452              is to be returned
453     Length - Supplies the length of the buffer in byte.  This variable
454              upon return recieves the remaining bytes free in the buffer
455  */
456 NTSTATUS
457 UDFQueryFsDeviceInfo(
458     IN PtrUDFIrpContext PtrIrpContext,
459     IN PVCB Vcb,
460     IN PFILE_FS_DEVICE_INFORMATION Buffer,
461     IN OUT PULONG Length
462     )
463 {
464     PAGED_CODE();
465 
466     UDFPrint(("  UDFQueryFsDeviceInfo: \n"));
467     //  Update the output buffer.
468     if (Vcb->TargetDeviceObject->DeviceType != FILE_DEVICE_CD_ROM && Vcb->TargetDeviceObject->DeviceType != FILE_DEVICE_DVD)
469     {
470         ASSERT(! (Vcb->TargetDeviceObject->Characteristics & (FILE_READ_ONLY_DEVICE | FILE_WRITE_ONCE_MEDIA)));
471         Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics & ~(FILE_READ_ONLY_DEVICE | FILE_WRITE_ONCE_MEDIA);
472     }
473     else
474     {
475         Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
476     }
477     Buffer->DeviceType = Vcb->TargetDeviceObject->DeviceType;
478     UDFPrint(("    Characteristics %x, DeviceType %x\n", Buffer->Characteristics, Buffer->DeviceType));
479     //  Adjust the length variable
480     *Length -= sizeof( FILE_FS_DEVICE_INFORMATION );
481     return STATUS_SUCCESS;
482 } // end UDFQueryFsDeviceInfo()
483 
484 /*
485     This routine implements the query volume attribute call.
486 
487 Arguments:
488 
489     Vcb    - Vcb for this volume.
490     Buffer - Supplies a pointer to the output buffer where the information
491              is to be returned
492     Length - Supplies the length of the buffer in byte.  This variable
493              upon return recieves the remaining bytes free in the buffer
494  */
495 NTSTATUS
496 UDFQueryFsAttributeInfo(
497     IN PtrUDFIrpContext PtrIrpContext,
498     IN PVCB Vcb,
499     IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
500     IN OUT PULONG Length
501     )
502 {
503     ULONG BytesToCopy;
504 
505     NTSTATUS Status = STATUS_SUCCESS;
506     PCWSTR FsTypeTitle;
507     ULONG FsTypeTitleLen;
508 
509     PAGED_CODE();
510     UDFPrint(("  UDFQueryFsAttributeInfo: \n"));
511     //  Fill out the fixed portion of the buffer.
512     Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH |
513                                    FILE_CASE_PRESERVED_NAMES |
514                                    (UDFStreamsSupported(Vcb) ? FILE_NAMED_STREAMS : 0) |
515 #ifdef ALLOW_SPARSE
516                                    FILE_SUPPORTS_SPARSE_FILES |
517 #endif //ALLOW_SPARSE
518 #ifdef UDF_ENABLE_SECURITY
519                                    (UDFNtAclSupported(Vcb) ? FILE_PERSISTENT_ACLS : 0) |
520 #endif //UDF_ENABLE_SECURITY
521                    ((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) ? FILE_READ_ONLY_VOLUME : 0) |
522 
523                                    FILE_UNICODE_ON_DISK;
524 
525     Buffer->MaximumComponentNameLength = UDF_X_NAME_LEN-1;
526 
527     *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName );
528     //  Make sure we can copy full unicode characters.
529     *Length &= ~1;
530     //  Determine how much of the file system name will fit.
531 
532 #define UDFSetFsTitle(tit) \
533                 FsTypeTitle = UDF_FS_TITLE_##tit; \
534                 FsTypeTitleLen = sizeof(UDF_FS_TITLE_##tit) - sizeof(WCHAR);
535 
536     switch(Vcb->TargetDeviceObject->DeviceType) {
537     case FILE_DEVICE_CD_ROM: {
538         if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
539             if(!Vcb->LastLBA) {
540                 UDFSetFsTitle(BLANK);
541             } else {
542                 UDFSetFsTitle(UNKNOWN);
543             }
544         } else
545         if(Vcb->CDR_Mode) {
546             if(Vcb->MediaClassEx == CdMediaClass_DVDR  ||
547                Vcb->MediaClassEx == CdMediaClass_DVDRW ||
548                Vcb->MediaClassEx == CdMediaClass_DVDRAM) {
549                 UDFSetFsTitle(DVDR);
550             } else
551             if(Vcb->MediaClassEx == CdMediaClass_DVDpR ||
552                Vcb->MediaClassEx == CdMediaClass_DVDpRW) {
553                 UDFSetFsTitle(DVDpR);
554             } else
555             if(Vcb->MediaClassEx == CdMediaClass_DVDROM) {
556                 UDFSetFsTitle(DVDROM);
557             } else
558             if(Vcb->MediaClassEx == CdMediaClass_CDROM) {
559                 UDFSetFsTitle(CDROM);
560             } else {
561                 UDFSetFsTitle(CDR);
562             }
563         } else {
564             if(Vcb->MediaClassEx == CdMediaClass_DVDROM ||
565                Vcb->MediaClassEx == CdMediaClass_DVDR ||
566                Vcb->MediaClassEx == CdMediaClass_DVDpR) {
567                 UDFSetFsTitle(DVDROM);
568             } else
569             if(Vcb->MediaClassEx == CdMediaClass_DVDR) {
570                 UDFSetFsTitle(DVDR);
571             } else
572             if(Vcb->MediaClassEx == CdMediaClass_DVDRW) {
573                 UDFSetFsTitle(DVDRW);
574             } else
575             if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) {
576                 UDFSetFsTitle(DVDpRW);
577             } else
578             if(Vcb->MediaClassEx == CdMediaClass_DVDRAM) {
579                 UDFSetFsTitle(DVDRAM);
580             } else
581             if(Vcb->MediaClassEx == CdMediaClass_CDROM) {
582                 UDFSetFsTitle(CDROM);
583             } else {
584                 UDFSetFsTitle(CDRW);
585             }
586         }
587         break;
588     }
589     default: {
590         UDFSetFsTitle(HDD);
591         break;
592     }
593     }
594 
595 #undef UDFSetFsTitle
596 
597     if (*Length >= FsTypeTitleLen) {
598         BytesToCopy = FsTypeTitleLen;
599     } else {
600         BytesToCopy = *Length;
601         Status = STATUS_BUFFER_OVERFLOW;
602     }
603 
604     *Length -= BytesToCopy;
605     //  Do the file system name.
606     Buffer->FileSystemNameLength = BytesToCopy;
607     RtlCopyMemory( &Buffer->FileSystemName[0], FsTypeTitle, BytesToCopy );
608     //  And return to our caller
609     return Status;
610 } // end UDFQueryFsAttributeInfo()
611 
612 
613 #ifndef UDF_READ_ONLY_BUILD
614 
615 NTSTATUS
616 NTAPI
617 UDFSetVolInfo(
618     PDEVICE_OBJECT      DeviceObject,       // the logical volume device object
619     PIRP                Irp                 // I/O Request Packet
620     )
621 {
622     NTSTATUS            RC = STATUS_SUCCESS;
623     PtrUDFIrpContext    PtrIrpContext = NULL;
624     BOOLEAN             AreWeTopLevel = FALSE;
625 
626     UDFPrint(("UDFSetVolInfo: \n"));
627 
628     FsRtlEnterFileSystem();
629     ASSERT(DeviceObject);
630     ASSERT(Irp);
631 
632     // set the top level context
633     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
634     ASSERT(!UDFIsFSDevObj(DeviceObject));
635 
636     _SEH2_TRY {
637 
638         // get an IRP context structure and issue the request
639         PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
640         ASSERT(PtrIrpContext);
641 
642         RC = UDFCommonSetVolInfo(PtrIrpContext, Irp);
643 
644     } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
645 
646         RC = UDFExceptionHandler(PtrIrpContext, Irp);
647 
648         UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
649     } _SEH2_END;
650 
651     if (AreWeTopLevel) {
652         IoSetTopLevelIrp(NULL);
653     }
654 
655     FsRtlExitFileSystem();
656 
657     return(RC);
658 } // end UDFSetVolInfo()
659 
660 
661 /*
662     This is the common routine for setting volume information called by both
663     the fsd and fsp threads.
664  */
665 NTSTATUS
666 UDFCommonSetVolInfo(
667     PtrUDFIrpContext                PtrIrpContext,
668     PIRP                            Irp
669     )
670 {
671     NTSTATUS RC = STATUS_INVALID_PARAMETER;
672     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
673     ULONG Length;
674     BOOLEAN CanWait = FALSE;
675     PVCB Vcb;
676     BOOLEAN PostRequest = FALSE;
677     BOOLEAN AcquiredVCB = FALSE;
678     PFILE_OBJECT            FileObject = NULL;
679 //    PtrUDFFCB               Fcb = NULL;
680     PtrUDFCCB               Ccb = NULL;
681 
682     _SEH2_TRY {
683 
684         UDFPrint(("UDFCommonSetVolInfo: \n"));
685         ASSERT(PtrIrpContext);
686         ASSERT(Irp);
687 
688         PAGED_CODE();
689 
690         FileObject = IrpSp->FileObject;
691         ASSERT(FileObject);
692 
693         // Get the FCB and CCB pointers.
694         Ccb = (PtrUDFCCB)(FileObject->FsContext2);
695         ASSERT(Ccb);
696 
697         if(Ccb && Ccb->Fcb && (Ccb->Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB)) {
698             UDFPrint(("    Can't change Label on Non-volume object\n"));
699             try_return(RC = STATUS_ACCESS_DENIED);
700         }
701 
702         Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension);
703         ASSERT(Vcb);
704         Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
705         //  Reference our input parameters to make things easier
706 
707         if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
708             UDFPrint(("    Can't change Label on blank volume ;)\n"));
709             try_return(RC = STATUS_ACCESS_DENIED);
710         }
711 
712         Length = IrpSp->Parameters.SetVolume.Length;
713         //  Acquire the Vcb for this volume.
714         CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
715         if (!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) {
716             PostRequest = TRUE;
717             try_return (RC = STATUS_PENDING);
718         }
719         AcquiredVCB = TRUE;
720 #ifdef UDF_ENABLE_SECURITY
721         RC = IoCheckFunctionAccess(
722             Ccb->PreviouslyGrantedAccess,
723             PtrIrpContext->MajorFunction,
724             PtrIrpContext->MinorFunction,
725             0,
726             NULL,
727             &(IrpSp->Parameters.SetVolume.FsInformationClass));
728         if(!NT_SUCCESS(RC)) {
729             try_return(RC);
730         }
731 #endif //UDF_ENABLE_SECURITY
732         switch (IrpSp->Parameters.SetVolume.FsInformationClass) {
733 
734         case FileFsLabelInformation:
735 
736             RC = UDFSetLabelInfo( PtrIrpContext, Vcb, (PFILE_FS_LABEL_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length );
737             Irp->IoStatus.Information = 0;
738             break;
739 
740         default:
741 
742             RC = STATUS_INVALID_DEVICE_REQUEST;
743             Irp->IoStatus.Information = 0;
744             break;
745 
746         }
747 
748         //  Set the information field to the number of bytes actually filled in
749         Irp->IoStatus.Information = IrpSp->Parameters.SetVolume.Length - Length;
750 
751 try_exit:   NOTHING;
752 
753     } _SEH2_FINALLY {
754 
755         if (AcquiredVCB) {
756             UDFReleaseResource(&(Vcb->VCBResource));
757             AcquiredVCB = FALSE;
758         }
759 
760         // Post IRP if required
761         if (PostRequest) {
762 
763             // Since, the I/O Manager gave us a system buffer, we do not
764             // need to "lock" anything.
765 
766             // Perform the post operation which will mark the IRP pending
767             // and will return STATUS_PENDING back to us
768             RC = UDFPostRequest(PtrIrpContext, Irp);
769 
770         } else {
771 
772             // Can complete the IRP here if no exception was encountered
773             if (!_SEH2_AbnormalTermination()) {
774                 Irp->IoStatus.Status = RC;
775 
776                 // Free up the Irp Context
777                 UDFReleaseIrpContext(PtrIrpContext);
778                 // complete the IRP
779                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
780             }
781         } // can we complete the IRP ?
782 
783     } _SEH2_END;
784 
785     return RC;
786 } // end UDFCommonSetVolInfo()
787 
788 /*
789     This sets Volume Label
790  */
791 NTSTATUS
792 UDFSetLabelInfo (
793     IN PtrUDFIrpContext PtrIrpContext,
794     IN PVCB Vcb,
795     IN PFILE_FS_LABEL_INFORMATION Buffer,
796     IN OUT PULONG Length
797     )
798 {
799     PAGED_CODE();
800 
801     UDFPrint(("  UDFSetLabelInfo: \n"));
802     if(Buffer->VolumeLabelLength > UDF_VOL_LABEL_LEN*sizeof(WCHAR)) {
803         // Too long Volume Label... NT doesn't like it
804         UDFPrint(("  UDFSetLabelInfo: STATUS_INVALID_VOLUME_LABEL\n"));
805         return STATUS_INVALID_VOLUME_LABEL;
806     }
807 
808     if(Vcb->VolIdent.Buffer) MyFreePool__(Vcb->VolIdent.Buffer);
809     Vcb->VolIdent.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Buffer->VolumeLabelLength+sizeof(WCHAR));
810     if(!Vcb->VolIdent.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
811 
812     Vcb->VolIdent.Length = (USHORT)Buffer->VolumeLabelLength;
813     Vcb->VolIdent.MaximumLength = (USHORT)Buffer->VolumeLabelLength+sizeof(WCHAR);
814     RtlCopyMemory(Vcb->VolIdent.Buffer, &(Buffer->VolumeLabel), Buffer->VolumeLabelLength);
815     Vcb->VolIdent.Buffer[Buffer->VolumeLabelLength/sizeof(WCHAR)] = 0;
816     UDFSetModified(Vcb);
817 
818     UDFPrint(("  UDFSetLabelInfo: OK\n"));
819     return STATUS_SUCCESS;
820 } // end UDFSetLabelInfo ()
821 
822 #endif //UDF_READ_ONLY_BUILD
823