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 Attributes
|= FILE_ATTRIBUTE_DIRECTORY
;
188 if (BooleanFlagOn(BasicInfo
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
))
190 DPRINT("Setting directory attribute on a file!\n");
191 return STATUS_INVALID_PARAMETER
;
195 if (Attributes
!= *FCB
->Attributes
)
197 *FCB
->Attributes
= Attributes
;
198 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
199 NotifyFilter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
203 if (vfatVolumeIsFatX(DeviceExt
))
205 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
207 FsdSystemTimeToDosDateTime(DeviceExt
,
208 &BasicInfo
->CreationTime
,
209 &FCB
->entry
.FatX
.CreationDate
,
210 &FCB
->entry
.FatX
.CreationTime
);
211 NotifyFilter
|= FILE_NOTIFY_CHANGE_CREATION
;
214 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
216 FsdSystemTimeToDosDateTime(DeviceExt
,
217 &BasicInfo
->LastAccessTime
,
218 &FCB
->entry
.FatX
.AccessDate
,
219 &FCB
->entry
.FatX
.AccessTime
);
220 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
223 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
225 FsdSystemTimeToDosDateTime(DeviceExt
,
226 &BasicInfo
->LastWriteTime
,
227 &FCB
->entry
.FatX
.UpdateDate
,
228 &FCB
->entry
.FatX
.UpdateTime
);
229 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
234 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
236 FsdSystemTimeToDosDateTime(DeviceExt
,
237 &BasicInfo
->CreationTime
,
238 &FCB
->entry
.Fat
.CreationDate
,
239 &FCB
->entry
.Fat
.CreationTime
);
240 NotifyFilter
|= FILE_NOTIFY_CHANGE_CREATION
;
243 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
245 FsdSystemTimeToDosDateTime(DeviceExt
,
246 &BasicInfo
->LastAccessTime
,
247 &FCB
->entry
.Fat
.AccessDate
,
249 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
252 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
254 FsdSystemTimeToDosDateTime(DeviceExt
,
255 &BasicInfo
->LastWriteTime
,
256 &FCB
->entry
.Fat
.UpdateDate
,
257 &FCB
->entry
.Fat
.UpdateTime
);
258 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
262 VfatUpdateEntry(FCB
, vfatVolumeIsFatX(DeviceExt
));
264 if (NotifyFilter
!= 0)
266 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
267 &(DeviceExt
->NotifyList
),
268 (PSTRING
)&FCB
->PathNameU
,
269 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
270 NULL
, NULL
, NotifyFilter
, FILE_ACTION_MODIFIED
,
274 return STATUS_SUCCESS
;
278 VfatGetBasicInformation(
279 PFILE_OBJECT FileObject
,
281 PDEVICE_EXTENSION DeviceExt
,
282 PFILE_BASIC_INFORMATION BasicInfo
,
285 UNREFERENCED_PARAMETER(FileObject
);
287 DPRINT("VfatGetBasicInformation()\n");
289 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
290 return STATUS_BUFFER_OVERFLOW
;
292 if (vfatVolumeIsFatX(DeviceExt
))
294 FsdDosDateTimeToSystemTime(DeviceExt
,
295 FCB
->entry
.FatX
.CreationDate
,
296 FCB
->entry
.FatX
.CreationTime
,
297 &BasicInfo
->CreationTime
);
298 FsdDosDateTimeToSystemTime(DeviceExt
,
299 FCB
->entry
.FatX
.AccessDate
,
300 FCB
->entry
.FatX
.AccessTime
,
301 &BasicInfo
->LastAccessTime
);
302 FsdDosDateTimeToSystemTime(DeviceExt
,
303 FCB
->entry
.FatX
.UpdateDate
,
304 FCB
->entry
.FatX
.UpdateTime
,
305 &BasicInfo
->LastWriteTime
);
306 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
310 FsdDosDateTimeToSystemTime(DeviceExt
,
311 FCB
->entry
.Fat
.CreationDate
,
312 FCB
->entry
.Fat
.CreationTime
,
313 &BasicInfo
->CreationTime
);
314 FsdDosDateTimeToSystemTime(DeviceExt
,
315 FCB
->entry
.Fat
.AccessDate
,
317 &BasicInfo
->LastAccessTime
);
318 FsdDosDateTimeToSystemTime(DeviceExt
,
319 FCB
->entry
.Fat
.UpdateDate
,
320 FCB
->entry
.Fat
.UpdateTime
,
321 &BasicInfo
->LastWriteTime
);
322 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
325 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
326 /* Synthesize FILE_ATTRIBUTE_NORMAL */
327 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
328 FILE_ATTRIBUTE_ARCHIVE
|
329 FILE_ATTRIBUTE_SYSTEM
|
330 FILE_ATTRIBUTE_HIDDEN
|
331 FILE_ATTRIBUTE_READONLY
)))
333 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
334 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
336 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
338 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
339 return STATUS_SUCCESS
;
345 VfatSetDispositionInformation(
346 PFILE_OBJECT FileObject
,
348 PDEVICE_EXTENSION DeviceExt
,
349 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
351 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
353 ASSERT(DeviceExt
!= NULL
);
354 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
357 if (!DispositionInfo
->DeleteFile
)
359 /* undelete the file */
360 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
361 FileObject
->DeletePending
= FALSE
;
362 return STATUS_SUCCESS
;
365 if (BooleanFlagOn(FCB
->Flags
, FCB_DELETE_PENDING
))
367 /* stream already marked for deletion. just update the file object */
368 FileObject
->DeletePending
= TRUE
;
369 return STATUS_SUCCESS
;
372 if (vfatFCBIsReadOnly(FCB
))
374 return STATUS_CANNOT_DELETE
;
377 if (vfatFCBIsRoot(FCB
) ||
378 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
379 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
381 /* we cannot delete a '.', '..' or the root directory */
382 return STATUS_ACCESS_DENIED
;
385 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
387 /* can't delete a file if its mapped into a process */
389 DPRINT("MmFlushImageSection returned FALSE\n");
390 return STATUS_CANNOT_DELETE
;
393 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(DeviceExt
, FCB
))
395 /* can't delete a non-empty directory */
397 return STATUS_DIRECTORY_NOT_EMPTY
;
401 FCB
->Flags
|= FCB_DELETE_PENDING
;
402 FileObject
->DeletePending
= TRUE
;
404 return STATUS_SUCCESS
;
408 vfatPrepareTargetForRename(
409 IN PDEVICE_EXTENSION DeviceExt
,
410 IN PVFATFCB
* ParentFCB
,
411 IN PUNICODE_STRING NewName
,
412 IN BOOLEAN ReplaceIfExists
,
413 IN PUNICODE_STRING ParentName
,
414 OUT PBOOLEAN Deleted
)
419 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
422 /* Try to open target */
423 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
425 if (NT_SUCCESS(Status
))
427 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
428 /* Check whether we are allowed to replace */
431 /* If that's a directory or a read-only file, we're not allowed */
432 if (vfatFCBIsDirectory(TargetFcb
) || vfatFCBIsReadOnly(TargetFcb
))
434 DPRINT("And this is a readonly file!\n");
435 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
437 vfatReleaseFCB(DeviceExt
, TargetFcb
);
438 return STATUS_OBJECT_NAME_COLLISION
;
442 /* If we still have a file object, close it. */
443 if (TargetFcb
->FileObject
)
445 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
447 DPRINT("MmFlushImageSection failed.\n");
448 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
450 vfatReleaseFCB(DeviceExt
, TargetFcb
);
451 return STATUS_ACCESS_DENIED
;
454 TargetFcb
->FileObject
->DeletePending
= TRUE
;
455 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
458 /* If we are here, ensure the file isn't open by anyone! */
459 if (TargetFcb
->OpenHandleCount
!= 0)
461 DPRINT("There are still open handles for this file.\n");
462 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
464 vfatReleaseFCB(DeviceExt
, TargetFcb
);
465 return STATUS_ACCESS_DENIED
;
468 /* Effectively delete old file to allow renaming */
469 DPRINT("Effectively deleting the file.\n");
470 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
471 vfatReleaseFCB(DeviceExt
, TargetFcb
);
473 return STATUS_SUCCESS
;
477 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
479 vfatReleaseFCB(DeviceExt
, TargetFcb
);
480 return STATUS_OBJECT_NAME_COLLISION
;
483 else if (*ParentFCB
!= NULL
)
485 return STATUS_SUCCESS
;
494 IsThereAChildOpened(PVFATFCB FCB
)
499 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
501 VolFCB
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
502 if (VolFCB
->OpenHandleCount
!= 0)
504 ASSERT(VolFCB
->parentFcb
== FCB
);
505 DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB
->PathNameU
, VolFCB
->RefCount
, VolFCB
->OpenHandleCount
);
509 if (vfatFCBIsDirectory(VolFCB
) && !IsListEmpty(&VolFCB
->ParentListHead
))
511 if (IsThereAChildOpened(VolFCB
))
524 PDEVICE_EXTENSION DeviceExt
,
530 if (IsListEmpty(&FCB
->ParentListHead
))
533 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
537 Child
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
538 DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child
->PathNameU
, Child
->RefCount
, FCB
->RefCount
);
540 Status
= vfatSetFCBNewDirName(DeviceExt
, Child
, FCB
);
541 if (!NT_SUCCESS(Status
))
544 if (vfatFCBIsDirectory(Child
))
546 VfatRenameChildFCB(DeviceExt
, Child
);
552 * FUNCTION: Set the file name information
556 VfatSetRenameInformation(
557 PFILE_OBJECT FileObject
,
559 PDEVICE_EXTENSION DeviceExt
,
560 PFILE_RENAME_INFORMATION RenameInfo
,
561 PFILE_OBJECT TargetFileObject
)
563 #ifdef NASSERTS_RENAME
564 #pragma push_macro("ASSERT")
566 #define ASSERT(x) ((VOID) 0)
569 UNICODE_STRING NewName
;
570 UNICODE_STRING SourcePath
;
571 UNICODE_STRING SourceFile
;
572 UNICODE_STRING NewPath
;
573 UNICODE_STRING NewFile
;
574 PFILE_OBJECT RootFileObject
;
576 UNICODE_STRING RenameInfoString
;
578 IO_STATUS_BLOCK IoStatusBlock
;
579 OBJECT_ATTRIBUTES ObjectAttributes
;
581 BOOLEAN DeletedTarget
;
582 ULONG OldReferences
, NewReferences
;
585 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
587 /* Disallow renaming root */
588 if (vfatFCBIsRoot(FCB
))
590 return STATUS_INVALID_PARAMETER
;
593 OldReferences
= FCB
->parentFcb
->RefCount
;
594 #ifdef NASSERTS_RENAME
595 UNREFERENCED_PARAMETER(OldReferences
);
598 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
599 if (RenameInfo
->RootDirectory
!= NULL
)
601 /* We cannot tolerate relative opening with a full path */
602 if (RenameInfo
->FileName
[0] == L
'\\')
604 return STATUS_OBJECT_NAME_INVALID
;
607 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
611 (PVOID
*)&RootFileObject
,
613 if (!NT_SUCCESS(Status
))
618 RootFCB
= RootFileObject
->FsContext
;
621 RtlInitEmptyUnicodeString(&NewName
, NULL
, 0);
624 if (TargetFileObject
== NULL
)
626 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
627 * information supplied by the user
630 /* First, setup a string we'll work on */
631 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
632 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
633 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
635 /* Check whether we have FQN */
636 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
638 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
639 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
640 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
641 RenameInfoString
.Buffer
[4] <= L
'Z'))
643 /* If so, open its target directory */
644 InitializeObjectAttributes(&ObjectAttributes
,
646 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
649 Status
= IoCreateFile(&TargetHandle
,
650 FILE_WRITE_DATA
| SYNCHRONIZE
,
654 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
656 FILE_OPEN_FOR_BACKUP_INTENT
,
660 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
661 if (!NT_SUCCESS(Status
))
666 /* Get its FO to get the FCB */
667 Status
= ObReferenceObjectByHandle(TargetHandle
,
671 (PVOID
*)&TargetFileObject
,
673 if (!NT_SUCCESS(Status
))
675 ZwClose(TargetHandle
);
679 /* Are we working on the same volume? */
680 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
682 ObDereferenceObject(TargetFileObject
);
683 ZwClose(TargetHandle
);
684 TargetFileObject
= NULL
;
685 Status
= STATUS_NOT_SAME_DEVICE
;
692 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
693 if (RenameInfo
->RootDirectory
!= NULL
)
695 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
697 else if (RenameInfo
->FileName
[0] != L
'\\')
699 /* We don't have full path, and we don't have root directory:
700 * => we move inside the same directory
702 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
704 else if (TargetFileObject
!= NULL
)
707 * => we need to use its correct path
709 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
712 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
713 if (NewName
.Buffer
== NULL
)
715 if (TargetFileObject
!= NULL
)
717 ObDereferenceObject(TargetFileObject
);
718 ZwClose(TargetHandle
);
719 TargetFileObject
= NULL
;
721 Status
= STATUS_INSUFFICIENT_RESOURCES
;
725 if (RenameInfo
->RootDirectory
!= NULL
)
727 /* Here, copy first absolute and then append relative */
728 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
729 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
730 NewName
.Length
+= sizeof(WCHAR
);
731 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
733 else if (RenameInfo
->FileName
[0] != L
'\\')
735 /* Here, copy first work directory and then append filename */
736 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
737 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
738 NewName
.Length
+= sizeof(WCHAR
);
739 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
741 else if (TargetFileObject
!= NULL
)
743 /* Here, copy first path name and then append filename */
744 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
745 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
746 NewName
.Length
+= sizeof(WCHAR
);
747 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
751 /* Here we should have full path, so simply copy it */
752 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
755 /* Do we have to cleanup some stuff? */
756 if (TargetFileObject
!= NULL
)
758 ObDereferenceObject(TargetFileObject
);
759 ZwClose(TargetHandle
);
760 TargetFileObject
= NULL
;
765 /* At that point, we shouldn't care about whether we are relative opening
766 * Target FO FCB should already have full path
769 /* Before constructing string, just make a sanity check (just to be sure!) */
770 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
772 Status
= STATUS_NOT_SAME_DEVICE
;
777 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
778 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
779 if (NewName
.Buffer
== NULL
)
781 Status
= STATUS_INSUFFICIENT_RESOURCES
;
785 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
786 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
787 NewName
.Length
+= sizeof(WCHAR
);
788 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
791 /* Explode our paths to get path & filename */
792 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
793 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
794 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
795 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
797 if (vfatFCBIsDirectory(FCB
) && !IsListEmpty(&FCB
->ParentListHead
))
799 if (IsThereAChildOpened(FCB
))
801 Status
= STATUS_ACCESS_DENIED
;
802 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
807 /* Are we working in place? */
808 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
810 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
812 Status
= STATUS_SUCCESS
;
813 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
817 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
819 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
820 &(DeviceExt
->NotifyList
),
821 (PSTRING
)&FCB
->PathNameU
,
822 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
825 (vfatFCBIsDirectory(FCB
) ?
826 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
827 FILE_ACTION_RENAMED_OLD_NAME
,
829 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
830 if (NT_SUCCESS(Status
))
832 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
833 &(DeviceExt
->NotifyList
),
834 (PSTRING
)&FCB
->PathNameU
,
835 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
838 (vfatFCBIsDirectory(FCB
) ?
839 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
840 FILE_ACTION_RENAMED_NEW_NAME
,
846 /* Try to find target */
847 ParentFCB
= FCB
->parentFcb
;
848 vfatGrabFCB(DeviceExt
, ParentFCB
);
849 Status
= vfatPrepareTargetForRename(DeviceExt
,
852 RenameInfo
->ReplaceIfExists
,
855 if (!NT_SUCCESS(Status
))
857 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
858 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
862 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
863 &(DeviceExt
->NotifyList
),
864 (PSTRING
)&FCB
->PathNameU
,
865 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
868 (vfatFCBIsDirectory(FCB
) ?
869 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
870 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
872 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
873 if (NT_SUCCESS(Status
))
877 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
878 &(DeviceExt
->NotifyList
),
879 (PSTRING
)&FCB
->PathNameU
,
880 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
883 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
884 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
885 FILE_ACTION_MODIFIED
,
890 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
891 &(DeviceExt
->NotifyList
),
892 (PSTRING
)&FCB
->PathNameU
,
893 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
896 (vfatFCBIsDirectory(FCB
) ?
897 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
898 FILE_ACTION_RENAMED_NEW_NAME
,
904 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
905 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
910 /* Try to find target */
912 OldParent
= FCB
->parentFcb
;
913 #ifdef NASSERTS_RENAME
914 UNREFERENCED_PARAMETER(OldParent
);
916 Status
= vfatPrepareTargetForRename(DeviceExt
,
919 RenameInfo
->ReplaceIfExists
,
922 if (!NT_SUCCESS(Status
))
924 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
928 NewReferences
= ParentFCB
->RefCount
;
929 #ifdef NASSERTS_RENAME
930 UNREFERENCED_PARAMETER(NewReferences
);
933 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
934 &(DeviceExt
->NotifyList
),
935 (PSTRING
)&FCB
->PathNameU
,
936 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
939 (vfatFCBIsDirectory(FCB
) ?
940 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
943 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
944 if (NT_SUCCESS(Status
))
948 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
949 &(DeviceExt
->NotifyList
),
950 (PSTRING
)&FCB
->PathNameU
,
951 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
954 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
955 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
956 FILE_ACTION_MODIFIED
,
961 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
962 &(DeviceExt
->NotifyList
),
963 (PSTRING
)&FCB
->PathNameU
,
964 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
967 (vfatFCBIsDirectory(FCB
) ?
968 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
975 if (NT_SUCCESS(Status
) && vfatFCBIsDirectory(FCB
))
977 VfatRenameChildFCB(DeviceExt
, FCB
);
980 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
981 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
983 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
984 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
985 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
988 #ifdef NASSERTS_RENAME
989 #pragma pop_macro("ASSERT")
994 * FUNCTION: Retrieve the file name information
998 VfatGetNameInformation(
999 PFILE_OBJECT FileObject
,
1001 PDEVICE_EXTENSION DeviceExt
,
1002 PFILE_NAME_INFORMATION NameInfo
,
1003 PULONG BufferLength
)
1007 UNREFERENCED_PARAMETER(FileObject
);
1008 UNREFERENCED_PARAMETER(DeviceExt
);
1010 ASSERT(NameInfo
!= NULL
);
1011 ASSERT(FCB
!= NULL
);
1013 /* If buffer can't hold at least the file name length, bail out */
1014 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
1015 return STATUS_BUFFER_OVERFLOW
;
1017 /* Save file name length, and as much file len, as buffer length allows */
1018 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
1020 /* Calculate amount of bytes to copy not to overflow the buffer */
1021 BytesToCopy
= min(FCB
->PathNameU
.Length
,
1022 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
1024 /* Fill in the bytes */
1025 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
1027 /* Check if we could write more but are not able to */
1028 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
1030 /* Return number of bytes written */
1031 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
1032 return STATUS_BUFFER_OVERFLOW
;
1035 /* We filled up as many bytes, as needed */
1036 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
1038 return STATUS_SUCCESS
;
1043 VfatGetInternalInformation(
1045 PDEVICE_EXTENSION DeviceExt
,
1046 PFILE_INTERNAL_INFORMATION InternalInfo
,
1047 PULONG BufferLength
)
1049 ASSERT(InternalInfo
);
1052 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
1053 return STATUS_BUFFER_OVERFLOW
;
1055 InternalInfo
->IndexNumber
.QuadPart
= (LONGLONG
)vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
) * DeviceExt
->FatInfo
.BytesPerCluster
;
1057 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
1058 return STATUS_SUCCESS
;
1063 * FUNCTION: Retrieve the file network open information
1067 VfatGetNetworkOpenInformation(
1069 PDEVICE_EXTENSION DeviceExt
,
1070 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
1071 PULONG BufferLength
)
1073 ASSERT(NetworkInfo
);
1076 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
1077 return(STATUS_BUFFER_OVERFLOW
);
1079 if (vfatVolumeIsFatX(DeviceExt
))
1081 FsdDosDateTimeToSystemTime(DeviceExt
,
1082 Fcb
->entry
.FatX
.CreationDate
,
1083 Fcb
->entry
.FatX
.CreationTime
,
1084 &NetworkInfo
->CreationTime
);
1085 FsdDosDateTimeToSystemTime(DeviceExt
,
1086 Fcb
->entry
.FatX
.AccessDate
,
1087 Fcb
->entry
.FatX
.AccessTime
,
1088 &NetworkInfo
->LastAccessTime
);
1089 FsdDosDateTimeToSystemTime(DeviceExt
,
1090 Fcb
->entry
.FatX
.UpdateDate
,
1091 Fcb
->entry
.FatX
.UpdateTime
,
1092 &NetworkInfo
->LastWriteTime
);
1093 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1097 FsdDosDateTimeToSystemTime(DeviceExt
,
1098 Fcb
->entry
.Fat
.CreationDate
,
1099 Fcb
->entry
.Fat
.CreationTime
,
1100 &NetworkInfo
->CreationTime
);
1101 FsdDosDateTimeToSystemTime(DeviceExt
,
1102 Fcb
->entry
.Fat
.AccessDate
,
1104 &NetworkInfo
->LastAccessTime
);
1105 FsdDosDateTimeToSystemTime(DeviceExt
,
1106 Fcb
->entry
.Fat
.UpdateDate
,
1107 Fcb
->entry
.Fat
.UpdateTime
,
1108 &NetworkInfo
->LastWriteTime
);
1109 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1112 if (vfatFCBIsDirectory(Fcb
))
1114 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1115 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1119 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1120 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1123 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1124 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1125 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1126 FILE_ATTRIBUTE_ARCHIVE
|
1127 FILE_ATTRIBUTE_SYSTEM
|
1128 FILE_ATTRIBUTE_HIDDEN
|
1129 FILE_ATTRIBUTE_READONLY
)))
1131 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1132 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1135 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1136 return STATUS_SUCCESS
;
1142 VfatGetEaInformation(
1143 PFILE_OBJECT FileObject
,
1145 PDEVICE_EXTENSION DeviceExt
,
1146 PFILE_EA_INFORMATION Info
,
1147 PULONG BufferLength
)
1149 UNREFERENCED_PARAMETER(FileObject
);
1150 UNREFERENCED_PARAMETER(Fcb
);
1152 /* FIXME - use SEH to access the buffer! */
1154 *BufferLength
-= sizeof(*Info
);
1155 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1156 DeviceExt
->FatInfo
.FatType
== FAT16
)
1159 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1161 return STATUS_SUCCESS
;
1166 * FUNCTION: Retrieve the all file information
1170 VfatGetAllInformation(
1171 PFILE_OBJECT FileObject
,
1173 PDEVICE_EXTENSION DeviceExt
,
1174 PFILE_ALL_INFORMATION Info
,
1175 PULONG BufferLength
)
1182 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1183 return STATUS_BUFFER_OVERFLOW
;
1185 /* Basic Information */
1186 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceExt
, &Info
->BasicInformation
, BufferLength
);
1187 if (!NT_SUCCESS(Status
)) return Status
;
1188 /* Standard Information */
1189 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1190 if (!NT_SUCCESS(Status
)) return Status
;
1191 /* Internal Information */
1192 Status
= VfatGetInternalInformation(Fcb
, DeviceExt
, &Info
->InternalInformation
, BufferLength
);
1193 if (!NT_SUCCESS(Status
)) return Status
;
1194 /* EA Information */
1195 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceExt
, &Info
->EaInformation
, BufferLength
);
1196 if (!NT_SUCCESS(Status
)) return Status
;
1197 /* Access Information: The IO-Manager adds this information */
1198 *BufferLength
-= sizeof(FILE_ACCESS_INFORMATION
);
1199 /* Position Information */
1200 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceExt
, &Info
->PositionInformation
, BufferLength
);
1201 if (!NT_SUCCESS(Status
)) return Status
;
1202 /* Mode Information: The IO-Manager adds this information */
1203 *BufferLength
-= sizeof(FILE_MODE_INFORMATION
);
1204 /* Alignment Information: The IO-Manager adds this information */
1205 *BufferLength
-= sizeof(FILE_ALIGNMENT_INFORMATION
);
1206 /* Name Information */
1207 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceExt
, &Info
->NameInformation
, BufferLength
);
1215 PFILE_OBJECT FileObject
,
1223 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, ClusterSize
);
1227 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1229 if (!vfatFCBIsDirectory(Fcb
))
1232 Fcb
->entry
.FatX
.FileSize
= Size
;
1234 Fcb
->entry
.Fat
.FileSize
= Size
;
1236 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1237 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1239 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1243 VfatSetAllocationSizeInformation(
1244 PFILE_OBJECT FileObject
,
1246 PDEVICE_EXTENSION DeviceExt
,
1247 PLARGE_INTEGER AllocationSize
)
1250 ULONG Cluster
, FirstCluster
;
1253 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1254 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1256 BOOLEAN AllocSizeChanged
= FALSE
, IsFatX
= vfatVolumeIsFatX(DeviceExt
);
1258 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1259 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1262 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1264 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1266 if (AllocationSize
->u
.HighPart
> 0)
1268 return STATUS_INVALID_PARAMETER
;
1271 if (OldSize
== NewSize
)
1273 return STATUS_SUCCESS
;
1276 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1278 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1280 AllocSizeChanged
= TRUE
;
1281 if (FirstCluster
== 0)
1283 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1284 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1285 if (!NT_SUCCESS(Status
))
1287 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1291 if (FirstCluster
== 0xffffffff)
1293 return STATUS_DISK_FULL
;
1296 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1297 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1299 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1302 NCluster
= Cluster
= FirstCluster
;
1303 Status
= STATUS_SUCCESS
;
1304 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1306 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1307 WriteCluster(DeviceExt
, Cluster
, 0);
1310 return STATUS_DISK_FULL
;
1315 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1319 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1321 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1322 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1326 ASSERT((FirstCluster
>> 16) == 0);
1327 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1333 if (Fcb
->LastCluster
> 0)
1335 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1337 Cluster
= Fcb
->LastCluster
;
1338 Status
= STATUS_SUCCESS
;
1342 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1343 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1349 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1350 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1354 if (!NT_SUCCESS(Status
))
1359 Fcb
->LastCluster
= Cluster
;
1360 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1362 /* FIXME: Check status */
1363 /* Cluster points now to the last cluster within the chain */
1364 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1365 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1367 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1371 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1372 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1374 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1376 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1377 WriteCluster(DeviceExt
, Cluster
, 0);
1380 return STATUS_DISK_FULL
;
1383 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1385 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1387 DPRINT("Check for the ability to set file size\n");
1388 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1389 (PLARGE_INTEGER
)AllocationSize
))
1391 DPRINT("Couldn't set file size!\n");
1392 return STATUS_USER_MAPPED_FILE
;
1394 DPRINT("Can set file size\n");
1396 AllocSizeChanged
= TRUE
;
1397 /* FIXME: Use the cached cluster/offset better way. */
1398 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1399 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1402 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1403 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1407 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1408 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1415 Fcb
->entry
.FatX
.FirstCluster
= 0;
1419 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1421 Fcb
->entry
.Fat
.FirstCluster
= 0;
1422 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1426 Fcb
->entry
.Fat
.FirstCluster
= 0;
1430 NCluster
= Cluster
= FirstCluster
;
1431 Status
= STATUS_SUCCESS
;
1434 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1436 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1437 WriteCluster(DeviceExt
, Cluster
, 0);
1443 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1446 /* Update the on-disk directory entry */
1447 Fcb
->Flags
|= FCB_IS_DIRTY
;
1448 if (AllocSizeChanged
)
1450 VfatUpdateEntry(Fcb
, vfatVolumeIsFatX(DeviceExt
));
1452 return STATUS_SUCCESS
;
1456 * FUNCTION: Retrieve the specified file information
1459 VfatQueryInformation(
1460 PVFAT_IRP_CONTEXT IrpContext
)
1462 FILE_INFORMATION_CLASS FileInformationClass
;
1465 NTSTATUS Status
= STATUS_SUCCESS
;
1472 /* INITIALIZATION */
1473 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1474 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1476 DPRINT("VfatQueryInformation is called for '%s'\n",
1477 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1481 DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
1482 IrpContext
->Irp
->IoStatus
.Information
= 0;
1483 return STATUS_INVALID_PARAMETER
;
1486 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1487 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1489 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1491 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1492 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1494 return VfatMarkIrpContextForQueue(IrpContext
);
1498 switch (FileInformationClass
)
1500 case FileStandardInformation
:
1501 Status
= VfatGetStandardInformation(FCB
,
1506 case FilePositionInformation
:
1507 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1509 IrpContext
->DeviceExt
,
1514 case FileBasicInformation
:
1515 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1517 IrpContext
->DeviceExt
,
1522 case FileNameInformation
:
1523 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1525 IrpContext
->DeviceExt
,
1530 case FileInternalInformation
:
1531 Status
= VfatGetInternalInformation(FCB
,
1532 IrpContext
->DeviceExt
,
1537 case FileNetworkOpenInformation
:
1538 Status
= VfatGetNetworkOpenInformation(FCB
,
1539 IrpContext
->DeviceExt
,
1544 case FileAllInformation
:
1545 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1547 IrpContext
->DeviceExt
,
1552 case FileEaInformation
:
1553 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1555 IrpContext
->DeviceExt
,
1560 case FileAlternateNameInformation
:
1561 Status
= STATUS_NOT_IMPLEMENTED
;
1565 Status
= STATUS_INVALID_PARAMETER
;
1568 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1570 ExReleaseResourceLite(&FCB
->MainResource
);
1573 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1574 IrpContext
->Irp
->IoStatus
.Information
=
1575 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1577 IrpContext
->Irp
->IoStatus
.Information
= 0;
1583 * FUNCTION: Retrieve the specified file information
1587 PVFAT_IRP_CONTEXT IrpContext
)
1589 FILE_INFORMATION_CLASS FileInformationClass
;
1591 NTSTATUS Status
= STATUS_SUCCESS
;
1597 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1599 /* INITIALIZATION */
1600 FileInformationClass
=
1601 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1602 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1603 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1605 DPRINT("VfatSetInformation is called for '%s'\n",
1606 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1608 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1609 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1613 DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
1614 IrpContext
->Irp
->IoStatus
.Information
= 0;
1615 return STATUS_INVALID_PARAMETER
;
1618 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1619 the file size would be allowed. If not, we bail with the right error.
1620 We must do this before acquiring the lock. */
1621 if (FileInformationClass
== FileEndOfFileInformation
)
1623 DPRINT("Check for the ability to set file size\n");
1624 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1625 (PLARGE_INTEGER
)SystemBuffer
))
1627 DPRINT("Couldn't set file size!\n");
1628 IrpContext
->Irp
->IoStatus
.Information
= 0;
1629 return STATUS_USER_MAPPED_FILE
;
1631 DPRINT("Can set file size\n");
1634 if (FileInformationClass
== FileRenameInformation
)
1636 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1637 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1639 return VfatMarkIrpContextForQueue(IrpContext
);
1643 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1645 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1646 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1648 if (FileInformationClass
== FileRenameInformation
)
1650 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1653 return VfatMarkIrpContextForQueue(IrpContext
);
1657 switch (FileInformationClass
)
1659 case FilePositionInformation
:
1660 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1664 case FileDispositionInformation
:
1665 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1667 IrpContext
->DeviceExt
,
1671 case FileAllocationInformation
:
1672 case FileEndOfFileInformation
:
1673 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1675 IrpContext
->DeviceExt
,
1676 (PLARGE_INTEGER
)SystemBuffer
);
1679 case FileBasicInformation
:
1680 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1682 IrpContext
->DeviceExt
,
1686 case FileRenameInformation
:
1687 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1689 IrpContext
->DeviceExt
,
1691 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1695 Status
= STATUS_NOT_SUPPORTED
;
1698 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1700 ExReleaseResourceLite(&FCB
->MainResource
);
1703 if (FileInformationClass
== FileRenameInformation
)
1705 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1708 IrpContext
->Irp
->IoStatus
.Information
= 0;