[NTFS]
[reactos.git] / reactos / drivers / filesystems / ntfs / volinfo.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2014 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/volume.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMERS: Eric Kohl
24 * Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "ntfs.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* FUNCTIONS ****************************************************************/
35
36 ULONGLONG
37 NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
38 {
39 NTSTATUS Status;
40 PFILE_RECORD_HEADER BitmapRecord;
41 PNTFS_ATTR_CONTEXT DataContext;
42 ULONGLONG BitmapDataSize;
43 PCHAR BitmapData;
44 ULONGLONG FreeClusters = 0;
45 ULONG Read = 0;
46 RTL_BITMAP Bitmap;
47
48 DPRINT1("NtfsGetFreeClusters(%p)\n", DeviceExt);
49
50 BitmapRecord = ExAllocatePoolWithTag(NonPagedPool,
51 DeviceExt->NtfsInfo.BytesPerFileRecord,
52 TAG_NTFS);
53 if (BitmapRecord == NULL)
54 {
55 return 0;
56 }
57
58 Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord);
59 if (!NT_SUCCESS(Status))
60 {
61 ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
62 return 0;
63 }
64
65 Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext);
66 if (!NT_SUCCESS(Status))
67 {
68 ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
69 return 0;
70 }
71
72 BitmapDataSize = AttributeDataLength(&DataContext->Record);
73 ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount);
74 BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS);
75 if (BitmapData == NULL)
76 {
77 ReleaseAttributeContext(DataContext);
78 ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
79 return 0;
80 }
81
82 /* FIXME: Totally underoptimized! */
83 for (; Read < BitmapDataSize; Read += DeviceExt->NtfsInfo.BytesPerSector)
84 {
85 ReadAttribute(DeviceExt, DataContext, Read, (PCHAR)((ULONG_PTR)BitmapData + Read), DeviceExt->NtfsInfo.BytesPerSector);
86 }
87 ReleaseAttributeContext(DataContext);
88
89 DPRINT1("Total clusters: %I64x\n", DeviceExt->NtfsInfo.ClusterCount);
90 DPRINT1("Total clusters in bitmap: %I64x\n", BitmapDataSize * 8);
91 DPRINT1("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - DeviceExt->NtfsInfo.ClusterCount) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector);
92
93 RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount);
94 FreeClusters = RtlNumberOfClearBits(&Bitmap);
95
96 ExFreePoolWithTag(BitmapData, TAG_NTFS);
97 ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
98
99 return FreeClusters;
100 }
101
102 static
103 NTSTATUS
104 NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,
105 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo,
106 PULONG BufferLength)
107 {
108 DPRINT("NtfsGetFsVolumeInformation() called\n");
109 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
110 DPRINT("BufferLength %lu\n", *BufferLength);
111
112 DPRINT("Vpb %p\n", DeviceObject->Vpb);
113
114 DPRINT("Required length %lu\n",
115 sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
116 DPRINT("LabelLength %hu\n",
117 DeviceObject->Vpb->VolumeLabelLength);
118 DPRINT("Label %*.S\n",
119 DeviceObject->Vpb->VolumeLabelLength / sizeof(WCHAR),
120 DeviceObject->Vpb->VolumeLabel);
121
122 if (*BufferLength < sizeof(FILE_FS_VOLUME_INFORMATION))
123 return STATUS_INFO_LENGTH_MISMATCH;
124
125 if (*BufferLength < (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength))
126 return STATUS_BUFFER_OVERFLOW;
127
128 /* valid entries */
129 FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
130 FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
131 memcpy(FsVolumeInfo->VolumeLabel,
132 DeviceObject->Vpb->VolumeLabel,
133 DeviceObject->Vpb->VolumeLabelLength);
134
135 /* dummy entries */
136 FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
137 FsVolumeInfo->SupportsObjects = FALSE;
138
139 *BufferLength -= (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
140
141 DPRINT("BufferLength %lu\n", *BufferLength);
142 DPRINT("NtfsGetFsVolumeInformation() done\n");
143
144 return STATUS_SUCCESS;
145 }
146
147
148 static
149 NTSTATUS
150 NtfsGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt,
151 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo,
152 PULONG BufferLength)
153 {
154 UNREFERENCED_PARAMETER(DeviceExt);
155
156 DPRINT("NtfsGetFsAttributeInformation()\n");
157 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
158 DPRINT("BufferLength %lu\n", *BufferLength);
159 DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8));
160
161 if (*BufferLength < sizeof (FILE_FS_ATTRIBUTE_INFORMATION))
162 return STATUS_INFO_LENGTH_MISMATCH;
163
164 if (*BufferLength < (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8))
165 return STATUS_BUFFER_OVERFLOW;
166
167 FsAttributeInfo->FileSystemAttributes =
168 FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_READ_ONLY_VOLUME;
169 FsAttributeInfo->MaximumComponentNameLength = 255;
170 FsAttributeInfo->FileSystemNameLength = 8;
171
172 memcpy(FsAttributeInfo->FileSystemName, L"NTFS", 8);
173
174 DPRINT("Finished NtfsGetFsAttributeInformation()\n");
175
176 *BufferLength -= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8);
177 DPRINT("BufferLength %lu\n", *BufferLength);
178
179 return STATUS_SUCCESS;
180 }
181
182
183 static
184 NTSTATUS
185 NtfsGetFsSizeInformation(PDEVICE_OBJECT DeviceObject,
186 PFILE_FS_SIZE_INFORMATION FsSizeInfo,
187 PULONG BufferLength)
188 {
189 PDEVICE_EXTENSION DeviceExt;
190 NTSTATUS Status = STATUS_SUCCESS;
191
192 DPRINT("NtfsGetFsSizeInformation()\n");
193 DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
194
195 if (*BufferLength < sizeof(FILE_FS_SIZE_INFORMATION))
196 return STATUS_BUFFER_OVERFLOW;
197
198 DeviceExt = DeviceObject->DeviceExtension;
199
200 FsSizeInfo->AvailableAllocationUnits.QuadPart = NtfsGetFreeClusters(DeviceExt);
201 FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->NtfsInfo.ClusterCount;
202 FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->NtfsInfo.SectorsPerCluster;
203 FsSizeInfo->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
204
205 DPRINT("Finished NtfsGetFsSizeInformation()\n");
206 if (NT_SUCCESS(Status))
207 *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION);
208
209 return Status;
210 }
211
212
213 static
214 NTSTATUS
215 NtfsGetFsDeviceInformation(PDEVICE_OBJECT DeviceObject,
216 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo,
217 PULONG BufferLength)
218 {
219 DPRINT("NtfsGetFsDeviceInformation()\n");
220 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo);
221 DPRINT("BufferLength %lu\n", *BufferLength);
222 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION));
223
224 if (*BufferLength < sizeof(FILE_FS_DEVICE_INFORMATION))
225 return STATUS_BUFFER_OVERFLOW;
226
227 FsDeviceInfo->DeviceType = FILE_DEVICE_DISK;
228 FsDeviceInfo->Characteristics = DeviceObject->Characteristics;
229
230 DPRINT("NtfsGetFsDeviceInformation() finished.\n");
231
232 *BufferLength -= sizeof(FILE_FS_DEVICE_INFORMATION);
233 DPRINT("BufferLength %lu\n", *BufferLength);
234
235 return STATUS_SUCCESS;
236 }
237
238
239 NTSTATUS
240 NtfsQueryVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
241 {
242 PIRP Irp;
243 PDEVICE_OBJECT DeviceObject;
244 FS_INFORMATION_CLASS FsInformationClass;
245 PIO_STACK_LOCATION Stack;
246 NTSTATUS Status = STATUS_SUCCESS;
247 PVOID SystemBuffer;
248 ULONG BufferLength;
249 PDEVICE_EXTENSION DeviceExt;
250
251 DPRINT("NtfsQueryVolumeInformation() called\n");
252
253 ASSERT(IrpContext);
254
255 Irp = IrpContext->Irp;
256 DeviceObject = IrpContext->DeviceObject;
257 DeviceExt = DeviceObject->DeviceExtension;
258 Stack = IrpContext->Stack;
259
260 if (!ExAcquireResourceSharedLite(&DeviceExt->DirResource,
261 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
262 {
263 return NtfsMarkIrpContextForQueue(IrpContext);
264 }
265
266 FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
267 BufferLength = Stack->Parameters.QueryVolume.Length;
268 SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
269 RtlZeroMemory(SystemBuffer, BufferLength);
270
271 DPRINT("FsInformationClass %d\n", FsInformationClass);
272 DPRINT("SystemBuffer %p\n", SystemBuffer);
273
274 switch (FsInformationClass)
275 {
276 case FileFsVolumeInformation:
277 Status = NtfsGetFsVolumeInformation(DeviceObject,
278 SystemBuffer,
279 &BufferLength);
280 break;
281
282 case FileFsAttributeInformation:
283 Status = NtfsGetFsAttributeInformation(DeviceObject->DeviceExtension,
284 SystemBuffer,
285 &BufferLength);
286 break;
287
288 case FileFsSizeInformation:
289 Status = NtfsGetFsSizeInformation(DeviceObject,
290 SystemBuffer,
291 &BufferLength);
292 break;
293
294 case FileFsDeviceInformation:
295 Status = NtfsGetFsDeviceInformation(DeviceObject,
296 SystemBuffer,
297 &BufferLength);
298 break;
299
300 default:
301 Status = STATUS_NOT_SUPPORTED;
302 }
303
304 ExReleaseResourceLite(&DeviceExt->DirResource);
305
306 if (NT_SUCCESS(Status))
307 Irp->IoStatus.Information =
308 Stack->Parameters.QueryVolume.Length - BufferLength;
309 else
310 Irp->IoStatus.Information = 0;
311
312 return Status;
313 }
314
315
316 NTSTATUS
317 NtfsSetVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
318 {
319 PIRP Irp;
320
321 DPRINT("NtfsSetVolumeInformation() called\n");
322
323 ASSERT(IrpContext);
324
325 Irp = IrpContext->Irp;
326 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
327 Irp->IoStatus.Information = 0;
328
329 return STATUS_NOT_SUPPORTED;
330 }
331
332 /* EOF */