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
UDFQueryVolInfo(PDEVICE_OBJECT DeviceObject,PIRP Irp)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
UDFCommonQueryVolInfo(PtrUDFIrpContext PtrIrpContext,PIRP Irp)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
UDFQueryFsVolumeInfo(IN PtrUDFIrpContext PtrIrpContext,IN PVCB Vcb,IN PFILE_FS_VOLUME_INFORMATION Buffer,IN OUT PULONG Length)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
UDFQueryFsSizeInfo(IN PtrUDFIrpContext PtrIrpContext,IN PVCB Vcb,IN PFILE_FS_SIZE_INFORMATION Buffer,IN OUT PULONG Length)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
UDFQueryFsFullSizeInfo(IN PtrUDFIrpContext PtrIrpContext,IN PVCB Vcb,IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,IN OUT PULONG Length)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
UDFQueryFsDeviceInfo(IN PtrUDFIrpContext PtrIrpContext,IN PVCB Vcb,IN PFILE_FS_DEVICE_INFORMATION Buffer,IN OUT PULONG Length)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
UDFQueryFsAttributeInfo(IN PtrUDFIrpContext PtrIrpContext,IN PVCB Vcb,IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,IN OUT PULONG Length)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
UDFSetVolInfo(PDEVICE_OBJECT DeviceObject,PIRP Irp)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
UDFCommonSetVolInfo(PtrUDFIrpContext PtrIrpContext,PIRP Irp)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
UDFSetLabelInfo(IN PtrUDFIrpContext PtrIrpContext,IN PVCB Vcb,IN PFILE_FS_LABEL_INFORMATION Buffer,IN OUT PULONG Length)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