2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/filesystems/fastfat/finfo.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Herve Poussineau (reactos@poussine.freesurf.fr)
8 * Pierre Schweitzer (pierre@reactos.org)
12 /* INCLUDES *****************************************************************/
19 #define NASSERTS_RENAME
21 /* GLOBALS ******************************************************************/
23 const char* FileInformationClassNames
[] =
26 "FileDirectoryInformation",
27 "FileFullDirectoryInformation",
28 "FileBothDirectoryInformation",
29 "FileBasicInformation",
30 "FileStandardInformation",
31 "FileInternalInformation",
33 "FileAccessInformation",
34 "FileNameInformation",
35 "FileRenameInformation",
36 "FileLinkInformation",
37 "FileNamesInformation",
38 "FileDispositionInformation",
39 "FilePositionInformation",
40 "FileFullEaInformation",
41 "FileModeInformation",
42 "FileAlignmentInformation",
44 "FileAllocationInformation",
45 "FileEndOfFileInformation",
46 "FileAlternateNameInformation",
47 "FileStreamInformation",
48 "FilePipeInformation",
49 "FilePipeLocalInformation",
50 "FilePipeRemoteInformation",
51 "FileMailslotQueryInformation",
52 "FileMailslotSetInformation",
53 "FileCompressionInformation",
54 "FileObjectIdInformation",
55 "FileCompletionInformation",
56 "FileMoveClusterInformation",
57 "FileQuotaInformation",
58 "FileReparsePointInformation",
59 "FileNetworkOpenInformation",
60 "FileAttributeTagInformation",
61 "FileTrackingInformation",
62 "FileIdBothDirectoryInformation",
63 "FileIdFullDirectoryInformation",
64 "FileValidDataLengthInformation",
65 "FileShortNameInformation",
66 "FileMaximumInformation"
69 /* FUNCTIONS ****************************************************************/
72 * FUNCTION: Retrieve the standard file information
75 VfatGetStandardInformation(
77 PFILE_STANDARD_INFORMATION StandardInfo
,
80 if (*BufferLength
< sizeof(FILE_STANDARD_INFORMATION
))
81 return STATUS_BUFFER_OVERFLOW
;
84 ASSERT(StandardInfo
!= NULL
);
87 if (vfatFCBIsDirectory(FCB
))
89 StandardInfo
->AllocationSize
.QuadPart
= 0;
90 StandardInfo
->EndOfFile
.QuadPart
= 0;
91 StandardInfo
->Directory
= TRUE
;
95 StandardInfo
->AllocationSize
= FCB
->RFCB
.AllocationSize
;
96 StandardInfo
->EndOfFile
= FCB
->RFCB
.FileSize
;
97 StandardInfo
->Directory
= FALSE
;
99 StandardInfo
->NumberOfLinks
= 1;
100 StandardInfo
->DeletePending
= BooleanFlagOn(FCB
->Flags
, FCB_DELETE_PENDING
);
102 *BufferLength
-= sizeof(FILE_STANDARD_INFORMATION
);
103 return STATUS_SUCCESS
;
108 VfatSetPositionInformation(
109 PFILE_OBJECT FileObject
,
110 PFILE_POSITION_INFORMATION PositionInfo
)
112 DPRINT("FsdSetPositionInformation()\n");
114 DPRINT("PositionInfo %p\n", PositionInfo
);
115 DPRINT("Setting position %u\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
117 FileObject
->CurrentByteOffset
.QuadPart
=
118 PositionInfo
->CurrentByteOffset
.QuadPart
;
120 return STATUS_SUCCESS
;
125 VfatGetPositionInformation(
126 PFILE_OBJECT FileObject
,
128 PDEVICE_EXTENSION DeviceExt
,
129 PFILE_POSITION_INFORMATION PositionInfo
,
132 UNREFERENCED_PARAMETER(FileObject
);
133 UNREFERENCED_PARAMETER(FCB
);
134 UNREFERENCED_PARAMETER(DeviceExt
);
136 DPRINT("VfatGetPositionInformation()\n");
138 if (*BufferLength
< sizeof(FILE_POSITION_INFORMATION
))
139 return STATUS_BUFFER_OVERFLOW
;
141 PositionInfo
->CurrentByteOffset
.QuadPart
=
142 FileObject
->CurrentByteOffset
.QuadPart
;
144 DPRINT("Getting position %I64x\n",
145 PositionInfo
->CurrentByteOffset
.QuadPart
);
147 *BufferLength
-= sizeof(FILE_POSITION_INFORMATION
);
148 return STATUS_SUCCESS
;
153 VfatSetBasicInformation(
154 PFILE_OBJECT FileObject
,
156 PDEVICE_EXTENSION DeviceExt
,
157 PFILE_BASIC_INFORMATION BasicInfo
)
161 DPRINT("VfatSetBasicInformation()\n");
163 ASSERT(NULL
!= FileObject
);
165 ASSERT(NULL
!= DeviceExt
);
166 ASSERT(NULL
!= BasicInfo
);
167 /* Check volume label bit */
168 ASSERT(0 == (*FCB
->Attributes
& _A_VOLID
));
172 if (BasicInfo
->FileAttributes
!= 0)
176 Attributes
= (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_ARCHIVE
|
177 FILE_ATTRIBUTE_SYSTEM
|
178 FILE_ATTRIBUTE_HIDDEN
|
179 FILE_ATTRIBUTE_DIRECTORY
|
180 FILE_ATTRIBUTE_READONLY
));
182 if (vfatFCBIsDirectory(FCB
))
184 if (BooleanFlagOn(BasicInfo
->FileAttributes
, FILE_ATTRIBUTE_TEMPORARY
))
186 DPRINT("Setting temporary attribute on a directory!\n");
187 return STATUS_INVALID_PARAMETER
;
190 Attributes
|= FILE_ATTRIBUTE_DIRECTORY
;
194 if (BooleanFlagOn(BasicInfo
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
))
196 DPRINT("Setting directory attribute on a file!\n");
197 return STATUS_INVALID_PARAMETER
;
201 if (Attributes
!= *FCB
->Attributes
)
203 *FCB
->Attributes
= Attributes
;
204 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
205 NotifyFilter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
209 if (vfatVolumeIsFatX(DeviceExt
))
211 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
213 FsdSystemTimeToDosDateTime(DeviceExt
,
214 &BasicInfo
->CreationTime
,
215 &FCB
->entry
.FatX
.CreationDate
,
216 &FCB
->entry
.FatX
.CreationTime
);
217 NotifyFilter
|= FILE_NOTIFY_CHANGE_CREATION
;
220 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
222 FsdSystemTimeToDosDateTime(DeviceExt
,
223 &BasicInfo
->LastAccessTime
,
224 &FCB
->entry
.FatX
.AccessDate
,
225 &FCB
->entry
.FatX
.AccessTime
);
226 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
229 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
231 FsdSystemTimeToDosDateTime(DeviceExt
,
232 &BasicInfo
->LastWriteTime
,
233 &FCB
->entry
.FatX
.UpdateDate
,
234 &FCB
->entry
.FatX
.UpdateTime
);
235 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
240 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
242 FsdSystemTimeToDosDateTime(DeviceExt
,
243 &BasicInfo
->CreationTime
,
244 &FCB
->entry
.Fat
.CreationDate
,
245 &FCB
->entry
.Fat
.CreationTime
);
246 NotifyFilter
|= FILE_NOTIFY_CHANGE_CREATION
;
249 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
251 FsdSystemTimeToDosDateTime(DeviceExt
,
252 &BasicInfo
->LastAccessTime
,
253 &FCB
->entry
.Fat
.AccessDate
,
255 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
258 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
260 FsdSystemTimeToDosDateTime(DeviceExt
,
261 &BasicInfo
->LastWriteTime
,
262 &FCB
->entry
.Fat
.UpdateDate
,
263 &FCB
->entry
.Fat
.UpdateTime
);
264 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
268 VfatUpdateEntry(DeviceExt
, FCB
);
270 if (NotifyFilter
!= 0)
272 vfatReportChange(DeviceExt
,
275 FILE_ACTION_MODIFIED
);
278 return STATUS_SUCCESS
;
282 VfatGetBasicInformation(
283 PFILE_OBJECT FileObject
,
285 PDEVICE_EXTENSION DeviceExt
,
286 PFILE_BASIC_INFORMATION BasicInfo
,
289 UNREFERENCED_PARAMETER(FileObject
);
291 DPRINT("VfatGetBasicInformation()\n");
293 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
294 return STATUS_BUFFER_OVERFLOW
;
296 if (vfatVolumeIsFatX(DeviceExt
))
298 FsdDosDateTimeToSystemTime(DeviceExt
,
299 FCB
->entry
.FatX
.CreationDate
,
300 FCB
->entry
.FatX
.CreationTime
,
301 &BasicInfo
->CreationTime
);
302 FsdDosDateTimeToSystemTime(DeviceExt
,
303 FCB
->entry
.FatX
.AccessDate
,
304 FCB
->entry
.FatX
.AccessTime
,
305 &BasicInfo
->LastAccessTime
);
306 FsdDosDateTimeToSystemTime(DeviceExt
,
307 FCB
->entry
.FatX
.UpdateDate
,
308 FCB
->entry
.FatX
.UpdateTime
,
309 &BasicInfo
->LastWriteTime
);
310 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
314 FsdDosDateTimeToSystemTime(DeviceExt
,
315 FCB
->entry
.Fat
.CreationDate
,
316 FCB
->entry
.Fat
.CreationTime
,
317 &BasicInfo
->CreationTime
);
318 FsdDosDateTimeToSystemTime(DeviceExt
,
319 FCB
->entry
.Fat
.AccessDate
,
321 &BasicInfo
->LastAccessTime
);
322 FsdDosDateTimeToSystemTime(DeviceExt
,
323 FCB
->entry
.Fat
.UpdateDate
,
324 FCB
->entry
.Fat
.UpdateTime
,
325 &BasicInfo
->LastWriteTime
);
326 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
329 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
330 /* Synthesize FILE_ATTRIBUTE_NORMAL */
331 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
332 FILE_ATTRIBUTE_ARCHIVE
|
333 FILE_ATTRIBUTE_SYSTEM
|
334 FILE_ATTRIBUTE_HIDDEN
|
335 FILE_ATTRIBUTE_READONLY
)))
337 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
338 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
340 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
342 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
343 return STATUS_SUCCESS
;
349 VfatSetDispositionInformation(
350 PFILE_OBJECT FileObject
,
352 PDEVICE_EXTENSION DeviceExt
,
353 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
355 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
357 ASSERT(DeviceExt
!= NULL
);
358 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
361 if (!DispositionInfo
->DeleteFile
)
363 /* undelete the file */
364 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
365 FileObject
->DeletePending
= FALSE
;
366 return STATUS_SUCCESS
;
369 if (BooleanFlagOn(FCB
->Flags
, FCB_DELETE_PENDING
))
371 /* stream already marked for deletion. just update the file object */
372 FileObject
->DeletePending
= TRUE
;
373 return STATUS_SUCCESS
;
376 if (vfatFCBIsReadOnly(FCB
))
378 return STATUS_CANNOT_DELETE
;
381 if (vfatFCBIsRoot(FCB
) ||
382 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
383 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
385 /* we cannot delete a '.', '..' or the root directory */
386 return STATUS_ACCESS_DENIED
;
389 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
391 /* can't delete a file if its mapped into a process */
393 DPRINT("MmFlushImageSection returned FALSE\n");
394 return STATUS_CANNOT_DELETE
;
397 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(DeviceExt
, FCB
))
399 /* can't delete a non-empty directory */
401 return STATUS_DIRECTORY_NOT_EMPTY
;
405 FCB
->Flags
|= FCB_DELETE_PENDING
;
406 FileObject
->DeletePending
= TRUE
;
408 return STATUS_SUCCESS
;
412 vfatPrepareTargetForRename(
413 IN PDEVICE_EXTENSION DeviceExt
,
414 IN PVFATFCB
* ParentFCB
,
415 IN PUNICODE_STRING NewName
,
416 IN BOOLEAN ReplaceIfExists
,
417 IN PUNICODE_STRING ParentName
,
418 OUT PBOOLEAN Deleted
)
423 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
426 /* Try to open target */
427 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
429 if (NT_SUCCESS(Status
))
431 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
432 /* Check whether we are allowed to replace */
435 /* If that's a directory or a read-only file, we're not allowed */
436 if (vfatFCBIsDirectory(TargetFcb
) || vfatFCBIsReadOnly(TargetFcb
))
438 DPRINT("And this is a readonly file!\n");
439 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
441 vfatReleaseFCB(DeviceExt
, TargetFcb
);
442 return STATUS_OBJECT_NAME_COLLISION
;
446 /* If we still have a file object, close it. */
447 if (TargetFcb
->FileObject
)
449 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
451 DPRINT("MmFlushImageSection failed.\n");
452 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
454 vfatReleaseFCB(DeviceExt
, TargetFcb
);
455 return STATUS_ACCESS_DENIED
;
458 TargetFcb
->FileObject
->DeletePending
= TRUE
;
459 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
462 /* If we are here, ensure the file isn't open by anyone! */
463 if (TargetFcb
->OpenHandleCount
!= 0)
465 DPRINT("There are still open handles for this file.\n");
466 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
468 vfatReleaseFCB(DeviceExt
, TargetFcb
);
469 return STATUS_ACCESS_DENIED
;
472 /* Effectively delete old file to allow renaming */
473 DPRINT("Effectively deleting the file.\n");
474 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
475 vfatReleaseFCB(DeviceExt
, TargetFcb
);
477 return STATUS_SUCCESS
;
481 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
483 vfatReleaseFCB(DeviceExt
, TargetFcb
);
484 return STATUS_OBJECT_NAME_COLLISION
;
487 else if (*ParentFCB
!= NULL
)
489 return STATUS_SUCCESS
;
498 IsThereAChildOpened(PVFATFCB FCB
)
503 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
505 VolFCB
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
506 if (VolFCB
->OpenHandleCount
!= 0)
508 ASSERT(VolFCB
->parentFcb
== FCB
);
509 DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB
->PathNameU
, VolFCB
->RefCount
, VolFCB
->OpenHandleCount
);
513 if (vfatFCBIsDirectory(VolFCB
) && !IsListEmpty(&VolFCB
->ParentListHead
))
515 if (IsThereAChildOpened(VolFCB
))
528 PDEVICE_EXTENSION DeviceExt
,
534 if (IsListEmpty(&FCB
->ParentListHead
))
537 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
541 Child
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
542 DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child
->PathNameU
, Child
->RefCount
, FCB
->RefCount
);
544 Status
= vfatSetFCBNewDirName(DeviceExt
, Child
, FCB
);
545 if (!NT_SUCCESS(Status
))
548 if (vfatFCBIsDirectory(Child
))
550 VfatRenameChildFCB(DeviceExt
, Child
);
556 * FUNCTION: Set the file name information
560 VfatSetRenameInformation(
561 PFILE_OBJECT FileObject
,
563 PDEVICE_EXTENSION DeviceExt
,
564 PFILE_RENAME_INFORMATION RenameInfo
,
565 PFILE_OBJECT TargetFileObject
)
567 #ifdef NASSERTS_RENAME
568 #pragma push_macro("ASSERT")
570 #define ASSERT(x) ((VOID) 0)
573 UNICODE_STRING NewName
;
574 UNICODE_STRING SourcePath
;
575 UNICODE_STRING SourceFile
;
576 UNICODE_STRING NewPath
;
577 UNICODE_STRING NewFile
;
578 PFILE_OBJECT RootFileObject
;
580 UNICODE_STRING RenameInfoString
;
582 IO_STATUS_BLOCK IoStatusBlock
;
583 OBJECT_ATTRIBUTES ObjectAttributes
;
585 BOOLEAN DeletedTarget
;
586 ULONG OldReferences
, NewReferences
;
589 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
591 /* Disallow renaming root */
592 if (vfatFCBIsRoot(FCB
))
594 return STATUS_INVALID_PARAMETER
;
597 OldReferences
= FCB
->parentFcb
->RefCount
;
598 #ifdef NASSERTS_RENAME
599 UNREFERENCED_PARAMETER(OldReferences
);
602 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
603 if (RenameInfo
->RootDirectory
!= NULL
)
605 /* We cannot tolerate relative opening with a full path */
606 if (RenameInfo
->FileName
[0] == L
'\\')
608 return STATUS_OBJECT_NAME_INVALID
;
611 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
615 (PVOID
*)&RootFileObject
,
617 if (!NT_SUCCESS(Status
))
622 RootFCB
= RootFileObject
->FsContext
;
625 RtlInitEmptyUnicodeString(&NewName
, NULL
, 0);
628 if (TargetFileObject
== NULL
)
630 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
631 * information supplied by the user
634 /* First, setup a string we'll work on */
635 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
636 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
637 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
639 /* Check whether we have FQN */
640 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
642 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
643 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
644 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
645 RenameInfoString
.Buffer
[4] <= L
'Z'))
647 /* If so, open its target directory */
648 InitializeObjectAttributes(&ObjectAttributes
,
650 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
653 Status
= IoCreateFile(&TargetHandle
,
654 FILE_WRITE_DATA
| SYNCHRONIZE
,
658 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
660 FILE_OPEN_FOR_BACKUP_INTENT
,
664 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
665 if (!NT_SUCCESS(Status
))
670 /* Get its FO to get the FCB */
671 Status
= ObReferenceObjectByHandle(TargetHandle
,
675 (PVOID
*)&TargetFileObject
,
677 if (!NT_SUCCESS(Status
))
679 ZwClose(TargetHandle
);
683 /* Are we working on the same volume? */
684 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
686 ObDereferenceObject(TargetFileObject
);
687 ZwClose(TargetHandle
);
688 TargetFileObject
= NULL
;
689 Status
= STATUS_NOT_SAME_DEVICE
;
696 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
697 if (RenameInfo
->RootDirectory
!= NULL
)
699 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
701 else if (RenameInfo
->FileName
[0] != L
'\\')
703 /* We don't have full path, and we don't have root directory:
704 * => we move inside the same directory
706 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
708 else if (TargetFileObject
!= NULL
)
711 * => we need to use its correct path
713 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
716 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
717 if (NewName
.Buffer
== NULL
)
719 if (TargetFileObject
!= NULL
)
721 ObDereferenceObject(TargetFileObject
);
722 ZwClose(TargetHandle
);
723 TargetFileObject
= NULL
;
725 Status
= STATUS_INSUFFICIENT_RESOURCES
;
729 if (RenameInfo
->RootDirectory
!= NULL
)
731 /* Here, copy first absolute and then append relative */
732 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
733 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
734 NewName
.Length
+= sizeof(WCHAR
);
735 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
737 else if (RenameInfo
->FileName
[0] != L
'\\')
739 /* Here, copy first work directory and then append filename */
740 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
741 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
742 NewName
.Length
+= sizeof(WCHAR
);
743 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
745 else if (TargetFileObject
!= NULL
)
747 /* Here, copy first path name and then append filename */
748 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
749 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
750 NewName
.Length
+= sizeof(WCHAR
);
751 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
755 /* Here we should have full path, so simply copy it */
756 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
759 /* Do we have to cleanup some stuff? */
760 if (TargetFileObject
!= NULL
)
762 ObDereferenceObject(TargetFileObject
);
763 ZwClose(TargetHandle
);
764 TargetFileObject
= NULL
;
769 /* At that point, we shouldn't care about whether we are relative opening
770 * Target FO FCB should already have full path
773 /* Before constructing string, just make a sanity check (just to be sure!) */
774 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
776 Status
= STATUS_NOT_SAME_DEVICE
;
781 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
782 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
783 if (NewName
.Buffer
== NULL
)
785 Status
= STATUS_INSUFFICIENT_RESOURCES
;
789 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
790 /* If \, it's already backslash terminated, don't add it */
791 if (!vfatFCBIsRoot(TargetFileObject
->FsContext
))
793 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
794 NewName
.Length
+= sizeof(WCHAR
);
796 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
799 /* Explode our paths to get path & filename */
800 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
801 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
802 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
803 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
805 if (vfatFCBIsDirectory(FCB
) && !IsListEmpty(&FCB
->ParentListHead
))
807 if (IsThereAChildOpened(FCB
))
809 Status
= STATUS_ACCESS_DENIED
;
810 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
815 /* Are we working in place? */
816 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
818 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
820 Status
= STATUS_SUCCESS
;
821 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
825 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
827 vfatReportChange(DeviceExt
,
829 (vfatFCBIsDirectory(FCB
) ?
830 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
831 FILE_ACTION_RENAMED_OLD_NAME
);
832 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
833 if (NT_SUCCESS(Status
))
835 vfatReportChange(DeviceExt
,
837 (vfatFCBIsDirectory(FCB
) ?
838 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
839 FILE_ACTION_RENAMED_NEW_NAME
);
844 /* Try to find target */
845 ParentFCB
= FCB
->parentFcb
;
846 vfatGrabFCB(DeviceExt
, ParentFCB
);
847 Status
= vfatPrepareTargetForRename(DeviceExt
,
850 RenameInfo
->ReplaceIfExists
,
853 if (!NT_SUCCESS(Status
))
855 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
856 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
860 vfatReportChange(DeviceExt
,
862 (vfatFCBIsDirectory(FCB
) ?
863 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
864 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
));
865 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
866 if (NT_SUCCESS(Status
))
870 vfatReportChange(DeviceExt
,
872 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
873 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
874 FILE_ACTION_MODIFIED
);
878 vfatReportChange(DeviceExt
,
880 (vfatFCBIsDirectory(FCB
) ?
881 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
882 FILE_ACTION_RENAMED_NEW_NAME
);
887 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
888 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
893 /* Try to find target */
895 OldParent
= FCB
->parentFcb
;
896 #ifdef NASSERTS_RENAME
897 UNREFERENCED_PARAMETER(OldParent
);
899 Status
= vfatPrepareTargetForRename(DeviceExt
,
902 RenameInfo
->ReplaceIfExists
,
905 if (!NT_SUCCESS(Status
))
907 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
911 NewReferences
= ParentFCB
->RefCount
;
912 #ifdef NASSERTS_RENAME
913 UNREFERENCED_PARAMETER(NewReferences
);
916 vfatReportChange(DeviceExt
,
918 (vfatFCBIsDirectory(FCB
) ?
919 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
920 FILE_ACTION_REMOVED
);
921 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
922 if (NT_SUCCESS(Status
))
926 vfatReportChange(DeviceExt
,
928 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
929 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
930 FILE_ACTION_MODIFIED
);
934 vfatReportChange(DeviceExt
,
936 (vfatFCBIsDirectory(FCB
) ?
937 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
943 if (NT_SUCCESS(Status
) && vfatFCBIsDirectory(FCB
))
945 VfatRenameChildFCB(DeviceExt
, FCB
);
948 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
949 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
951 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
952 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
953 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
956 #ifdef NASSERTS_RENAME
957 #pragma pop_macro("ASSERT")
962 * FUNCTION: Retrieve the file name information
966 VfatGetNameInformation(
967 PFILE_OBJECT FileObject
,
969 PDEVICE_EXTENSION DeviceExt
,
970 PFILE_NAME_INFORMATION NameInfo
,
975 UNREFERENCED_PARAMETER(FileObject
);
976 UNREFERENCED_PARAMETER(DeviceExt
);
978 ASSERT(NameInfo
!= NULL
);
981 /* If buffer can't hold at least the file name length, bail out */
982 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
983 return STATUS_BUFFER_OVERFLOW
;
985 /* Save file name length, and as much file len, as buffer length allows */
986 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
988 /* Calculate amount of bytes to copy not to overflow the buffer */
989 BytesToCopy
= min(FCB
->PathNameU
.Length
,
990 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
992 /* Fill in the bytes */
993 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
995 /* Check if we could write more but are not able to */
996 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
998 /* Return number of bytes written */
999 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
1000 return STATUS_BUFFER_OVERFLOW
;
1003 /* We filled up as many bytes, as needed */
1004 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
1006 return STATUS_SUCCESS
;
1011 VfatGetInternalInformation(
1013 PDEVICE_EXTENSION DeviceExt
,
1014 PFILE_INTERNAL_INFORMATION InternalInfo
,
1015 PULONG BufferLength
)
1017 ASSERT(InternalInfo
);
1020 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
1021 return STATUS_BUFFER_OVERFLOW
;
1023 InternalInfo
->IndexNumber
.QuadPart
= (LONGLONG
)vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
) * DeviceExt
->FatInfo
.BytesPerCluster
;
1025 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
1026 return STATUS_SUCCESS
;
1031 * FUNCTION: Retrieve the file network open information
1035 VfatGetNetworkOpenInformation(
1037 PDEVICE_EXTENSION DeviceExt
,
1038 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
1039 PULONG BufferLength
)
1041 ASSERT(NetworkInfo
);
1044 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
1045 return(STATUS_BUFFER_OVERFLOW
);
1047 if (vfatVolumeIsFatX(DeviceExt
))
1049 FsdDosDateTimeToSystemTime(DeviceExt
,
1050 Fcb
->entry
.FatX
.CreationDate
,
1051 Fcb
->entry
.FatX
.CreationTime
,
1052 &NetworkInfo
->CreationTime
);
1053 FsdDosDateTimeToSystemTime(DeviceExt
,
1054 Fcb
->entry
.FatX
.AccessDate
,
1055 Fcb
->entry
.FatX
.AccessTime
,
1056 &NetworkInfo
->LastAccessTime
);
1057 FsdDosDateTimeToSystemTime(DeviceExt
,
1058 Fcb
->entry
.FatX
.UpdateDate
,
1059 Fcb
->entry
.FatX
.UpdateTime
,
1060 &NetworkInfo
->LastWriteTime
);
1061 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1065 FsdDosDateTimeToSystemTime(DeviceExt
,
1066 Fcb
->entry
.Fat
.CreationDate
,
1067 Fcb
->entry
.Fat
.CreationTime
,
1068 &NetworkInfo
->CreationTime
);
1069 FsdDosDateTimeToSystemTime(DeviceExt
,
1070 Fcb
->entry
.Fat
.AccessDate
,
1072 &NetworkInfo
->LastAccessTime
);
1073 FsdDosDateTimeToSystemTime(DeviceExt
,
1074 Fcb
->entry
.Fat
.UpdateDate
,
1075 Fcb
->entry
.Fat
.UpdateTime
,
1076 &NetworkInfo
->LastWriteTime
);
1077 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1080 if (vfatFCBIsDirectory(Fcb
))
1082 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1083 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1087 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1088 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1091 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1092 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1093 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1094 FILE_ATTRIBUTE_ARCHIVE
|
1095 FILE_ATTRIBUTE_SYSTEM
|
1096 FILE_ATTRIBUTE_HIDDEN
|
1097 FILE_ATTRIBUTE_READONLY
)))
1099 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1100 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1103 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1104 return STATUS_SUCCESS
;
1110 VfatGetEaInformation(
1111 PFILE_OBJECT FileObject
,
1113 PDEVICE_EXTENSION DeviceExt
,
1114 PFILE_EA_INFORMATION Info
,
1115 PULONG BufferLength
)
1117 UNREFERENCED_PARAMETER(FileObject
);
1118 UNREFERENCED_PARAMETER(Fcb
);
1120 /* FIXME - use SEH to access the buffer! */
1122 *BufferLength
-= sizeof(*Info
);
1123 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1124 DeviceExt
->FatInfo
.FatType
== FAT16
)
1127 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1129 return STATUS_SUCCESS
;
1134 * FUNCTION: Retrieve the all file information
1138 VfatGetAllInformation(
1139 PFILE_OBJECT FileObject
,
1141 PDEVICE_EXTENSION DeviceExt
,
1142 PFILE_ALL_INFORMATION Info
,
1143 PULONG BufferLength
)
1150 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1151 return STATUS_BUFFER_OVERFLOW
;
1153 *BufferLength
-= (sizeof(FILE_ACCESS_INFORMATION
) + sizeof(FILE_MODE_INFORMATION
) + sizeof(FILE_ALIGNMENT_INFORMATION
));
1155 /* Basic Information */
1156 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceExt
, &Info
->BasicInformation
, BufferLength
);
1157 if (!NT_SUCCESS(Status
)) return Status
;
1158 /* Standard Information */
1159 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1160 if (!NT_SUCCESS(Status
)) return Status
;
1161 /* Internal Information */
1162 Status
= VfatGetInternalInformation(Fcb
, DeviceExt
, &Info
->InternalInformation
, BufferLength
);
1163 if (!NT_SUCCESS(Status
)) return Status
;
1164 /* EA Information */
1165 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceExt
, &Info
->EaInformation
, BufferLength
);
1166 if (!NT_SUCCESS(Status
)) return Status
;
1167 /* Position Information */
1168 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceExt
, &Info
->PositionInformation
, BufferLength
);
1169 if (!NT_SUCCESS(Status
)) return Status
;
1170 /* Name Information */
1171 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceExt
, &Info
->NameInformation
, BufferLength
);
1179 PFILE_OBJECT FileObject
,
1187 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, ClusterSize
);
1191 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1193 if (!vfatFCBIsDirectory(Fcb
))
1196 Fcb
->entry
.FatX
.FileSize
= Size
;
1198 Fcb
->entry
.Fat
.FileSize
= Size
;
1200 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1201 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1203 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1207 VfatSetAllocationSizeInformation(
1208 PFILE_OBJECT FileObject
,
1210 PDEVICE_EXTENSION DeviceExt
,
1211 PLARGE_INTEGER AllocationSize
)
1214 ULONG Cluster
, FirstCluster
;
1217 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1218 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1220 BOOLEAN AllocSizeChanged
= FALSE
, IsFatX
= vfatVolumeIsFatX(DeviceExt
);
1222 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1223 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1226 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1228 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1230 if (AllocationSize
->u
.HighPart
> 0)
1232 return STATUS_INVALID_PARAMETER
;
1235 if (OldSize
== NewSize
)
1237 return STATUS_SUCCESS
;
1240 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1242 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1244 AllocSizeChanged
= TRUE
;
1245 if (FirstCluster
== 0)
1247 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1248 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1249 if (!NT_SUCCESS(Status
))
1251 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1255 if (FirstCluster
== 0xffffffff)
1257 return STATUS_DISK_FULL
;
1260 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1261 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1263 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1266 NCluster
= Cluster
= FirstCluster
;
1267 Status
= STATUS_SUCCESS
;
1268 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1270 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1271 WriteCluster(DeviceExt
, Cluster
, 0);
1274 return STATUS_DISK_FULL
;
1279 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1283 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1285 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1286 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1290 ASSERT((FirstCluster
>> 16) == 0);
1291 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1297 if (Fcb
->LastCluster
> 0)
1299 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1301 Cluster
= Fcb
->LastCluster
;
1302 Status
= STATUS_SUCCESS
;
1306 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1307 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1313 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1314 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1318 if (!NT_SUCCESS(Status
))
1323 Fcb
->LastCluster
= Cluster
;
1324 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1326 /* FIXME: Check status */
1327 /* Cluster points now to the last cluster within the chain */
1328 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1329 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1331 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1335 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1336 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1338 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1340 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1341 WriteCluster(DeviceExt
, Cluster
, 0);
1344 return STATUS_DISK_FULL
;
1347 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1349 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1351 DPRINT("Check for the ability to set file size\n");
1352 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1353 (PLARGE_INTEGER
)AllocationSize
))
1355 DPRINT("Couldn't set file size!\n");
1356 return STATUS_USER_MAPPED_FILE
;
1358 DPRINT("Can set file size\n");
1360 AllocSizeChanged
= TRUE
;
1361 /* FIXME: Use the cached cluster/offset better way. */
1362 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1363 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1366 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1367 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1371 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1372 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1379 Fcb
->entry
.FatX
.FirstCluster
= 0;
1383 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1385 Fcb
->entry
.Fat
.FirstCluster
= 0;
1386 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1390 Fcb
->entry
.Fat
.FirstCluster
= 0;
1394 NCluster
= Cluster
= FirstCluster
;
1395 Status
= STATUS_SUCCESS
;
1398 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1400 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1401 WriteCluster(DeviceExt
, Cluster
, 0);
1405 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1407 FAT32UpdateFreeClustersCount(DeviceExt
);
1412 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1415 /* Update the on-disk directory entry */
1416 Fcb
->Flags
|= FCB_IS_DIRTY
;
1417 if (AllocSizeChanged
)
1419 VfatUpdateEntry(DeviceExt
, Fcb
);
1421 vfatReportChange(DeviceExt
, Fcb
, FILE_NOTIFY_CHANGE_SIZE
, FILE_ACTION_MODIFIED
);
1423 return STATUS_SUCCESS
;
1427 * FUNCTION: Retrieve the specified file information
1430 VfatQueryInformation(
1431 PVFAT_IRP_CONTEXT IrpContext
)
1433 FILE_INFORMATION_CLASS FileInformationClass
;
1436 NTSTATUS Status
= STATUS_SUCCESS
;
1443 /* INITIALIZATION */
1444 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1445 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1447 DPRINT("VfatQueryInformation is called for '%s'\n",
1448 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1452 DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
1453 IrpContext
->Irp
->IoStatus
.Information
= 0;
1454 return STATUS_INVALID_PARAMETER
;
1457 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1458 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1460 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1462 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1463 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1465 return VfatMarkIrpContextForQueue(IrpContext
);
1469 switch (FileInformationClass
)
1471 case FileStandardInformation
:
1472 Status
= VfatGetStandardInformation(FCB
,
1477 case FilePositionInformation
:
1478 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1480 IrpContext
->DeviceExt
,
1485 case FileBasicInformation
:
1486 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1488 IrpContext
->DeviceExt
,
1493 case FileNameInformation
:
1494 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1496 IrpContext
->DeviceExt
,
1501 case FileInternalInformation
:
1502 Status
= VfatGetInternalInformation(FCB
,
1503 IrpContext
->DeviceExt
,
1508 case FileNetworkOpenInformation
:
1509 Status
= VfatGetNetworkOpenInformation(FCB
,
1510 IrpContext
->DeviceExt
,
1515 case FileAllInformation
:
1516 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1518 IrpContext
->DeviceExt
,
1523 case FileEaInformation
:
1524 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1526 IrpContext
->DeviceExt
,
1531 case FileAlternateNameInformation
:
1532 Status
= STATUS_NOT_IMPLEMENTED
;
1536 Status
= STATUS_INVALID_PARAMETER
;
1539 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1541 ExReleaseResourceLite(&FCB
->MainResource
);
1544 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1545 IrpContext
->Irp
->IoStatus
.Information
=
1546 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1548 IrpContext
->Irp
->IoStatus
.Information
= 0;
1554 * FUNCTION: Retrieve the specified file information
1558 PVFAT_IRP_CONTEXT IrpContext
)
1560 FILE_INFORMATION_CLASS FileInformationClass
;
1562 NTSTATUS Status
= STATUS_SUCCESS
;
1569 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1571 /* INITIALIZATION */
1572 FileInformationClass
=
1573 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1574 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1575 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1577 DPRINT("VfatSetInformation is called for '%s'\n",
1578 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1580 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1581 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1585 DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
1586 IrpContext
->Irp
->IoStatus
.Information
= 0;
1587 return STATUS_INVALID_PARAMETER
;
1590 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1591 the file size would be allowed. If not, we bail with the right error.
1592 We must do this before acquiring the lock. */
1593 if (FileInformationClass
== FileEndOfFileInformation
)
1595 DPRINT("Check for the ability to set file size\n");
1596 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1597 (PLARGE_INTEGER
)SystemBuffer
))
1599 DPRINT("Couldn't set file size!\n");
1600 IrpContext
->Irp
->IoStatus
.Information
= 0;
1601 return STATUS_USER_MAPPED_FILE
;
1603 DPRINT("Can set file size\n");
1607 if (FileInformationClass
== FileRenameInformation
|| FileInformationClass
== FileAllocationInformation
||
1608 FileInformationClass
== FileEndOfFileInformation
|| FileInformationClass
== FileBasicInformation
)
1615 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1616 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1618 return VfatMarkIrpContextForQueue(IrpContext
);
1622 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1624 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1625 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1629 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1632 return VfatMarkIrpContextForQueue(IrpContext
);
1636 switch (FileInformationClass
)
1638 case FilePositionInformation
:
1639 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1643 case FileDispositionInformation
:
1644 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1646 IrpContext
->DeviceExt
,
1650 case FileAllocationInformation
:
1651 case FileEndOfFileInformation
:
1652 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1654 IrpContext
->DeviceExt
,
1655 (PLARGE_INTEGER
)SystemBuffer
);
1658 case FileBasicInformation
:
1659 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1661 IrpContext
->DeviceExt
,
1665 case FileRenameInformation
:
1666 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1668 IrpContext
->DeviceExt
,
1670 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1674 Status
= STATUS_NOT_SUPPORTED
;
1677 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1679 ExReleaseResourceLite(&FCB
->MainResource
);
1684 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1687 IrpContext
->Irp
->IoStatus
.Information
= 0;