xref: /reactos/drivers/filesystems/ext2/src/volinfo.c (revision 321bcc05)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             volinfo.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 
14 /* GLOBALS ***************************************************************/
15 
16 extern PEXT2_GLOBAL Ext2Global;
17 
18 /* DEFINITIONS *************************************************************/
19 
20 #ifdef ALLOC_PRAGMA
21 #pragma alloc_text(PAGE, Ext2QueryVolumeInformation)
22 #pragma alloc_text(PAGE, Ext2SetVolumeInformation)
23 #endif
24 
25 
26 NTSTATUS
27 Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
28 {
29     PDEVICE_OBJECT          DeviceObject;
30     PEXT2_VCB               Vcb = NULL;
31     PIRP                    Irp = NULL;
32     PIO_STACK_LOCATION      IoStackLocation = NULL;
33     PVOID                   Buffer;
34     ULONG                   Length;
35     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
36     FS_INFORMATION_CLASS    FsInformationClass;
37     BOOLEAN                 VcbResourceAcquired = FALSE;
38 
39     _SEH2_TRY {
40 
41         ASSERT(IrpContext != NULL);
42         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
43                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
44 
45         DeviceObject = IrpContext->DeviceObject;
46 
47         //
48         // This request is not allowed on the main device object
49         //
50         if (IsExt2FsDevice(DeviceObject)) {
51             Status = STATUS_INVALID_DEVICE_REQUEST;
52             _SEH2_LEAVE;
53         }
54 
55         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
56         ASSERT(Vcb != NULL);
57         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
58                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
59 
60         if (!IsMounted(Vcb)) {
61             Status = STATUS_VOLUME_DISMOUNTED;
62             _SEH2_LEAVE;
63         }
64 
65         if (!ExAcquireResourceSharedLite(
66                     &Vcb->MainResource,
67                     IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
68                 )) {
69 
70             Status = STATUS_PENDING;
71             _SEH2_LEAVE;
72         }
73         VcbResourceAcquired = TRUE;
74 
75         Irp = IrpContext->Irp;
76         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
77         FsInformationClass =
78             IoStackLocation->Parameters.QueryVolume.FsInformationClass;
79 
80         Length = IoStackLocation->Parameters.QueryVolume.Length;
81         Buffer = Irp->AssociatedIrp.SystemBuffer;
82 
83         RtlZeroMemory(Buffer, Length);
84 
85         switch (FsInformationClass) {
86 
87         case FileFsVolumeInformation:
88         {
89             PFILE_FS_VOLUME_INFORMATION FsVolInfo;
90             ULONG                       VolumeLabelLength;
91             ULONG                       RequiredLength;
92 
93             if (Length < sizeof(FILE_FS_VOLUME_INFORMATION)) {
94                 Status = STATUS_BUFFER_OVERFLOW;
95                 _SEH2_LEAVE;
96             }
97 
98             FsVolInfo = (PFILE_FS_VOLUME_INFORMATION) Buffer;
99             FsVolInfo->VolumeCreationTime.QuadPart = 0;
100             FsVolInfo->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
101             VolumeLabelLength = Vcb->Vpb->VolumeLabelLength;
102             FsVolInfo->VolumeLabelLength = VolumeLabelLength;
103             /* We don't support ObjectId */
104             FsVolInfo->SupportsObjects = FALSE;
105 
106             RequiredLength = sizeof(FILE_FS_VOLUME_INFORMATION)
107                              + VolumeLabelLength - sizeof(WCHAR);
108 
109             if (Length < RequiredLength) {
110                 Irp->IoStatus.Information =
111                     sizeof(FILE_FS_VOLUME_INFORMATION);
112                 Status = STATUS_BUFFER_OVERFLOW;
113                 _SEH2_LEAVE;
114             }
115 
116             RtlCopyMemory(FsVolInfo->VolumeLabel, Vcb->Vpb->VolumeLabel, Vcb->Vpb->VolumeLabelLength);
117 
118             Irp->IoStatus.Information = RequiredLength;
119             Status = STATUS_SUCCESS;
120         }
121         break;
122 
123         case FileFsSizeInformation:
124         {
125             PFILE_FS_SIZE_INFORMATION FsSizeInfo;
126 
127             if (Length < sizeof(FILE_FS_SIZE_INFORMATION)) {
128                 Status = STATUS_BUFFER_OVERFLOW;
129                 _SEH2_LEAVE;
130             }
131 
132             FsSizeInfo = (PFILE_FS_SIZE_INFORMATION) Buffer;
133             FsSizeInfo->TotalAllocationUnits.QuadPart =
134                 ext3_blocks_count(SUPER_BLOCK);
135             FsSizeInfo->AvailableAllocationUnits.QuadPart =
136                 ext3_free_blocks_count(SUPER_BLOCK);
137             FsSizeInfo->SectorsPerAllocationUnit =
138                 Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector;
139             FsSizeInfo->BytesPerSector =
140                 Vcb->DiskGeometry.BytesPerSector;
141 
142             Irp->IoStatus.Information = sizeof(FILE_FS_SIZE_INFORMATION);
143             Status = STATUS_SUCCESS;
144         }
145         break;
146 
147         case FileFsDeviceInformation:
148         {
149             PFILE_FS_DEVICE_INFORMATION FsDevInfo;
150 
151             if (Length < sizeof(FILE_FS_DEVICE_INFORMATION)) {
152                 Status = STATUS_BUFFER_OVERFLOW;
153                 _SEH2_LEAVE;
154             }
155 
156             FsDevInfo = (PFILE_FS_DEVICE_INFORMATION) Buffer;
157             FsDevInfo->DeviceType =
158                 Vcb->TargetDeviceObject->DeviceType;
159 
160             if (FsDevInfo->DeviceType != FILE_DEVICE_DISK) {
161                 DbgBreak();
162             }
163 
164             FsDevInfo->Characteristics =
165                 Vcb->TargetDeviceObject->Characteristics;
166 
167             if (IsVcbReadOnly(Vcb)) {
168                 SetFlag( FsDevInfo->Characteristics,
169                          FILE_READ_ONLY_DEVICE   );
170             }
171 
172             Irp->IoStatus.Information = sizeof(FILE_FS_DEVICE_INFORMATION);
173             Status = STATUS_SUCCESS;
174         }
175         break;
176 
177         case FileFsAttributeInformation:
178         {
179             PFILE_FS_ATTRIBUTE_INFORMATION  FsAttrInfo;
180             ULONG                           RequiredLength;
181 
182             if (Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) {
183                 Status = STATUS_BUFFER_OVERFLOW;
184                 _SEH2_LEAVE;
185             }
186 
187             FsAttrInfo =
188                 (PFILE_FS_ATTRIBUTE_INFORMATION) Buffer;
189             FsAttrInfo->FileSystemAttributes = FILE_SUPPORTS_HARD_LINKS |
190                 FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
191                 FILE_SUPPORTS_REPARSE_POINTS;
192             if (IsVcbReadOnly(Vcb)) {
193                 FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
194             }
195             FsAttrInfo->MaximumComponentNameLength = EXT2_NAME_LEN;
196             FsAttrInfo->FileSystemNameLength = 8;
197 
198             RequiredLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) +
199                              8 - sizeof(WCHAR);
200 
201             if (Length < RequiredLength) {
202                 Irp->IoStatus.Information =
203                     sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
204                 Status = STATUS_BUFFER_OVERFLOW;
205                 _SEH2_LEAVE;
206             }
207 
208             if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
209                 RtlCopyMemory(FsAttrInfo->FileSystemName,  L"EXT4\0", 10);
210             } else if (Vcb->IsExt3fs) {
211                 RtlCopyMemory(FsAttrInfo->FileSystemName,  L"EXT3\0", 10);
212             } else {
213                 RtlCopyMemory(FsAttrInfo->FileSystemName,  L"EXT2\0", 10);
214             }
215 
216             Irp->IoStatus.Information = RequiredLength;
217             Status = STATUS_SUCCESS;
218         }
219         break;
220 
221 #if (_WIN32_WINNT >= 0x0500)
222 
223         case FileFsFullSizeInformation:
224         {
225             PFILE_FS_FULL_SIZE_INFORMATION PFFFSI;
226 
227             if (Length < sizeof(FILE_FS_FULL_SIZE_INFORMATION)) {
228                 Status = STATUS_BUFFER_OVERFLOW;
229                 _SEH2_LEAVE;
230             }
231 
232             PFFFSI = (PFILE_FS_FULL_SIZE_INFORMATION) Buffer;
233 
234             /*
235                             typedef struct _FILE_FS_FULL_SIZE_INFORMATION {
236                                 LARGE_INTEGER   TotalAllocationUnits;
237                                 LARGE_INTEGER   CallerAvailableAllocationUnits;
238                                 LARGE_INTEGER   ActualAvailableAllocationUnits;
239                                 ULONG           SectorsPerAllocationUnit;
240                                 ULONG           BytesPerSector;
241                             } FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;
242             */
243 
244             {
245                 PFFFSI->TotalAllocationUnits.QuadPart =
246                     ext3_blocks_count(SUPER_BLOCK);
247 
248                 PFFFSI->CallerAvailableAllocationUnits.QuadPart =
249                     ext3_free_blocks_count(SUPER_BLOCK);
250 
251                 /* - Vcb->SuperBlock->s_r_blocks_count; */
252                 PFFFSI->ActualAvailableAllocationUnits.QuadPart =
253                     ext3_free_blocks_count(SUPER_BLOCK);
254             }
255 
256             PFFFSI->SectorsPerAllocationUnit =
257                 Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector;
258 
259             PFFFSI->BytesPerSector = Vcb->DiskGeometry.BytesPerSector;
260 
261             Irp->IoStatus.Information = sizeof(FILE_FS_FULL_SIZE_INFORMATION);
262             Status = STATUS_SUCCESS;
263         }
264         break;
265 
266 #endif // (_WIN32_WINNT >= 0x0500)
267 
268         default:
269             Status = STATUS_INVALID_INFO_CLASS;
270             break;
271         }
272 
273     } _SEH2_FINALLY {
274 
275         if (VcbResourceAcquired) {
276             ExReleaseResourceLite(&Vcb->MainResource);
277         }
278 
279         if (!IrpContext->ExceptionInProgress) {
280             if (Status == STATUS_PENDING) {
281                 Ext2QueueRequest(IrpContext);
282             } else {
283                 Ext2CompleteIrpContext(IrpContext, Status);
284             }
285         }
286     } _SEH2_END;
287 
288     return Status;
289 }
290 
291 NTSTATUS
292 Ext2SetVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
293 {
294     PDEVICE_OBJECT          DeviceObject;
295     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
296     PEXT2_VCB               Vcb = NULL;
297     PIRP                    Irp;
298     PIO_STACK_LOCATION      IoStackLocation;
299     FS_INFORMATION_CLASS    FsInformationClass;
300     BOOLEAN                 VcbResourceAcquired = FALSE;
301 
302     _SEH2_TRY {
303 
304         ASSERT(IrpContext != NULL);
305 
306         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
307                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
308 
309         DeviceObject = IrpContext->DeviceObject;
310 
311         //
312         // This request is not allowed on the main device object
313         //
314         if (IsExt2FsDevice(DeviceObject)) {
315             Status = STATUS_INVALID_DEVICE_REQUEST;
316             _SEH2_LEAVE;
317         }
318 
319         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
320         ASSERT(Vcb != NULL);
321         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
322                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
323         ASSERT(IsMounted(Vcb));
324 
325         if (IsVcbReadOnly(Vcb)) {
326             Status = STATUS_MEDIA_WRITE_PROTECTED;
327             _SEH2_LEAVE;
328         }
329 
330         if (!ExAcquireResourceExclusiveLite(
331                     &Vcb->MainResource, TRUE)) {
332             Status = STATUS_PENDING;
333             _SEH2_LEAVE;
334         }
335         VcbResourceAcquired = TRUE;
336 
337         Ext2VerifyVcb(IrpContext, Vcb);
338 
339         Irp = IrpContext->Irp;
340         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
341 
342         //Notes: SetVolume is not defined in ntddk.h of win2k ddk,
343         //       But it's same to QueryVolume ....
344         FsInformationClass =
345             IoStackLocation->Parameters./*SetVolume*/QueryVolume.FsInformationClass;
346 
347         switch (FsInformationClass) {
348 
349         case FileFsLabelInformation:
350         {
351             PFILE_FS_LABEL_INFORMATION      VolLabelInfo = NULL;
352             ULONG                           VolLabelLen;
353             UNICODE_STRING                  LabelName  ;
354 
355             OEM_STRING                      OemName;
356 
357             VolLabelInfo = (PFILE_FS_LABEL_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
358             VolLabelLen = VolLabelInfo->VolumeLabelLength;
359 
360             if (VolLabelLen > (16 * sizeof(WCHAR))) {
361                 Status = STATUS_INVALID_VOLUME_LABEL;
362                 _SEH2_LEAVE;
363             }
364 
365             RtlCopyMemory( Vcb->Vpb->VolumeLabel,
366                            VolLabelInfo->VolumeLabel,
367                            VolLabelLen );
368 
369             RtlZeroMemory(Vcb->SuperBlock->s_volume_name, 16);
370             LabelName.Buffer = VolLabelInfo->VolumeLabel;
371             LabelName.MaximumLength = (USHORT)16 * sizeof(WCHAR);
372             LabelName.Length = (USHORT)VolLabelLen;
373 
374             OemName.Buffer = SUPER_BLOCK->s_volume_name;
375             OemName.Length  = 0;
376             OemName.MaximumLength = 16;
377 
378             Ext2UnicodeToOEM(Vcb, &OemName, &LabelName);
379             Vcb->Vpb->VolumeLabelLength = (USHORT) VolLabelLen;
380 
381             if (Ext2SaveSuper(IrpContext, Vcb)) {
382                 Status = STATUS_SUCCESS;
383             }
384 
385             Irp->IoStatus.Information = 0;
386         }
387         break;
388 
389         default:
390             Status = STATUS_INVALID_INFO_CLASS;
391         }
392 
393     } _SEH2_FINALLY {
394 
395         if (VcbResourceAcquired) {
396             ExReleaseResourceLite(&Vcb->MainResource);
397         }
398 
399         if (!IrpContext->ExceptionInProgress) {
400             if (Status == STATUS_PENDING) {
401                 Ext2QueueRequest(IrpContext);
402             } else {
403                 Ext2CompleteIrpContext(IrpContext, Status);
404             }
405         }
406     } _SEH2_END;
407 
408     return Status;
409 }
410