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