Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / filesystems / udfs / volinfo.cpp
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