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_OBJECT DeviceObject
,
129 PFILE_POSITION_INFORMATION PositionInfo
,
132 UNREFERENCED_PARAMETER(FileObject
);
133 UNREFERENCED_PARAMETER(FCB
);
134 UNREFERENCED_PARAMETER(DeviceObject
);
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
)
159 DPRINT("VfatSetBasicInformation()\n");
161 ASSERT(NULL
!= FileObject
);
163 ASSERT(NULL
!= DeviceExt
);
164 ASSERT(NULL
!= BasicInfo
);
165 /* Check volume label bit */
166 ASSERT(0 == (*FCB
->Attributes
& _A_VOLID
));
168 if (BooleanFlagOn(FCB
->Flags
, FCB_IS_FATX_ENTRY
))
170 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
172 FsdSystemTimeToDosDateTime(DeviceExt
,
173 &BasicInfo
->CreationTime
,
174 &FCB
->entry
.FatX
.CreationDate
,
175 &FCB
->entry
.FatX
.CreationTime
);
178 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
180 FsdSystemTimeToDosDateTime(DeviceExt
,
181 &BasicInfo
->LastAccessTime
,
182 &FCB
->entry
.FatX
.AccessDate
,
183 &FCB
->entry
.FatX
.AccessTime
);
186 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
188 FsdSystemTimeToDosDateTime(DeviceExt
,
189 &BasicInfo
->LastWriteTime
,
190 &FCB
->entry
.FatX
.UpdateDate
,
191 &FCB
->entry
.FatX
.UpdateTime
);
196 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
198 FsdSystemTimeToDosDateTime(DeviceExt
,
199 &BasicInfo
->CreationTime
,
200 &FCB
->entry
.Fat
.CreationDate
,
201 &FCB
->entry
.Fat
.CreationTime
);
204 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
206 FsdSystemTimeToDosDateTime(DeviceExt
,
207 &BasicInfo
->LastAccessTime
,
208 &FCB
->entry
.Fat
.AccessDate
,
212 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
214 FsdSystemTimeToDosDateTime(DeviceExt
,
215 &BasicInfo
->LastWriteTime
,
216 &FCB
->entry
.Fat
.UpdateDate
,
217 &FCB
->entry
.Fat
.UpdateTime
);
221 if (BasicInfo
->FileAttributes
)
223 *FCB
->Attributes
= (unsigned char)((*FCB
->Attributes
&
224 (FILE_ATTRIBUTE_DIRECTORY
| 0x48)) |
225 (BasicInfo
->FileAttributes
&
226 (FILE_ATTRIBUTE_ARCHIVE
|
227 FILE_ATTRIBUTE_SYSTEM
|
228 FILE_ATTRIBUTE_HIDDEN
|
229 FILE_ATTRIBUTE_READONLY
)));
230 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
233 VfatUpdateEntry(FCB
);
235 return STATUS_SUCCESS
;
239 VfatGetBasicInformation(
240 PFILE_OBJECT FileObject
,
242 PDEVICE_OBJECT DeviceObject
,
243 PFILE_BASIC_INFORMATION BasicInfo
,
246 PDEVICE_EXTENSION DeviceExt
;
248 UNREFERENCED_PARAMETER(FileObject
);
250 DPRINT("VfatGetBasicInformation()\n");
252 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
254 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
255 return STATUS_BUFFER_OVERFLOW
;
257 if (BooleanFlagOn(FCB
->Flags
, FCB_IS_FATX_ENTRY
))
259 FsdDosDateTimeToSystemTime(DeviceExt
,
260 FCB
->entry
.FatX
.CreationDate
,
261 FCB
->entry
.FatX
.CreationTime
,
262 &BasicInfo
->CreationTime
);
263 FsdDosDateTimeToSystemTime(DeviceExt
,
264 FCB
->entry
.FatX
.AccessDate
,
265 FCB
->entry
.FatX
.AccessTime
,
266 &BasicInfo
->LastAccessTime
);
267 FsdDosDateTimeToSystemTime(DeviceExt
,
268 FCB
->entry
.FatX
.UpdateDate
,
269 FCB
->entry
.FatX
.UpdateTime
,
270 &BasicInfo
->LastWriteTime
);
271 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
275 FsdDosDateTimeToSystemTime(DeviceExt
,
276 FCB
->entry
.Fat
.CreationDate
,
277 FCB
->entry
.Fat
.CreationTime
,
278 &BasicInfo
->CreationTime
);
279 FsdDosDateTimeToSystemTime(DeviceExt
,
280 FCB
->entry
.Fat
.AccessDate
,
282 &BasicInfo
->LastAccessTime
);
283 FsdDosDateTimeToSystemTime(DeviceExt
,
284 FCB
->entry
.Fat
.UpdateDate
,
285 FCB
->entry
.Fat
.UpdateTime
,
286 &BasicInfo
->LastWriteTime
);
287 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
290 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
291 /* Synthesize FILE_ATTRIBUTE_NORMAL */
292 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
293 FILE_ATTRIBUTE_ARCHIVE
|
294 FILE_ATTRIBUTE_SYSTEM
|
295 FILE_ATTRIBUTE_HIDDEN
|
296 FILE_ATTRIBUTE_READONLY
)))
298 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
299 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
301 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
303 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
304 return STATUS_SUCCESS
;
310 VfatSetDispositionInformation(
311 PFILE_OBJECT FileObject
,
313 PDEVICE_OBJECT DeviceObject
,
314 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
317 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
320 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
322 ASSERT(DeviceExt
!= NULL
);
323 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
326 if (!DispositionInfo
->DeleteFile
)
328 /* undelete the file */
329 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
330 FileObject
->DeletePending
= FALSE
;
331 return STATUS_SUCCESS
;
334 if (BooleanFlagOn(FCB
->Flags
, FCB_DELETE_PENDING
))
336 /* stream already marked for deletion. just update the file object */
337 FileObject
->DeletePending
= TRUE
;
338 return STATUS_SUCCESS
;
341 if (*FCB
->Attributes
& FILE_ATTRIBUTE_READONLY
)
343 return STATUS_CANNOT_DELETE
;
346 if (vfatFCBIsRoot(FCB
) ||
347 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
348 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
350 /* we cannot delete a '.', '..' or the root directory */
351 return STATUS_ACCESS_DENIED
;
354 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
356 /* can't delete a file if its mapped into a process */
358 DPRINT("MmFlushImageSection returned FALSE\n");
359 return STATUS_CANNOT_DELETE
;
362 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
364 /* can't delete a non-empty directory */
366 return STATUS_DIRECTORY_NOT_EMPTY
;
370 FCB
->Flags
|= FCB_DELETE_PENDING
;
371 FileObject
->DeletePending
= TRUE
;
373 return STATUS_SUCCESS
;
377 vfatPrepareTargetForRename(
378 IN PDEVICE_EXTENSION DeviceExt
,
379 IN PVFATFCB
* ParentFCB
,
380 IN PUNICODE_STRING NewName
,
381 IN BOOLEAN ReplaceIfExists
,
382 IN PUNICODE_STRING ParentName
,
383 OUT PBOOLEAN Deleted
)
388 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
391 /* Try to open target */
392 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
394 if (NT_SUCCESS(Status
))
396 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
397 /* Check whether we are allowed to replace */
400 /* If that's a directory or a read-only file, we're not allowed */
401 if (vfatFCBIsDirectory(TargetFcb
) || ((*TargetFcb
->Attributes
& FILE_ATTRIBUTE_READONLY
) == FILE_ATTRIBUTE_READONLY
))
403 DPRINT("And this is a readonly file!\n");
404 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
406 vfatReleaseFCB(DeviceExt
, TargetFcb
);
407 return STATUS_OBJECT_NAME_COLLISION
;
411 /* If we still have a file object, close it. */
412 if (TargetFcb
->FileObject
)
414 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
416 DPRINT("MmFlushImageSection failed.\n");
417 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
419 vfatReleaseFCB(DeviceExt
, TargetFcb
);
420 return STATUS_ACCESS_DENIED
;
423 TargetFcb
->FileObject
->DeletePending
= TRUE
;
424 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
427 /* If we are here, ensure the file isn't open by anyone! */
428 if (TargetFcb
->OpenHandleCount
!= 0)
430 DPRINT("There are still open handles for this file.\n");
431 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
433 vfatReleaseFCB(DeviceExt
, TargetFcb
);
434 return STATUS_ACCESS_DENIED
;
437 /* Effectively delete old file to allow renaming */
438 DPRINT("Effectively deleting the file.\n");
439 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
440 vfatReleaseFCB(DeviceExt
, TargetFcb
);
442 return STATUS_SUCCESS
;
446 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
448 vfatReleaseFCB(DeviceExt
, TargetFcb
);
449 return STATUS_OBJECT_NAME_COLLISION
;
452 else if (*ParentFCB
!= NULL
)
454 return STATUS_SUCCESS
;
463 IsThereAChildOpened(PVFATFCB FCB
)
468 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
470 VolFCB
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
471 if (VolFCB
->OpenHandleCount
!= 0)
473 ASSERT(VolFCB
->parentFcb
== FCB
);
474 DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB
->PathNameU
, VolFCB
->RefCount
, VolFCB
->OpenHandleCount
);
478 if (vfatFCBIsDirectory(VolFCB
) && !IsListEmpty(&VolFCB
->ParentListHead
))
480 if (IsThereAChildOpened(VolFCB
))
493 PDEVICE_EXTENSION DeviceExt
,
499 if (IsListEmpty(&FCB
->ParentListHead
))
502 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
506 Child
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
507 DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child
->PathNameU
, Child
->RefCount
, FCB
->RefCount
);
509 Status
= vfatSetFCBNewDirName(DeviceExt
, Child
, FCB
);
510 if (!NT_SUCCESS(Status
))
513 if (vfatFCBIsDirectory(Child
))
515 VfatRenameChildFCB(DeviceExt
, Child
);
521 * FUNCTION: Set the file name information
525 VfatSetRenameInformation(
526 PFILE_OBJECT FileObject
,
528 PDEVICE_EXTENSION DeviceExt
,
529 PFILE_RENAME_INFORMATION RenameInfo
,
530 PFILE_OBJECT TargetFileObject
)
532 #ifdef NASSERTS_RENAME
533 #pragma push_macro("ASSERT")
535 #define ASSERT(x) ((VOID) 0)
538 UNICODE_STRING NewName
;
539 UNICODE_STRING SourcePath
;
540 UNICODE_STRING SourceFile
;
541 UNICODE_STRING NewPath
;
542 UNICODE_STRING NewFile
;
543 PFILE_OBJECT RootFileObject
;
545 UNICODE_STRING RenameInfoString
;
547 IO_STATUS_BLOCK IoStatusBlock
;
548 OBJECT_ATTRIBUTES ObjectAttributes
;
550 BOOLEAN DeletedTarget
;
551 ULONG OldReferences
, NewReferences
;
554 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
556 /* Disallow renaming root */
557 if (vfatFCBIsRoot(FCB
))
559 return STATUS_INVALID_PARAMETER
;
562 OldReferences
= FCB
->parentFcb
->RefCount
;
563 #ifdef NASSERTS_RENAME
564 UNREFERENCED_PARAMETER(OldReferences
);
567 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
568 if (RenameInfo
->RootDirectory
!= NULL
)
570 /* We cannot tolerate relative opening with a full path */
571 if (RenameInfo
->FileName
[0] == L
'\\')
573 return STATUS_OBJECT_NAME_INVALID
;
576 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
580 (PVOID
*)&RootFileObject
,
582 if (!NT_SUCCESS(Status
))
587 RootFCB
= RootFileObject
->FsContext
;
590 RtlInitEmptyUnicodeString(&NewName
, NULL
, 0);
593 if (TargetFileObject
== NULL
)
595 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
596 * information supplied by the user
599 /* First, setup a string we'll work on */
600 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
601 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
602 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
604 /* Check whether we have FQN */
605 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
607 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
608 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
609 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
610 RenameInfoString
.Buffer
[4] <= L
'Z'))
612 /* If so, open its target directory */
613 InitializeObjectAttributes(&ObjectAttributes
,
615 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
618 Status
= IoCreateFile(&TargetHandle
,
619 FILE_WRITE_DATA
| SYNCHRONIZE
,
623 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
625 FILE_OPEN_FOR_BACKUP_INTENT
,
629 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
630 if (!NT_SUCCESS(Status
))
635 /* Get its FO to get the FCB */
636 Status
= ObReferenceObjectByHandle(TargetHandle
,
640 (PVOID
*)&TargetFileObject
,
642 if (!NT_SUCCESS(Status
))
644 ZwClose(TargetHandle
);
648 /* Are we working on the same volume? */
649 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
651 ObDereferenceObject(TargetFileObject
);
652 ZwClose(TargetHandle
);
653 TargetFileObject
= NULL
;
654 Status
= STATUS_NOT_SAME_DEVICE
;
661 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
662 if (RenameInfo
->RootDirectory
!= NULL
)
664 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
666 else if (RenameInfo
->FileName
[0] != L
'\\')
668 /* We don't have full path, and we don't have root directory:
669 * => we move inside the same directory
671 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
673 else if (TargetFileObject
!= NULL
)
676 * => we need to use its correct path
678 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
681 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
682 if (NewName
.Buffer
== NULL
)
684 if (TargetFileObject
!= NULL
)
686 ObDereferenceObject(TargetFileObject
);
687 ZwClose(TargetHandle
);
688 TargetFileObject
= NULL
;
690 Status
= STATUS_INSUFFICIENT_RESOURCES
;
694 if (RenameInfo
->RootDirectory
!= NULL
)
696 /* Here, copy first absolute and then append relative */
697 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
698 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
699 NewName
.Length
+= sizeof(WCHAR
);
700 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
702 else if (RenameInfo
->FileName
[0] != L
'\\')
704 /* Here, copy first work directory and then append filename */
705 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
706 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
707 NewName
.Length
+= sizeof(WCHAR
);
708 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
710 else if (TargetFileObject
!= NULL
)
712 /* Here, copy first path name and then append filename */
713 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
714 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
715 NewName
.Length
+= sizeof(WCHAR
);
716 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
720 /* Here we should have full path, so simply copy it */
721 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
724 /* Do we have to cleanup some stuff? */
725 if (TargetFileObject
!= NULL
)
727 ObDereferenceObject(TargetFileObject
);
728 ZwClose(TargetHandle
);
729 TargetFileObject
= NULL
;
734 /* At that point, we shouldn't care about whether we are relative opening
735 * Target FO FCB should already have full path
738 /* Before constructing string, just make a sanity check (just to be sure!) */
739 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
741 Status
= STATUS_NOT_SAME_DEVICE
;
746 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
747 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
748 if (NewName
.Buffer
== NULL
)
750 Status
= STATUS_INSUFFICIENT_RESOURCES
;
754 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
755 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
756 NewName
.Length
+= sizeof(WCHAR
);
757 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
760 /* Explode our paths to get path & filename */
761 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
762 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
763 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
764 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
766 if (vfatFCBIsDirectory(FCB
) && !IsListEmpty(&FCB
->ParentListHead
))
768 if (IsThereAChildOpened(FCB
))
770 Status
= STATUS_ACCESS_DENIED
;
771 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
776 /* Are we working in place? */
777 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
779 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
781 Status
= STATUS_SUCCESS
;
782 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
786 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
788 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
789 &(DeviceExt
->NotifyList
),
790 (PSTRING
)&FCB
->PathNameU
,
791 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
794 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
795 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
796 FILE_ACTION_RENAMED_OLD_NAME
,
798 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
799 if (NT_SUCCESS(Status
))
801 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
802 &(DeviceExt
->NotifyList
),
803 (PSTRING
)&FCB
->PathNameU
,
804 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
807 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
808 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
809 FILE_ACTION_RENAMED_NEW_NAME
,
815 /* Try to find target */
816 ParentFCB
= FCB
->parentFcb
;
817 vfatGrabFCB(DeviceExt
, ParentFCB
);
818 Status
= vfatPrepareTargetForRename(DeviceExt
,
821 RenameInfo
->ReplaceIfExists
,
824 if (!NT_SUCCESS(Status
))
826 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
827 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
831 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
832 &(DeviceExt
->NotifyList
),
833 (PSTRING
)&FCB
->PathNameU
,
834 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
837 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
838 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
839 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
841 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
842 if (NT_SUCCESS(Status
))
846 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
847 &(DeviceExt
->NotifyList
),
848 (PSTRING
)&FCB
->PathNameU
,
849 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
852 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
853 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
854 FILE_ACTION_MODIFIED
,
859 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
860 &(DeviceExt
->NotifyList
),
861 (PSTRING
)&FCB
->PathNameU
,
862 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
865 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
866 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
867 FILE_ACTION_RENAMED_NEW_NAME
,
873 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
874 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
879 /* Try to find target */
881 OldParent
= FCB
->parentFcb
;
882 #ifdef NASSERTS_RENAME
883 UNREFERENCED_PARAMETER(OldParent
);
885 Status
= vfatPrepareTargetForRename(DeviceExt
,
888 RenameInfo
->ReplaceIfExists
,
891 if (!NT_SUCCESS(Status
))
893 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
897 NewReferences
= ParentFCB
->RefCount
;
898 #ifdef NASSERTS_RENAME
899 UNREFERENCED_PARAMETER(NewReferences
);
902 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
903 &(DeviceExt
->NotifyList
),
904 (PSTRING
)&FCB
->PathNameU
,
905 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
908 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
909 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
912 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
913 if (NT_SUCCESS(Status
))
917 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
918 &(DeviceExt
->NotifyList
),
919 (PSTRING
)&FCB
->PathNameU
,
920 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
923 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
924 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
925 FILE_ACTION_MODIFIED
,
930 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
931 &(DeviceExt
->NotifyList
),
932 (PSTRING
)&FCB
->PathNameU
,
933 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
936 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
937 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
944 if (NT_SUCCESS(Status
) && vfatFCBIsDirectory(FCB
))
946 VfatRenameChildFCB(DeviceExt
, FCB
);
949 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
950 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
952 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
953 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
954 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
957 #ifdef NASSERTS_RENAME
958 #pragma pop_macro("ASSERT")
963 * FUNCTION: Retrieve the file name information
967 VfatGetNameInformation(
968 PFILE_OBJECT FileObject
,
970 PDEVICE_OBJECT DeviceObject
,
971 PFILE_NAME_INFORMATION NameInfo
,
976 UNREFERENCED_PARAMETER(FileObject
);
977 UNREFERENCED_PARAMETER(DeviceObject
);
979 ASSERT(NameInfo
!= NULL
);
982 /* If buffer can't hold at least the file name length, bail out */
983 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
984 return STATUS_BUFFER_OVERFLOW
;
986 /* Save file name length, and as much file len, as buffer length allows */
987 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
989 /* Calculate amount of bytes to copy not to overflow the buffer */
990 BytesToCopy
= min(FCB
->PathNameU
.Length
,
991 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
993 /* Fill in the bytes */
994 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
996 /* Check if we could write more but are not able to */
997 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
999 /* Return number of bytes written */
1000 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
1001 return STATUS_BUFFER_OVERFLOW
;
1004 /* We filled up as many bytes, as needed */
1005 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
1007 return STATUS_SUCCESS
;
1012 VfatGetInternalInformation(
1014 PFILE_INTERNAL_INFORMATION InternalInfo
,
1015 PULONG BufferLength
)
1017 ASSERT(InternalInfo
);
1020 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
1021 return STATUS_BUFFER_OVERFLOW
;
1022 // FIXME: get a real index, that can be used in a create operation
1023 InternalInfo
->IndexNumber
.QuadPart
= 0;
1024 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
1025 return STATUS_SUCCESS
;
1030 * FUNCTION: Retrieve the file network open information
1034 VfatGetNetworkOpenInformation(
1036 PDEVICE_EXTENSION DeviceExt
,
1037 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
1038 PULONG BufferLength
)
1040 ASSERT(NetworkInfo
);
1043 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
1044 return(STATUS_BUFFER_OVERFLOW
);
1046 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_FATX_ENTRY
))
1048 FsdDosDateTimeToSystemTime(DeviceExt
,
1049 Fcb
->entry
.FatX
.CreationDate
,
1050 Fcb
->entry
.FatX
.CreationTime
,
1051 &NetworkInfo
->CreationTime
);
1052 FsdDosDateTimeToSystemTime(DeviceExt
,
1053 Fcb
->entry
.FatX
.AccessDate
,
1054 Fcb
->entry
.FatX
.AccessTime
,
1055 &NetworkInfo
->LastAccessTime
);
1056 FsdDosDateTimeToSystemTime(DeviceExt
,
1057 Fcb
->entry
.FatX
.UpdateDate
,
1058 Fcb
->entry
.FatX
.UpdateTime
,
1059 &NetworkInfo
->LastWriteTime
);
1060 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1064 FsdDosDateTimeToSystemTime(DeviceExt
,
1065 Fcb
->entry
.Fat
.CreationDate
,
1066 Fcb
->entry
.Fat
.CreationTime
,
1067 &NetworkInfo
->CreationTime
);
1068 FsdDosDateTimeToSystemTime(DeviceExt
,
1069 Fcb
->entry
.Fat
.AccessDate
,
1071 &NetworkInfo
->LastAccessTime
);
1072 FsdDosDateTimeToSystemTime(DeviceExt
,
1073 Fcb
->entry
.Fat
.UpdateDate
,
1074 Fcb
->entry
.Fat
.UpdateTime
,
1075 &NetworkInfo
->LastWriteTime
);
1076 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1079 if (vfatFCBIsDirectory(Fcb
))
1081 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1082 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1086 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1087 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1090 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1091 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1092 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1093 FILE_ATTRIBUTE_ARCHIVE
|
1094 FILE_ATTRIBUTE_SYSTEM
|
1095 FILE_ATTRIBUTE_HIDDEN
|
1096 FILE_ATTRIBUTE_READONLY
)))
1098 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1099 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1102 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1103 return STATUS_SUCCESS
;
1109 VfatGetEaInformation(
1110 PFILE_OBJECT FileObject
,
1112 PDEVICE_OBJECT DeviceObject
,
1113 PFILE_EA_INFORMATION Info
,
1114 PULONG BufferLength
)
1116 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1118 UNREFERENCED_PARAMETER(FileObject
);
1119 UNREFERENCED_PARAMETER(Fcb
);
1121 /* FIXME - use SEH to access the buffer! */
1123 *BufferLength
-= sizeof(*Info
);
1124 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1125 DeviceExt
->FatInfo
.FatType
== FAT16
)
1128 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1130 return STATUS_SUCCESS
;
1135 * FUNCTION: Retrieve the all file information
1139 VfatGetAllInformation(
1140 PFILE_OBJECT FileObject
,
1142 PDEVICE_OBJECT DeviceObject
,
1143 PFILE_ALL_INFORMATION Info
,
1144 PULONG BufferLength
)
1151 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1152 return STATUS_BUFFER_OVERFLOW
;
1154 /* Basic Information */
1155 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
1156 if (!NT_SUCCESS(Status
)) return Status
;
1157 /* Standard Information */
1158 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1159 if (!NT_SUCCESS(Status
)) return Status
;
1160 /* Internal Information */
1161 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
1162 if (!NT_SUCCESS(Status
)) return Status
;
1163 /* EA Information */
1164 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceObject
, &Info
->EaInformation
, BufferLength
);
1165 if (!NT_SUCCESS(Status
)) return Status
;
1166 /* Access Information: The IO-Manager adds this information */
1167 *BufferLength
-= sizeof(FILE_ACCESS_INFORMATION
);
1168 /* Position Information */
1169 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
1170 if (!NT_SUCCESS(Status
)) return Status
;
1171 /* Mode Information: The IO-Manager adds this information */
1172 *BufferLength
-= sizeof(FILE_MODE_INFORMATION
);
1173 /* Alignment Information: The IO-Manager adds this information */
1174 *BufferLength
-= sizeof(FILE_ALIGNMENT_INFORMATION
);
1175 /* Name Information */
1176 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
1184 PFILE_OBJECT FileObject
,
1191 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, ClusterSize
);
1195 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1197 if (!vfatFCBIsDirectory(Fcb
))
1199 if (BooleanFlagOn(Fcb
->Flags
, FCB_IS_FATX_ENTRY
))
1200 Fcb
->entry
.FatX
.FileSize
= Size
;
1202 Fcb
->entry
.Fat
.FileSize
= Size
;
1204 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1205 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1207 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1211 VfatSetAllocationSizeInformation(
1212 PFILE_OBJECT FileObject
,
1214 PDEVICE_EXTENSION DeviceExt
,
1215 PLARGE_INTEGER AllocationSize
)
1218 ULONG Cluster
, FirstCluster
;
1221 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1222 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1224 BOOLEAN AllocSizeChanged
= FALSE
, IsFatX
= BooleanFlagOn(Fcb
->Flags
, FCB_IS_FATX_ENTRY
);
1226 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1227 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1230 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1232 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1234 if (AllocationSize
->u
.HighPart
> 0)
1236 return STATUS_INVALID_PARAMETER
;
1239 if (OldSize
== NewSize
)
1241 return STATUS_SUCCESS
;
1244 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1246 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1248 AllocSizeChanged
= TRUE
;
1249 if (FirstCluster
== 0)
1251 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1252 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1253 if (!NT_SUCCESS(Status
))
1255 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1259 if (FirstCluster
== 0xffffffff)
1261 return STATUS_DISK_FULL
;
1264 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1265 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1267 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1270 NCluster
= Cluster
= FirstCluster
;
1271 Status
= STATUS_SUCCESS
;
1272 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1274 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1275 WriteCluster(DeviceExt
, Cluster
, 0);
1278 return STATUS_DISK_FULL
;
1283 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1287 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1289 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1290 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1294 ASSERT((FirstCluster
>> 16) == 0);
1295 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1301 if (Fcb
->LastCluster
> 0)
1303 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1305 Cluster
= Fcb
->LastCluster
;
1306 Status
= STATUS_SUCCESS
;
1310 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1311 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1317 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1318 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1322 if (!NT_SUCCESS(Status
))
1327 Fcb
->LastCluster
= Cluster
;
1328 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1330 /* FIXME: Check status */
1331 /* Cluster points now to the last cluster within the chain */
1332 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1333 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1335 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1339 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1340 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1342 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1344 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1345 WriteCluster(DeviceExt
, Cluster
, 0);
1348 return STATUS_DISK_FULL
;
1351 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1353 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1355 DPRINT("Check for the ability to set file size\n");
1356 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1357 (PLARGE_INTEGER
)AllocationSize
))
1359 DPRINT("Couldn't set file size!\n");
1360 return STATUS_USER_MAPPED_FILE
;
1362 DPRINT("Can set file size\n");
1364 AllocSizeChanged
= TRUE
;
1365 /* FIXME: Use the cached cluster/offset better way. */
1366 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1367 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1370 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1371 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1375 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1376 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1383 Fcb
->entry
.FatX
.FirstCluster
= 0;
1387 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1389 Fcb
->entry
.Fat
.FirstCluster
= 0;
1390 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1394 Fcb
->entry
.Fat
.FirstCluster
= 0;
1398 NCluster
= Cluster
= FirstCluster
;
1399 Status
= STATUS_SUCCESS
;
1402 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1404 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1405 WriteCluster(DeviceExt
, Cluster
, 0);
1411 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1414 /* Update the on-disk directory entry */
1415 Fcb
->Flags
|= FCB_IS_DIRTY
;
1416 if (AllocSizeChanged
)
1418 VfatUpdateEntry(Fcb
);
1420 return STATUS_SUCCESS
;
1424 * FUNCTION: Retrieve the specified file information
1427 VfatQueryInformation(
1428 PVFAT_IRP_CONTEXT IrpContext
)
1430 FILE_INFORMATION_CLASS FileInformationClass
;
1433 NTSTATUS Status
= STATUS_SUCCESS
;
1440 /* INITIALIZATION */
1441 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1442 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1444 DPRINT("VfatQueryInformation is called for '%s'\n",
1445 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1449 DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
1450 IrpContext
->Irp
->IoStatus
.Information
= 0;
1451 return STATUS_INVALID_PARAMETER
;
1454 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1455 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1457 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1459 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1460 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1462 return VfatMarkIrpContextForQueue(IrpContext
);
1466 switch (FileInformationClass
)
1468 case FileStandardInformation
:
1469 Status
= VfatGetStandardInformation(FCB
,
1474 case FilePositionInformation
:
1475 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1477 IrpContext
->DeviceObject
,
1482 case FileBasicInformation
:
1483 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1485 IrpContext
->DeviceObject
,
1490 case FileNameInformation
:
1491 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1493 IrpContext
->DeviceObject
,
1498 case FileInternalInformation
:
1499 Status
= VfatGetInternalInformation(FCB
,
1504 case FileNetworkOpenInformation
:
1505 Status
= VfatGetNetworkOpenInformation(FCB
,
1506 IrpContext
->DeviceExt
,
1511 case FileAllInformation
:
1512 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1514 IrpContext
->DeviceObject
,
1519 case FileEaInformation
:
1520 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1522 IrpContext
->DeviceObject
,
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
;
1564 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1566 /* INITIALIZATION */
1567 FileInformationClass
=
1568 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1569 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1570 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1572 DPRINT("VfatSetInformation is called for '%s'\n",
1573 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1575 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1576 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1580 DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
1581 IrpContext
->Irp
->IoStatus
.Information
= 0;
1582 return STATUS_INVALID_PARAMETER
;
1585 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1586 the file size would be allowed. If not, we bail with the right error.
1587 We must do this before acquiring the lock. */
1588 if (FileInformationClass
== FileEndOfFileInformation
)
1590 DPRINT("Check for the ability to set file size\n");
1591 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1592 (PLARGE_INTEGER
)SystemBuffer
))
1594 DPRINT("Couldn't set file size!\n");
1595 IrpContext
->Irp
->IoStatus
.Information
= 0;
1596 return STATUS_USER_MAPPED_FILE
;
1598 DPRINT("Can set file size\n");
1601 if (FileInformationClass
== FileRenameInformation
)
1603 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1604 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1606 return VfatMarkIrpContextForQueue(IrpContext
);
1610 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1612 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1613 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1615 if (FileInformationClass
== FileRenameInformation
)
1617 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1620 return VfatMarkIrpContextForQueue(IrpContext
);
1624 switch (FileInformationClass
)
1626 case FilePositionInformation
:
1627 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1631 case FileDispositionInformation
:
1632 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1634 IrpContext
->DeviceObject
,
1638 case FileAllocationInformation
:
1639 case FileEndOfFileInformation
:
1640 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1642 IrpContext
->DeviceExt
,
1643 (PLARGE_INTEGER
)SystemBuffer
);
1646 case FileBasicInformation
:
1647 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1649 IrpContext
->DeviceExt
,
1653 case FileRenameInformation
:
1654 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1656 IrpContext
->DeviceExt
,
1658 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1662 Status
= STATUS_NOT_SUPPORTED
;
1665 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1667 ExReleaseResourceLite(&FCB
->MainResource
);
1670 if (FileInformationClass
== FileRenameInformation
)
1672 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1675 IrpContext
->Irp
->IoStatus
.Information
= 0;