[IPHLPAPI] Implement getOwnerModUdpTable() and getOwnerModTcpTable()
[reactos.git] / drivers / filesystems / fastfat / volume.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/volume.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Herve Poussineau (reactos@poussine.freesurf.fr)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "vfat.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS ****************************************************************/
18
19 static
20 NTSTATUS
21 FsdGetFsVolumeInformation(
22 PDEVICE_OBJECT DeviceObject,
23 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo,
24 PULONG BufferLength)
25 {
26 NTSTATUS Status;
27 PDEVICE_EXTENSION DeviceExt;
28
29 DPRINT("FsdGetFsVolumeInformation()\n");
30 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
31 DPRINT("BufferLength %lu\n", *BufferLength);
32
33 DPRINT("Required length %lu\n", FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + DeviceObject->Vpb->VolumeLabelLength);
34 DPRINT("LabelLength %hu\n", DeviceObject->Vpb->VolumeLabelLength);
35 DPRINT("Label %.*S\n", DeviceObject->Vpb->VolumeLabelLength / sizeof(WCHAR), DeviceObject->Vpb->VolumeLabel);
36
37 ASSERT(*BufferLength >= sizeof(FILE_FS_VOLUME_INFORMATION));
38 *BufferLength -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel);
39
40 DeviceExt = DeviceObject->DeviceExtension;
41
42 /* valid entries */
43 FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
44 FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
45 if (*BufferLength < DeviceObject->Vpb->VolumeLabelLength)
46 {
47 Status = STATUS_BUFFER_OVERFLOW;
48 RtlCopyMemory(FsVolumeInfo->VolumeLabel,
49 DeviceObject->Vpb->VolumeLabel,
50 *BufferLength);
51 *BufferLength = 0;
52 }
53 else
54 {
55 Status = STATUS_SUCCESS;
56 RtlCopyMemory(FsVolumeInfo->VolumeLabel,
57 DeviceObject->Vpb->VolumeLabel,
58 FsVolumeInfo->VolumeLabelLength);
59 *BufferLength -= DeviceObject->Vpb->VolumeLabelLength;
60 }
61
62 if (vfatVolumeIsFatX(DeviceExt))
63 {
64 FsdDosDateTimeToSystemTime(DeviceExt,
65 DeviceExt->VolumeFcb->entry.FatX.CreationDate,
66 DeviceExt->VolumeFcb->entry.FatX.CreationTime,
67 &FsVolumeInfo->VolumeCreationTime);
68 }
69 else
70 {
71 FsdDosDateTimeToSystemTime(DeviceExt,
72 DeviceExt->VolumeFcb->entry.Fat.CreationDate,
73 DeviceExt->VolumeFcb->entry.Fat.CreationTime,
74 &FsVolumeInfo->VolumeCreationTime);
75 }
76
77 FsVolumeInfo->SupportsObjects = FALSE;
78
79 DPRINT("Finished FsdGetFsVolumeInformation()\n");
80 DPRINT("BufferLength %lu\n", *BufferLength);
81
82 return Status;
83 }
84
85
86 static
87 NTSTATUS
88 FsdGetFsAttributeInformation(
89 PDEVICE_EXTENSION DeviceExt,
90 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo,
91 PULONG BufferLength)
92 {
93 NTSTATUS Status;
94 PCWSTR pName;
95 ULONG Length;
96
97 DPRINT("FsdGetFsAttributeInformation()\n");
98 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
99 DPRINT("BufferLength %lu\n", *BufferLength);
100
101 ASSERT(*BufferLength >= sizeof(FILE_FS_ATTRIBUTE_INFORMATION));
102 *BufferLength -= FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
103
104 if (DeviceExt->FatInfo.FatType == FAT32)
105 {
106 pName = L"FAT32";
107 }
108 else
109 {
110 pName = L"FAT";
111 }
112
113 Length = wcslen(pName) * sizeof(WCHAR);
114 DPRINT("Required length %lu\n", (FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) + Length));
115
116 if (*BufferLength < Length)
117 {
118 Status = STATUS_BUFFER_OVERFLOW;
119 Length = *BufferLength;
120 }
121 else
122 {
123 Status = STATUS_SUCCESS;
124 }
125
126 FsAttributeInfo->FileSystemAttributes =
127 FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK;
128
129 FsAttributeInfo->MaximumComponentNameLength = 255;
130
131 FsAttributeInfo->FileSystemNameLength = Length;
132
133 RtlCopyMemory(FsAttributeInfo->FileSystemName, pName, Length);
134
135 DPRINT("Finished FsdGetFsAttributeInformation()\n");
136
137 *BufferLength -= Length;
138 DPRINT("BufferLength %lu\n", *BufferLength);
139
140 return Status;
141 }
142
143
144 static
145 NTSTATUS
146 FsdGetFsSizeInformation(
147 PDEVICE_OBJECT DeviceObject,
148 PFILE_FS_SIZE_INFORMATION FsSizeInfo,
149 PULONG BufferLength)
150 {
151 PDEVICE_EXTENSION DeviceExt;
152 NTSTATUS Status;
153
154 DPRINT("FsdGetFsSizeInformation()\n");
155 DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
156
157 ASSERT(*BufferLength >= sizeof(FILE_FS_SIZE_INFORMATION));
158
159 DeviceExt = DeviceObject->DeviceExtension;
160 Status = CountAvailableClusters(DeviceExt, &FsSizeInfo->AvailableAllocationUnits);
161
162 FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->FatInfo.NumberOfClusters;
163 FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->FatInfo.SectorsPerCluster;
164 FsSizeInfo->BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
165
166 DPRINT("Finished FsdGetFsSizeInformation()\n");
167 if (NT_SUCCESS(Status))
168 *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION);
169
170 return Status;
171 }
172
173
174 static
175 NTSTATUS
176 FsdGetFsDeviceInformation(
177 PDEVICE_OBJECT DeviceObject,
178 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo,
179 PULONG BufferLength)
180 {
181 DPRINT("FsdGetFsDeviceInformation()\n");
182 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo);
183 DPRINT("BufferLength %lu\n", *BufferLength);
184 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION));
185
186 ASSERT(*BufferLength >= sizeof(FILE_FS_DEVICE_INFORMATION));
187
188 FsDeviceInfo->DeviceType = FILE_DEVICE_DISK;
189 FsDeviceInfo->Characteristics = DeviceObject->Characteristics;
190
191 DPRINT("FsdGetFsDeviceInformation() finished.\n");
192
193 *BufferLength -= sizeof(FILE_FS_DEVICE_INFORMATION);
194 DPRINT("BufferLength %lu\n", *BufferLength);
195
196 return STATUS_SUCCESS;
197 }
198
199
200 static
201 NTSTATUS
202 FsdGetFsFullSizeInformation(
203 PDEVICE_OBJECT DeviceObject,
204 PFILE_FS_FULL_SIZE_INFORMATION FsSizeInfo,
205 PULONG BufferLength)
206 {
207 PDEVICE_EXTENSION DeviceExt;
208 NTSTATUS Status;
209
210 DPRINT("FsdGetFsFullSizeInformation()\n");
211 DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
212
213 ASSERT(*BufferLength >= sizeof(FILE_FS_FULL_SIZE_INFORMATION));
214
215 DeviceExt = DeviceObject->DeviceExtension;
216 Status = CountAvailableClusters(DeviceExt, &FsSizeInfo->CallerAvailableAllocationUnits);
217
218 FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->FatInfo.NumberOfClusters;
219 FsSizeInfo->ActualAvailableAllocationUnits.QuadPart = FsSizeInfo->CallerAvailableAllocationUnits.QuadPart;
220 FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->FatInfo.SectorsPerCluster;
221 FsSizeInfo->BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
222
223 DPRINT("Finished FsdGetFsFullSizeInformation()\n");
224 if (NT_SUCCESS(Status))
225 *BufferLength -= sizeof(FILE_FS_FULL_SIZE_INFORMATION);
226
227 return Status;
228 }
229
230
231 static
232 NTSTATUS
233 FsdSetFsLabelInformation(
234 PDEVICE_OBJECT DeviceObject,
235 PFILE_FS_LABEL_INFORMATION FsLabelInfo)
236 {
237 PDEVICE_EXTENSION DeviceExt;
238 PVOID Context = NULL;
239 ULONG DirIndex = 0;
240 PDIR_ENTRY Entry;
241 PVFATFCB pRootFcb;
242 LARGE_INTEGER FileOffset;
243 BOOLEAN LabelFound = FALSE;
244 DIR_ENTRY VolumeLabelDirEntry;
245 ULONG VolumeLabelDirIndex;
246 ULONG LabelLen;
247 NTSTATUS Status = STATUS_UNSUCCESSFUL;
248 OEM_STRING StringO;
249 UNICODE_STRING StringW;
250 CHAR cString[43];
251 ULONG SizeDirEntry;
252 ULONG EntriesPerPage;
253 BOOLEAN IsFatX;
254
255 DPRINT("FsdSetFsLabelInformation()\n");
256
257 DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
258 IsFatX = vfatVolumeIsFatX(DeviceExt);
259
260 if (sizeof(DeviceObject->Vpb->VolumeLabel) < FsLabelInfo->VolumeLabelLength)
261 {
262 return STATUS_NAME_TOO_LONG;
263 }
264
265 if (IsFatX)
266 {
267 if (FsLabelInfo->VolumeLabelLength / sizeof(WCHAR) > 42)
268 return STATUS_NAME_TOO_LONG;
269
270 SizeDirEntry = sizeof(FATX_DIR_ENTRY);
271 EntriesPerPage = FATX_ENTRIES_PER_PAGE;
272 }
273 else
274 {
275 if (FsLabelInfo->VolumeLabelLength / sizeof(WCHAR) > 11)
276 return STATUS_NAME_TOO_LONG;
277
278 SizeDirEntry = sizeof(FAT_DIR_ENTRY);
279 EntriesPerPage = FAT_ENTRIES_PER_PAGE;
280 }
281
282 /* Create Volume label dir entry */
283 LabelLen = FsLabelInfo->VolumeLabelLength / sizeof(WCHAR);
284 RtlZeroMemory(&VolumeLabelDirEntry, SizeDirEntry);
285 StringW.Buffer = FsLabelInfo->VolumeLabel;
286 StringW.Length = StringW.MaximumLength = (USHORT)FsLabelInfo->VolumeLabelLength;
287 StringO.Buffer = cString;
288 StringO.Length = 0;
289 StringO.MaximumLength = 42;
290 Status = RtlUnicodeStringToOemString(&StringO, &StringW, FALSE);
291 if (!NT_SUCCESS(Status))
292 return Status;
293
294 if (IsFatX)
295 {
296 RtlCopyMemory(VolumeLabelDirEntry.FatX.Filename, cString, LabelLen);
297 memset(&VolumeLabelDirEntry.FatX.Filename[LabelLen], ' ', 42 - LabelLen);
298 VolumeLabelDirEntry.FatX.Attrib = _A_VOLID;
299 }
300 else
301 {
302 RtlCopyMemory(VolumeLabelDirEntry.Fat.Filename, cString, max(sizeof(VolumeLabelDirEntry.Fat.Filename), LabelLen));
303 if (LabelLen > sizeof(VolumeLabelDirEntry.Fat.Filename))
304 {
305 memset(VolumeLabelDirEntry.Fat.Ext, ' ', sizeof(VolumeLabelDirEntry.Fat.Ext));
306 RtlCopyMemory(VolumeLabelDirEntry.Fat.Ext, cString + sizeof(VolumeLabelDirEntry.Fat.Filename), LabelLen - sizeof(VolumeLabelDirEntry.Fat.Filename));
307 }
308 else
309 {
310 memset(&VolumeLabelDirEntry.Fat.Filename[LabelLen], ' ', sizeof(VolumeLabelDirEntry.Fat.Filename) - LabelLen);
311 }
312 VolumeLabelDirEntry.Fat.Attrib = _A_VOLID;
313 }
314
315 pRootFcb = vfatOpenRootFCB(DeviceExt);
316 Status = vfatFCBInitializeCacheFromVolume(DeviceExt, pRootFcb);
317 if (!NT_SUCCESS(Status))
318 {
319 return Status;
320 }
321
322 /* Search existing volume entry on disk */
323 FileOffset.QuadPart = 0;
324 _SEH2_TRY
325 {
326 CcPinRead(pRootFcb->FileObject, &FileOffset, SizeDirEntry, PIN_WAIT, &Context, (PVOID*)&Entry);
327 }
328 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
329 {
330 Status = _SEH2_GetExceptionCode();
331 }
332 _SEH2_END;
333
334 if (NT_SUCCESS(Status))
335 {
336 while (TRUE)
337 {
338 if (ENTRY_VOLUME(IsFatX, Entry))
339 {
340 /* Update entry */
341 LabelFound = TRUE;
342 RtlCopyMemory(Entry, &VolumeLabelDirEntry, SizeDirEntry);
343 CcSetDirtyPinnedData(Context, NULL);
344 Status = STATUS_SUCCESS;
345 break;
346 }
347
348 if (ENTRY_END(IsFatX, Entry))
349 {
350 break;
351 }
352
353 DirIndex++;
354 Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
355 if ((DirIndex % EntriesPerPage) == 0)
356 {
357 CcUnpinData(Context);
358 FileOffset.u.LowPart += PAGE_SIZE;
359 _SEH2_TRY
360 {
361 CcPinRead(pRootFcb->FileObject, &FileOffset, SizeDirEntry, PIN_WAIT, &Context, (PVOID*)&Entry);
362 }
363 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
364 {
365 Status = _SEH2_GetExceptionCode();
366 }
367 _SEH2_END;
368
369 if (!NT_SUCCESS(Status))
370 {
371 Context = NULL;
372 break;
373 }
374 }
375 }
376
377 if (Context)
378 {
379 CcUnpinData(Context);
380 }
381 }
382
383 if (!LabelFound)
384 {
385 /* Add new entry for label */
386 if (!vfatFindDirSpace(DeviceExt, pRootFcb, 1, &VolumeLabelDirIndex))
387 Status = STATUS_DISK_FULL;
388 else
389 {
390 FileOffset.u.HighPart = 0;
391 FileOffset.u.LowPart = VolumeLabelDirIndex * SizeDirEntry;
392
393 Status = STATUS_SUCCESS;
394 _SEH2_TRY
395 {
396 CcPinRead(pRootFcb->FileObject, &FileOffset, SizeDirEntry, PIN_WAIT, &Context, (PVOID*)&Entry);
397 }
398 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
399 {
400 Status = _SEH2_GetExceptionCode();
401 }
402 _SEH2_END;
403
404 if (NT_SUCCESS(Status))
405 {
406 RtlCopyMemory(Entry, &VolumeLabelDirEntry, SizeDirEntry);
407 CcSetDirtyPinnedData(Context, NULL);
408 CcUnpinData(Context);
409 Status = STATUS_SUCCESS;
410 }
411 }
412 }
413
414 vfatReleaseFCB(DeviceExt, pRootFcb);
415 if (!NT_SUCCESS(Status))
416 {
417 return Status;
418 }
419
420 /* Update volume label in memory */
421 DeviceObject->Vpb->VolumeLabelLength = (USHORT)FsLabelInfo->VolumeLabelLength;
422 RtlCopyMemory(DeviceObject->Vpb->VolumeLabel, FsLabelInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabelLength);
423
424 return Status;
425 }
426
427
428 /*
429 * FUNCTION: Retrieve the specified volume information
430 */
431 NTSTATUS
432 VfatQueryVolumeInformation(
433 PVFAT_IRP_CONTEXT IrpContext)
434 {
435 FS_INFORMATION_CLASS FsInformationClass;
436 NTSTATUS RC = STATUS_SUCCESS;
437 PVOID SystemBuffer;
438 ULONG BufferLength;
439
440 /* PRECONDITION */
441 ASSERT(IrpContext);
442
443 DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext);
444
445 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource,
446 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
447 {
448 DPRINT1("DirResource failed!\n");
449 return VfatMarkIrpContextForQueue(IrpContext);
450 }
451
452 /* INITIALIZATION */
453 FsInformationClass = IrpContext->Stack->Parameters.QueryVolume.FsInformationClass;
454 BufferLength = IrpContext->Stack->Parameters.QueryVolume.Length;
455 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
456
457 DPRINT("FsInformationClass %d\n", FsInformationClass);
458 DPRINT("SystemBuffer %p\n", SystemBuffer);
459
460 switch (FsInformationClass)
461 {
462 case FileFsVolumeInformation:
463 RC = FsdGetFsVolumeInformation(IrpContext->DeviceObject,
464 SystemBuffer,
465 &BufferLength);
466 break;
467
468 case FileFsAttributeInformation:
469 RC = FsdGetFsAttributeInformation(IrpContext->DeviceObject->DeviceExtension,
470 SystemBuffer,
471 &BufferLength);
472 break;
473
474 case FileFsSizeInformation:
475 RC = FsdGetFsSizeInformation(IrpContext->DeviceObject,
476 SystemBuffer,
477 &BufferLength);
478 break;
479
480 case FileFsDeviceInformation:
481 RC = FsdGetFsDeviceInformation(IrpContext->DeviceObject,
482 SystemBuffer,
483 &BufferLength);
484 break;
485
486 case FileFsFullSizeInformation:
487 RC = FsdGetFsFullSizeInformation(IrpContext->DeviceObject,
488 SystemBuffer,
489 &BufferLength);
490 break;
491
492 default:
493 RC = STATUS_NOT_SUPPORTED;
494 }
495
496 ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
497
498 IrpContext->Irp->IoStatus.Information =
499 IrpContext->Stack->Parameters.QueryVolume.Length - BufferLength;
500
501 return RC;
502 }
503
504
505 /*
506 * FUNCTION: Set the specified volume information
507 */
508 NTSTATUS
509 VfatSetVolumeInformation(
510 PVFAT_IRP_CONTEXT IrpContext)
511 {
512 FS_INFORMATION_CLASS FsInformationClass;
513 NTSTATUS Status = STATUS_SUCCESS;
514 PVOID SystemBuffer;
515 ULONG BufferLength;
516 PIO_STACK_LOCATION Stack = IrpContext->Stack;
517
518 /* PRECONDITION */
519 ASSERT(IrpContext);
520
521 DPRINT("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext);
522
523 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource,
524 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
525 {
526 return VfatMarkIrpContextForQueue(IrpContext);
527 }
528
529 FsInformationClass = Stack->Parameters.SetVolume.FsInformationClass;
530 BufferLength = Stack->Parameters.SetVolume.Length;
531 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
532
533 DPRINT("FsInformationClass %d\n", FsInformationClass);
534 DPRINT("BufferLength %u\n", BufferLength);
535 DPRINT("SystemBuffer %p\n", SystemBuffer);
536
537 switch (FsInformationClass)
538 {
539 case FileFsLabelInformation:
540 Status = FsdSetFsLabelInformation(IrpContext->DeviceObject,
541 SystemBuffer);
542 break;
543
544 default:
545 Status = STATUS_NOT_SUPPORTED;
546 }
547
548 ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
549 IrpContext->Irp->IoStatus.Information = 0;
550
551 return Status;
552 }
553
554 /* EOF */