3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/finfo.c
6 * PURPOSE: VFAT Filesystem
7 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
11 /* INCLUDES *****************************************************************/
13 #include <ddk/ntddk.h>
21 /* FUNCTIONS ****************************************************************/
24 VfatGetStandardInformation(PVFATFCB FCB,
25 PFILE_STANDARD_INFORMATION StandardInfo,
28 * FUNCTION: Retrieve the standard file information
32 if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
33 return STATUS_BUFFER_OVERFLOW;
36 assert (StandardInfo != NULL);
39 RtlZeroMemory(StandardInfo,
40 sizeof(FILE_STANDARD_INFORMATION));
42 StandardInfo->AllocationSize = FCB->RFCB.AllocationSize;
43 StandardInfo->EndOfFile = FCB->RFCB.FileSize;
44 StandardInfo->NumberOfLinks = 0;
45 StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
46 StandardInfo->Directory = FCB->entry.Attrib & 0x10 ? TRUE : FALSE;
48 *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
49 return(STATUS_SUCCESS);
53 VfatSetPositionInformation(PFILE_OBJECT FileObject,
54 PFILE_POSITION_INFORMATION PositionInfo)
56 DPRINT ("FsdSetPositionInformation()\n");
58 DPRINT ("PositionInfo %x\n", PositionInfo);
59 DPRINT ("Setting position %d\n", PositionInfo->CurrentByteOffset.u.LowPart);
60 memcpy (&FileObject->CurrentByteOffset, &PositionInfo->CurrentByteOffset,
61 sizeof (LARGE_INTEGER));
63 return (STATUS_SUCCESS);
67 VfatGetPositionInformation(PFILE_OBJECT FileObject,
69 PDEVICE_OBJECT DeviceObject,
70 PFILE_POSITION_INFORMATION PositionInfo,
73 DPRINT ("VfatGetPositionInformation()\n");
75 if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
76 return STATUS_BUFFER_OVERFLOW;
78 PositionInfo->CurrentByteOffset.QuadPart =
79 FileObject->CurrentByteOffset.QuadPart;
81 DPRINT("Getting position %I64x\n",
82 PositionInfo->CurrentByteOffset.QuadPart);
84 *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
85 return(STATUS_SUCCESS);
89 VfatSetBasicInformation(PFILE_OBJECT FileObject,
91 PDEVICE_EXTENSION DeviceExt,
92 PFILE_BASIC_INFORMATION BasicInfo)
94 DPRINT("VfatSetBasicInformation()\n");
96 assert (NULL != FileObject);
98 assert (NULL != DeviceExt);
99 assert (NULL != BasicInfo);
100 /* Check volume label bit */
101 assert(0 == (FCB->entry.Attrib & 0x08));
103 FsdFileTimeToDosDateTime(&(BasicInfo->CreationTime),
104 &(FCB->entry.CreationDate),
105 &(FCB->entry.CreationTime));
106 FsdFileTimeToDosDateTime(&(BasicInfo->LastAccessTime),
107 &(FCB->entry.AccessDate),
109 FsdFileTimeToDosDateTime(&(BasicInfo->LastWriteTime),
110 &(FCB->entry.UpdateDate),
111 &(FCB->entry.UpdateTime));
113 FCB->entry.Attrib = (FCB->entry.Attrib &
114 (FILE_ATTRIBUTE_DIRECTORY | 0x48)) |
115 (BasicInfo->FileAttributes &
116 (FILE_ATTRIBUTE_ARCHIVE |
117 FILE_ATTRIBUTE_SYSTEM |
118 FILE_ATTRIBUTE_HIDDEN |
119 FILE_ATTRIBUTE_READONLY));
120 DPRINT("Setting attributes 0x%02x\n", FCB->entry.Attrib);
122 VfatUpdateEntry(DeviceExt, FileObject);
124 return(STATUS_SUCCESS);
128 VfatGetBasicInformation(PFILE_OBJECT FileObject,
130 PDEVICE_OBJECT DeviceObject,
131 PFILE_BASIC_INFORMATION BasicInfo,
134 DPRINT("VfatGetBasicInformation()\n");
136 if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
137 return STATUS_BUFFER_OVERFLOW;
139 FsdDosDateTimeToFileTime(FCB->entry.CreationDate,
140 FCB->entry.CreationTime,
141 &BasicInfo->CreationTime);
142 FsdDosDateTimeToFileTime(FCB->entry.AccessDate,
144 &BasicInfo->LastAccessTime);
145 FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,
146 FCB->entry.UpdateTime,
147 &BasicInfo->LastWriteTime);
148 BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
150 BasicInfo->FileAttributes = FCB->entry.Attrib;
151 /* Synthesize FILE_ATTRIBUTE_NORMAL */
152 if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
153 FILE_ATTRIBUTE_ARCHIVE |
154 FILE_ATTRIBUTE_SYSTEM |
155 FILE_ATTRIBUTE_HIDDEN |
156 FILE_ATTRIBUTE_READONLY)))
158 BasicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
160 DPRINT("Getting attributes 0x%02x\n", BasicInfo->FileAttributes);
162 *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
163 return(STATUS_SUCCESS);
168 VfatSetDispositionInformation(PFILE_OBJECT FileObject,
170 PDEVICE_OBJECT DeviceObject,
171 PFILE_DISPOSITION_INFORMATION DispositionInfo)
177 NTSTATUS Status = STATUS_SUCCESS;
180 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
182 DPRINT ("FsdSetDispositionInformation()\n");
184 assert (DeviceExt != NULL);
185 assert (DeviceExt->FatInfo.BytesPerCluster != 0);
186 assert (FCB != NULL);
188 if (!wcscmp(FCB->PathName, L"\\") || !wcscmp(FCB->ObjectName, L"..")
189 || !wcscmp(FCB->ObjectName, L"."))
191 // we cannot delete a '.', '..' or the root directory
192 return STATUS_ACCESS_DENIED;
194 if (DispositionInfo->DoDeleteFile)
196 if (MmFlushImageSection (FileObject->SectionObjectPointers, MmFlushForDelete))
198 KeAcquireSpinLock (&DeviceExt->FcbListLock, &oldIrql);
199 count = FCB->RefCount;
200 if (FCB->RefCount > 1)
202 DPRINT1("%d %x\n", FCB->RefCount, CcGetFileObjectFromSectionPtrs(FileObject->SectionObjectPointers));
203 Status = STATUS_ACCESS_DENIED;
207 FCB->Flags |= FCB_DELETE_PENDING;
208 FileObject->DeletePending = TRUE;
210 KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
214 DPRINT1("MmFlushImageSection returned FALSE\n");
215 Status = STATUS_ACCESS_DENIED;
217 DPRINT("RefCount:%d\n", count);
218 if (NT_SUCCESS(Status) && vfatFCBIsDirectory(FCB))
220 memset (&tmpFcb, 0, sizeof(VFATFCB));
221 tmpFcb.ObjectName = tmpFcb.PathName;
224 // skip '.' and '..', start by 2
226 Status = FindFile (DeviceExt, &tmpFcb, FCB, star, &Index, NULL);
227 if (NT_SUCCESS(Status))
229 DPRINT1("found: \'%S\'\n", tmpFcb.PathName);
230 Status = STATUS_DIRECTORY_NOT_EMPTY;
231 FCB->Flags &= ~FCB_DELETE_PENDING;
232 FileObject->DeletePending = FALSE;
236 Status = STATUS_SUCCESS;
241 FileObject->DeletePending = FALSE;
246 VfatGetNameInformation(PFILE_OBJECT FileObject,
248 PDEVICE_OBJECT DeviceObject,
249 PFILE_NAME_INFORMATION NameInfo,
252 * FUNCTION: Retrieve the file name information
257 assert (NameInfo != NULL);
258 assert (FCB != NULL);
260 NameLength = wcslen(FCB->PathName) * sizeof(WCHAR);
261 if (*BufferLength < sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR))
262 return STATUS_BUFFER_OVERFLOW;
264 NameInfo->FileNameLength = NameLength;
265 memcpy(NameInfo->FileName, FCB->PathName, NameLength + sizeof(WCHAR));
267 *BufferLength -= (sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR));
269 return STATUS_SUCCESS;
273 VfatGetInternalInformation(PVFATFCB Fcb,
274 PFILE_INTERNAL_INFORMATION InternalInfo,
277 assert (InternalInfo);
280 if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
281 return STATUS_BUFFER_OVERFLOW;
282 // FIXME: get a real index, that can be used in a create operation
283 InternalInfo->IndexNumber.QuadPart = 0;
284 *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
285 return STATUS_SUCCESS;
290 VfatGetNetworkOpenInformation(PVFATFCB Fcb,
291 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
294 * FUNCTION: Retrieve the file network open information
297 assert (NetworkInfo);
300 if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
301 return(STATUS_BUFFER_OVERFLOW);
303 FsdDosDateTimeToFileTime(Fcb->entry.CreationDate,
304 Fcb->entry.CreationTime,
305 &NetworkInfo->CreationTime);
306 FsdDosDateTimeToFileTime(Fcb->entry.AccessDate,
308 &NetworkInfo->LastAccessTime);
309 FsdDosDateTimeToFileTime(Fcb->entry.UpdateDate,
310 Fcb->entry.UpdateTime,
311 &NetworkInfo->LastWriteTime);
312 NetworkInfo->ChangeTime = NetworkInfo->LastWriteTime;
313 NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
314 NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
315 NetworkInfo->FileAttributes = Fcb->entry.Attrib;
317 *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
318 return STATUS_SUCCESS;
323 VfatGetAllInformation(PFILE_OBJECT FileObject,
325 PFILE_ALL_INFORMATION Info,
328 * FUNCTION: Retrieve the all file information
336 NameLength = wcslen(Fcb->PathName) * sizeof(WCHAR);
337 if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + NameLength + sizeof(WCHAR))
338 return(STATUS_BUFFER_OVERFLOW);
340 /* Basic Information */
341 FsdDosDateTimeToFileTime(Fcb->entry.CreationDate,
342 Fcb->entry.CreationTime,
343 &Info->BasicInformation.CreationTime);
344 FsdDosDateTimeToFileTime(Fcb->entry.AccessDate,
346 &Info->BasicInformation.LastAccessTime);
347 FsdDosDateTimeToFileTime(Fcb->entry.UpdateDate,
348 Fcb->entry.UpdateTime,
349 &Info->BasicInformation.LastWriteTime);
350 Info->BasicInformation.ChangeTime = Info->BasicInformation.LastWriteTime;
351 Info->BasicInformation.FileAttributes = Fcb->entry.Attrib;
353 /* Standard Information */
354 Info->StandardInformation.AllocationSize = Fcb->RFCB.AllocationSize;
355 Info->StandardInformation.EndOfFile = Fcb->RFCB.FileSize;
356 Info->StandardInformation.NumberOfLinks = 0;
357 Info->StandardInformation.DeletePending = Fcb->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
358 Info->StandardInformation.Directory = Fcb->entry.Attrib & 0x10 ? TRUE : FALSE;
360 /* Internal Information */
361 /* FIXME: get a real index, that can be used in a create operation */
362 Info->InternalInformation.IndexNumber.QuadPart = 0;
365 Info->EaInformation.EaSize = 0;
367 /* Access Information */
368 /* The IO-Manager adds this information */
370 /* Position Information */
371 Info->PositionInformation.CurrentByteOffset.QuadPart = FileObject->CurrentByteOffset.QuadPart;
373 /* Mode Information */
374 /* The IO-Manager adds this information */
376 /* Alignment Information */
377 /* The IO-Manager adds this information */
379 /* Name Information */
380 Info->NameInformation.FileNameLength = NameLength;
381 RtlCopyMemory(Info->NameInformation.FileName, Fcb->PathName, NameLength + sizeof(WCHAR));
383 *BufferLength -= (sizeof(FILE_ALL_INFORMATION) + NameLength + sizeof(WCHAR));
385 return STATUS_SUCCESS;
388 VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize)
392 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
396 Fcb->RFCB.AllocationSize.QuadPart = 0LL;
398 if (!vfatFCBIsDirectory(Fcb))
400 Fcb->entry.FileSize = Size;
402 Fcb->RFCB.FileSize.QuadPart = Size;
403 Fcb->RFCB.ValidDataLength.QuadPart = Size;
405 if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
407 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
412 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
414 PDEVICE_EXTENSION DeviceExt,
415 PLARGE_INTEGER AllocationSize)
418 ULONG Cluster, FirstCluster;
422 ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
423 ULONG NewSize = AllocationSize->u.LowPart;
426 DPRINT("VfatSetAllocationSizeInformation()\n");
428 OldSize = Fcb->entry.FileSize;
429 if (AllocationSize->u.HighPart > 0)
431 return STATUS_INVALID_PARAMETER;
433 if (OldSize == NewSize)
435 return(STATUS_SUCCESS);
438 FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
440 if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart)
442 if (FirstCluster == 0)
444 Status = NextCluster (DeviceExt, Fcb, FirstCluster, &FirstCluster, TRUE);
445 if (!NT_SUCCESS(Status))
447 DPRINT1("NextCluster failed. Status = %x\n", Status);
450 if (FirstCluster == 0xffffffff)
452 return STATUS_DISK_FULL;
454 Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster,
455 ROUND_DOWN(NewSize - 1, ClusterSize),
457 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
460 NCluster = Cluster = FirstCluster;
461 Status = STATUS_SUCCESS;
462 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
464 Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
465 WriteCluster (DeviceExt, Cluster, 0);
468 return STATUS_DISK_FULL;
470 Fcb->entry.FirstCluster = (FirstCluster & 0x0000FFFF);
471 Fcb->entry.FirstClusterHigh = (FirstCluster & 0xFFFF0000) >> 16;
475 Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster,
476 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
478 /* FIXME: Check status */
479 /* Cluster points now to the last cluster within the chain */
480 Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster,
481 ROUND_DOWN(NewSize - 1, ClusterSize),
483 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
487 Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
488 WriteCluster(DeviceExt, Cluster, 0xffffffff);
490 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
492 Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
493 WriteCluster (DeviceExt, Cluster, 0);
496 return STATUS_DISK_FULL;
499 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
501 else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
503 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
506 Status = OffsetToCluster(DeviceExt, Fcb, Cluster,
507 ROUND_DOWN(NewSize - 1, ClusterSize),
511 Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
512 WriteCluster(DeviceExt, Cluster, 0xffffffff);
517 Fcb->entry.FirstCluster = 0;
518 Fcb->entry.FirstClusterHigh = 0;
520 NCluster = Cluster = FirstCluster;
521 Status = STATUS_SUCCESS;
523 while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
525 Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
526 WriteCluster (DeviceExt, Cluster, 0);
532 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
534 /* Update the on-disk directory entry */
535 VfatUpdateEntry(DeviceExt, FileObject);
536 return STATUS_SUCCESS;
539 NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
541 * FUNCTION: Retrieve the specified file information
544 FILE_INFORMATION_CLASS FileInformationClass;
547 NTSTATUS RC = STATUS_SUCCESS;
555 FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
556 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
558 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
559 BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
561 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
563 if (!ExAcquireResourceSharedLite(&FCB->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
565 return VfatQueueRequest (IrpContext);
570 switch (FileInformationClass)
572 case FileStandardInformation:
573 RC = VfatGetStandardInformation(FCB,
577 case FilePositionInformation:
578 RC = VfatGetPositionInformation(IrpContext->FileObject,
580 IrpContext->DeviceObject,
584 case FileBasicInformation:
585 RC = VfatGetBasicInformation(IrpContext->FileObject,
587 IrpContext->DeviceObject,
591 case FileNameInformation:
592 RC = VfatGetNameInformation(IrpContext->FileObject,
594 IrpContext->DeviceObject,
598 case FileInternalInformation:
599 RC = VfatGetInternalInformation(FCB,
603 case FileNetworkOpenInformation:
604 RC = VfatGetNetworkOpenInformation(FCB,
608 case FileAllInformation:
609 RC = VfatGetAllInformation(IrpContext->FileObject,
615 case FileAlternateNameInformation:
616 RC = STATUS_NOT_IMPLEMENTED;
619 RC = STATUS_NOT_SUPPORTED;
622 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
624 ExReleaseResourceLite(&FCB->MainResource);
626 IrpContext->Irp->IoStatus.Status = RC;
628 IrpContext->Irp->IoStatus.Information =
629 IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
631 IrpContext->Irp->IoStatus.Information = 0;
632 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
633 VfatFreeIrpContext(IrpContext);
638 NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
640 * FUNCTION: Retrieve the specified file information
643 FILE_INFORMATION_CLASS FileInformationClass;
645 NTSTATUS RC = STATUS_SUCCESS;
647 BOOL CanWait = IrpContext->Flags & IRPCONTEXT_CANWAIT;
652 DPRINT("VfatSetInformation(IrpContext %x)\n", IrpContext);
655 FileInformationClass =
656 IrpContext->Stack->Parameters.SetFile.FileInformationClass;
657 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
658 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
660 DPRINT("FileInformationClass %d\n", FileInformationClass);
661 DPRINT("SystemBuffer %x\n", SystemBuffer);
663 if (FCB->Flags & FCB_IS_PAGE_FILE)
665 if (!ExAcquireResourceExclusiveLite(&FCB->PagingIoResource, CanWait))
667 return(VfatQueueRequest (IrpContext));
672 if (!ExAcquireResourceExclusiveLite(&FCB->MainResource, CanWait))
674 return(VfatQueueRequest (IrpContext));
678 switch (FileInformationClass)
680 case FilePositionInformation:
681 RC = VfatSetPositionInformation(IrpContext->FileObject,
684 case FileDispositionInformation:
685 RC = VfatSetDispositionInformation(IrpContext->FileObject,
687 IrpContext->DeviceObject,
690 case FileAllocationInformation:
691 case FileEndOfFileInformation:
692 RC = VfatSetAllocationSizeInformation(IrpContext->FileObject,
694 IrpContext->DeviceExt,
695 (PLARGE_INTEGER)SystemBuffer);
697 case FileBasicInformation:
698 RC = VfatSetBasicInformation(IrpContext->FileObject,
700 IrpContext->DeviceExt,
703 case FileRenameInformation:
704 RC = STATUS_NOT_IMPLEMENTED;
707 RC = STATUS_NOT_SUPPORTED;
710 if (FCB->Flags & FCB_IS_PAGE_FILE)
712 ExReleaseResourceLite(&FCB->PagingIoResource);
716 ExReleaseResourceLite(&FCB->MainResource);
719 IrpContext->Irp->IoStatus.Status = RC;
720 IrpContext->Irp->IoStatus.Information = 0;
721 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
722 VfatFreeIrpContext(IrpContext);