2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/finfo.c
5 * PURPOSE: File Information support routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9 /* INCLUDES *****************************************************************/
14 /* FUNCTIONS ****************************************************************/
18 FatiQueryBasicInformation(IN PFAT_IRP_CONTEXT IrpContext
,
20 IN PFILE_OBJECT FileObject
,
21 IN OUT PFILE_BASIC_INFORMATION Buffer
,
25 RtlZeroMemory(Buffer
, sizeof(FILE_BASIC_INFORMATION
));
27 /* Deduct the written length */
28 *Length
-= sizeof(FILE_BASIC_INFORMATION
);
30 /* Check if it's a dir or a file */
31 if (FatNodeType(Fcb
) == FAT_NTC_FCB
)
33 // FIXME: Read dirent and get times from there
34 Buffer
->LastAccessTime
.QuadPart
= 0;
35 Buffer
->CreationTime
.QuadPart
= 0;
36 Buffer
->LastWriteTime
.QuadPart
= 0;
40 // FIXME: May not be really correct
41 Buffer
->FileAttributes
= 0;
42 DPRINT1("Basic info of a directory '%wZ' is requested!\n", &Fcb
->FullFileName
);
46 /* If attribute is 0, set normal */
47 if (Buffer
->FileAttributes
== 0)
48 Buffer
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
53 FatiQueryStandardInformation(IN PFAT_IRP_CONTEXT IrpContext
,
55 IN PFILE_OBJECT FileObject
,
56 IN OUT PFILE_STANDARD_INFORMATION Buffer
,
60 RtlZeroMemory(Buffer
, sizeof(FILE_STANDARD_INFORMATION
));
62 /* Deduct the written length */
63 *Length
-= sizeof(FILE_STANDARD_INFORMATION
);
65 Buffer
->NumberOfLinks
= 1;
66 Buffer
->DeletePending
= FALSE
; // FIXME
68 /* Check if it's a dir or a file */
69 if (FatNodeType(Fcb
) == FAT_NTC_FCB
)
71 Buffer
->Directory
= FALSE
;
73 Buffer
->EndOfFile
.LowPart
= Fcb
->FatHandle
->Filesize
;
74 Buffer
->AllocationSize
= Buffer
->EndOfFile
;
75 DPRINT("Filesize %d, chain length %d\n", Fcb
->FatHandle
->Filesize
, Fcb
->FatHandle
->iChainLength
);
79 Buffer
->Directory
= TRUE
;
85 FatiQueryInternalInformation(IN PFAT_IRP_CONTEXT IrpContext
,
87 IN PFILE_OBJECT FileObject
,
88 IN OUT PFILE_INTERNAL_INFORMATION Buffer
,
96 FatiQueryNameInformation(IN PFAT_IRP_CONTEXT IrpContext
,
98 IN PFILE_OBJECT FileObject
,
99 IN OUT PFILE_NAME_INFORMATION Buffer
,
104 BOOLEAN Overflow
= FALSE
;
106 /* Deduct the minimum written length */
107 *Length
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]);
109 /* Build full name if needed */
110 if (!Fcb
->FullFileName
.Buffer
)
112 FatSetFullFileNameInFcb(IrpContext
, Fcb
);
115 DPRINT("FullFileName %wZ\n", &Fcb
->FullFileName
);
117 if (*Length
< Fcb
->FullFileName
.Length
- Trim
)
119 /* Buffer can't fit all data */
125 /* Deduct the amount of bytes we are going to write */
126 ByteSize
= Fcb
->FullFileName
.Length
- Trim
;
131 RtlCopyMemory(Buffer
->FileName
,
132 Fcb
->FullFileName
.Buffer
,
136 Buffer
->FileNameLength
= Fcb
->FullFileName
.Length
- Trim
;
138 /* Is this a shortname query? */
141 /* Yes, not supported atm */
145 /* Indicate overflow by passing -1 as the length */
146 if (Overflow
) *Length
= -1;
151 FatiQueryInformation(IN PFAT_IRP_CONTEXT IrpContext
,
154 PFILE_OBJECT FileObject
;
155 PIO_STACK_LOCATION IrpSp
;
156 FILE_INFORMATION_CLASS InfoClass
;
157 TYPE_OF_OPEN FileType
;
163 BOOLEAN VcbLocked
= FALSE
, FcbLocked
= FALSE
;
164 NTSTATUS Status
= STATUS_SUCCESS
;
166 /* Get IRP stack location */
167 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
169 /* Get the file object */
170 FileObject
= IrpSp
->FileObject
;
172 /* Copy variables to something with shorter names */
173 InfoClass
= IrpSp
->Parameters
.QueryFile
.FileInformationClass
;
174 Length
= IrpSp
->Parameters
.QueryFile
.Length
;
175 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
177 DPRINT("FatiQueryInformation\n", 0);
178 DPRINT("\tIrp = %08lx\n", Irp
);
179 DPRINT("\tLength = %08lx\n", Length
);
180 DPRINT("\tFileInformationClass = %08lx\n", InfoClass
);
181 DPRINT("\tBuffer = %08lx\n", Buffer
);
183 FileType
= FatDecodeFileObject(FileObject
, &Vcb
, &Fcb
, &Ccb
);
185 DPRINT("Vcb %p, Fcb %p, Ccb %p, open type %d\n", Vcb
, Fcb
, Ccb
, FileType
);
187 /* Acquire VCB lock */
188 if (InfoClass
== FileNameInformation
||
189 InfoClass
== FileAllInformation
)
191 if (!FatAcquireExclusiveVcb(IrpContext
, Vcb
))
196 /* Remember we locked the VCB */
200 /* Acquire FCB lock */
201 // FIXME: If not paging file
202 if (!FatAcquireSharedFcb(IrpContext
, Fcb
))
210 case FileBasicInformation
:
211 FatiQueryBasicInformation(IrpContext
, Fcb
, FileObject
, Buffer
, &Length
);
213 case FileStandardInformation
:
214 FatiQueryStandardInformation(IrpContext
, Fcb
, FileObject
, Buffer
, &Length
);
216 case FileInternalInformation
:
217 FatiQueryInternalInformation(IrpContext
, Fcb
, FileObject
, Buffer
, &Length
);
219 case FileNameInformation
:
220 FatiQueryNameInformation(IrpContext
, Fcb
, FileObject
, Buffer
, &Length
);
223 DPRINT1("Unimplemented information class %d requested\n", InfoClass
);
224 Status
= STATUS_INVALID_PARAMETER
;
227 /* Check for buffer overflow */
230 Status
= STATUS_BUFFER_OVERFLOW
;
234 /* Set IoStatus.Information to amount of filled bytes */
235 Irp
->IoStatus
.Information
= IrpSp
->Parameters
.QueryFile
.Length
- Length
;
237 /* Release FCB locks */
238 if (FcbLocked
) FatReleaseFcb(IrpContext
, Fcb
);
239 if (VcbLocked
) FatReleaseVcb(IrpContext
, Vcb
);
241 /* Complete request and return status */
242 FatCompleteRequest(IrpContext
, Irp
, Status
);
248 FatQueryInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
251 BOOLEAN TopLevel
, CanWait
;
252 PFAT_IRP_CONTEXT IrpContext
;
256 Status
= STATUS_INVALID_DEVICE_REQUEST
;
258 /* Get CanWait flag */
259 if (IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
)
260 CanWait
= IoIsOperationSynchronous(Irp
);
262 /* Enter FsRtl critical region */
263 FsRtlEnterFileSystem();
265 /* Set Top Level IRP if not set */
266 TopLevel
= FatIsTopLevelIrp(Irp
);
268 /* Build an irp context */
269 IrpContext
= FatBuildIrpContext(Irp
, CanWait
);
271 /* Perform the actual read */
272 Status
= FatiQueryInformation(IrpContext
, Irp
);
274 /* Restore top level Irp */
275 if (TopLevel
) IoSetTopLevelIrp(NULL
);
277 /* Leave FsRtl critical region */
278 FsRtlExitFileSystem();
285 FatSetEndOfFileInfo(IN PFAT_IRP_CONTEXT IrpContext
,
287 IN PFILE_OBJECT FileObject
,
291 PFILE_END_OF_FILE_INFORMATION Buffer
;
293 ULONG InitialFileSize
;
294 ULONG InitialValidDataLength
;
295 //ULONG InitialValidDataToDisk;
296 BOOLEAN CacheMapInitialized
= FALSE
;
297 BOOLEAN ResourceAcquired
= FALSE
;
300 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
302 if (FatNodeType(Fcb
) != FAT_NTC_FCB
)
304 /* Trying to change size of a dir */
305 Status
= STATUS_INVALID_DEVICE_REQUEST
;
309 /* Validate new size */
310 if (!FatIsIoRangeValid(Buffer
->EndOfFile
, 0))
312 Status
= STATUS_DISK_FULL
;
316 NewFileSize
= Buffer
->EndOfFile
.LowPart
;
318 /* Lookup allocation size if needed */
319 if (Fcb
->Header
.AllocationSize
.QuadPart
== (LONGLONG
)-1)
320 UNIMPLEMENTED
;//FatLookupFileAllocationSize(IrpContext, Fcb);
322 /* Cache the file if there is a data section */
323 if (FileObject
->SectionObjectPointer
->DataSectionObject
&&
324 (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
) &&
325 !FlagOn(Irp
->Flags
, IRP_PAGING_IO
))
327 if (FlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
329 /* This is a really weird condition */
331 //Raise(STATUS_FILE_CLOSED);
334 /* Initialize the cache map */
335 CcInitializeCacheMap(FileObject
,
336 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
,
338 &FatGlobalData
.CacheMgrCallbacks
,
341 CacheMapInitialized
= TRUE
;
344 /* Lazy write case */
345 if (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.SetFile
.AdvanceOnly
)
347 if (!IsFileDeleted(Fcb
) &&
348 (Fcb
->Condition
== FcbGood
))
350 /* Clamp the new file size */
351 if (NewFileSize
>= Fcb
->Header
.FileSize
.LowPart
)
352 NewFileSize
= Fcb
->Header
.FileSize
.LowPart
;
354 ASSERT(NewFileSize
<= Fcb
->Header
.AllocationSize
.LowPart
);
356 /* Never reduce the file size here! */
358 // TODO: Actually change file size
359 DPRINT1("Actually changing file size is missing\n");
361 /* Notify about file size change */
362 FatNotifyReportChange(IrpContext
,
365 FILE_NOTIFY_CHANGE_SIZE
,
366 FILE_ACTION_MODIFIED
);
370 DPRINT1("Cannot set size on deleted file\n");
373 Status
= STATUS_SUCCESS
;
377 if ( NewFileSize
> Fcb
->Header
.AllocationSize
.LowPart
)
379 // TODO: Increase file size
380 DPRINT1("Actually changing file size is missing\n");
383 if (Fcb
->Header
.FileSize
.LowPart
!= NewFileSize
)
385 if (NewFileSize
< Fcb
->Header
.FileSize
.LowPart
)
387 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
390 Status
= STATUS_USER_MAPPED_FILE
;
392 /* Free up resources if necessary */
393 if (CacheMapInitialized
)
394 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
399 ResourceAcquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.PagingIoResource
, TRUE
);
402 /* Set new file sizes */
403 InitialFileSize
= Fcb
->Header
.FileSize
.LowPart
;
404 InitialValidDataLength
= Fcb
->Header
.ValidDataLength
.LowPart
;
405 //InitialValidDataToDisk = Fcb->ValidDataToDisk;
407 Fcb
->Header
.FileSize
.LowPart
= NewFileSize
;
409 /* Adjust valid data length if new size is less than that */
410 if (Fcb
->Header
.ValidDataLength
.LowPart
> NewFileSize
)
411 Fcb
->Header
.ValidDataLength
.LowPart
= NewFileSize
;
413 //if (Fcb->ValidDataToDisk > NewFileSize)
414 // Fcb->ValidDataToDisk = NewFileSize;
416 DPRINT1("New file size is 0x%08lx\n", NewFileSize
);
418 /* Update cache mapping */
419 CcSetFileSizes(FileObject
,
420 (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
422 /* Notify about size change */
423 FatNotifyReportChange(IrpContext
,
426 FILE_NOTIFY_CHANGE_SIZE
,
427 FILE_ACTION_MODIFIED
);
429 /* Set truncate on close flag */
430 SetFlag(Fcb
->State
, FCB_STATE_TRUNCATE_ON_CLOSE
);
433 /* Set modified flag */
434 FileObject
->Flags
|= FO_FILE_MODIFIED
;
436 /* Free up resources if necessary */
437 if (CacheMapInitialized
)
438 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
440 if (ResourceAcquired
)
441 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
443 return STATUS_SUCCESS
;
448 FatiSetInformation(IN PFAT_IRP_CONTEXT IrpContext
,
451 PFILE_OBJECT FileObject
;
452 PIO_STACK_LOCATION IrpSp
;
453 FILE_INFORMATION_CLASS InfoClass
;
454 TYPE_OF_OPEN TypeOfOpen
;
460 NTSTATUS Status
= STATUS_SUCCESS
;
461 BOOLEAN VcbAcquired
= FALSE
, FcbAcquired
= FALSE
;
463 /* Get IRP stack location */
464 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
466 /* Get the file object */
467 FileObject
= IrpSp
->FileObject
;
469 /* Copy variables to something with shorter names */
470 InfoClass
= IrpSp
->Parameters
.SetFile
.FileInformationClass
;
471 Length
= IrpSp
->Parameters
.SetFile
.Length
;
472 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
474 DPRINT("FatiSetInformation\n", 0);
475 DPRINT("\tIrp = %08lx\n", Irp
);
476 DPRINT("\tLength = %08lx\n", Length
);
477 DPRINT("\tFileInformationClass = %08lx\n", InfoClass
);
478 DPRINT("\tFileObject = %08lx\n", IrpSp
->Parameters
.SetFile
.FileObject
);
479 DPRINT("\tBuffer = %08lx\n", Buffer
);
481 TypeOfOpen
= FatDecodeFileObject(FileObject
, &Vcb
, &Fcb
, &Ccb
);
483 DPRINT("Vcb %p, Fcb %p, Ccb %p, open type %d\n", Vcb
, Fcb
, Ccb
, TypeOfOpen
);
488 Status
= STATUS_INVALID_PARAMETER
;
489 /* Complete request and return status */
490 FatCompleteRequest(IrpContext
, Irp
, Status
);
494 if (!FlagOn(Fcb
->State
, FCB_STATE_PAGEFILE
) &&
495 ((InfoClass
== FileEndOfFileInformation
) ||
496 (InfoClass
== FileAllocationInformation
)))
498 Status
= FsRtlCheckOplock(&Fcb
->Fcb
.Oplock
,
504 if (Status
!= STATUS_SUCCESS
)
506 /* Complete request and return status */
507 FatCompleteRequest(IrpContext
, Irp
, Status
);
511 /* Update Fast IO flag */
512 Fcb
->Header
.IsFastIoPossible
= FatIsFastIoPossible(Fcb
);
516 case UserDirectoryOpen
:
520 Status
= STATUS_INVALID_PARAMETER
;
521 /* Complete request and return status */
522 FatCompleteRequest(IrpContext
, Irp
, Status
);
526 /* If it's a root DCB - fail */
527 if (FatNodeType(Fcb
) == FAT_NTC_ROOT_DCB
)
529 if (InfoClass
== FileDispositionInformation
)
530 Status
= STATUS_CANNOT_DELETE
;
532 Status
= STATUS_INVALID_PARAMETER
;
534 /* Complete request and return status */
535 FatCompleteRequest(IrpContext
, Irp
, Status
);
539 /* Acquire the volume lock if needed */
540 if (InfoClass
== FileDispositionInformation
||
541 InfoClass
== FileRenameInformation
)
543 if (!FatAcquireExclusiveVcb(IrpContext
, Vcb
))
551 /* Acquire FCB lock */
552 if (!FlagOn(Fcb
->State
, FCB_STATE_PAGEFILE
))
554 if (!FatAcquireExclusiveFcb(IrpContext
, Fcb
))
566 case FileBasicInformation
:
567 //Status = FatSetBasicInfo(IrpContext, Irp, Fcb, Ccb);
568 DPRINT1("FileBasicInformation\n");
571 case FileDispositionInformation
:
572 if (FlagOn(Vcb
->State
, VCB_STATE_FLAG_DEFERRED_FLUSH
) &&
573 !FlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
))
579 //Status = FatSetDispositionInfo(IrpContext, Irp, FileObject, Fcb);
580 DPRINT1("FileDispositionInformation\n");
585 case FileRenameInformation
:
586 if (!FlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
))
592 //Status = FatSetRenameInfo(IrpContext, Irp, Vcb, Fcb, Ccb);
593 DPRINT1("FileRenameInformation\n");
595 /* NOTE: Request must not be completed here!
596 That's why Irp/IrpContext are set to NULL */
597 if (Status
== STATUS_PENDING
)
605 case FilePositionInformation
:
606 //Status = FatSetPositionInfo(IrpContext, Irp, FileObject);
607 DPRINT1("FilePositionInformation\n");
610 case FileLinkInformation
:
611 Status
= STATUS_INVALID_DEVICE_REQUEST
;
614 case FileAllocationInformation
:
615 //Status = FatSetAllocationInfo(IrpContext, Irp, Fcb, FileObject);
616 DPRINT1("FileAllocationInformation\n");
619 case FileEndOfFileInformation
:
620 Status
= FatSetEndOfFileInfo(IrpContext
, Irp
, FileObject
, Vcb
, Fcb
);
624 Status
= STATUS_INVALID_PARAMETER
;
628 if (FcbAcquired
) FatReleaseFcb(IrpContext
, Fcb
);
629 if (VcbAcquired
) FatReleaseVcb(IrpContext
, Vcb
);
631 /* Complete request and return status */
632 FatCompleteRequest(IrpContext
, Irp
, Status
);
638 FatSetInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
641 BOOLEAN TopLevel
, CanWait
;
642 PFAT_IRP_CONTEXT IrpContext
;
646 Status
= STATUS_INVALID_DEVICE_REQUEST
;
648 /* Get CanWait flag */
649 if (IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
)
650 CanWait
= IoIsOperationSynchronous(Irp
);
652 /* Enter FsRtl critical region */
653 FsRtlEnterFileSystem();
655 /* Set Top Level IRP if not set */
656 TopLevel
= FatIsTopLevelIrp(Irp
);
658 /* Build an irp context */
659 IrpContext
= FatBuildIrpContext(Irp
, CanWait
);
661 /* Perform the actual read */
662 Status
= FatiSetInformation(IrpContext
, Irp
);
664 /* Restore top level Irp */
665 if (TopLevel
) IoSetTopLevelIrp(NULL
);
667 /* Leave FsRtl critical region */
668 FsRtlExitFileSystem();