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(FCB
, vfatVolumeIsFatX(DeviceExt
));
270 if (NotifyFilter
!= 0)
272 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
273 &(DeviceExt
->NotifyList
),
274 (PSTRING
)&FCB
->PathNameU
,
275 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
276 NULL
, NULL
, NotifyFilter
, FILE_ACTION_MODIFIED
,
280 return STATUS_SUCCESS
;
284 VfatGetBasicInformation(
285 PFILE_OBJECT FileObject
,
287 PDEVICE_EXTENSION DeviceExt
,
288 PFILE_BASIC_INFORMATION BasicInfo
,
291 UNREFERENCED_PARAMETER(FileObject
);
293 DPRINT("VfatGetBasicInformation()\n");
295 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
296 return STATUS_BUFFER_OVERFLOW
;
298 if (vfatVolumeIsFatX(DeviceExt
))
300 FsdDosDateTimeToSystemTime(DeviceExt
,
301 FCB
->entry
.FatX
.CreationDate
,
302 FCB
->entry
.FatX
.CreationTime
,
303 &BasicInfo
->CreationTime
);
304 FsdDosDateTimeToSystemTime(DeviceExt
,
305 FCB
->entry
.FatX
.AccessDate
,
306 FCB
->entry
.FatX
.AccessTime
,
307 &BasicInfo
->LastAccessTime
);
308 FsdDosDateTimeToSystemTime(DeviceExt
,
309 FCB
->entry
.FatX
.UpdateDate
,
310 FCB
->entry
.FatX
.UpdateTime
,
311 &BasicInfo
->LastWriteTime
);
312 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
316 FsdDosDateTimeToSystemTime(DeviceExt
,
317 FCB
->entry
.Fat
.CreationDate
,
318 FCB
->entry
.Fat
.CreationTime
,
319 &BasicInfo
->CreationTime
);
320 FsdDosDateTimeToSystemTime(DeviceExt
,
321 FCB
->entry
.Fat
.AccessDate
,
323 &BasicInfo
->LastAccessTime
);
324 FsdDosDateTimeToSystemTime(DeviceExt
,
325 FCB
->entry
.Fat
.UpdateDate
,
326 FCB
->entry
.Fat
.UpdateTime
,
327 &BasicInfo
->LastWriteTime
);
328 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
331 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
332 /* Synthesize FILE_ATTRIBUTE_NORMAL */
333 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
334 FILE_ATTRIBUTE_ARCHIVE
|
335 FILE_ATTRIBUTE_SYSTEM
|
336 FILE_ATTRIBUTE_HIDDEN
|
337 FILE_ATTRIBUTE_READONLY
)))
339 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
340 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
342 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
344 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
345 return STATUS_SUCCESS
;
351 VfatSetDispositionInformation(
352 PFILE_OBJECT FileObject
,
354 PDEVICE_EXTENSION DeviceExt
,
355 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
357 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
359 ASSERT(DeviceExt
!= NULL
);
360 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
363 if (!DispositionInfo
->DeleteFile
)
365 /* undelete the file */
366 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
367 FileObject
->DeletePending
= FALSE
;
368 return STATUS_SUCCESS
;
371 if (BooleanFlagOn(FCB
->Flags
, FCB_DELETE_PENDING
))
373 /* stream already marked for deletion. just update the file object */
374 FileObject
->DeletePending
= TRUE
;
375 return STATUS_SUCCESS
;
378 if (vfatFCBIsReadOnly(FCB
))
380 return STATUS_CANNOT_DELETE
;
383 if (vfatFCBIsRoot(FCB
) ||
384 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
385 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
387 /* we cannot delete a '.', '..' or the root directory */
388 return STATUS_ACCESS_DENIED
;
391 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
393 /* can't delete a file if its mapped into a process */
395 DPRINT("MmFlushImageSection returned FALSE\n");
396 return STATUS_CANNOT_DELETE
;
399 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(DeviceExt
, FCB
))
401 /* can't delete a non-empty directory */
403 return STATUS_DIRECTORY_NOT_EMPTY
;
407 FCB
->Flags
|= FCB_DELETE_PENDING
;
408 FileObject
->DeletePending
= TRUE
;
410 return STATUS_SUCCESS
;
414 vfatPrepareTargetForRename(
415 IN PDEVICE_EXTENSION DeviceExt
,
416 IN PVFATFCB
* ParentFCB
,
417 IN PUNICODE_STRING NewName
,
418 IN BOOLEAN ReplaceIfExists
,
419 IN PUNICODE_STRING ParentName
,
420 OUT PBOOLEAN Deleted
)
425 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
428 /* Try to open target */
429 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
431 if (NT_SUCCESS(Status
))
433 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
434 /* Check whether we are allowed to replace */
437 /* If that's a directory or a read-only file, we're not allowed */
438 if (vfatFCBIsDirectory(TargetFcb
) || vfatFCBIsReadOnly(TargetFcb
))
440 DPRINT("And this is a readonly file!\n");
441 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
443 vfatReleaseFCB(DeviceExt
, TargetFcb
);
444 return STATUS_OBJECT_NAME_COLLISION
;
448 /* If we still have a file object, close it. */
449 if (TargetFcb
->FileObject
)
451 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
453 DPRINT("MmFlushImageSection failed.\n");
454 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
456 vfatReleaseFCB(DeviceExt
, TargetFcb
);
457 return STATUS_ACCESS_DENIED
;
460 TargetFcb
->FileObject
->DeletePending
= TRUE
;
461 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
464 /* If we are here, ensure the file isn't open by anyone! */
465 if (TargetFcb
->OpenHandleCount
!= 0)
467 DPRINT("There are still open handles for this file.\n");
468 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
470 vfatReleaseFCB(DeviceExt
, TargetFcb
);
471 return STATUS_ACCESS_DENIED
;
474 /* Effectively delete old file to allow renaming */
475 DPRINT("Effectively deleting the file.\n");
476 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
477 vfatReleaseFCB(DeviceExt
, TargetFcb
);
479 return STATUS_SUCCESS
;
483 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
485 vfatReleaseFCB(DeviceExt
, TargetFcb
);
486 return STATUS_OBJECT_NAME_COLLISION
;
489 else if (*ParentFCB
!= NULL
)
491 return STATUS_SUCCESS
;
500 IsThereAChildOpened(PVFATFCB FCB
)
505 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
507 VolFCB
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
508 if (VolFCB
->OpenHandleCount
!= 0)
510 ASSERT(VolFCB
->parentFcb
== FCB
);
511 DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB
->PathNameU
, VolFCB
->RefCount
, VolFCB
->OpenHandleCount
);
515 if (vfatFCBIsDirectory(VolFCB
) && !IsListEmpty(&VolFCB
->ParentListHead
))
517 if (IsThereAChildOpened(VolFCB
))
530 PDEVICE_EXTENSION DeviceExt
,
536 if (IsListEmpty(&FCB
->ParentListHead
))
539 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
543 Child
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
544 DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child
->PathNameU
, Child
->RefCount
, FCB
->RefCount
);
546 Status
= vfatSetFCBNewDirName(DeviceExt
, Child
, FCB
);
547 if (!NT_SUCCESS(Status
))
550 if (vfatFCBIsDirectory(Child
))
552 VfatRenameChildFCB(DeviceExt
, Child
);
558 * FUNCTION: Set the file name information
562 VfatSetRenameInformation(
563 PFILE_OBJECT FileObject
,
565 PDEVICE_EXTENSION DeviceExt
,
566 PFILE_RENAME_INFORMATION RenameInfo
,
567 PFILE_OBJECT TargetFileObject
)
569 #ifdef NASSERTS_RENAME
570 #pragma push_macro("ASSERT")
572 #define ASSERT(x) ((VOID) 0)
575 UNICODE_STRING NewName
;
576 UNICODE_STRING SourcePath
;
577 UNICODE_STRING SourceFile
;
578 UNICODE_STRING NewPath
;
579 UNICODE_STRING NewFile
;
580 PFILE_OBJECT RootFileObject
;
582 UNICODE_STRING RenameInfoString
;
584 IO_STATUS_BLOCK IoStatusBlock
;
585 OBJECT_ATTRIBUTES ObjectAttributes
;
587 BOOLEAN DeletedTarget
;
588 ULONG OldReferences
, NewReferences
;
591 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
593 /* Disallow renaming root */
594 if (vfatFCBIsRoot(FCB
))
596 return STATUS_INVALID_PARAMETER
;
599 OldReferences
= FCB
->parentFcb
->RefCount
;
600 #ifdef NASSERTS_RENAME
601 UNREFERENCED_PARAMETER(OldReferences
);
604 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
605 if (RenameInfo
->RootDirectory
!= NULL
)
607 /* We cannot tolerate relative opening with a full path */
608 if (RenameInfo
->FileName
[0] == L
'\\')
610 return STATUS_OBJECT_NAME_INVALID
;
613 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
617 (PVOID
*)&RootFileObject
,
619 if (!NT_SUCCESS(Status
))
624 RootFCB
= RootFileObject
->FsContext
;
627 RtlInitEmptyUnicodeString(&NewName
, NULL
, 0);
630 if (TargetFileObject
== NULL
)
632 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
633 * information supplied by the user
636 /* First, setup a string we'll work on */
637 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
638 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
639 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
641 /* Check whether we have FQN */
642 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
644 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
645 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
646 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
647 RenameInfoString
.Buffer
[4] <= L
'Z'))
649 /* If so, open its target directory */
650 InitializeObjectAttributes(&ObjectAttributes
,
652 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
655 Status
= IoCreateFile(&TargetHandle
,
656 FILE_WRITE_DATA
| SYNCHRONIZE
,
660 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
662 FILE_OPEN_FOR_BACKUP_INTENT
,
666 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
667 if (!NT_SUCCESS(Status
))
672 /* Get its FO to get the FCB */
673 Status
= ObReferenceObjectByHandle(TargetHandle
,
677 (PVOID
*)&TargetFileObject
,
679 if (!NT_SUCCESS(Status
))
681 ZwClose(TargetHandle
);
685 /* Are we working on the same volume? */
686 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
688 ObDereferenceObject(TargetFileObject
);
689 ZwClose(TargetHandle
);
690 TargetFileObject
= NULL
;
691 Status
= STATUS_NOT_SAME_DEVICE
;
698 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
699 if (RenameInfo
->RootDirectory
!= NULL
)
701 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
703 else if (RenameInfo
->FileName
[0] != L
'\\')
705 /* We don't have full path, and we don't have root directory:
706 * => we move inside the same directory
708 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
710 else if (TargetFileObject
!= NULL
)
713 * => we need to use its correct path
715 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
718 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
719 if (NewName
.Buffer
== NULL
)
721 if (TargetFileObject
!= NULL
)
723 ObDereferenceObject(TargetFileObject
);
724 ZwClose(TargetHandle
);
725 TargetFileObject
= NULL
;
727 Status
= STATUS_INSUFFICIENT_RESOURCES
;
731 if (RenameInfo
->RootDirectory
!= NULL
)
733 /* Here, copy first absolute and then append relative */
734 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
735 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
736 NewName
.Length
+= sizeof(WCHAR
);
737 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
739 else if (RenameInfo
->FileName
[0] != L
'\\')
741 /* Here, copy first work directory and then append filename */
742 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
743 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
744 NewName
.Length
+= sizeof(WCHAR
);
745 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
747 else if (TargetFileObject
!= NULL
)
749 /* Here, copy first path name and then append filename */
750 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
751 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
752 NewName
.Length
+= sizeof(WCHAR
);
753 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
757 /* Here we should have full path, so simply copy it */
758 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
761 /* Do we have to cleanup some stuff? */
762 if (TargetFileObject
!= NULL
)
764 ObDereferenceObject(TargetFileObject
);
765 ZwClose(TargetHandle
);
766 TargetFileObject
= NULL
;
771 /* At that point, we shouldn't care about whether we are relative opening
772 * Target FO FCB should already have full path
775 /* Before constructing string, just make a sanity check (just to be sure!) */
776 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
778 Status
= STATUS_NOT_SAME_DEVICE
;
783 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
784 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
785 if (NewName
.Buffer
== NULL
)
787 Status
= STATUS_INSUFFICIENT_RESOURCES
;
791 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
792 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
793 NewName
.Length
+= sizeof(WCHAR
);
794 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
797 /* Explode our paths to get path & filename */
798 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
799 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
800 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
801 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
803 if (vfatFCBIsDirectory(FCB
) && !IsListEmpty(&FCB
->ParentListHead
))
805 if (IsThereAChildOpened(FCB
))
807 Status
= STATUS_ACCESS_DENIED
;
808 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
813 /* Are we working in place? */
814 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
816 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
818 Status
= STATUS_SUCCESS
;
819 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
823 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
825 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
826 &(DeviceExt
->NotifyList
),
827 (PSTRING
)&FCB
->PathNameU
,
828 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
831 (vfatFCBIsDirectory(FCB
) ?
832 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
833 FILE_ACTION_RENAMED_OLD_NAME
,
835 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
836 if (NT_SUCCESS(Status
))
838 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
839 &(DeviceExt
->NotifyList
),
840 (PSTRING
)&FCB
->PathNameU
,
841 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
844 (vfatFCBIsDirectory(FCB
) ?
845 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
846 FILE_ACTION_RENAMED_NEW_NAME
,
852 /* Try to find target */
853 ParentFCB
= FCB
->parentFcb
;
854 vfatGrabFCB(DeviceExt
, ParentFCB
);
855 Status
= vfatPrepareTargetForRename(DeviceExt
,
858 RenameInfo
->ReplaceIfExists
,
861 if (!NT_SUCCESS(Status
))
863 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
864 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
868 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
869 &(DeviceExt
->NotifyList
),
870 (PSTRING
)&FCB
->PathNameU
,
871 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
874 (vfatFCBIsDirectory(FCB
) ?
875 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
876 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
878 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
879 if (NT_SUCCESS(Status
))
883 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
884 &(DeviceExt
->NotifyList
),
885 (PSTRING
)&FCB
->PathNameU
,
886 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
889 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
890 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
891 FILE_ACTION_MODIFIED
,
896 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
897 &(DeviceExt
->NotifyList
),
898 (PSTRING
)&FCB
->PathNameU
,
899 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
902 (vfatFCBIsDirectory(FCB
) ?
903 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
904 FILE_ACTION_RENAMED_NEW_NAME
,
910 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
911 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
916 /* Try to find target */
918 OldParent
= FCB
->parentFcb
;
919 #ifdef NASSERTS_RENAME
920 UNREFERENCED_PARAMETER(OldParent
);
922 Status
= vfatPrepareTargetForRename(DeviceExt
,
925 RenameInfo
->ReplaceIfExists
,
928 if (!NT_SUCCESS(Status
))
930 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
934 NewReferences
= ParentFCB
->RefCount
;
935 #ifdef NASSERTS_RENAME
936 UNREFERENCED_PARAMETER(NewReferences
);
939 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
940 &(DeviceExt
->NotifyList
),
941 (PSTRING
)&FCB
->PathNameU
,
942 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
945 (vfatFCBIsDirectory(FCB
) ?
946 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
949 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
950 if (NT_SUCCESS(Status
))
954 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
955 &(DeviceExt
->NotifyList
),
956 (PSTRING
)&FCB
->PathNameU
,
957 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
960 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
961 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
962 FILE_ACTION_MODIFIED
,
967 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
968 &(DeviceExt
->NotifyList
),
969 (PSTRING
)&FCB
->PathNameU
,
970 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
973 (vfatFCBIsDirectory(FCB
) ?
974 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
981 if (NT_SUCCESS(Status
) && vfatFCBIsDirectory(FCB
))
983 VfatRenameChildFCB(DeviceExt
, FCB
);
986 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
987 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
989 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
990 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
991 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
994 #ifdef NASSERTS_RENAME
995 #pragma pop_macro("ASSERT")
1000 * FUNCTION: Retrieve the file name information
1004 VfatGetNameInformation(
1005 PFILE_OBJECT FileObject
,
1007 PDEVICE_EXTENSION DeviceExt
,
1008 PFILE_NAME_INFORMATION NameInfo
,
1009 PULONG BufferLength
)
1013 UNREFERENCED_PARAMETER(FileObject
);
1014 UNREFERENCED_PARAMETER(DeviceExt
);
1016 ASSERT(NameInfo
!= NULL
);
1017 ASSERT(FCB
!= NULL
);
1019 /* If buffer can't hold at least the file name length, bail out */
1020 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
1021 return STATUS_BUFFER_OVERFLOW
;
1023 /* Save file name length, and as much file len, as buffer length allows */
1024 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
1026 /* Calculate amount of bytes to copy not to overflow the buffer */
1027 BytesToCopy
= min(FCB
->PathNameU
.Length
,
1028 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
1030 /* Fill in the bytes */
1031 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
1033 /* Check if we could write more but are not able to */
1034 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
1036 /* Return number of bytes written */
1037 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
1038 return STATUS_BUFFER_OVERFLOW
;
1041 /* We filled up as many bytes, as needed */
1042 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
1044 return STATUS_SUCCESS
;
1049 VfatGetInternalInformation(
1051 PDEVICE_EXTENSION DeviceExt
,
1052 PFILE_INTERNAL_INFORMATION InternalInfo
,
1053 PULONG BufferLength
)
1055 ASSERT(InternalInfo
);
1058 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
1059 return STATUS_BUFFER_OVERFLOW
;
1061 InternalInfo
->IndexNumber
.QuadPart
= (LONGLONG
)vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
) * DeviceExt
->FatInfo
.BytesPerCluster
;
1063 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
1064 return STATUS_SUCCESS
;
1069 * FUNCTION: Retrieve the file network open information
1073 VfatGetNetworkOpenInformation(
1075 PDEVICE_EXTENSION DeviceExt
,
1076 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
1077 PULONG BufferLength
)
1079 ASSERT(NetworkInfo
);
1082 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
1083 return(STATUS_BUFFER_OVERFLOW
);
1085 if (vfatVolumeIsFatX(DeviceExt
))
1087 FsdDosDateTimeToSystemTime(DeviceExt
,
1088 Fcb
->entry
.FatX
.CreationDate
,
1089 Fcb
->entry
.FatX
.CreationTime
,
1090 &NetworkInfo
->CreationTime
);
1091 FsdDosDateTimeToSystemTime(DeviceExt
,
1092 Fcb
->entry
.FatX
.AccessDate
,
1093 Fcb
->entry
.FatX
.AccessTime
,
1094 &NetworkInfo
->LastAccessTime
);
1095 FsdDosDateTimeToSystemTime(DeviceExt
,
1096 Fcb
->entry
.FatX
.UpdateDate
,
1097 Fcb
->entry
.FatX
.UpdateTime
,
1098 &NetworkInfo
->LastWriteTime
);
1099 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1103 FsdDosDateTimeToSystemTime(DeviceExt
,
1104 Fcb
->entry
.Fat
.CreationDate
,
1105 Fcb
->entry
.Fat
.CreationTime
,
1106 &NetworkInfo
->CreationTime
);
1107 FsdDosDateTimeToSystemTime(DeviceExt
,
1108 Fcb
->entry
.Fat
.AccessDate
,
1110 &NetworkInfo
->LastAccessTime
);
1111 FsdDosDateTimeToSystemTime(DeviceExt
,
1112 Fcb
->entry
.Fat
.UpdateDate
,
1113 Fcb
->entry
.Fat
.UpdateTime
,
1114 &NetworkInfo
->LastWriteTime
);
1115 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1118 if (vfatFCBIsDirectory(Fcb
))
1120 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1121 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1125 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1126 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1129 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1130 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1131 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1132 FILE_ATTRIBUTE_ARCHIVE
|
1133 FILE_ATTRIBUTE_SYSTEM
|
1134 FILE_ATTRIBUTE_HIDDEN
|
1135 FILE_ATTRIBUTE_READONLY
)))
1137 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1138 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1141 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1142 return STATUS_SUCCESS
;
1148 VfatGetEaInformation(
1149 PFILE_OBJECT FileObject
,
1151 PDEVICE_EXTENSION DeviceExt
,
1152 PFILE_EA_INFORMATION Info
,
1153 PULONG BufferLength
)
1155 UNREFERENCED_PARAMETER(FileObject
);
1156 UNREFERENCED_PARAMETER(Fcb
);
1158 /* FIXME - use SEH to access the buffer! */
1160 *BufferLength
-= sizeof(*Info
);
1161 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1162 DeviceExt
->FatInfo
.FatType
== FAT16
)
1165 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1167 return STATUS_SUCCESS
;
1172 * FUNCTION: Retrieve the all file information
1176 VfatGetAllInformation(
1177 PFILE_OBJECT FileObject
,
1179 PDEVICE_EXTENSION DeviceExt
,
1180 PFILE_ALL_INFORMATION Info
,
1181 PULONG BufferLength
)
1188 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1189 return STATUS_BUFFER_OVERFLOW
;
1191 *BufferLength
-= (sizeof(FILE_ACCESS_INFORMATION
) + sizeof(FILE_MODE_INFORMATION
) + sizeof(FILE_ALIGNMENT_INFORMATION
));
1193 /* Basic Information */
1194 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceExt
, &Info
->BasicInformation
, BufferLength
);
1195 if (!NT_SUCCESS(Status
)) return Status
;
1196 /* Standard Information */
1197 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1198 if (!NT_SUCCESS(Status
)) return Status
;
1199 /* Internal Information */
1200 Status
= VfatGetInternalInformation(Fcb
, DeviceExt
, &Info
->InternalInformation
, BufferLength
);
1201 if (!NT_SUCCESS(Status
)) return Status
;
1202 /* EA Information */
1203 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceExt
, &Info
->EaInformation
, BufferLength
);
1204 if (!NT_SUCCESS(Status
)) return Status
;
1205 /* Position Information */
1206 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceExt
, &Info
->PositionInformation
, BufferLength
);
1207 if (!NT_SUCCESS(Status
)) return Status
;
1208 /* Name Information */
1209 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceExt
, &Info
->NameInformation
, BufferLength
);
1217 PFILE_OBJECT FileObject
,
1225 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, ClusterSize
);
1229 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1231 if (!vfatFCBIsDirectory(Fcb
))
1234 Fcb
->entry
.FatX
.FileSize
= Size
;
1236 Fcb
->entry
.Fat
.FileSize
= Size
;
1238 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1239 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1241 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1245 VfatSetAllocationSizeInformation(
1246 PFILE_OBJECT FileObject
,
1248 PDEVICE_EXTENSION DeviceExt
,
1249 PLARGE_INTEGER AllocationSize
)
1252 ULONG Cluster
, FirstCluster
;
1255 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1256 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1258 BOOLEAN AllocSizeChanged
= FALSE
, IsFatX
= vfatVolumeIsFatX(DeviceExt
);
1260 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1261 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1264 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1266 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1268 if (AllocationSize
->u
.HighPart
> 0)
1270 return STATUS_INVALID_PARAMETER
;
1273 if (OldSize
== NewSize
)
1275 return STATUS_SUCCESS
;
1278 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1280 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1282 AllocSizeChanged
= TRUE
;
1283 if (FirstCluster
== 0)
1285 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1286 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1287 if (!NT_SUCCESS(Status
))
1289 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1293 if (FirstCluster
== 0xffffffff)
1295 return STATUS_DISK_FULL
;
1298 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1299 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1301 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1304 NCluster
= Cluster
= FirstCluster
;
1305 Status
= STATUS_SUCCESS
;
1306 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1308 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1309 WriteCluster(DeviceExt
, Cluster
, 0);
1312 return STATUS_DISK_FULL
;
1317 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1321 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1323 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1324 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1328 ASSERT((FirstCluster
>> 16) == 0);
1329 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1335 if (Fcb
->LastCluster
> 0)
1337 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1339 Cluster
= Fcb
->LastCluster
;
1340 Status
= STATUS_SUCCESS
;
1344 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1345 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1351 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1352 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1356 if (!NT_SUCCESS(Status
))
1361 Fcb
->LastCluster
= Cluster
;
1362 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1364 /* FIXME: Check status */
1365 /* Cluster points now to the last cluster within the chain */
1366 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1367 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1369 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1373 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1374 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1376 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1378 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1379 WriteCluster(DeviceExt
, Cluster
, 0);
1382 return STATUS_DISK_FULL
;
1385 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1387 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1389 DPRINT("Check for the ability to set file size\n");
1390 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1391 (PLARGE_INTEGER
)AllocationSize
))
1393 DPRINT("Couldn't set file size!\n");
1394 return STATUS_USER_MAPPED_FILE
;
1396 DPRINT("Can set file size\n");
1398 AllocSizeChanged
= TRUE
;
1399 /* FIXME: Use the cached cluster/offset better way. */
1400 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1401 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1404 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1405 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1409 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1410 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1417 Fcb
->entry
.FatX
.FirstCluster
= 0;
1421 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1423 Fcb
->entry
.Fat
.FirstCluster
= 0;
1424 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1428 Fcb
->entry
.Fat
.FirstCluster
= 0;
1432 NCluster
= Cluster
= FirstCluster
;
1433 Status
= STATUS_SUCCESS
;
1436 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1438 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1439 WriteCluster(DeviceExt
, Cluster
, 0);
1445 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1448 /* Update the on-disk directory entry */
1449 Fcb
->Flags
|= FCB_IS_DIRTY
;
1450 if (AllocSizeChanged
)
1452 VfatUpdateEntry(Fcb
, vfatVolumeIsFatX(DeviceExt
));
1454 return STATUS_SUCCESS
;
1458 * FUNCTION: Retrieve the specified file information
1461 VfatQueryInformation(
1462 PVFAT_IRP_CONTEXT IrpContext
)
1464 FILE_INFORMATION_CLASS FileInformationClass
;
1467 NTSTATUS Status
= STATUS_SUCCESS
;
1474 /* INITIALIZATION */
1475 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1476 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1478 DPRINT("VfatQueryInformation is called for '%s'\n",
1479 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1483 DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
1484 IrpContext
->Irp
->IoStatus
.Information
= 0;
1485 return STATUS_INVALID_PARAMETER
;
1488 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1489 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1491 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1493 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1494 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1496 return VfatMarkIrpContextForQueue(IrpContext
);
1500 switch (FileInformationClass
)
1502 case FileStandardInformation
:
1503 Status
= VfatGetStandardInformation(FCB
,
1508 case FilePositionInformation
:
1509 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1511 IrpContext
->DeviceExt
,
1516 case FileBasicInformation
:
1517 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1519 IrpContext
->DeviceExt
,
1524 case FileNameInformation
:
1525 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1527 IrpContext
->DeviceExt
,
1532 case FileInternalInformation
:
1533 Status
= VfatGetInternalInformation(FCB
,
1534 IrpContext
->DeviceExt
,
1539 case FileNetworkOpenInformation
:
1540 Status
= VfatGetNetworkOpenInformation(FCB
,
1541 IrpContext
->DeviceExt
,
1546 case FileAllInformation
:
1547 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1549 IrpContext
->DeviceExt
,
1554 case FileEaInformation
:
1555 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1557 IrpContext
->DeviceExt
,
1562 case FileAlternateNameInformation
:
1563 Status
= STATUS_NOT_IMPLEMENTED
;
1567 Status
= STATUS_INVALID_PARAMETER
;
1570 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1572 ExReleaseResourceLite(&FCB
->MainResource
);
1575 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1576 IrpContext
->Irp
->IoStatus
.Information
=
1577 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1579 IrpContext
->Irp
->IoStatus
.Information
= 0;
1585 * FUNCTION: Retrieve the specified file information
1589 PVFAT_IRP_CONTEXT IrpContext
)
1591 FILE_INFORMATION_CLASS FileInformationClass
;
1593 NTSTATUS Status
= STATUS_SUCCESS
;
1599 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1601 /* INITIALIZATION */
1602 FileInformationClass
=
1603 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1604 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1605 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1607 DPRINT("VfatSetInformation is called for '%s'\n",
1608 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1610 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1611 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1615 DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
1616 IrpContext
->Irp
->IoStatus
.Information
= 0;
1617 return STATUS_INVALID_PARAMETER
;
1620 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1621 the file size would be allowed. If not, we bail with the right error.
1622 We must do this before acquiring the lock. */
1623 if (FileInformationClass
== FileEndOfFileInformation
)
1625 DPRINT("Check for the ability to set file size\n");
1626 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1627 (PLARGE_INTEGER
)SystemBuffer
))
1629 DPRINT("Couldn't set file size!\n");
1630 IrpContext
->Irp
->IoStatus
.Information
= 0;
1631 return STATUS_USER_MAPPED_FILE
;
1633 DPRINT("Can set file size\n");
1636 if (FileInformationClass
== FileRenameInformation
)
1638 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1639 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1641 return VfatMarkIrpContextForQueue(IrpContext
);
1645 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1647 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1648 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1650 if (FileInformationClass
== FileRenameInformation
)
1652 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1655 return VfatMarkIrpContextForQueue(IrpContext
);
1659 switch (FileInformationClass
)
1661 case FilePositionInformation
:
1662 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1666 case FileDispositionInformation
:
1667 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1669 IrpContext
->DeviceExt
,
1673 case FileAllocationInformation
:
1674 case FileEndOfFileInformation
:
1675 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1677 IrpContext
->DeviceExt
,
1678 (PLARGE_INTEGER
)SystemBuffer
);
1681 case FileBasicInformation
:
1682 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1684 IrpContext
->DeviceExt
,
1688 case FileRenameInformation
:
1689 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1691 IrpContext
->DeviceExt
,
1693 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1697 Status
= STATUS_NOT_SUPPORTED
;
1700 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1702 ExReleaseResourceLite(&FCB
->MainResource
);
1705 if (FileInformationClass
== FileRenameInformation
)
1707 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1710 IrpContext
->Irp
->IoStatus
.Information
= 0;