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
= FCB
->Flags
& FCB_DELETE_PENDING
? TRUE
: FALSE
;
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 (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 (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 (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
)
344 return STATUS_CANNOT_DELETE
;
347 if (vfatFCBIsRoot(FCB
) ||
348 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
349 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
351 /* we cannot delete a '.', '..' or the root directory */
354 return STATUS_CANNOT_DELETE
;
355 // return STATUS_ACCESS_DENIED;
358 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
360 /* can't delete a file if its mapped into a process */
362 DPRINT("MmFlushImageSection returned FALSE\n");
364 return STATUS_CANNOT_DELETE
;
367 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
369 /* can't delete a non-empty directory */
372 return STATUS_DIRECTORY_NOT_EMPTY
;
376 FCB
->Flags
|= FCB_DELETE_PENDING
;
377 FileObject
->DeletePending
= TRUE
;
379 return STATUS_SUCCESS
;
383 vfatPrepareTargetForRename(
384 IN PDEVICE_EXTENSION DeviceExt
,
385 IN PVFATFCB
* ParentFCB
,
386 IN PUNICODE_STRING NewName
,
387 IN BOOLEAN ReplaceIfExists
,
388 IN PUNICODE_STRING ParentName
,
389 OUT PBOOLEAN Deleted
)
394 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
397 /* Try to open target */
398 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
400 if (NT_SUCCESS(Status
))
402 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
403 /* Check whether we are allowed to replace */
406 /* If that's a directory or a read-only file, we're not allowed */
407 if (vfatFCBIsDirectory(TargetFcb
) || ((*TargetFcb
->Attributes
& FILE_ATTRIBUTE_READONLY
) == FILE_ATTRIBUTE_READONLY
))
409 DPRINT("And this is a readonly file!\n");
410 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
412 vfatReleaseFCB(DeviceExt
, TargetFcb
);
413 return STATUS_OBJECT_NAME_COLLISION
;
417 /* If we still have a file object, close it. */
418 if (TargetFcb
->FileObject
)
420 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
422 DPRINT("MmFlushImageSection failed.\n");
423 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
425 vfatReleaseFCB(DeviceExt
, TargetFcb
);
426 return STATUS_ACCESS_DENIED
;
429 TargetFcb
->FileObject
->DeletePending
= TRUE
;
430 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
433 /* If we are here, ensure the file isn't open by anyone! */
434 if (TargetFcb
->OpenHandleCount
!= 0)
436 DPRINT("There are still open handles for this file.\n");
437 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
439 vfatReleaseFCB(DeviceExt
, TargetFcb
);
440 return STATUS_ACCESS_DENIED
;
443 /* Effectively delete old file to allow renaming */
444 DPRINT("Effectively deleting the file.\n");
445 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
446 vfatReleaseFCB(DeviceExt
, TargetFcb
);
448 return STATUS_SUCCESS
;
452 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
454 vfatReleaseFCB(DeviceExt
, TargetFcb
);
455 return STATUS_OBJECT_NAME_COLLISION
;
458 else if (*ParentFCB
!= NULL
)
460 return STATUS_SUCCESS
;
468 * FUNCTION: Set the file name information
472 VfatSetRenameInformation(
473 PFILE_OBJECT FileObject
,
475 PDEVICE_EXTENSION DeviceExt
,
476 PFILE_RENAME_INFORMATION RenameInfo
,
477 PFILE_OBJECT TargetFileObject
)
479 #ifdef NASSERTS_RENAME
480 #pragma push_macro("ASSERT")
482 #define ASSERT(x) ((VOID) 0)
485 UNICODE_STRING NewName
;
486 UNICODE_STRING SourcePath
;
487 UNICODE_STRING SourceFile
;
488 UNICODE_STRING NewPath
;
489 UNICODE_STRING NewFile
;
490 PFILE_OBJECT RootFileObject
;
492 UNICODE_STRING RenameInfoString
;
494 IO_STATUS_BLOCK IoStatusBlock
;
495 OBJECT_ATTRIBUTES ObjectAttributes
;
497 BOOLEAN DeletedTarget
;
498 ULONG OldReferences
, NewReferences
;
501 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
503 /* Disallow renaming root */
504 if (vfatFCBIsRoot(FCB
))
506 return STATUS_INVALID_PARAMETER
;
509 OldReferences
= FCB
->parentFcb
->RefCount
;
510 #ifdef NASSERTS_RENAME
511 UNREFERENCED_PARAMETER(OldReferences
);
514 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
515 if (RenameInfo
->RootDirectory
!= NULL
)
517 /* We cannot tolerate relative opening with a full path */
518 if (RenameInfo
->FileName
[0] == L
'\\')
520 return STATUS_OBJECT_NAME_INVALID
;
523 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
527 (PVOID
*)&RootFileObject
,
529 if (!NT_SUCCESS(Status
))
534 RootFCB
= RootFileObject
->FsContext
;
537 RtlInitEmptyUnicodeString(&NewName
, NULL
, 0);
540 if (TargetFileObject
== NULL
)
542 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
543 * information supplied by the user
546 /* First, setup a string we'll work on */
547 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
548 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
549 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
551 /* Check whether we have FQN */
552 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
554 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
555 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
556 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
557 RenameInfoString
.Buffer
[4] <= L
'Z'))
559 /* If so, open its target directory */
560 InitializeObjectAttributes(&ObjectAttributes
,
562 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
565 Status
= IoCreateFile(&TargetHandle
,
566 FILE_WRITE_DATA
| SYNCHRONIZE
,
570 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
572 FILE_OPEN_FOR_BACKUP_INTENT
,
576 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
577 if (!NT_SUCCESS(Status
))
582 /* Get its FO to get the FCB */
583 Status
= ObReferenceObjectByHandle(TargetHandle
,
587 (PVOID
*)&TargetFileObject
,
589 if (!NT_SUCCESS(Status
))
591 ZwClose(TargetHandle
);
595 /* Are we working on the same volume? */
596 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
598 ObDereferenceObject(TargetFileObject
);
599 ZwClose(TargetHandle
);
600 TargetFileObject
= NULL
;
601 Status
= STATUS_NOT_SAME_DEVICE
;
608 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
609 if (RenameInfo
->RootDirectory
!= NULL
)
611 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
613 else if (RenameInfo
->FileName
[0] != L
'\\')
615 /* We don't have full path, and we don't have root directory:
616 * => we move inside the same directory
618 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
620 else if (TargetFileObject
!= NULL
)
623 * => we need to use its correct path
625 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
628 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
629 if (NewName
.Buffer
== NULL
)
631 if (TargetFileObject
!= NULL
)
633 ObDereferenceObject(TargetFileObject
);
634 ZwClose(TargetHandle
);
635 TargetFileObject
= NULL
;
637 Status
= STATUS_INSUFFICIENT_RESOURCES
;
641 if (RenameInfo
->RootDirectory
!= NULL
)
643 /* Here, copy first absolute and then append relative */
644 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
645 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
646 NewName
.Length
+= sizeof(WCHAR
);
647 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
649 else if (RenameInfo
->FileName
[0] != L
'\\')
651 /* Here, copy first work directory and then append filename */
652 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
653 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
654 NewName
.Length
+= sizeof(WCHAR
);
655 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
657 else if (TargetFileObject
!= NULL
)
659 /* Here, copy first path name and then append filename */
660 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
661 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
662 NewName
.Length
+= sizeof(WCHAR
);
663 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
667 /* Here we should have full path, so simply copy it */
668 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
671 /* Do we have to cleanup some stuff? */
672 if (TargetFileObject
!= NULL
)
674 ObDereferenceObject(TargetFileObject
);
675 ZwClose(TargetHandle
);
676 TargetFileObject
= NULL
;
681 /* At that point, we shouldn't care about whether we are relative opening
682 * Target FO FCB should already have full path
685 /* Before constructing string, just make a sanity check (just to be sure!) */
686 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
688 Status
= STATUS_NOT_SAME_DEVICE
;
693 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
694 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
695 if (NewName
.Buffer
== NULL
)
697 Status
= STATUS_INSUFFICIENT_RESOURCES
;
701 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
702 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
703 NewName
.Length
+= sizeof(WCHAR
);
704 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
707 /* Explode our paths to get path & filename */
708 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
709 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
710 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
711 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
713 /* Are we working in place? */
714 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
716 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
718 Status
= STATUS_SUCCESS
;
719 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
723 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
725 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
726 &(DeviceExt
->NotifyList
),
727 (PSTRING
)&FCB
->PathNameU
,
728 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
731 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
732 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
733 FILE_ACTION_RENAMED_OLD_NAME
,
735 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
736 if (NT_SUCCESS(Status
))
738 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
739 &(DeviceExt
->NotifyList
),
740 (PSTRING
)&FCB
->PathNameU
,
741 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
744 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
745 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
746 FILE_ACTION_RENAMED_NEW_NAME
,
752 /* Try to find target */
753 ParentFCB
= FCB
->parentFcb
;
754 vfatGrabFCB(DeviceExt
, ParentFCB
);
755 Status
= vfatPrepareTargetForRename(DeviceExt
,
758 RenameInfo
->ReplaceIfExists
,
761 if (!NT_SUCCESS(Status
))
763 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
764 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
768 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
769 &(DeviceExt
->NotifyList
),
770 (PSTRING
)&FCB
->PathNameU
,
771 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
774 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
775 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
776 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
778 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
779 if (NT_SUCCESS(Status
))
783 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
784 &(DeviceExt
->NotifyList
),
785 (PSTRING
)&FCB
->PathNameU
,
786 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
789 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
790 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
791 FILE_ACTION_MODIFIED
,
796 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
797 &(DeviceExt
->NotifyList
),
798 (PSTRING
)&FCB
->PathNameU
,
799 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
802 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
803 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
804 FILE_ACTION_RENAMED_NEW_NAME
,
810 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
811 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
816 /* Try to find target */
818 OldParent
= FCB
->parentFcb
;
819 #ifdef NASSERTS_RENAME
820 UNREFERENCED_PARAMETER(OldParent
);
822 Status
= vfatPrepareTargetForRename(DeviceExt
,
825 RenameInfo
->ReplaceIfExists
,
828 if (!NT_SUCCESS(Status
))
830 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
834 NewReferences
= ParentFCB
->RefCount
;
835 #ifdef NASSERTS_RENAME
836 UNREFERENCED_PARAMETER(NewReferences
);
839 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
840 &(DeviceExt
->NotifyList
),
841 (PSTRING
)&FCB
->PathNameU
,
842 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
845 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
846 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
849 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
850 if (NT_SUCCESS(Status
))
854 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
855 &(DeviceExt
->NotifyList
),
856 (PSTRING
)&FCB
->PathNameU
,
857 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
860 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
861 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
862 FILE_ACTION_MODIFIED
,
867 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
868 &(DeviceExt
->NotifyList
),
869 (PSTRING
)&FCB
->PathNameU
,
870 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
873 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
874 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
881 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
882 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
884 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
885 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
886 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
889 #ifdef NASSERTS_RENAME
890 #pragma pop_macro("ASSERT")
895 * FUNCTION: Retrieve the file name information
899 VfatGetNameInformation(
900 PFILE_OBJECT FileObject
,
902 PDEVICE_OBJECT DeviceObject
,
903 PFILE_NAME_INFORMATION NameInfo
,
908 UNREFERENCED_PARAMETER(FileObject
);
909 UNREFERENCED_PARAMETER(DeviceObject
);
911 ASSERT(NameInfo
!= NULL
);
914 /* If buffer can't hold at least the file name length, bail out */
915 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
916 return STATUS_BUFFER_OVERFLOW
;
918 /* Save file name length, and as much file len, as buffer length allows */
919 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
921 /* Calculate amount of bytes to copy not to overflow the buffer */
922 BytesToCopy
= min(FCB
->PathNameU
.Length
,
923 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
925 /* Fill in the bytes */
926 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
928 /* Check if we could write more but are not able to */
929 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
931 /* Return number of bytes written */
932 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
933 return STATUS_BUFFER_OVERFLOW
;
936 /* We filled up as many bytes, as needed */
937 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
939 return STATUS_SUCCESS
;
944 VfatGetInternalInformation(
946 PFILE_INTERNAL_INFORMATION InternalInfo
,
949 ASSERT(InternalInfo
);
952 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
953 return STATUS_BUFFER_OVERFLOW
;
954 // FIXME: get a real index, that can be used in a create operation
955 InternalInfo
->IndexNumber
.QuadPart
= 0;
956 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
957 return STATUS_SUCCESS
;
962 * FUNCTION: Retrieve the file network open information
966 VfatGetNetworkOpenInformation(
968 PDEVICE_EXTENSION DeviceExt
,
969 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
975 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
976 return(STATUS_BUFFER_OVERFLOW
);
978 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
980 FsdDosDateTimeToSystemTime(DeviceExt
,
981 Fcb
->entry
.FatX
.CreationDate
,
982 Fcb
->entry
.FatX
.CreationTime
,
983 &NetworkInfo
->CreationTime
);
984 FsdDosDateTimeToSystemTime(DeviceExt
,
985 Fcb
->entry
.FatX
.AccessDate
,
986 Fcb
->entry
.FatX
.AccessTime
,
987 &NetworkInfo
->LastAccessTime
);
988 FsdDosDateTimeToSystemTime(DeviceExt
,
989 Fcb
->entry
.FatX
.UpdateDate
,
990 Fcb
->entry
.FatX
.UpdateTime
,
991 &NetworkInfo
->LastWriteTime
);
992 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
996 FsdDosDateTimeToSystemTime(DeviceExt
,
997 Fcb
->entry
.Fat
.CreationDate
,
998 Fcb
->entry
.Fat
.CreationTime
,
999 &NetworkInfo
->CreationTime
);
1000 FsdDosDateTimeToSystemTime(DeviceExt
,
1001 Fcb
->entry
.Fat
.AccessDate
,
1003 &NetworkInfo
->LastAccessTime
);
1004 FsdDosDateTimeToSystemTime(DeviceExt
,
1005 Fcb
->entry
.Fat
.UpdateDate
,
1006 Fcb
->entry
.Fat
.UpdateTime
,
1007 &NetworkInfo
->LastWriteTime
);
1008 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1011 if (vfatFCBIsDirectory(Fcb
))
1013 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1014 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1018 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1019 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1022 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1023 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1024 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1025 FILE_ATTRIBUTE_ARCHIVE
|
1026 FILE_ATTRIBUTE_SYSTEM
|
1027 FILE_ATTRIBUTE_HIDDEN
|
1028 FILE_ATTRIBUTE_READONLY
)))
1030 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1031 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1034 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1035 return STATUS_SUCCESS
;
1041 VfatGetEaInformation(
1042 PFILE_OBJECT FileObject
,
1044 PDEVICE_OBJECT DeviceObject
,
1045 PFILE_EA_INFORMATION Info
,
1046 PULONG BufferLength
)
1048 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1050 UNREFERENCED_PARAMETER(FileObject
);
1051 UNREFERENCED_PARAMETER(Fcb
);
1053 /* FIXME - use SEH to access the buffer! */
1055 *BufferLength
-= sizeof(*Info
);
1056 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1057 DeviceExt
->FatInfo
.FatType
== FAT16
)
1060 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1062 return STATUS_SUCCESS
;
1067 * FUNCTION: Retrieve the all file information
1071 VfatGetAllInformation(
1072 PFILE_OBJECT FileObject
,
1074 PDEVICE_OBJECT DeviceObject
,
1075 PFILE_ALL_INFORMATION Info
,
1076 PULONG BufferLength
)
1079 ULONG InitialBufferLength
= *BufferLength
;
1084 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
))
1085 return STATUS_BUFFER_OVERFLOW
;
1087 /* Basic Information */
1088 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
1089 if (!NT_SUCCESS(Status
)) return Status
;
1090 /* Standard Information */
1091 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1092 if (!NT_SUCCESS(Status
)) return Status
;
1093 /* Internal Information */
1094 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
1095 if (!NT_SUCCESS(Status
)) return Status
;
1096 /* EA Information */
1097 Info
->EaInformation
.EaSize
= 0;
1098 /* Access Information: The IO-Manager adds this information */
1099 /* Position Information */
1100 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
1101 if (!NT_SUCCESS(Status
)) return Status
;
1102 /* Mode Information: The IO-Manager adds this information */
1103 /* Alignment Information: The IO-Manager adds this information */
1104 /* Name Information */
1105 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
1107 *BufferLength
= InitialBufferLength
- sizeof(FILE_ALL_INFORMATION
);
1108 if (InitialBufferLength
> sizeof(FILE_ALL_INFORMATION
))
1109 *BufferLength
-= min(InitialBufferLength
- sizeof(FILE_ALL_INFORMATION
), Fcb
->PathNameU
.Length
);
1117 PFILE_OBJECT FileObject
,
1124 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
1128 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1130 if (!vfatFCBIsDirectory(Fcb
))
1132 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1133 Fcb
->entry
.FatX
.FileSize
= Size
;
1135 Fcb
->entry
.Fat
.FileSize
= Size
;
1137 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1138 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1140 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1144 VfatSetAllocationSizeInformation(
1145 PFILE_OBJECT FileObject
,
1147 PDEVICE_EXTENSION DeviceExt
,
1148 PLARGE_INTEGER AllocationSize
)
1151 ULONG Cluster
, FirstCluster
;
1154 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1155 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1157 BOOLEAN AllocSizeChanged
= FALSE
;
1159 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1160 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1162 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1163 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1165 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1167 if (AllocationSize
->u
.HighPart
> 0)
1169 return STATUS_INVALID_PARAMETER
;
1172 if (OldSize
== NewSize
)
1174 return STATUS_SUCCESS
;
1177 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1179 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1181 AllocSizeChanged
= TRUE
;
1182 if (FirstCluster
== 0)
1184 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1185 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1186 if (!NT_SUCCESS(Status
))
1188 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1192 if (FirstCluster
== 0xffffffff)
1194 return STATUS_DISK_FULL
;
1197 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1198 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1200 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1203 NCluster
= Cluster
= FirstCluster
;
1204 Status
= STATUS_SUCCESS
;
1205 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1207 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1208 WriteCluster(DeviceExt
, Cluster
, 0);
1211 return STATUS_DISK_FULL
;
1214 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1216 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1220 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1222 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1223 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1227 ASSERT((FirstCluster
>> 16) == 0);
1228 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1234 if (Fcb
->LastCluster
> 0)
1236 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1238 Cluster
= Fcb
->LastCluster
;
1239 Status
= STATUS_SUCCESS
;
1243 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1244 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1250 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1251 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1255 if (!NT_SUCCESS(Status
))
1260 Fcb
->LastCluster
= Cluster
;
1261 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1263 /* FIXME: Check status */
1264 /* Cluster points now to the last cluster within the chain */
1265 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1266 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1268 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1272 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1273 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1275 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1277 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1278 WriteCluster(DeviceExt
, Cluster
, 0);
1281 return STATUS_DISK_FULL
;
1284 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1286 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1288 DPRINT("Check for the ability to set file size\n");
1289 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1290 (PLARGE_INTEGER
)AllocationSize
))
1292 DPRINT("Couldn't set file size!\n");
1293 return STATUS_USER_MAPPED_FILE
;
1295 DPRINT("Can set file size\n");
1297 AllocSizeChanged
= TRUE
;
1298 /* FIXME: Use the cached cluster/offset better way. */
1299 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1300 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1303 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1304 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1308 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1309 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1314 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1316 Fcb
->entry
.FatX
.FirstCluster
= 0;
1320 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1322 Fcb
->entry
.Fat
.FirstCluster
= 0;
1323 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1327 Fcb
->entry
.Fat
.FirstCluster
= 0;
1331 NCluster
= Cluster
= FirstCluster
;
1332 Status
= STATUS_SUCCESS
;
1335 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1337 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1338 WriteCluster(DeviceExt
, Cluster
, 0);
1344 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1347 /* Update the on-disk directory entry */
1348 Fcb
->Flags
|= FCB_IS_DIRTY
;
1349 if (AllocSizeChanged
)
1351 VfatUpdateEntry(Fcb
);
1353 return STATUS_SUCCESS
;
1357 * FUNCTION: Retrieve the specified file information
1360 VfatQueryInformation(
1361 PVFAT_IRP_CONTEXT IrpContext
)
1363 FILE_INFORMATION_CLASS FileInformationClass
;
1364 PVFATFCB FCB
= NULL
;
1366 NTSTATUS Status
= STATUS_SUCCESS
;
1373 /* INITIALIZATION */
1374 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1375 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1377 DPRINT("VfatQueryInformation is called for '%s'\n",
1378 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1381 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1382 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1384 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1386 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1387 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1389 return VfatMarkIrpContextForQueue(IrpContext
);
1393 switch (FileInformationClass
)
1395 case FileStandardInformation
:
1396 Status
= VfatGetStandardInformation(FCB
,
1401 case FilePositionInformation
:
1402 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1404 IrpContext
->DeviceObject
,
1409 case FileBasicInformation
:
1410 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1412 IrpContext
->DeviceObject
,
1417 case FileNameInformation
:
1418 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1420 IrpContext
->DeviceObject
,
1425 case FileInternalInformation
:
1426 Status
= VfatGetInternalInformation(FCB
,
1431 case FileNetworkOpenInformation
:
1432 Status
= VfatGetNetworkOpenInformation(FCB
,
1433 IrpContext
->DeviceExt
,
1438 case FileAllInformation
:
1439 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1441 IrpContext
->DeviceObject
,
1446 case FileEaInformation
:
1447 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1449 IrpContext
->DeviceObject
,
1454 case FileAlternateNameInformation
:
1455 Status
= STATUS_NOT_IMPLEMENTED
;
1459 Status
= STATUS_INVALID_PARAMETER
;
1462 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1464 ExReleaseResourceLite(&FCB
->MainResource
);
1467 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1468 IrpContext
->Irp
->IoStatus
.Information
=
1469 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1471 IrpContext
->Irp
->IoStatus
.Information
= 0;
1477 * FUNCTION: Retrieve the specified file information
1481 PVFAT_IRP_CONTEXT IrpContext
)
1483 FILE_INFORMATION_CLASS FileInformationClass
;
1484 PVFATFCB FCB
= NULL
;
1485 NTSTATUS Status
= STATUS_SUCCESS
;
1491 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1493 /* INITIALIZATION */
1494 FileInformationClass
=
1495 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1496 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1497 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1499 DPRINT("VfatSetInformation is called for '%s'\n",
1500 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1502 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1503 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1505 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1506 the file size would be allowed. If not, we bail with the right error.
1507 We must do this before acquiring the lock. */
1508 if (FileInformationClass
== FileEndOfFileInformation
)
1510 DPRINT("Check for the ability to set file size\n");
1511 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1512 (PLARGE_INTEGER
)SystemBuffer
))
1514 DPRINT("Couldn't set file size!\n");
1515 IrpContext
->Irp
->IoStatus
.Information
= 0;
1516 return STATUS_USER_MAPPED_FILE
;
1518 DPRINT("Can set file size\n");
1521 if (FileInformationClass
== FileRenameInformation
)
1523 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1524 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1526 return VfatMarkIrpContextForQueue(IrpContext
);
1530 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1532 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1533 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1535 if (FileInformationClass
== FileRenameInformation
)
1537 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1540 return VfatMarkIrpContextForQueue(IrpContext
);
1544 switch (FileInformationClass
)
1546 case FilePositionInformation
:
1547 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1551 case FileDispositionInformation
:
1552 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1554 IrpContext
->DeviceObject
,
1558 case FileAllocationInformation
:
1559 case FileEndOfFileInformation
:
1560 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1562 IrpContext
->DeviceExt
,
1563 (PLARGE_INTEGER
)SystemBuffer
);
1566 case FileBasicInformation
:
1567 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1569 IrpContext
->DeviceExt
,
1573 case FileRenameInformation
:
1574 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1576 IrpContext
->DeviceExt
,
1578 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1582 Status
= STATUS_NOT_SUPPORTED
;
1585 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1587 ExReleaseResourceLite(&FCB
->MainResource
);
1590 if (FileInformationClass
== FileRenameInformation
)
1592 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1595 IrpContext
->Irp
->IoStatus
.Information
= 0;