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 (vfatVolumeIsFatX(DeviceExt
))
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
, vfatVolumeIsFatX(DeviceExt
));
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 (vfatVolumeIsFatX(DeviceExt
))
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
)
316 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
318 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
320 ASSERT(DeviceExt
!= NULL
);
321 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
324 if (!DispositionInfo
->DeleteFile
)
326 /* undelete the file */
327 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
328 FileObject
->DeletePending
= FALSE
;
329 return STATUS_SUCCESS
;
332 if (BooleanFlagOn(FCB
->Flags
, FCB_DELETE_PENDING
))
334 /* stream already marked for deletion. just update the file object */
335 FileObject
->DeletePending
= TRUE
;
336 return STATUS_SUCCESS
;
339 if (vfatFCBIsReadOnly(FCB
))
341 return STATUS_CANNOT_DELETE
;
344 if (vfatFCBIsRoot(FCB
) ||
345 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
346 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
348 /* we cannot delete a '.', '..' or the root directory */
349 return STATUS_ACCESS_DENIED
;
352 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
354 /* can't delete a file if its mapped into a process */
356 DPRINT("MmFlushImageSection returned FALSE\n");
357 return STATUS_CANNOT_DELETE
;
360 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(DeviceExt
, FCB
))
362 /* can't delete a non-empty directory */
364 return STATUS_DIRECTORY_NOT_EMPTY
;
368 FCB
->Flags
|= FCB_DELETE_PENDING
;
369 FileObject
->DeletePending
= TRUE
;
371 return STATUS_SUCCESS
;
375 vfatPrepareTargetForRename(
376 IN PDEVICE_EXTENSION DeviceExt
,
377 IN PVFATFCB
* ParentFCB
,
378 IN PUNICODE_STRING NewName
,
379 IN BOOLEAN ReplaceIfExists
,
380 IN PUNICODE_STRING ParentName
,
381 OUT PBOOLEAN Deleted
)
386 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
389 /* Try to open target */
390 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
392 if (NT_SUCCESS(Status
))
394 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
395 /* Check whether we are allowed to replace */
398 /* If that's a directory or a read-only file, we're not allowed */
399 if (vfatFCBIsDirectory(TargetFcb
) || vfatFCBIsReadOnly(TargetFcb
))
401 DPRINT("And this is a readonly file!\n");
402 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
404 vfatReleaseFCB(DeviceExt
, TargetFcb
);
405 return STATUS_OBJECT_NAME_COLLISION
;
409 /* If we still have a file object, close it. */
410 if (TargetFcb
->FileObject
)
412 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
414 DPRINT("MmFlushImageSection failed.\n");
415 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
417 vfatReleaseFCB(DeviceExt
, TargetFcb
);
418 return STATUS_ACCESS_DENIED
;
421 TargetFcb
->FileObject
->DeletePending
= TRUE
;
422 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
425 /* If we are here, ensure the file isn't open by anyone! */
426 if (TargetFcb
->OpenHandleCount
!= 0)
428 DPRINT("There are still open handles for this file.\n");
429 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
431 vfatReleaseFCB(DeviceExt
, TargetFcb
);
432 return STATUS_ACCESS_DENIED
;
435 /* Effectively delete old file to allow renaming */
436 DPRINT("Effectively deleting the file.\n");
437 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
438 vfatReleaseFCB(DeviceExt
, TargetFcb
);
440 return STATUS_SUCCESS
;
444 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
446 vfatReleaseFCB(DeviceExt
, TargetFcb
);
447 return STATUS_OBJECT_NAME_COLLISION
;
450 else if (*ParentFCB
!= NULL
)
452 return STATUS_SUCCESS
;
461 IsThereAChildOpened(PVFATFCB FCB
)
466 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
468 VolFCB
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
469 if (VolFCB
->OpenHandleCount
!= 0)
471 ASSERT(VolFCB
->parentFcb
== FCB
);
472 DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB
->PathNameU
, VolFCB
->RefCount
, VolFCB
->OpenHandleCount
);
476 if (vfatFCBIsDirectory(VolFCB
) && !IsListEmpty(&VolFCB
->ParentListHead
))
478 if (IsThereAChildOpened(VolFCB
))
491 PDEVICE_EXTENSION DeviceExt
,
497 if (IsListEmpty(&FCB
->ParentListHead
))
500 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
504 Child
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
505 DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child
->PathNameU
, Child
->RefCount
, FCB
->RefCount
);
507 Status
= vfatSetFCBNewDirName(DeviceExt
, Child
, FCB
);
508 if (!NT_SUCCESS(Status
))
511 if (vfatFCBIsDirectory(Child
))
513 VfatRenameChildFCB(DeviceExt
, Child
);
519 * FUNCTION: Set the file name information
523 VfatSetRenameInformation(
524 PFILE_OBJECT FileObject
,
526 PDEVICE_EXTENSION DeviceExt
,
527 PFILE_RENAME_INFORMATION RenameInfo
,
528 PFILE_OBJECT TargetFileObject
)
530 #ifdef NASSERTS_RENAME
531 #pragma push_macro("ASSERT")
533 #define ASSERT(x) ((VOID) 0)
536 UNICODE_STRING NewName
;
537 UNICODE_STRING SourcePath
;
538 UNICODE_STRING SourceFile
;
539 UNICODE_STRING NewPath
;
540 UNICODE_STRING NewFile
;
541 PFILE_OBJECT RootFileObject
;
543 UNICODE_STRING RenameInfoString
;
545 IO_STATUS_BLOCK IoStatusBlock
;
546 OBJECT_ATTRIBUTES ObjectAttributes
;
548 BOOLEAN DeletedTarget
;
549 ULONG OldReferences
, NewReferences
;
552 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
554 /* Disallow renaming root */
555 if (vfatFCBIsRoot(FCB
))
557 return STATUS_INVALID_PARAMETER
;
560 OldReferences
= FCB
->parentFcb
->RefCount
;
561 #ifdef NASSERTS_RENAME
562 UNREFERENCED_PARAMETER(OldReferences
);
565 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
566 if (RenameInfo
->RootDirectory
!= NULL
)
568 /* We cannot tolerate relative opening with a full path */
569 if (RenameInfo
->FileName
[0] == L
'\\')
571 return STATUS_OBJECT_NAME_INVALID
;
574 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
578 (PVOID
*)&RootFileObject
,
580 if (!NT_SUCCESS(Status
))
585 RootFCB
= RootFileObject
->FsContext
;
588 RtlInitEmptyUnicodeString(&NewName
, NULL
, 0);
591 if (TargetFileObject
== NULL
)
593 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
594 * information supplied by the user
597 /* First, setup a string we'll work on */
598 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
599 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
600 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
602 /* Check whether we have FQN */
603 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
605 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
606 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
607 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
608 RenameInfoString
.Buffer
[4] <= L
'Z'))
610 /* If so, open its target directory */
611 InitializeObjectAttributes(&ObjectAttributes
,
613 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
616 Status
= IoCreateFile(&TargetHandle
,
617 FILE_WRITE_DATA
| SYNCHRONIZE
,
621 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
623 FILE_OPEN_FOR_BACKUP_INTENT
,
627 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
628 if (!NT_SUCCESS(Status
))
633 /* Get its FO to get the FCB */
634 Status
= ObReferenceObjectByHandle(TargetHandle
,
638 (PVOID
*)&TargetFileObject
,
640 if (!NT_SUCCESS(Status
))
642 ZwClose(TargetHandle
);
646 /* Are we working on the same volume? */
647 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
649 ObDereferenceObject(TargetFileObject
);
650 ZwClose(TargetHandle
);
651 TargetFileObject
= NULL
;
652 Status
= STATUS_NOT_SAME_DEVICE
;
659 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
660 if (RenameInfo
->RootDirectory
!= NULL
)
662 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
664 else if (RenameInfo
->FileName
[0] != L
'\\')
666 /* We don't have full path, and we don't have root directory:
667 * => we move inside the same directory
669 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
671 else if (TargetFileObject
!= NULL
)
674 * => we need to use its correct path
676 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
679 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
680 if (NewName
.Buffer
== NULL
)
682 if (TargetFileObject
!= NULL
)
684 ObDereferenceObject(TargetFileObject
);
685 ZwClose(TargetHandle
);
686 TargetFileObject
= NULL
;
688 Status
= STATUS_INSUFFICIENT_RESOURCES
;
692 if (RenameInfo
->RootDirectory
!= NULL
)
694 /* Here, copy first absolute and then append relative */
695 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
696 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
697 NewName
.Length
+= sizeof(WCHAR
);
698 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
700 else if (RenameInfo
->FileName
[0] != L
'\\')
702 /* Here, copy first work directory and then append filename */
703 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
704 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
705 NewName
.Length
+= sizeof(WCHAR
);
706 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
708 else if (TargetFileObject
!= NULL
)
710 /* Here, copy first path name and then append filename */
711 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
712 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
713 NewName
.Length
+= sizeof(WCHAR
);
714 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
718 /* Here we should have full path, so simply copy it */
719 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
722 /* Do we have to cleanup some stuff? */
723 if (TargetFileObject
!= NULL
)
725 ObDereferenceObject(TargetFileObject
);
726 ZwClose(TargetHandle
);
727 TargetFileObject
= NULL
;
732 /* At that point, we shouldn't care about whether we are relative opening
733 * Target FO FCB should already have full path
736 /* Before constructing string, just make a sanity check (just to be sure!) */
737 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
739 Status
= STATUS_NOT_SAME_DEVICE
;
744 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
745 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
746 if (NewName
.Buffer
== NULL
)
748 Status
= STATUS_INSUFFICIENT_RESOURCES
;
752 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
753 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
754 NewName
.Length
+= sizeof(WCHAR
);
755 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
758 /* Explode our paths to get path & filename */
759 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
760 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
761 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
762 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
764 if (vfatFCBIsDirectory(FCB
) && !IsListEmpty(&FCB
->ParentListHead
))
766 if (IsThereAChildOpened(FCB
))
768 Status
= STATUS_ACCESS_DENIED
;
769 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
774 /* Are we working in place? */
775 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
777 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
779 Status
= STATUS_SUCCESS
;
780 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
784 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
786 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
787 &(DeviceExt
->NotifyList
),
788 (PSTRING
)&FCB
->PathNameU
,
789 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
792 (vfatFCBIsDirectory(FCB
) ?
793 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
794 FILE_ACTION_RENAMED_OLD_NAME
,
796 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
797 if (NT_SUCCESS(Status
))
799 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
800 &(DeviceExt
->NotifyList
),
801 (PSTRING
)&FCB
->PathNameU
,
802 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
805 (vfatFCBIsDirectory(FCB
) ?
806 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
807 FILE_ACTION_RENAMED_NEW_NAME
,
813 /* Try to find target */
814 ParentFCB
= FCB
->parentFcb
;
815 vfatGrabFCB(DeviceExt
, ParentFCB
);
816 Status
= vfatPrepareTargetForRename(DeviceExt
,
819 RenameInfo
->ReplaceIfExists
,
822 if (!NT_SUCCESS(Status
))
824 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
825 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
829 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
830 &(DeviceExt
->NotifyList
),
831 (PSTRING
)&FCB
->PathNameU
,
832 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
835 (vfatFCBIsDirectory(FCB
) ?
836 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
837 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
839 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
840 if (NT_SUCCESS(Status
))
844 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
845 &(DeviceExt
->NotifyList
),
846 (PSTRING
)&FCB
->PathNameU
,
847 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
850 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
851 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
852 FILE_ACTION_MODIFIED
,
857 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
858 &(DeviceExt
->NotifyList
),
859 (PSTRING
)&FCB
->PathNameU
,
860 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
863 (vfatFCBIsDirectory(FCB
) ?
864 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
865 FILE_ACTION_RENAMED_NEW_NAME
,
871 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
872 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
877 /* Try to find target */
879 OldParent
= FCB
->parentFcb
;
880 #ifdef NASSERTS_RENAME
881 UNREFERENCED_PARAMETER(OldParent
);
883 Status
= vfatPrepareTargetForRename(DeviceExt
,
886 RenameInfo
->ReplaceIfExists
,
889 if (!NT_SUCCESS(Status
))
891 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
895 NewReferences
= ParentFCB
->RefCount
;
896 #ifdef NASSERTS_RENAME
897 UNREFERENCED_PARAMETER(NewReferences
);
900 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
901 &(DeviceExt
->NotifyList
),
902 (PSTRING
)&FCB
->PathNameU
,
903 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
906 (vfatFCBIsDirectory(FCB
) ?
907 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
910 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
911 if (NT_SUCCESS(Status
))
915 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
916 &(DeviceExt
->NotifyList
),
917 (PSTRING
)&FCB
->PathNameU
,
918 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
921 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
922 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
923 FILE_ACTION_MODIFIED
,
928 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
929 &(DeviceExt
->NotifyList
),
930 (PSTRING
)&FCB
->PathNameU
,
931 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
934 (vfatFCBIsDirectory(FCB
) ?
935 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
942 if (NT_SUCCESS(Status
) && vfatFCBIsDirectory(FCB
))
944 VfatRenameChildFCB(DeviceExt
, FCB
);
947 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
948 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
950 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
951 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
952 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
955 #ifdef NASSERTS_RENAME
956 #pragma pop_macro("ASSERT")
961 * FUNCTION: Retrieve the file name information
965 VfatGetNameInformation(
966 PFILE_OBJECT FileObject
,
968 PDEVICE_OBJECT DeviceObject
,
969 PFILE_NAME_INFORMATION NameInfo
,
974 UNREFERENCED_PARAMETER(FileObject
);
975 UNREFERENCED_PARAMETER(DeviceObject
);
977 ASSERT(NameInfo
!= NULL
);
980 /* If buffer can't hold at least the file name length, bail out */
981 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
982 return STATUS_BUFFER_OVERFLOW
;
984 /* Save file name length, and as much file len, as buffer length allows */
985 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
987 /* Calculate amount of bytes to copy not to overflow the buffer */
988 BytesToCopy
= min(FCB
->PathNameU
.Length
,
989 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
991 /* Fill in the bytes */
992 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
994 /* Check if we could write more but are not able to */
995 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
997 /* Return number of bytes written */
998 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
999 return STATUS_BUFFER_OVERFLOW
;
1002 /* We filled up as many bytes, as needed */
1003 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
1005 return STATUS_SUCCESS
;
1010 VfatGetInternalInformation(
1012 PFILE_INTERNAL_INFORMATION InternalInfo
,
1013 PULONG BufferLength
)
1015 ASSERT(InternalInfo
);
1018 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
1019 return STATUS_BUFFER_OVERFLOW
;
1020 // FIXME: get a real index, that can be used in a create operation
1021 InternalInfo
->IndexNumber
.QuadPart
= 0;
1022 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
1023 return STATUS_SUCCESS
;
1028 * FUNCTION: Retrieve the file network open information
1032 VfatGetNetworkOpenInformation(
1034 PDEVICE_EXTENSION DeviceExt
,
1035 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
1036 PULONG BufferLength
)
1038 ASSERT(NetworkInfo
);
1041 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
1042 return(STATUS_BUFFER_OVERFLOW
);
1044 if (vfatVolumeIsFatX(DeviceExt
))
1046 FsdDosDateTimeToSystemTime(DeviceExt
,
1047 Fcb
->entry
.FatX
.CreationDate
,
1048 Fcb
->entry
.FatX
.CreationTime
,
1049 &NetworkInfo
->CreationTime
);
1050 FsdDosDateTimeToSystemTime(DeviceExt
,
1051 Fcb
->entry
.FatX
.AccessDate
,
1052 Fcb
->entry
.FatX
.AccessTime
,
1053 &NetworkInfo
->LastAccessTime
);
1054 FsdDosDateTimeToSystemTime(DeviceExt
,
1055 Fcb
->entry
.FatX
.UpdateDate
,
1056 Fcb
->entry
.FatX
.UpdateTime
,
1057 &NetworkInfo
->LastWriteTime
);
1058 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1062 FsdDosDateTimeToSystemTime(DeviceExt
,
1063 Fcb
->entry
.Fat
.CreationDate
,
1064 Fcb
->entry
.Fat
.CreationTime
,
1065 &NetworkInfo
->CreationTime
);
1066 FsdDosDateTimeToSystemTime(DeviceExt
,
1067 Fcb
->entry
.Fat
.AccessDate
,
1069 &NetworkInfo
->LastAccessTime
);
1070 FsdDosDateTimeToSystemTime(DeviceExt
,
1071 Fcb
->entry
.Fat
.UpdateDate
,
1072 Fcb
->entry
.Fat
.UpdateTime
,
1073 &NetworkInfo
->LastWriteTime
);
1074 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1077 if (vfatFCBIsDirectory(Fcb
))
1079 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1080 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1084 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1085 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1088 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1089 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1090 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1091 FILE_ATTRIBUTE_ARCHIVE
|
1092 FILE_ATTRIBUTE_SYSTEM
|
1093 FILE_ATTRIBUTE_HIDDEN
|
1094 FILE_ATTRIBUTE_READONLY
)))
1096 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1097 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1100 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1101 return STATUS_SUCCESS
;
1107 VfatGetEaInformation(
1108 PFILE_OBJECT FileObject
,
1110 PDEVICE_OBJECT DeviceObject
,
1111 PFILE_EA_INFORMATION Info
,
1112 PULONG BufferLength
)
1114 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1116 UNREFERENCED_PARAMETER(FileObject
);
1117 UNREFERENCED_PARAMETER(Fcb
);
1119 /* FIXME - use SEH to access the buffer! */
1121 *BufferLength
-= sizeof(*Info
);
1122 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1123 DeviceExt
->FatInfo
.FatType
== FAT16
)
1126 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1128 return STATUS_SUCCESS
;
1133 * FUNCTION: Retrieve the all file information
1137 VfatGetAllInformation(
1138 PFILE_OBJECT FileObject
,
1140 PDEVICE_OBJECT DeviceObject
,
1141 PFILE_ALL_INFORMATION Info
,
1142 PULONG BufferLength
)
1149 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1150 return STATUS_BUFFER_OVERFLOW
;
1152 /* Basic Information */
1153 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
1154 if (!NT_SUCCESS(Status
)) return Status
;
1155 /* Standard Information */
1156 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1157 if (!NT_SUCCESS(Status
)) return Status
;
1158 /* Internal Information */
1159 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
1160 if (!NT_SUCCESS(Status
)) return Status
;
1161 /* EA Information */
1162 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceObject
, &Info
->EaInformation
, BufferLength
);
1163 if (!NT_SUCCESS(Status
)) return Status
;
1164 /* Access Information: The IO-Manager adds this information */
1165 *BufferLength
-= sizeof(FILE_ACCESS_INFORMATION
);
1166 /* Position Information */
1167 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
1168 if (!NT_SUCCESS(Status
)) return Status
;
1169 /* Mode Information: The IO-Manager adds this information */
1170 *BufferLength
-= sizeof(FILE_MODE_INFORMATION
);
1171 /* Alignment Information: The IO-Manager adds this information */
1172 *BufferLength
-= sizeof(FILE_ALIGNMENT_INFORMATION
);
1173 /* Name Information */
1174 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
1182 PFILE_OBJECT FileObject
,
1190 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, ClusterSize
);
1194 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1196 if (!vfatFCBIsDirectory(Fcb
))
1199 Fcb
->entry
.FatX
.FileSize
= Size
;
1201 Fcb
->entry
.Fat
.FileSize
= Size
;
1203 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1204 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1206 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1210 VfatSetAllocationSizeInformation(
1211 PFILE_OBJECT FileObject
,
1213 PDEVICE_EXTENSION DeviceExt
,
1214 PLARGE_INTEGER AllocationSize
)
1217 ULONG Cluster
, FirstCluster
;
1220 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1221 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1223 BOOLEAN AllocSizeChanged
= FALSE
, IsFatX
= vfatVolumeIsFatX(DeviceExt
);
1225 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1226 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1229 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1231 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1233 if (AllocationSize
->u
.HighPart
> 0)
1235 return STATUS_INVALID_PARAMETER
;
1238 if (OldSize
== NewSize
)
1240 return STATUS_SUCCESS
;
1243 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1245 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1247 AllocSizeChanged
= TRUE
;
1248 if (FirstCluster
== 0)
1250 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1251 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1252 if (!NT_SUCCESS(Status
))
1254 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1258 if (FirstCluster
== 0xffffffff)
1260 return STATUS_DISK_FULL
;
1263 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1264 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1266 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1269 NCluster
= Cluster
= FirstCluster
;
1270 Status
= STATUS_SUCCESS
;
1271 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1273 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1274 WriteCluster(DeviceExt
, Cluster
, 0);
1277 return STATUS_DISK_FULL
;
1282 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1286 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1288 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1289 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1293 ASSERT((FirstCluster
>> 16) == 0);
1294 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1300 if (Fcb
->LastCluster
> 0)
1302 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1304 Cluster
= Fcb
->LastCluster
;
1305 Status
= STATUS_SUCCESS
;
1309 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1310 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1316 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1317 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1321 if (!NT_SUCCESS(Status
))
1326 Fcb
->LastCluster
= Cluster
;
1327 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1329 /* FIXME: Check status */
1330 /* Cluster points now to the last cluster within the chain */
1331 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1332 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1334 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1338 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1339 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1341 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1343 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1344 WriteCluster(DeviceExt
, Cluster
, 0);
1347 return STATUS_DISK_FULL
;
1350 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1352 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1354 DPRINT("Check for the ability to set file size\n");
1355 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1356 (PLARGE_INTEGER
)AllocationSize
))
1358 DPRINT("Couldn't set file size!\n");
1359 return STATUS_USER_MAPPED_FILE
;
1361 DPRINT("Can set file size\n");
1363 AllocSizeChanged
= TRUE
;
1364 /* FIXME: Use the cached cluster/offset better way. */
1365 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1366 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1369 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1370 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1374 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1375 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1382 Fcb
->entry
.FatX
.FirstCluster
= 0;
1386 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1388 Fcb
->entry
.Fat
.FirstCluster
= 0;
1389 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1393 Fcb
->entry
.Fat
.FirstCluster
= 0;
1397 NCluster
= Cluster
= FirstCluster
;
1398 Status
= STATUS_SUCCESS
;
1401 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1403 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1404 WriteCluster(DeviceExt
, Cluster
, 0);
1410 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1413 /* Update the on-disk directory entry */
1414 Fcb
->Flags
|= FCB_IS_DIRTY
;
1415 if (AllocSizeChanged
)
1417 VfatUpdateEntry(Fcb
, vfatVolumeIsFatX(DeviceExt
));
1419 return STATUS_SUCCESS
;
1423 * FUNCTION: Retrieve the specified file information
1426 VfatQueryInformation(
1427 PVFAT_IRP_CONTEXT IrpContext
)
1429 FILE_INFORMATION_CLASS FileInformationClass
;
1432 NTSTATUS Status
= STATUS_SUCCESS
;
1439 /* INITIALIZATION */
1440 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1441 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1443 DPRINT("VfatQueryInformation is called for '%s'\n",
1444 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1448 DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
1449 IrpContext
->Irp
->IoStatus
.Information
= 0;
1450 return STATUS_INVALID_PARAMETER
;
1453 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1454 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1456 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1458 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1459 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1461 return VfatMarkIrpContextForQueue(IrpContext
);
1465 switch (FileInformationClass
)
1467 case FileStandardInformation
:
1468 Status
= VfatGetStandardInformation(FCB
,
1473 case FilePositionInformation
:
1474 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1476 IrpContext
->DeviceObject
,
1481 case FileBasicInformation
:
1482 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1484 IrpContext
->DeviceObject
,
1489 case FileNameInformation
:
1490 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1492 IrpContext
->DeviceObject
,
1497 case FileInternalInformation
:
1498 Status
= VfatGetInternalInformation(FCB
,
1503 case FileNetworkOpenInformation
:
1504 Status
= VfatGetNetworkOpenInformation(FCB
,
1505 IrpContext
->DeviceExt
,
1510 case FileAllInformation
:
1511 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1513 IrpContext
->DeviceObject
,
1518 case FileEaInformation
:
1519 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1521 IrpContext
->DeviceObject
,
1526 case FileAlternateNameInformation
:
1527 Status
= STATUS_NOT_IMPLEMENTED
;
1531 Status
= STATUS_INVALID_PARAMETER
;
1534 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1536 ExReleaseResourceLite(&FCB
->MainResource
);
1539 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1540 IrpContext
->Irp
->IoStatus
.Information
=
1541 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1543 IrpContext
->Irp
->IoStatus
.Information
= 0;
1549 * FUNCTION: Retrieve the specified file information
1553 PVFAT_IRP_CONTEXT IrpContext
)
1555 FILE_INFORMATION_CLASS FileInformationClass
;
1557 NTSTATUS Status
= STATUS_SUCCESS
;
1563 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1565 /* INITIALIZATION */
1566 FileInformationClass
=
1567 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1568 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1569 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1571 DPRINT("VfatSetInformation is called for '%s'\n",
1572 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1574 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1575 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1579 DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
1580 IrpContext
->Irp
->IoStatus
.Information
= 0;
1581 return STATUS_INVALID_PARAMETER
;
1584 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1585 the file size would be allowed. If not, we bail with the right error.
1586 We must do this before acquiring the lock. */
1587 if (FileInformationClass
== FileEndOfFileInformation
)
1589 DPRINT("Check for the ability to set file size\n");
1590 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1591 (PLARGE_INTEGER
)SystemBuffer
))
1593 DPRINT("Couldn't set file size!\n");
1594 IrpContext
->Irp
->IoStatus
.Information
= 0;
1595 return STATUS_USER_MAPPED_FILE
;
1597 DPRINT("Can set file size\n");
1600 if (FileInformationClass
== FileRenameInformation
)
1602 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1603 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1605 return VfatMarkIrpContextForQueue(IrpContext
);
1609 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1611 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1612 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1614 if (FileInformationClass
== FileRenameInformation
)
1616 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1619 return VfatMarkIrpContextForQueue(IrpContext
);
1623 switch (FileInformationClass
)
1625 case FilePositionInformation
:
1626 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1630 case FileDispositionInformation
:
1631 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1633 IrpContext
->DeviceObject
,
1637 case FileAllocationInformation
:
1638 case FileEndOfFileInformation
:
1639 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1641 IrpContext
->DeviceExt
,
1642 (PLARGE_INTEGER
)SystemBuffer
);
1645 case FileBasicInformation
:
1646 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1648 IrpContext
->DeviceExt
,
1652 case FileRenameInformation
:
1653 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1655 IrpContext
->DeviceExt
,
1657 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1661 Status
= STATUS_NOT_SUPPORTED
;
1664 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1666 ExReleaseResourceLite(&FCB
->MainResource
);
1669 if (FileInformationClass
== FileRenameInformation
)
1671 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1674 IrpContext
->Irp
->IoStatus
.Information
= 0;