[NTFS]
[reactos.git] / reactos / drivers / filesystems / ntfs / volinfo.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 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 * PROGRAMMER: Eric Kohl
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include "ntfs.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /* FUNCTIONS ****************************************************************/
34
35 ULONGLONG
36 NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
37 {
38 NTSTATUS Status;
39 PFILE_RECORD_HEADER BitmapRecord;
40 PNTFS_ATTR_CONTEXT DataContext;
41 ULONGLONG BitmapDataSize;
42 PCHAR BitmapData;
43 ULONGLONG FreeClusters = 0;
44 ULONG Read = 0;
45 RTL_BITMAP Bitmap;
46
47 DPRINT1("NtfsGetFreeClusters(%p)\n", DeviceExt);
48
49 BitmapRecord = ExAllocatePoolWithTag(NonPagedPool,
50 DeviceExt->NtfsInfo.BytesPerFileRecord,
51 TAG_NTFS);
52 if (BitmapRecord == NULL)
53 {
54 return 0;
55 }
56
57 Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord);
58 if (!NT_SUCCESS(Status))
59 {
60 ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
61 return 0;
62 }
63
64 Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext);
65 if (!NT_SUCCESS(Status))
66 {
67 ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
68 return 0;
69 }
70
71 BitmapDataSize = AttributeDataLength(&DataContext->Record);
72 ASSERT((BitmapDataSize * 8) >= (DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster));
73 BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS);
74 if (BitmapData == NULL)
75 {
76 ReleaseAttributeContext(DataContext);
77 ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
78 return 0;
79 }
80
81 /* FIXME: Totally underoptimized! */
82 for (; Read < BitmapDataSize; Read += DeviceExt->NtfsInfo.BytesPerSector)
83 {
84 ReadAttribute(DeviceExt, DataContext, Read, (PCHAR)((ULONG_PTR)BitmapData + Read), DeviceExt->NtfsInfo.BytesPerSector);
85 }
86 ReleaseAttributeContext(DataContext);
87
88 DPRINT1("Total clusters: %I64x\n", DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster);
89 DPRINT1("Total clusters in bitmap: %I64x\n", BitmapDataSize * 8);
90 DPRINT1("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - (DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster)) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector);
91
92 RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster);
93 FreeClusters = RtlNumberOfClearBits(&Bitmap);
94
95 ExFreePoolWithTag(BitmapData, TAG_NTFS);
96 ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
97
98 return FreeClusters;
99 }
100
101 static
102 NTSTATUS
103 NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,
104 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo,
105 PULONG BufferLength)
106 {
107 DPRINT("NtfsGetFsVolumeInformation() called\n");
108 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
109 DPRINT("BufferLength %lu\n", *BufferLength);
110
111 DPRINT("Vpb %p\n", DeviceObject->Vpb);
112
113 DPRINT("Required length %lu\n",
114 sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
115 DPRINT("LabelLength %hu\n",
116 DeviceObject->Vpb->VolumeLabelLength);
117 DPRINT("Label %*.S\n",
118 DeviceObject->Vpb->VolumeLabelLength / sizeof(WCHAR),
119 DeviceObject->Vpb->VolumeLabel);
120
121 if (*BufferLength < sizeof(FILE_FS_VOLUME_INFORMATION))
122 return STATUS_INFO_LENGTH_MISMATCH;
123
124 if (*BufferLength < (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength))
125 return STATUS_BUFFER_OVERFLOW;
126
127 /* valid entries */
128 FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
129 FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
130 memcpy(FsVolumeInfo->VolumeLabel,
131 DeviceObject->Vpb->VolumeLabel,
132 DeviceObject->Vpb->VolumeLabelLength);
133
134 /* dummy entries */
135 FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
136 FsVolumeInfo->SupportsObjects = FALSE;
137
138 *BufferLength -= (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
139
140 DPRINT("BufferLength %lu\n", *BufferLength);
141 DPRINT("NtfsGetFsVolumeInformation() done\n");
142
143 return STATUS_SUCCESS;
144 }
145
146
147 static
148 NTSTATUS
149 NtfsGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt,
150 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo,
151 PULONG BufferLength)
152 {
153 UNREFERENCED_PARAMETER(DeviceExt);
154
155 DPRINT("NtfsGetFsAttributeInformation()\n");
156 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
157 DPRINT("BufferLength %lu\n", *BufferLength);
158 DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8));
159
160 if (*BufferLength < sizeof (FILE_FS_ATTRIBUTE_INFORMATION))
161 return STATUS_INFO_LENGTH_MISMATCH;
162
163 if (*BufferLength < (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8))
164 return STATUS_BUFFER_OVERFLOW;
165
166 FsAttributeInfo->FileSystemAttributes =
167 FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK;
168 FsAttributeInfo->MaximumComponentNameLength = 255;
169 FsAttributeInfo->FileSystemNameLength = 8;
170
171 memcpy(FsAttributeInfo->FileSystemName, L"NTFS", 8);
172
173 DPRINT("Finished NtfsGetFsAttributeInformation()\n");
174
175 *BufferLength -= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8);
176 DPRINT("BufferLength %lu\n", *BufferLength);
177
178 return STATUS_SUCCESS;
179 }
180
181
182 static
183 NTSTATUS
184 NtfsGetFsSizeInformation(PDEVICE_OBJECT DeviceObject,
185 PFILE_FS_SIZE_INFORMATION FsSizeInfo,
186 PULONG BufferLength)
187 {
188 PDEVICE_EXTENSION DeviceExt;
189 NTSTATUS Status = STATUS_SUCCESS;
190
191 DPRINT("NtfsGetFsSizeInformation()\n");
192 DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
193
194 if (*BufferLength < sizeof(FILE_FS_SIZE_INFORMATION))
195 return STATUS_BUFFER_OVERFLOW;
196
197 DeviceExt = DeviceObject->DeviceExtension;
198
199 FsSizeInfo->AvailableAllocationUnits.QuadPart = NtfsGetFreeClusters(DeviceExt);
200 FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster;
201 FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->NtfsInfo.SectorsPerCluster;
202 FsSizeInfo->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
203
204 DPRINT("Finished NtfsGetFsSizeInformation()\n");
205 if (NT_SUCCESS(Status))
206 *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION);
207
208 return Status;
209 }
210
211
212 static
213 NTSTATUS
214 NtfsGetFsDeviceInformation(PDEVICE_OBJECT DeviceObject,
215 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo,
216 PULONG BufferLength)
217 {
218 DPRINT("NtfsGetFsDeviceInformation()\n");
219 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo);
220 DPRINT("BufferLength %lu\n", *BufferLength);
221 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION));
222
223 if (*BufferLength < sizeof(FILE_FS_DEVICE_INFORMATION))
224 return STATUS_BUFFER_OVERFLOW;
225
226 FsDeviceInfo->DeviceType = FILE_DEVICE_DISK;
227 FsDeviceInfo->Characteristics = DeviceObject->Characteristics;
228
229 DPRINT("NtfsGetFsDeviceInformation() finished.\n");
230
231 *BufferLength -= sizeof(FILE_FS_DEVICE_INFORMATION);
232 DPRINT("BufferLength %lu\n", *BufferLength);
233
234 return STATUS_SUCCESS;
235 }
236
237
238 NTSTATUS
239 NtfsQueryVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
240 {
241 PIRP Irp;
242 PDEVICE_OBJECT DeviceObject;
243 FS_INFORMATION_CLASS FsInformationClass;
244 PIO_STACK_LOCATION Stack;
245 NTSTATUS Status = STATUS_SUCCESS;
246 PVOID SystemBuffer;
247 ULONG BufferLength;
248
249 DPRINT("NtfsQueryVolumeInformation() called\n");
250
251 ASSERT(IrpContext);
252
253 Irp = IrpContext->Irp;
254 DeviceObject = IrpContext->DeviceObject;
255 Stack = IoGetCurrentIrpStackLocation(Irp);
256 FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
257 BufferLength = Stack->Parameters.QueryVolume.Length;
258 SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
259 RtlZeroMemory(SystemBuffer, BufferLength);
260
261 DPRINT("FsInformationClass %d\n", FsInformationClass);
262 DPRINT("SystemBuffer %p\n", SystemBuffer);
263
264 switch (FsInformationClass)
265 {
266 case FileFsVolumeInformation:
267 Status = NtfsGetFsVolumeInformation(DeviceObject,
268 SystemBuffer,
269 &BufferLength);
270 break;
271
272 case FileFsAttributeInformation:
273 Status = NtfsGetFsAttributeInformation(DeviceObject->DeviceExtension,
274 SystemBuffer,
275 &BufferLength);
276 break;
277
278 case FileFsSizeInformation:
279 Status = NtfsGetFsSizeInformation(DeviceObject,
280 SystemBuffer,
281 &BufferLength);
282 break;
283
284 case FileFsDeviceInformation:
285 Status = NtfsGetFsDeviceInformation(DeviceObject,
286 SystemBuffer,
287 &BufferLength);
288 break;
289
290 default:
291 Status = STATUS_NOT_SUPPORTED;
292 }
293
294 if (NT_SUCCESS(Status))
295 Irp->IoStatus.Information =
296 Stack->Parameters.QueryVolume.Length - BufferLength;
297 else
298 Irp->IoStatus.Information = 0;
299
300 return Status;
301 }
302
303
304 NTSTATUS
305 NtfsSetVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
306 {
307 PIRP Irp;
308
309 DPRINT("NtfsSetVolumeInformation() called\n");
310
311 ASSERT(IrpContext);
312
313 Irp = IrpContext->Irp;
314 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
315 Irp->IoStatus.Information = 0;
316
317 return STATUS_NOT_SUPPORTED;
318 }
319
320 /* EOF */