1 /* $Id: finfo.c,v 1.19 2002/09/07 15:12:03 chorns Exp $
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 PDEVICE_OBJECT DeviceObject
,
26 PFILE_STANDARD_INFORMATION StandardInfo
,
29 * FUNCTION: Retrieve the standard file information
32 PDEVICE_EXTENSION DeviceExtension
;
34 if (*BufferLength
< sizeof(FILE_STANDARD_INFORMATION
))
35 return STATUS_BUFFER_OVERFLOW
;
37 DeviceExtension
= DeviceObject
->DeviceExtension
;
39 assert (DeviceExtension
!= NULL
);
40 assert (DeviceExtension
->FatInfo
.BytesPerCluster
!= 0);
41 assert (StandardInfo
!= NULL
);
44 RtlZeroMemory(StandardInfo
,
45 sizeof(FILE_STANDARD_INFORMATION
));
47 StandardInfo
->AllocationSize
= FCB
->RFCB
.AllocationSize
;
48 StandardInfo
->EndOfFile
= FCB
->RFCB
.FileSize
;
49 StandardInfo
->NumberOfLinks
= 0;
50 StandardInfo
->DeletePending
= FCB
->Flags
& FCB_DELETE_PENDING
? TRUE
: FALSE
;
51 StandardInfo
->Directory
= FCB
->entry
.Attrib
& 0x10 ? TRUE
: FALSE
;
53 *BufferLength
-= sizeof(FILE_STANDARD_INFORMATION
);
54 return(STATUS_SUCCESS
);
58 VfatSetPositionInformation(PFILE_OBJECT FileObject
,
60 PDEVICE_OBJECT DeviceObject
,
61 PFILE_POSITION_INFORMATION PositionInfo
)
63 DPRINT ("FsdSetPositionInformation()\n");
65 DPRINT ("PositionInfo %x\n", PositionInfo
);
66 DPRINT ("Setting position %d\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
67 memcpy (&FileObject
->CurrentByteOffset
, &PositionInfo
->CurrentByteOffset
,
68 sizeof (LARGE_INTEGER
));
70 return (STATUS_SUCCESS
);
74 VfatGetPositionInformation(PFILE_OBJECT FileObject
,
76 PDEVICE_OBJECT DeviceObject
,
77 PFILE_POSITION_INFORMATION PositionInfo
,
80 DPRINT ("VfatGetPositionInformation()\n");
82 if (*BufferLength
< sizeof(FILE_POSITION_INFORMATION
))
83 return STATUS_BUFFER_OVERFLOW
;
85 PositionInfo
->CurrentByteOffset
.QuadPart
=
86 FileObject
->CurrentByteOffset
.QuadPart
;
88 DPRINT("Getting position %I64x\n",
89 PositionInfo
->CurrentByteOffset
.QuadPart
);
91 *BufferLength
-= sizeof(FILE_POSITION_INFORMATION
);
92 return(STATUS_SUCCESS
);
96 VfatGetBasicInformation(PFILE_OBJECT FileObject
,
98 PDEVICE_OBJECT DeviceObject
,
99 PFILE_BASIC_INFORMATION BasicInfo
,
102 DPRINT("VfatGetBasicInformation()\n");
104 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
105 return STATUS_BUFFER_OVERFLOW
;
107 FsdDosDateTimeToFileTime(FCB
->entry
.CreationDate
,
108 FCB
->entry
.CreationTime
,
109 &BasicInfo
->CreationTime
);
110 FsdDosDateTimeToFileTime(FCB
->entry
.AccessDate
,
112 &BasicInfo
->LastAccessTime
);
113 FsdDosDateTimeToFileTime(FCB
->entry
.UpdateDate
,
114 FCB
->entry
.UpdateTime
,
115 &BasicInfo
->LastWriteTime
);
116 FsdDosDateTimeToFileTime(FCB
->entry
.UpdateDate
,
117 FCB
->entry
.UpdateTime
,
118 &BasicInfo
->ChangeTime
);
120 BasicInfo
->FileAttributes
= FCB
->entry
.Attrib
;
121 DPRINT("Getting attributes %x\n", BasicInfo
->FileAttributes
);
123 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
124 return(STATUS_SUCCESS
);
129 VfatSetDispositionInformation(PFILE_OBJECT FileObject
,
131 PDEVICE_OBJECT DeviceObject
,
132 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
138 NTSTATUS Status
= STATUS_SUCCESS
;
141 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
143 DPRINT ("FsdSetDispositionInformation()\n");
145 assert (DeviceExt
!= NULL
);
146 assert (DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
147 assert (FCB
!= NULL
);
149 if (!wcscmp(FCB
->PathName
, L
"\\") || !wcscmp(FCB
->ObjectName
, L
"..")
150 || !wcscmp(FCB
->ObjectName
, L
"."))
152 // we cannot delete a '.', '..' or the root directory
153 return STATUS_ACCESS_DENIED
;
155 if (DispositionInfo
->DoDeleteFile
)
157 KeAcquireSpinLock (&DeviceExt
->FcbListLock
, &oldIrql
);
158 count
= FCB
->RefCount
;
159 if (FCB
->RefCount
> 1)
160 Status
= STATUS_ACCESS_DENIED
;
163 FCB
->Flags
|= FCB_DELETE_PENDING
;
164 FileObject
->DeletePending
= TRUE
;
166 KeReleaseSpinLock(&DeviceExt
->FcbListLock
, oldIrql
);
167 DPRINT("RefCount:%d\n", count
);
168 if (NT_SUCCESS(Status
) && vfatFCBIsDirectory(DeviceExt
, FCB
))
170 memset (&tmpFcb
, 0, sizeof(VFATFCB
));
171 tmpFcb
.ObjectName
= tmpFcb
.PathName
;
174 // skip '.' and '..', start by 2
176 Status
= FindFile (DeviceExt
, &tmpFcb
, FCB
, star
, &Index
, NULL
);
177 if (NT_SUCCESS(Status
))
179 DPRINT1("found: \'%S\'\n", tmpFcb
.PathName
);
180 Status
= STATUS_DIRECTORY_NOT_EMPTY
;
181 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
182 FileObject
->DeletePending
= FALSE
;
186 Status
= STATUS_SUCCESS
;
191 FileObject
->DeletePending
= FALSE
;
196 VfatGetNameInformation(PFILE_OBJECT FileObject
,
198 PDEVICE_OBJECT DeviceObject
,
199 PFILE_NAME_INFORMATION NameInfo
,
202 * FUNCTION: Retrieve the file name information
207 assert (NameInfo
!= NULL
);
208 assert (FCB
!= NULL
);
210 NameLength
= wcslen(FCB
->PathName
) * sizeof(WCHAR
);
211 if (*BufferLength
< sizeof(FILE_NAME_INFORMATION
) + NameLength
)
212 return STATUS_BUFFER_OVERFLOW
;
214 NameInfo
->FileNameLength
= NameLength
;
215 memcpy(NameInfo
->FileName
,
217 NameLength
+ sizeof(WCHAR
));
220 (sizeof(FILE_NAME_INFORMATION
) + NameLength
+ sizeof(WCHAR
));
222 return STATUS_SUCCESS
;
226 VfatGetInternalInformation(PVFATFCB Fcb
,
227 PFILE_INTERNAL_INFORMATION InternalInfo
,
230 assert (InternalInfo
);
233 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
234 return STATUS_BUFFER_OVERFLOW
;
235 // FIXME: get a real index, that can be used in a create operation
236 InternalInfo
->IndexNumber
.QuadPart
= 0;
237 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
238 return STATUS_SUCCESS
;
243 VfatGetNetworkOpenInformation(PVFATFCB Fcb
,
244 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
247 * FUNCTION: Retrieve the file network open information
250 assert (NetworkInfo
);
253 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
254 return(STATUS_BUFFER_OVERFLOW
);
256 FsdDosDateTimeToFileTime(Fcb
->entry
.CreationDate
,
257 Fcb
->entry
.CreationTime
,
258 &NetworkInfo
->CreationTime
);
259 FsdDosDateTimeToFileTime(Fcb
->entry
.AccessDate
,
261 &NetworkInfo
->LastAccessTime
);
262 FsdDosDateTimeToFileTime(Fcb
->entry
.UpdateDate
,
263 Fcb
->entry
.UpdateTime
,
264 &NetworkInfo
->LastWriteTime
);
265 FsdDosDateTimeToFileTime(Fcb
->entry
.UpdateDate
,
266 Fcb
->entry
.UpdateTime
,
267 &NetworkInfo
->ChangeTime
);
268 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
269 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
270 NetworkInfo
->FileAttributes
= Fcb
->entry
.Attrib
;
272 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
273 return STATUS_SUCCESS
;
278 VfatGetAllInformation(PFILE_OBJECT FileObject
,
280 PFILE_ALL_INFORMATION Info
,
283 * FUNCTION: Retrieve the all file information
291 NameLength
= wcslen(Fcb
->PathName
) * sizeof(WCHAR
);
292 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
) + NameLength
)
293 return(STATUS_BUFFER_OVERFLOW
);
295 /* Basic Information */
296 FsdDosDateTimeToFileTime(Fcb
->entry
.CreationDate
,
297 Fcb
->entry
.CreationTime
,
298 &Info
->BasicInformation
.CreationTime
);
299 FsdDosDateTimeToFileTime(Fcb
->entry
.AccessDate
,
301 &Info
->BasicInformation
.LastAccessTime
);
302 FsdDosDateTimeToFileTime(Fcb
->entry
.UpdateDate
,
303 Fcb
->entry
.UpdateTime
,
304 &Info
->BasicInformation
.LastWriteTime
);
305 FsdDosDateTimeToFileTime(Fcb
->entry
.UpdateDate
,
306 Fcb
->entry
.UpdateTime
,
307 &Info
->BasicInformation
.ChangeTime
);
308 Info
->BasicInformation
.FileAttributes
= Fcb
->entry
.Attrib
;
310 /* Standard Information */
311 Info
->StandardInformation
.AllocationSize
= Fcb
->RFCB
.AllocationSize
;
312 Info
->StandardInformation
.EndOfFile
= Fcb
->RFCB
.FileSize
;
313 Info
->StandardInformation
.NumberOfLinks
= 0;
314 Info
->StandardInformation
.DeletePending
= Fcb
->Flags
& FCB_DELETE_PENDING
? TRUE
: FALSE
;
315 Info
->StandardInformation
.Directory
= Fcb
->entry
.Attrib
& 0x10 ? TRUE
: FALSE
;
317 /* Internal Information */
318 /* FIXME: get a real index, that can be used in a create operation */
319 Info
->InternalInformation
.IndexNumber
.QuadPart
= 0;
322 Info
->EaInformation
.EaSize
= 0;
324 /* Access Information */
325 /* The IO-Manager adds this information */
327 /* Position Information */
328 Info
->PositionInformation
.CurrentByteOffset
.QuadPart
= FileObject
->CurrentByteOffset
.QuadPart
;
330 /* Mode Information */
331 /* The IO-Manager adds this information */
333 /* Alignment Information */
334 /* The IO-Manager adds this information */
336 /* Name Information */
337 Info
->NameInformation
.FileNameLength
= NameLength
;
338 RtlCopyMemory(Info
->NameInformation
.FileName
,
340 NameLength
+ sizeof(WCHAR
));
342 *BufferLength
-= (sizeof(FILE_ALL_INFORMATION
) + NameLength
+ sizeof(WCHAR
));
344 return STATUS_SUCCESS
;
348 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject
,
350 PDEVICE_EXTENSION DeviceExt
,
351 PLARGE_INTEGER AllocationSize
)
358 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
359 ULONG NewSize
= AllocationSize
->u
.LowPart
;
362 DPRINT("VfatSetAllocationSizeInformation()\n");
364 OldSize
= Fcb
->entry
.FileSize
;
365 if (AllocationSize
->u
.HighPart
> 0)
367 return STATUS_INVALID_PARAMETER
;
369 if (OldSize
== NewSize
)
371 return(STATUS_SUCCESS
);
373 Cluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
375 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
379 Status
= NextCluster (DeviceExt
, Fcb
, Cluster
, &Cluster
, TRUE
);
380 if (!NT_SUCCESS(Status
))
382 DPRINT1("NextCluster failed.\n");
385 if (Cluster
== 0xffffffff)
387 return STATUS_DISK_FULL
;
389 Status
= OffsetToCluster(DeviceExt
, Fcb
, Cluster
,
390 ROUND_DOWN(NewSize
- 1, ClusterSize
),
392 if (NCluster
== 0xffffffff)
396 while (Cluster
!= 0xffffffff)
398 NextCluster (DeviceExt
, Fcb
, Cluster
, &NCluster
, FALSE
);
399 WriteCluster (DeviceExt
, Cluster
, 0);
402 return STATUS_DISK_FULL
;
404 Fcb
->entry
.FirstCluster
= (Cluster
& 0x0000FFFF);
405 Fcb
->entry
.FirstClusterHigh
= (Cluster
& 0xFFFF0000) >> 16;
409 Status
= OffsetToCluster(DeviceExt
, Fcb
, Cluster
,
410 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
412 /* Cluster points now to the last cluster within the chain */
413 Status
= OffsetToCluster(DeviceExt
, Fcb
, Cluster
,
414 ROUND_DOWN(NewSize
- 1, ClusterSize
),
416 if (NCluster
== 0xffffffff)
420 NextCluster (DeviceExt
, Fcb
, Cluster
, &NCluster
, FALSE
);
421 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
423 while (Cluster
!= 0xffffffff)
425 NextCluster (DeviceExt
, Fcb
, Cluster
, &NCluster
, FALSE
);
426 WriteCluster (DeviceExt
, Cluster
, 0);
429 return STATUS_DISK_FULL
;
433 else if (NewSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
)
437 Status
= OffsetToCluster(DeviceExt
, Fcb
, Cluster
,
438 ROUND_DOWN(NewSize
- 1, ClusterSize
),
442 Status
= NextCluster (DeviceExt
, Fcb
, Cluster
, &NCluster
, FALSE
);
443 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
445 while (Cluster
!= 0xffffffff)
447 NextCluster (DeviceExt
, Fcb
, Cluster
, &NCluster
, FALSE
);
448 WriteCluster (DeviceExt
, Cluster
, 0);
452 Fcb
->entry
.FileSize
= NewSize
;
455 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(NewSize
- 1, ClusterSize
);
459 Fcb
->RFCB
.AllocationSize
.QuadPart
= 0LL;
460 Fcb
->entry
.FirstCluster
= 0;
461 Fcb
->entry
.FirstClusterHigh
= 0;
463 Fcb
->RFCB
.FileSize
.QuadPart
= NewSize
;
464 Fcb
->RFCB
.ValidDataLength
.QuadPart
= NewSize
;
466 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
468 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
470 /* Update the on-disk directory entry */
471 VfatUpdateEntry(DeviceExt
, FileObject
);
472 return STATUS_SUCCESS
;
475 NTSTATUS
VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext
)
477 * FUNCTION: Retrieve the specified file information
480 FILE_INFORMATION_CLASS FileInformationClass
;
483 NTSTATUS RC
= STATUS_SUCCESS
;
491 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
492 FCB
= ((PVFATCCB
) IrpContext
->FileObject
->FsContext2
)->pFcb
;
494 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
495 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
497 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
499 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
, IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
501 return VfatQueueRequest (IrpContext
);
506 switch (FileInformationClass
)
508 case FileStandardInformation
:
509 RC
= VfatGetStandardInformation(FCB
,
510 IrpContext
->DeviceObject
,
514 case FilePositionInformation
:
515 RC
= VfatGetPositionInformation(IrpContext
->FileObject
,
517 IrpContext
->DeviceObject
,
521 case FileBasicInformation
:
522 RC
= VfatGetBasicInformation(IrpContext
->FileObject
,
524 IrpContext
->DeviceObject
,
528 case FileNameInformation
:
529 RC
= VfatGetNameInformation(IrpContext
->FileObject
,
531 IrpContext
->DeviceObject
,
535 case FileInternalInformation
:
536 RC
= VfatGetInternalInformation(FCB
,
540 case FileNetworkOpenInformation
:
541 RC
= VfatGetNetworkOpenInformation(FCB
,
545 case FileAllInformation
:
546 RC
= VfatGetAllInformation(IrpContext
->FileObject
,
552 case FileAlternateNameInformation
:
553 RC
= STATUS_NOT_IMPLEMENTED
;
556 RC
= STATUS_NOT_SUPPORTED
;
559 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
561 ExReleaseResourceLite(&FCB
->MainResource
);
563 IrpContext
->Irp
->IoStatus
.Status
= RC
;
565 IrpContext
->Irp
->IoStatus
.Information
=
566 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
568 IrpContext
->Irp
->IoStatus
.Information
= 0;
569 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
570 VfatFreeIrpContext(IrpContext
);
575 NTSTATUS
VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext
)
577 * FUNCTION: Retrieve the specified file information
580 FILE_INFORMATION_CLASS FileInformationClass
;
582 NTSTATUS RC
= STATUS_SUCCESS
;
584 BOOL CanWait
= IrpContext
->Flags
& IRPCONTEXT_CANWAIT
;
589 DPRINT("VfatSetInformation(IrpContext %x)\n", IrpContext
);
592 FileInformationClass
=
593 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
594 FCB
= ((PVFATCCB
) IrpContext
->FileObject
->FsContext2
)->pFcb
;
595 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
597 DPRINT("FileInformationClass %d\n", FileInformationClass
);
598 DPRINT("SystemBuffer %x\n", SystemBuffer
);
600 if (FCB
->Flags
& FCB_IS_PAGE_FILE
)
602 if (!ExAcquireResourceExclusiveLite(&FCB
->PagingIoResource
, CanWait
))
604 return(VfatQueueRequest (IrpContext
));
609 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
, CanWait
))
611 return(VfatQueueRequest (IrpContext
));
615 switch (FileInformationClass
)
617 case FilePositionInformation
:
618 RC
= VfatSetPositionInformation(IrpContext
->FileObject
,
620 IrpContext
->DeviceObject
,
623 case FileDispositionInformation
:
624 RC
= VfatSetDispositionInformation(IrpContext
->FileObject
,
626 IrpContext
->DeviceObject
,
629 case FileAllocationInformation
:
630 case FileEndOfFileInformation
:
631 RC
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
633 IrpContext
->DeviceExt
,
634 (PLARGE_INTEGER
)SystemBuffer
);
636 case FileBasicInformation
:
637 case FileRenameInformation
:
638 RC
= STATUS_NOT_IMPLEMENTED
;
641 RC
= STATUS_NOT_SUPPORTED
;
644 if (FCB
->Flags
& FCB_IS_PAGE_FILE
)
646 ExReleaseResourceLite(&FCB
->PagingIoResource
);
650 ExReleaseResourceLite(&FCB
->MainResource
);
653 IrpContext
->Irp
->IoStatus
.Status
= RC
;
654 IrpContext
->Irp
->IoStatus
.Information
= 0;
655 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
656 VfatFreeIrpContext(IrpContext
);