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
)
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 (BasicInfo
->FileAttributes
!= 0)
172 Attributes
= (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_ARCHIVE
|
173 FILE_ATTRIBUTE_SYSTEM
|
174 FILE_ATTRIBUTE_HIDDEN
|
175 FILE_ATTRIBUTE_DIRECTORY
|
176 FILE_ATTRIBUTE_READONLY
));
178 if (vfatFCBIsDirectory(FCB
))
180 Attributes
|= FILE_ATTRIBUTE_DIRECTORY
;
184 if (BooleanFlagOn(BasicInfo
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
))
186 DPRINT("Setting directory attribute on a file!\n");
187 return STATUS_INVALID_PARAMETER
;
191 if (Attributes
!= *FCB
->Attributes
)
193 *FCB
->Attributes
= Attributes
;
194 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
198 if (vfatVolumeIsFatX(DeviceExt
))
200 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
202 FsdSystemTimeToDosDateTime(DeviceExt
,
203 &BasicInfo
->CreationTime
,
204 &FCB
->entry
.FatX
.CreationDate
,
205 &FCB
->entry
.FatX
.CreationTime
);
208 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
210 FsdSystemTimeToDosDateTime(DeviceExt
,
211 &BasicInfo
->LastAccessTime
,
212 &FCB
->entry
.FatX
.AccessDate
,
213 &FCB
->entry
.FatX
.AccessTime
);
216 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
218 FsdSystemTimeToDosDateTime(DeviceExt
,
219 &BasicInfo
->LastWriteTime
,
220 &FCB
->entry
.FatX
.UpdateDate
,
221 &FCB
->entry
.FatX
.UpdateTime
);
226 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
228 FsdSystemTimeToDosDateTime(DeviceExt
,
229 &BasicInfo
->CreationTime
,
230 &FCB
->entry
.Fat
.CreationDate
,
231 &FCB
->entry
.Fat
.CreationTime
);
234 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
236 FsdSystemTimeToDosDateTime(DeviceExt
,
237 &BasicInfo
->LastAccessTime
,
238 &FCB
->entry
.Fat
.AccessDate
,
242 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
244 FsdSystemTimeToDosDateTime(DeviceExt
,
245 &BasicInfo
->LastWriteTime
,
246 &FCB
->entry
.Fat
.UpdateDate
,
247 &FCB
->entry
.Fat
.UpdateTime
);
251 VfatUpdateEntry(FCB
, vfatVolumeIsFatX(DeviceExt
));
253 return STATUS_SUCCESS
;
257 VfatGetBasicInformation(
258 PFILE_OBJECT FileObject
,
260 PDEVICE_EXTENSION DeviceExt
,
261 PFILE_BASIC_INFORMATION BasicInfo
,
264 UNREFERENCED_PARAMETER(FileObject
);
266 DPRINT("VfatGetBasicInformation()\n");
268 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
269 return STATUS_BUFFER_OVERFLOW
;
271 if (vfatVolumeIsFatX(DeviceExt
))
273 FsdDosDateTimeToSystemTime(DeviceExt
,
274 FCB
->entry
.FatX
.CreationDate
,
275 FCB
->entry
.FatX
.CreationTime
,
276 &BasicInfo
->CreationTime
);
277 FsdDosDateTimeToSystemTime(DeviceExt
,
278 FCB
->entry
.FatX
.AccessDate
,
279 FCB
->entry
.FatX
.AccessTime
,
280 &BasicInfo
->LastAccessTime
);
281 FsdDosDateTimeToSystemTime(DeviceExt
,
282 FCB
->entry
.FatX
.UpdateDate
,
283 FCB
->entry
.FatX
.UpdateTime
,
284 &BasicInfo
->LastWriteTime
);
285 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
289 FsdDosDateTimeToSystemTime(DeviceExt
,
290 FCB
->entry
.Fat
.CreationDate
,
291 FCB
->entry
.Fat
.CreationTime
,
292 &BasicInfo
->CreationTime
);
293 FsdDosDateTimeToSystemTime(DeviceExt
,
294 FCB
->entry
.Fat
.AccessDate
,
296 &BasicInfo
->LastAccessTime
);
297 FsdDosDateTimeToSystemTime(DeviceExt
,
298 FCB
->entry
.Fat
.UpdateDate
,
299 FCB
->entry
.Fat
.UpdateTime
,
300 &BasicInfo
->LastWriteTime
);
301 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
304 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
305 /* Synthesize FILE_ATTRIBUTE_NORMAL */
306 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
307 FILE_ATTRIBUTE_ARCHIVE
|
308 FILE_ATTRIBUTE_SYSTEM
|
309 FILE_ATTRIBUTE_HIDDEN
|
310 FILE_ATTRIBUTE_READONLY
)))
312 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
313 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
315 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
317 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
318 return STATUS_SUCCESS
;
324 VfatSetDispositionInformation(
325 PFILE_OBJECT FileObject
,
327 PDEVICE_EXTENSION DeviceExt
,
328 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
330 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
332 ASSERT(DeviceExt
!= NULL
);
333 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
336 if (!DispositionInfo
->DeleteFile
)
338 /* undelete the file */
339 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
340 FileObject
->DeletePending
= FALSE
;
341 return STATUS_SUCCESS
;
344 if (BooleanFlagOn(FCB
->Flags
, FCB_DELETE_PENDING
))
346 /* stream already marked for deletion. just update the file object */
347 FileObject
->DeletePending
= TRUE
;
348 return STATUS_SUCCESS
;
351 if (vfatFCBIsReadOnly(FCB
))
353 return STATUS_CANNOT_DELETE
;
356 if (vfatFCBIsRoot(FCB
) ||
357 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
358 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
360 /* we cannot delete a '.', '..' or the root directory */
361 return STATUS_ACCESS_DENIED
;
364 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
366 /* can't delete a file if its mapped into a process */
368 DPRINT("MmFlushImageSection returned FALSE\n");
369 return STATUS_CANNOT_DELETE
;
372 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(DeviceExt
, FCB
))
374 /* can't delete a non-empty directory */
376 return STATUS_DIRECTORY_NOT_EMPTY
;
380 FCB
->Flags
|= FCB_DELETE_PENDING
;
381 FileObject
->DeletePending
= TRUE
;
383 return STATUS_SUCCESS
;
387 vfatPrepareTargetForRename(
388 IN PDEVICE_EXTENSION DeviceExt
,
389 IN PVFATFCB
* ParentFCB
,
390 IN PUNICODE_STRING NewName
,
391 IN BOOLEAN ReplaceIfExists
,
392 IN PUNICODE_STRING ParentName
,
393 OUT PBOOLEAN Deleted
)
398 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
401 /* Try to open target */
402 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
404 if (NT_SUCCESS(Status
))
406 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
407 /* Check whether we are allowed to replace */
410 /* If that's a directory or a read-only file, we're not allowed */
411 if (vfatFCBIsDirectory(TargetFcb
) || vfatFCBIsReadOnly(TargetFcb
))
413 DPRINT("And this is a readonly file!\n");
414 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
416 vfatReleaseFCB(DeviceExt
, TargetFcb
);
417 return STATUS_OBJECT_NAME_COLLISION
;
421 /* If we still have a file object, close it. */
422 if (TargetFcb
->FileObject
)
424 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
426 DPRINT("MmFlushImageSection failed.\n");
427 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
429 vfatReleaseFCB(DeviceExt
, TargetFcb
);
430 return STATUS_ACCESS_DENIED
;
433 TargetFcb
->FileObject
->DeletePending
= TRUE
;
434 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
437 /* If we are here, ensure the file isn't open by anyone! */
438 if (TargetFcb
->OpenHandleCount
!= 0)
440 DPRINT("There are still open handles for this file.\n");
441 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
443 vfatReleaseFCB(DeviceExt
, TargetFcb
);
444 return STATUS_ACCESS_DENIED
;
447 /* Effectively delete old file to allow renaming */
448 DPRINT("Effectively deleting the file.\n");
449 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
450 vfatReleaseFCB(DeviceExt
, TargetFcb
);
452 return STATUS_SUCCESS
;
456 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
458 vfatReleaseFCB(DeviceExt
, TargetFcb
);
459 return STATUS_OBJECT_NAME_COLLISION
;
462 else if (*ParentFCB
!= NULL
)
464 return STATUS_SUCCESS
;
473 IsThereAChildOpened(PVFATFCB FCB
)
478 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
480 VolFCB
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
481 if (VolFCB
->OpenHandleCount
!= 0)
483 ASSERT(VolFCB
->parentFcb
== FCB
);
484 DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB
->PathNameU
, VolFCB
->RefCount
, VolFCB
->OpenHandleCount
);
488 if (vfatFCBIsDirectory(VolFCB
) && !IsListEmpty(&VolFCB
->ParentListHead
))
490 if (IsThereAChildOpened(VolFCB
))
503 PDEVICE_EXTENSION DeviceExt
,
509 if (IsListEmpty(&FCB
->ParentListHead
))
512 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
516 Child
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
517 DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child
->PathNameU
, Child
->RefCount
, FCB
->RefCount
);
519 Status
= vfatSetFCBNewDirName(DeviceExt
, Child
, FCB
);
520 if (!NT_SUCCESS(Status
))
523 if (vfatFCBIsDirectory(Child
))
525 VfatRenameChildFCB(DeviceExt
, Child
);
531 * FUNCTION: Set the file name information
535 VfatSetRenameInformation(
536 PFILE_OBJECT FileObject
,
538 PDEVICE_EXTENSION DeviceExt
,
539 PFILE_RENAME_INFORMATION RenameInfo
,
540 PFILE_OBJECT TargetFileObject
)
542 #ifdef NASSERTS_RENAME
543 #pragma push_macro("ASSERT")
545 #define ASSERT(x) ((VOID) 0)
548 UNICODE_STRING NewName
;
549 UNICODE_STRING SourcePath
;
550 UNICODE_STRING SourceFile
;
551 UNICODE_STRING NewPath
;
552 UNICODE_STRING NewFile
;
553 PFILE_OBJECT RootFileObject
;
555 UNICODE_STRING RenameInfoString
;
557 IO_STATUS_BLOCK IoStatusBlock
;
558 OBJECT_ATTRIBUTES ObjectAttributes
;
560 BOOLEAN DeletedTarget
;
561 ULONG OldReferences
, NewReferences
;
564 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
566 /* Disallow renaming root */
567 if (vfatFCBIsRoot(FCB
))
569 return STATUS_INVALID_PARAMETER
;
572 OldReferences
= FCB
->parentFcb
->RefCount
;
573 #ifdef NASSERTS_RENAME
574 UNREFERENCED_PARAMETER(OldReferences
);
577 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
578 if (RenameInfo
->RootDirectory
!= NULL
)
580 /* We cannot tolerate relative opening with a full path */
581 if (RenameInfo
->FileName
[0] == L
'\\')
583 return STATUS_OBJECT_NAME_INVALID
;
586 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
590 (PVOID
*)&RootFileObject
,
592 if (!NT_SUCCESS(Status
))
597 RootFCB
= RootFileObject
->FsContext
;
600 RtlInitEmptyUnicodeString(&NewName
, NULL
, 0);
603 if (TargetFileObject
== NULL
)
605 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
606 * information supplied by the user
609 /* First, setup a string we'll work on */
610 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
611 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
612 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
614 /* Check whether we have FQN */
615 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
617 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
618 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
619 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
620 RenameInfoString
.Buffer
[4] <= L
'Z'))
622 /* If so, open its target directory */
623 InitializeObjectAttributes(&ObjectAttributes
,
625 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
628 Status
= IoCreateFile(&TargetHandle
,
629 FILE_WRITE_DATA
| SYNCHRONIZE
,
633 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
635 FILE_OPEN_FOR_BACKUP_INTENT
,
639 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
640 if (!NT_SUCCESS(Status
))
645 /* Get its FO to get the FCB */
646 Status
= ObReferenceObjectByHandle(TargetHandle
,
650 (PVOID
*)&TargetFileObject
,
652 if (!NT_SUCCESS(Status
))
654 ZwClose(TargetHandle
);
658 /* Are we working on the same volume? */
659 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
661 ObDereferenceObject(TargetFileObject
);
662 ZwClose(TargetHandle
);
663 TargetFileObject
= NULL
;
664 Status
= STATUS_NOT_SAME_DEVICE
;
671 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
672 if (RenameInfo
->RootDirectory
!= NULL
)
674 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
676 else if (RenameInfo
->FileName
[0] != L
'\\')
678 /* We don't have full path, and we don't have root directory:
679 * => we move inside the same directory
681 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
683 else if (TargetFileObject
!= NULL
)
686 * => we need to use its correct path
688 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
691 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
692 if (NewName
.Buffer
== NULL
)
694 if (TargetFileObject
!= NULL
)
696 ObDereferenceObject(TargetFileObject
);
697 ZwClose(TargetHandle
);
698 TargetFileObject
= NULL
;
700 Status
= STATUS_INSUFFICIENT_RESOURCES
;
704 if (RenameInfo
->RootDirectory
!= NULL
)
706 /* Here, copy first absolute and then append relative */
707 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
708 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
709 NewName
.Length
+= sizeof(WCHAR
);
710 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
712 else if (RenameInfo
->FileName
[0] != L
'\\')
714 /* Here, copy first work directory and then append filename */
715 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
716 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
717 NewName
.Length
+= sizeof(WCHAR
);
718 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
720 else if (TargetFileObject
!= NULL
)
722 /* Here, copy first path name and then append filename */
723 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
724 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
725 NewName
.Length
+= sizeof(WCHAR
);
726 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
730 /* Here we should have full path, so simply copy it */
731 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
734 /* Do we have to cleanup some stuff? */
735 if (TargetFileObject
!= NULL
)
737 ObDereferenceObject(TargetFileObject
);
738 ZwClose(TargetHandle
);
739 TargetFileObject
= NULL
;
744 /* At that point, we shouldn't care about whether we are relative opening
745 * Target FO FCB should already have full path
748 /* Before constructing string, just make a sanity check (just to be sure!) */
749 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
751 Status
= STATUS_NOT_SAME_DEVICE
;
756 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
757 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
758 if (NewName
.Buffer
== NULL
)
760 Status
= STATUS_INSUFFICIENT_RESOURCES
;
764 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
765 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
766 NewName
.Length
+= sizeof(WCHAR
);
767 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
770 /* Explode our paths to get path & filename */
771 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
772 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
773 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
774 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
776 if (vfatFCBIsDirectory(FCB
) && !IsListEmpty(&FCB
->ParentListHead
))
778 if (IsThereAChildOpened(FCB
))
780 Status
= STATUS_ACCESS_DENIED
;
781 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
786 /* Are we working in place? */
787 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
789 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
791 Status
= STATUS_SUCCESS
;
792 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
796 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
798 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
799 &(DeviceExt
->NotifyList
),
800 (PSTRING
)&FCB
->PathNameU
,
801 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
804 (vfatFCBIsDirectory(FCB
) ?
805 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
806 FILE_ACTION_RENAMED_OLD_NAME
,
808 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
809 if (NT_SUCCESS(Status
))
811 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
812 &(DeviceExt
->NotifyList
),
813 (PSTRING
)&FCB
->PathNameU
,
814 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
817 (vfatFCBIsDirectory(FCB
) ?
818 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
819 FILE_ACTION_RENAMED_NEW_NAME
,
825 /* Try to find target */
826 ParentFCB
= FCB
->parentFcb
;
827 vfatGrabFCB(DeviceExt
, ParentFCB
);
828 Status
= vfatPrepareTargetForRename(DeviceExt
,
831 RenameInfo
->ReplaceIfExists
,
834 if (!NT_SUCCESS(Status
))
836 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
837 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
841 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
842 &(DeviceExt
->NotifyList
),
843 (PSTRING
)&FCB
->PathNameU
,
844 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
847 (vfatFCBIsDirectory(FCB
) ?
848 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
849 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
851 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
852 if (NT_SUCCESS(Status
))
856 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
857 &(DeviceExt
->NotifyList
),
858 (PSTRING
)&FCB
->PathNameU
,
859 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
862 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
863 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
864 FILE_ACTION_MODIFIED
,
869 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
870 &(DeviceExt
->NotifyList
),
871 (PSTRING
)&FCB
->PathNameU
,
872 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
875 (vfatFCBIsDirectory(FCB
) ?
876 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
877 FILE_ACTION_RENAMED_NEW_NAME
,
883 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
884 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
889 /* Try to find target */
891 OldParent
= FCB
->parentFcb
;
892 #ifdef NASSERTS_RENAME
893 UNREFERENCED_PARAMETER(OldParent
);
895 Status
= vfatPrepareTargetForRename(DeviceExt
,
898 RenameInfo
->ReplaceIfExists
,
901 if (!NT_SUCCESS(Status
))
903 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
907 NewReferences
= ParentFCB
->RefCount
;
908 #ifdef NASSERTS_RENAME
909 UNREFERENCED_PARAMETER(NewReferences
);
912 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
913 &(DeviceExt
->NotifyList
),
914 (PSTRING
)&FCB
->PathNameU
,
915 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
918 (vfatFCBIsDirectory(FCB
) ?
919 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
922 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
923 if (NT_SUCCESS(Status
))
927 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
928 &(DeviceExt
->NotifyList
),
929 (PSTRING
)&FCB
->PathNameU
,
930 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
933 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
934 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
935 FILE_ACTION_MODIFIED
,
940 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
941 &(DeviceExt
->NotifyList
),
942 (PSTRING
)&FCB
->PathNameU
,
943 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
946 (vfatFCBIsDirectory(FCB
) ?
947 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
954 if (NT_SUCCESS(Status
) && vfatFCBIsDirectory(FCB
))
956 VfatRenameChildFCB(DeviceExt
, FCB
);
959 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
960 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
962 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
963 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
964 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
967 #ifdef NASSERTS_RENAME
968 #pragma pop_macro("ASSERT")
973 * FUNCTION: Retrieve the file name information
977 VfatGetNameInformation(
978 PFILE_OBJECT FileObject
,
980 PDEVICE_EXTENSION DeviceExt
,
981 PFILE_NAME_INFORMATION NameInfo
,
986 UNREFERENCED_PARAMETER(FileObject
);
987 UNREFERENCED_PARAMETER(DeviceExt
);
989 ASSERT(NameInfo
!= NULL
);
992 /* If buffer can't hold at least the file name length, bail out */
993 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
994 return STATUS_BUFFER_OVERFLOW
;
996 /* Save file name length, and as much file len, as buffer length allows */
997 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
999 /* Calculate amount of bytes to copy not to overflow the buffer */
1000 BytesToCopy
= min(FCB
->PathNameU
.Length
,
1001 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
1003 /* Fill in the bytes */
1004 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
1006 /* Check if we could write more but are not able to */
1007 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
1009 /* Return number of bytes written */
1010 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
1011 return STATUS_BUFFER_OVERFLOW
;
1014 /* We filled up as many bytes, as needed */
1015 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
1017 return STATUS_SUCCESS
;
1022 VfatGetInternalInformation(
1024 PDEVICE_EXTENSION DeviceExt
,
1025 PFILE_INTERNAL_INFORMATION InternalInfo
,
1026 PULONG BufferLength
)
1028 ASSERT(InternalInfo
);
1031 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
1032 return STATUS_BUFFER_OVERFLOW
;
1034 InternalInfo
->IndexNumber
.QuadPart
= (LONGLONG
)vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
) * DeviceExt
->FatInfo
.BytesPerCluster
;
1036 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
1037 return STATUS_SUCCESS
;
1042 * FUNCTION: Retrieve the file network open information
1046 VfatGetNetworkOpenInformation(
1048 PDEVICE_EXTENSION DeviceExt
,
1049 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
1050 PULONG BufferLength
)
1052 ASSERT(NetworkInfo
);
1055 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
1056 return(STATUS_BUFFER_OVERFLOW
);
1058 if (vfatVolumeIsFatX(DeviceExt
))
1060 FsdDosDateTimeToSystemTime(DeviceExt
,
1061 Fcb
->entry
.FatX
.CreationDate
,
1062 Fcb
->entry
.FatX
.CreationTime
,
1063 &NetworkInfo
->CreationTime
);
1064 FsdDosDateTimeToSystemTime(DeviceExt
,
1065 Fcb
->entry
.FatX
.AccessDate
,
1066 Fcb
->entry
.FatX
.AccessTime
,
1067 &NetworkInfo
->LastAccessTime
);
1068 FsdDosDateTimeToSystemTime(DeviceExt
,
1069 Fcb
->entry
.FatX
.UpdateDate
,
1070 Fcb
->entry
.FatX
.UpdateTime
,
1071 &NetworkInfo
->LastWriteTime
);
1072 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1076 FsdDosDateTimeToSystemTime(DeviceExt
,
1077 Fcb
->entry
.Fat
.CreationDate
,
1078 Fcb
->entry
.Fat
.CreationTime
,
1079 &NetworkInfo
->CreationTime
);
1080 FsdDosDateTimeToSystemTime(DeviceExt
,
1081 Fcb
->entry
.Fat
.AccessDate
,
1083 &NetworkInfo
->LastAccessTime
);
1084 FsdDosDateTimeToSystemTime(DeviceExt
,
1085 Fcb
->entry
.Fat
.UpdateDate
,
1086 Fcb
->entry
.Fat
.UpdateTime
,
1087 &NetworkInfo
->LastWriteTime
);
1088 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1091 if (vfatFCBIsDirectory(Fcb
))
1093 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1094 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1098 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1099 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1102 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1103 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1104 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1105 FILE_ATTRIBUTE_ARCHIVE
|
1106 FILE_ATTRIBUTE_SYSTEM
|
1107 FILE_ATTRIBUTE_HIDDEN
|
1108 FILE_ATTRIBUTE_READONLY
)))
1110 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1111 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1114 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1115 return STATUS_SUCCESS
;
1121 VfatGetEaInformation(
1122 PFILE_OBJECT FileObject
,
1124 PDEVICE_EXTENSION DeviceExt
,
1125 PFILE_EA_INFORMATION Info
,
1126 PULONG BufferLength
)
1128 UNREFERENCED_PARAMETER(FileObject
);
1129 UNREFERENCED_PARAMETER(Fcb
);
1131 /* FIXME - use SEH to access the buffer! */
1133 *BufferLength
-= sizeof(*Info
);
1134 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1135 DeviceExt
->FatInfo
.FatType
== FAT16
)
1138 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1140 return STATUS_SUCCESS
;
1145 * FUNCTION: Retrieve the all file information
1149 VfatGetAllInformation(
1150 PFILE_OBJECT FileObject
,
1152 PDEVICE_EXTENSION DeviceExt
,
1153 PFILE_ALL_INFORMATION Info
,
1154 PULONG BufferLength
)
1161 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1162 return STATUS_BUFFER_OVERFLOW
;
1164 /* Basic Information */
1165 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceExt
, &Info
->BasicInformation
, BufferLength
);
1166 if (!NT_SUCCESS(Status
)) return Status
;
1167 /* Standard Information */
1168 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1169 if (!NT_SUCCESS(Status
)) return Status
;
1170 /* Internal Information */
1171 Status
= VfatGetInternalInformation(Fcb
, DeviceExt
, &Info
->InternalInformation
, BufferLength
);
1172 if (!NT_SUCCESS(Status
)) return Status
;
1173 /* EA Information */
1174 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceExt
, &Info
->EaInformation
, BufferLength
);
1175 if (!NT_SUCCESS(Status
)) return Status
;
1176 /* Access Information: The IO-Manager adds this information */
1177 *BufferLength
-= sizeof(FILE_ACCESS_INFORMATION
);
1178 /* Position Information */
1179 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceExt
, &Info
->PositionInformation
, BufferLength
);
1180 if (!NT_SUCCESS(Status
)) return Status
;
1181 /* Mode Information: The IO-Manager adds this information */
1182 *BufferLength
-= sizeof(FILE_MODE_INFORMATION
);
1183 /* Alignment Information: The IO-Manager adds this information */
1184 *BufferLength
-= sizeof(FILE_ALIGNMENT_INFORMATION
);
1185 /* Name Information */
1186 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceExt
, &Info
->NameInformation
, BufferLength
);
1194 PFILE_OBJECT FileObject
,
1202 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, ClusterSize
);
1206 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1208 if (!vfatFCBIsDirectory(Fcb
))
1211 Fcb
->entry
.FatX
.FileSize
= Size
;
1213 Fcb
->entry
.Fat
.FileSize
= Size
;
1215 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1216 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1218 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1222 VfatSetAllocationSizeInformation(
1223 PFILE_OBJECT FileObject
,
1225 PDEVICE_EXTENSION DeviceExt
,
1226 PLARGE_INTEGER AllocationSize
)
1229 ULONG Cluster
, FirstCluster
;
1232 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1233 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1235 BOOLEAN AllocSizeChanged
= FALSE
, IsFatX
= vfatVolumeIsFatX(DeviceExt
);
1237 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1238 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1241 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1243 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1245 if (AllocationSize
->u
.HighPart
> 0)
1247 return STATUS_INVALID_PARAMETER
;
1250 if (OldSize
== NewSize
)
1252 return STATUS_SUCCESS
;
1255 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1257 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1259 AllocSizeChanged
= TRUE
;
1260 if (FirstCluster
== 0)
1262 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1263 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1264 if (!NT_SUCCESS(Status
))
1266 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1270 if (FirstCluster
== 0xffffffff)
1272 return STATUS_DISK_FULL
;
1275 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1276 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1278 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1281 NCluster
= Cluster
= FirstCluster
;
1282 Status
= STATUS_SUCCESS
;
1283 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1285 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1286 WriteCluster(DeviceExt
, Cluster
, 0);
1289 return STATUS_DISK_FULL
;
1294 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1298 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1300 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1301 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1305 ASSERT((FirstCluster
>> 16) == 0);
1306 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1312 if (Fcb
->LastCluster
> 0)
1314 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1316 Cluster
= Fcb
->LastCluster
;
1317 Status
= STATUS_SUCCESS
;
1321 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1322 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1328 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1329 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1333 if (!NT_SUCCESS(Status
))
1338 Fcb
->LastCluster
= Cluster
;
1339 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1341 /* FIXME: Check status */
1342 /* Cluster points now to the last cluster within the chain */
1343 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1344 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1346 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1350 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1351 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1353 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1355 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1356 WriteCluster(DeviceExt
, Cluster
, 0);
1359 return STATUS_DISK_FULL
;
1362 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1364 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1366 DPRINT("Check for the ability to set file size\n");
1367 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1368 (PLARGE_INTEGER
)AllocationSize
))
1370 DPRINT("Couldn't set file size!\n");
1371 return STATUS_USER_MAPPED_FILE
;
1373 DPRINT("Can set file size\n");
1375 AllocSizeChanged
= TRUE
;
1376 /* FIXME: Use the cached cluster/offset better way. */
1377 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1378 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1381 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1382 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1386 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1387 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1394 Fcb
->entry
.FatX
.FirstCluster
= 0;
1398 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1400 Fcb
->entry
.Fat
.FirstCluster
= 0;
1401 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1405 Fcb
->entry
.Fat
.FirstCluster
= 0;
1409 NCluster
= Cluster
= FirstCluster
;
1410 Status
= STATUS_SUCCESS
;
1413 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1415 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1416 WriteCluster(DeviceExt
, Cluster
, 0);
1422 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
, vfatVolumeIsFatX(DeviceExt
));
1425 /* Update the on-disk directory entry */
1426 Fcb
->Flags
|= FCB_IS_DIRTY
;
1427 if (AllocSizeChanged
)
1429 VfatUpdateEntry(Fcb
, vfatVolumeIsFatX(DeviceExt
));
1431 return STATUS_SUCCESS
;
1435 * FUNCTION: Retrieve the specified file information
1438 VfatQueryInformation(
1439 PVFAT_IRP_CONTEXT IrpContext
)
1441 FILE_INFORMATION_CLASS FileInformationClass
;
1444 NTSTATUS Status
= STATUS_SUCCESS
;
1451 /* INITIALIZATION */
1452 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1453 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1455 DPRINT("VfatQueryInformation is called for '%s'\n",
1456 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1460 DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
1461 IrpContext
->Irp
->IoStatus
.Information
= 0;
1462 return STATUS_INVALID_PARAMETER
;
1465 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1466 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1468 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1470 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1471 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1473 return VfatMarkIrpContextForQueue(IrpContext
);
1477 switch (FileInformationClass
)
1479 case FileStandardInformation
:
1480 Status
= VfatGetStandardInformation(FCB
,
1485 case FilePositionInformation
:
1486 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1488 IrpContext
->DeviceExt
,
1493 case FileBasicInformation
:
1494 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1496 IrpContext
->DeviceExt
,
1501 case FileNameInformation
:
1502 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1504 IrpContext
->DeviceExt
,
1509 case FileInternalInformation
:
1510 Status
= VfatGetInternalInformation(FCB
,
1511 IrpContext
->DeviceExt
,
1516 case FileNetworkOpenInformation
:
1517 Status
= VfatGetNetworkOpenInformation(FCB
,
1518 IrpContext
->DeviceExt
,
1523 case FileAllInformation
:
1524 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1526 IrpContext
->DeviceExt
,
1531 case FileEaInformation
:
1532 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1534 IrpContext
->DeviceExt
,
1539 case FileAlternateNameInformation
:
1540 Status
= STATUS_NOT_IMPLEMENTED
;
1544 Status
= STATUS_INVALID_PARAMETER
;
1547 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1549 ExReleaseResourceLite(&FCB
->MainResource
);
1552 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1553 IrpContext
->Irp
->IoStatus
.Information
=
1554 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1556 IrpContext
->Irp
->IoStatus
.Information
= 0;
1562 * FUNCTION: Retrieve the specified file information
1566 PVFAT_IRP_CONTEXT IrpContext
)
1568 FILE_INFORMATION_CLASS FileInformationClass
;
1570 NTSTATUS Status
= STATUS_SUCCESS
;
1576 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1578 /* INITIALIZATION */
1579 FileInformationClass
=
1580 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1581 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1582 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1584 DPRINT("VfatSetInformation is called for '%s'\n",
1585 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1587 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1588 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1592 DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
1593 IrpContext
->Irp
->IoStatus
.Information
= 0;
1594 return STATUS_INVALID_PARAMETER
;
1597 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1598 the file size would be allowed. If not, we bail with the right error.
1599 We must do this before acquiring the lock. */
1600 if (FileInformationClass
== FileEndOfFileInformation
)
1602 DPRINT("Check for the ability to set file size\n");
1603 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1604 (PLARGE_INTEGER
)SystemBuffer
))
1606 DPRINT("Couldn't set file size!\n");
1607 IrpContext
->Irp
->IoStatus
.Information
= 0;
1608 return STATUS_USER_MAPPED_FILE
;
1610 DPRINT("Can set file size\n");
1613 if (FileInformationClass
== FileRenameInformation
)
1615 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1616 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1618 return VfatMarkIrpContextForQueue(IrpContext
);
1622 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1624 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1625 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1627 if (FileInformationClass
== FileRenameInformation
)
1629 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1632 return VfatMarkIrpContextForQueue(IrpContext
);
1636 switch (FileInformationClass
)
1638 case FilePositionInformation
:
1639 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1643 case FileDispositionInformation
:
1644 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1646 IrpContext
->DeviceExt
,
1650 case FileAllocationInformation
:
1651 case FileEndOfFileInformation
:
1652 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1654 IrpContext
->DeviceExt
,
1655 (PLARGE_INTEGER
)SystemBuffer
);
1658 case FileBasicInformation
:
1659 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1661 IrpContext
->DeviceExt
,
1665 case FileRenameInformation
:
1666 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1668 IrpContext
->DeviceExt
,
1670 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1674 Status
= STATUS_NOT_SUPPORTED
;
1677 if (!BooleanFlagOn(FCB
->Flags
, FCB_IS_PAGE_FILE
))
1679 ExReleaseResourceLite(&FCB
->MainResource
);
1682 if (FileInformationClass
== FileRenameInformation
)
1684 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1687 IrpContext
->Irp
->IoStatus
.Information
= 0;