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 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
791 NewName
.Length
+= sizeof(WCHAR
);
792 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
795 /* Explode our paths to get path & filename */
796 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
797 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
798 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
799 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
801 if (vfatFCBIsDirectory(FCB
) && !IsListEmpty(&FCB
->ParentListHead
))
803 if (IsThereAChildOpened(FCB
))
805 Status
= STATUS_ACCESS_DENIED
;
806 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
811 /* Are we working in place? */
812 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
814 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
816 Status
= STATUS_SUCCESS
;
817 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
821 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
823 vfatReportChange(DeviceExt
,
825 (vfatFCBIsDirectory(FCB
) ?
826 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
827 FILE_ACTION_RENAMED_OLD_NAME
);
828 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
829 if (NT_SUCCESS(Status
))
831 vfatReportChange(DeviceExt
,
833 (vfatFCBIsDirectory(FCB
) ?
834 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
835 FILE_ACTION_RENAMED_NEW_NAME
);
840 /* Try to find target */
841 ParentFCB
= FCB
->parentFcb
;
842 vfatGrabFCB(DeviceExt
, ParentFCB
);
843 Status
= vfatPrepareTargetForRename(DeviceExt
,
846 RenameInfo
->ReplaceIfExists
,
849 if (!NT_SUCCESS(Status
))
851 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
852 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
856 vfatReportChange(DeviceExt
,
858 (vfatFCBIsDirectory(FCB
) ?
859 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
860 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
));
861 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
862 if (NT_SUCCESS(Status
))
866 vfatReportChange(DeviceExt
,
868 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
869 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
870 FILE_ACTION_MODIFIED
);
874 vfatReportChange(DeviceExt
,
876 (vfatFCBIsDirectory(FCB
) ?
877 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
878 FILE_ACTION_RENAMED_NEW_NAME
);
883 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
884 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
889 /* Try to find target */
891 OldParent
= FCB
->parentFcb
;
892 #ifdef NASSERTS_RENAME
893 UNREFERENCED_PARAMETER(OldParent
);
895 Status
= vfatPrepareTargetForRename(DeviceExt
,
898 RenameInfo
->ReplaceIfExists
,
901 if (!NT_SUCCESS(Status
))
903 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
907 NewReferences
= ParentFCB
->RefCount
;
908 #ifdef NASSERTS_RENAME
909 UNREFERENCED_PARAMETER(NewReferences
);
912 vfatReportChange(DeviceExt
,
914 (vfatFCBIsDirectory(FCB
) ?
915 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
916 FILE_ACTION_REMOVED
);
917 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
918 if (NT_SUCCESS(Status
))
922 vfatReportChange(DeviceExt
,
924 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
925 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
926 FILE_ACTION_MODIFIED
);
930 vfatReportChange(DeviceExt
,
932 (vfatFCBIsDirectory(FCB
) ?
933 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
939 if (NT_SUCCESS(Status
) && vfatFCBIsDirectory(FCB
))
941 VfatRenameChildFCB(DeviceExt
, FCB
);
944 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
945 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
947 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
948 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
949 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
952 #ifdef NASSERTS_RENAME
953 #pragma pop_macro("ASSERT")
958 * FUNCTION: Retrieve the file name information
962 VfatGetNameInformation(
963 PFILE_OBJECT FileObject
,
965 PDEVICE_EXTENSION DeviceExt
,
966 PFILE_NAME_INFORMATION NameInfo
,
971 UNREFERENCED_PARAMETER(FileObject
);
972 UNREFERENCED_PARAMETER(DeviceExt
);
974 ASSERT(NameInfo
!= NULL
);
977 /* If buffer can't hold at least the file name length, bail out */
978 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
979 return STATUS_BUFFER_OVERFLOW
;
981 /* Save file name length, and as much file len, as buffer length allows */
982 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
984 /* Calculate amount of bytes to copy not to overflow the buffer */
985 BytesToCopy
= min(FCB
->PathNameU
.Length
,
986 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
988 /* Fill in the bytes */
989 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
991 /* Check if we could write more but are not able to */
992 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
994 /* Return number of bytes written */
995 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
996 return STATUS_BUFFER_OVERFLOW
;
999 /* We filled up as many bytes, as needed */
1000 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
1002 return STATUS_SUCCESS
;
1007 VfatGetInternalInformation(
1009 PDEVICE_EXTENSION DeviceExt
,
1010 PFILE_INTERNAL_INFORMATION InternalInfo
,
1011 PULONG BufferLength
)
1013 ASSERT(InternalInfo
);
1016 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
1017 return STATUS_BUFFER_OVERFLOW
;
1019 InternalInfo
->IndexNumber
.QuadPart
= (LONGLONG
)vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
) * DeviceExt
->FatInfo
.BytesPerCluster
;
1021 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
1022 return STATUS_SUCCESS
;
1027 * FUNCTION: Retrieve the file network open information
1031 VfatGetNetworkOpenInformation(
1033 PDEVICE_EXTENSION DeviceExt
,
1034 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
1035 PULONG BufferLength
)
1037 ASSERT(NetworkInfo
);
1040 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
1041 return(STATUS_BUFFER_OVERFLOW
);
1043 if (vfatVolumeIsFatX(DeviceExt
))
1045 FsdDosDateTimeToSystemTime(DeviceExt
,
1046 Fcb
->entry
.FatX
.CreationDate
,
1047 Fcb
->entry
.FatX
.CreationTime
,
1048 &NetworkInfo
->CreationTime
);
1049 FsdDosDateTimeToSystemTime(DeviceExt
,
1050 Fcb
->entry
.FatX
.AccessDate
,
1051 Fcb
->entry
.FatX
.AccessTime
,
1052 &NetworkInfo
->LastAccessTime
);
1053 FsdDosDateTimeToSystemTime(DeviceExt
,
1054 Fcb
->entry
.FatX
.UpdateDate
,
1055 Fcb
->entry
.FatX
.UpdateTime
,
1056 &NetworkInfo
->LastWriteTime
);
1057 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1061 FsdDosDateTimeToSystemTime(DeviceExt
,
1062 Fcb
->entry
.Fat
.CreationDate
,
1063 Fcb
->entry
.Fat
.CreationTime
,
1064 &NetworkInfo
->CreationTime
);
1065 FsdDosDateTimeToSystemTime(DeviceExt
,
1066 Fcb
->entry
.Fat
.AccessDate
,
1068 &NetworkInfo
->LastAccessTime
);
1069 FsdDosDateTimeToSystemTime(DeviceExt
,
1070 Fcb
->entry
.Fat
.UpdateDate
,
1071 Fcb
->entry
.Fat
.UpdateTime
,
1072 &NetworkInfo
->LastWriteTime
);
1073 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1076 if (vfatFCBIsDirectory(Fcb
))
1078 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1079 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1083 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1084 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1087 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1088 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1089 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1090 FILE_ATTRIBUTE_ARCHIVE
|
1091 FILE_ATTRIBUTE_SYSTEM
|
1092 FILE_ATTRIBUTE_HIDDEN
|
1093 FILE_ATTRIBUTE_READONLY
)))
1095 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1096 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1099 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1100 return STATUS_SUCCESS
;
1106 VfatGetEaInformation(
1107 PFILE_OBJECT FileObject
,
1109 PDEVICE_EXTENSION DeviceExt
,
1110 PFILE_EA_INFORMATION Info
,
1111 PULONG BufferLength
)
1113 UNREFERENCED_PARAMETER(FileObject
);
1114 UNREFERENCED_PARAMETER(Fcb
);
1116 /* FIXME - use SEH to access the buffer! */
1118 *BufferLength
-= sizeof(*Info
);
1119 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1120 DeviceExt
->FatInfo
.FatType
== FAT16
)
1123 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1125 return STATUS_SUCCESS
;
1130 * FUNCTION: Retrieve the all file information
1134 VfatGetAllInformation(
1135 PFILE_OBJECT FileObject
,
1137 PDEVICE_EXTENSION DeviceExt
,
1138 PFILE_ALL_INFORMATION Info
,
1139 PULONG BufferLength
)
1146 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1147 return STATUS_BUFFER_OVERFLOW
;
1149 *BufferLength
-= (sizeof(FILE_ACCESS_INFORMATION
) + sizeof(FILE_MODE_INFORMATION
) + sizeof(FILE_ALIGNMENT_INFORMATION
));
1151 /* Basic Information */
1152 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceExt
, &Info
->BasicInformation
, BufferLength
);
1153 if (!NT_SUCCESS(Status
)) return Status
;
1154 /* Standard Information */
1155 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1156 if (!NT_SUCCESS(Status
)) return Status
;
1157 /* Internal Information */
1158 Status
= VfatGetInternalInformation(Fcb
, DeviceExt
, &Info
->InternalInformation
, BufferLength
);
1159 if (!NT_SUCCESS(Status
)) return Status
;
1160 /* EA Information */
1161 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceExt
, &Info
->EaInformation
, BufferLength
);
1162 if (!NT_SUCCESS(Status
)) return Status
;
1163 /* Position Information */
1164 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceExt
, &Info
->PositionInformation
, BufferLength
);
1165 if (!NT_SUCCESS(Status
)) return Status
;
1166 /* Name Information */
1167 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceExt
, &Info
->NameInformation
, BufferLength
);
1175 PFILE_OBJECT FileObject
,
1183 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, ClusterSize
);
1187 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1189 if (!vfatFCBIsDirectory(Fcb
))
1192 Fcb
->entry
.FatX
.FileSize
= Size
;
1194 Fcb
->entry
.Fat
.FileSize
= Size
;
1196 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1197 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1199 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1203 VfatSetAllocationSizeInformation(
1204 PFILE_OBJECT FileObject
,
1206 PDEVICE_EXTENSION DeviceExt
,
1207 PLARGE_INTEGER AllocationSize
)
1210 ULONG Cluster
, FirstCluster
;
1213 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1214 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1216 BOOLEAN AllocSizeChanged
= FALSE
, IsFatX
= vfatVolumeIsFatX(DeviceExt
);
1218 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1219 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1222 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1224 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1226 if (AllocationSize
->u
.HighPart
> 0)
1228 return STATUS_INVALID_PARAMETER
;
1231 if (OldSize
== NewSize
)
1233 return STATUS_SUCCESS
;
1236 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1238 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1240 AllocSizeChanged
= TRUE
;
1241 if (FirstCluster
== 0)
1243 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1244 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1245 if (!NT_SUCCESS(Status
))
1247 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1251 if (FirstCluster
== 0xffffffff)
1253 return STATUS_DISK_FULL
;
1256 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1257 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1259 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1262 NCluster
= Cluster
= FirstCluster
;
1263 Status
= STATUS_SUCCESS
;
1264 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1266 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1267 WriteCluster(DeviceExt
, Cluster
, 0);
1270 return STATUS_DISK_FULL
;
1275 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1279 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1281 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1282 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1286 ASSERT((FirstCluster
>> 16) == 0);
1287 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1293 if (Fcb
->LastCluster
> 0)
1295 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1297 Cluster
= Fcb
->LastCluster
;
1298 Status
= STATUS_SUCCESS
;
1302 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1303 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1309 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1310 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1314 if (!NT_SUCCESS(Status
))
1319 Fcb
->LastCluster
= Cluster
;
1320 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1322 /* FIXME: Check status */
1323 /* Cluster points now to the last cluster within the chain */
1324 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1325 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1327 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1331 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1332 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1334 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1336 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1337 WriteCluster(DeviceExt
, Cluster
, 0);
1340 return STATUS_DISK_FULL
;
1343 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1345 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1347 DPRINT("Check for the ability to set file size\n");
1348 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1349 (PLARGE_INTEGER
)AllocationSize
))
1351 DPRINT("Couldn't set file size!\n");
1352 return STATUS_USER_MAPPED_FILE
;
1354 DPRINT("Can set file size\n");
1356 AllocSizeChanged
= TRUE
;
1357 /* FIXME: Use the cached cluster/offset better way. */
1358 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1359 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1362 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1363 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1367 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1368 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1375 Fcb
->entry
.FatX
.FirstCluster
= 0;
1379 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1381 Fcb
->entry
.Fat
.FirstCluster
= 0;
1382 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1386 Fcb
->entry
.Fat
.FirstCluster
= 0;
1390 NCluster
= Cluster
= FirstCluster
;
1391 Status
= STATUS_SUCCESS
;
1394 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1396 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1397 WriteCluster(DeviceExt
, Cluster
, 0);
1401 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1403 FAT32UpdateFreeClustersCount(DeviceExt
);
1408 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1411 /* Update the on-disk directory entry */
1412 Fcb
->Flags
|= FCB_IS_DIRTY
;
1413 if (AllocSizeChanged
)
1415 VfatUpdateEntry(DeviceExt
, Fcb
);
1417 vfatReportChange(DeviceExt
, Fcb
, FILE_NOTIFY_CHANGE_SIZE
, FILE_ACTION_MODIFIED
);
1419 return STATUS_SUCCESS
;
1423 * FUNCTION: Retrieve the specified file information
1426 VfatQueryInformation(
1427 PVFAT_IRP_CONTEXT IrpContext
)
1429 FILE_INFORMATION_CLASS FileInformationClass
;
1432 NTSTATUS Status
= STATUS_SUCCESS
;
1439 /* INITIALIZATION */
1440 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1441 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1443 DPRINT("VfatQueryInformation is called for '%s'\n",
1444 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1448 DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
1449 IrpContext
->Irp
->IoStatus
.Information
= 0;
1450 return STATUS_INVALID_PARAMETER
;
1453 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1454 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1456 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1458 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1459 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1461 return VfatMarkIrpContextForQueue(IrpContext
);
1465 switch (FileInformationClass
)
1467 case FileStandardInformation
:
1468 Status
= VfatGetStandardInformation(FCB
,
1473 case FilePositionInformation
:
1474 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1476 IrpContext
->DeviceExt
,
1481 case FileBasicInformation
:
1482 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1484 IrpContext
->DeviceExt
,
1489 case FileNameInformation
:
1490 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1492 IrpContext
->DeviceExt
,
1497 case FileInternalInformation
:
1498 Status
= VfatGetInternalInformation(FCB
,
1499 IrpContext
->DeviceExt
,
1504 case FileNetworkOpenInformation
:
1505 Status
= VfatGetNetworkOpenInformation(FCB
,
1506 IrpContext
->DeviceExt
,
1511 case FileAllInformation
:
1512 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1514 IrpContext
->DeviceExt
,
1519 case FileEaInformation
:
1520 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1522 IrpContext
->DeviceExt
,
1527 case FileAlternateNameInformation
:
1528 Status
= STATUS_NOT_IMPLEMENTED
;
1532 Status
= STATUS_INVALID_PARAMETER
;
1535 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1537 ExReleaseResourceLite(&FCB
->MainResource
);
1540 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1541 IrpContext
->Irp
->IoStatus
.Information
=
1542 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1544 IrpContext
->Irp
->IoStatus
.Information
= 0;
1550 * FUNCTION: Retrieve the specified file information
1554 PVFAT_IRP_CONTEXT IrpContext
)
1556 FILE_INFORMATION_CLASS FileInformationClass
;
1558 NTSTATUS Status
= STATUS_SUCCESS
;
1565 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1567 /* INITIALIZATION */
1568 FileInformationClass
=
1569 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1570 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1571 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1573 DPRINT("VfatSetInformation is called for '%s'\n",
1574 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1576 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1577 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1581 DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
1582 IrpContext
->Irp
->IoStatus
.Information
= 0;
1583 return STATUS_INVALID_PARAMETER
;
1586 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1587 the file size would be allowed. If not, we bail with the right error.
1588 We must do this before acquiring the lock. */
1589 if (FileInformationClass
== FileEndOfFileInformation
)
1591 DPRINT("Check for the ability to set file size\n");
1592 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1593 (PLARGE_INTEGER
)SystemBuffer
))
1595 DPRINT("Couldn't set file size!\n");
1596 IrpContext
->Irp
->IoStatus
.Information
= 0;
1597 return STATUS_USER_MAPPED_FILE
;
1599 DPRINT("Can set file size\n");
1603 if (FileInformationClass
== FileRenameInformation
|| FileInformationClass
== FileAllocationInformation
||
1604 FileInformationClass
== FileEndOfFileInformation
|| FileInformationClass
== FileBasicInformation
)
1611 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1612 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1614 return VfatMarkIrpContextForQueue(IrpContext
);
1618 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1620 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1621 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1625 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1628 return VfatMarkIrpContextForQueue(IrpContext
);
1632 switch (FileInformationClass
)
1634 case FilePositionInformation
:
1635 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1639 case FileDispositionInformation
:
1640 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1642 IrpContext
->DeviceExt
,
1646 case FileAllocationInformation
:
1647 case FileEndOfFileInformation
:
1648 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1650 IrpContext
->DeviceExt
,
1651 (PLARGE_INTEGER
)SystemBuffer
);
1654 case FileBasicInformation
:
1655 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1657 IrpContext
->DeviceExt
,
1661 case FileRenameInformation
:
1662 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1664 IrpContext
->DeviceExt
,
1666 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1670 Status
= STATUS_NOT_SUPPORTED
;
1673 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1675 ExReleaseResourceLite(&FCB
->MainResource
);
1680 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1683 IrpContext
->Irp
->IoStatus
.Information
= 0;