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
76 VfatGetStandardInformation(
78 PFILE_STANDARD_INFORMATION StandardInfo
,
81 if (*BufferLength
< sizeof(FILE_STANDARD_INFORMATION
))
82 return STATUS_BUFFER_OVERFLOW
;
85 ASSERT(StandardInfo
!= NULL
);
88 if (vfatFCBIsDirectory(FCB
))
90 StandardInfo
->AllocationSize
.QuadPart
= 0;
91 StandardInfo
->EndOfFile
.QuadPart
= 0;
92 StandardInfo
->Directory
= TRUE
;
96 StandardInfo
->AllocationSize
= FCB
->RFCB
.AllocationSize
;
97 StandardInfo
->EndOfFile
= FCB
->RFCB
.FileSize
;
98 StandardInfo
->Directory
= FALSE
;
100 StandardInfo
->NumberOfLinks
= 1;
101 StandardInfo
->DeletePending
= FCB
->Flags
& FCB_DELETE_PENDING
? TRUE
: FALSE
;
103 *BufferLength
-= sizeof(FILE_STANDARD_INFORMATION
);
104 return STATUS_SUCCESS
;
109 VfatSetPositionInformation(
110 PFILE_OBJECT FileObject
,
111 PFILE_POSITION_INFORMATION PositionInfo
)
113 DPRINT("FsdSetPositionInformation()\n");
115 DPRINT("PositionInfo %p\n", PositionInfo
);
116 DPRINT("Setting position %u\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
118 FileObject
->CurrentByteOffset
.QuadPart
=
119 PositionInfo
->CurrentByteOffset
.QuadPart
;
121 return STATUS_SUCCESS
;
126 VfatGetPositionInformation(
127 PFILE_OBJECT FileObject
,
129 PDEVICE_OBJECT DeviceObject
,
130 PFILE_POSITION_INFORMATION PositionInfo
,
133 UNREFERENCED_PARAMETER(FileObject
);
134 UNREFERENCED_PARAMETER(FCB
);
135 UNREFERENCED_PARAMETER(DeviceObject
);
137 DPRINT("VfatGetPositionInformation()\n");
139 if (*BufferLength
< sizeof(FILE_POSITION_INFORMATION
))
140 return STATUS_BUFFER_OVERFLOW
;
142 PositionInfo
->CurrentByteOffset
.QuadPart
=
143 FileObject
->CurrentByteOffset
.QuadPart
;
145 DPRINT("Getting position %I64x\n",
146 PositionInfo
->CurrentByteOffset
.QuadPart
);
148 *BufferLength
-= sizeof(FILE_POSITION_INFORMATION
);
149 return STATUS_SUCCESS
;
154 VfatSetBasicInformation(
155 PFILE_OBJECT FileObject
,
157 PDEVICE_EXTENSION DeviceExt
,
158 PFILE_BASIC_INFORMATION BasicInfo
)
160 DPRINT("VfatSetBasicInformation()\n");
162 ASSERT(NULL
!= FileObject
);
164 ASSERT(NULL
!= DeviceExt
);
165 ASSERT(NULL
!= BasicInfo
);
166 /* Check volume label bit */
167 ASSERT(0 == (*FCB
->Attributes
& _A_VOLID
));
169 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
171 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
173 FsdSystemTimeToDosDateTime(DeviceExt
,
174 &BasicInfo
->CreationTime
,
175 &FCB
->entry
.FatX
.CreationDate
,
176 &FCB
->entry
.FatX
.CreationTime
);
179 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
181 FsdSystemTimeToDosDateTime(DeviceExt
,
182 &BasicInfo
->LastAccessTime
,
183 &FCB
->entry
.FatX
.AccessDate
,
184 &FCB
->entry
.FatX
.AccessTime
);
187 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
189 FsdSystemTimeToDosDateTime(DeviceExt
,
190 &BasicInfo
->LastWriteTime
,
191 &FCB
->entry
.FatX
.UpdateDate
,
192 &FCB
->entry
.FatX
.UpdateTime
);
197 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
199 FsdSystemTimeToDosDateTime(DeviceExt
,
200 &BasicInfo
->CreationTime
,
201 &FCB
->entry
.Fat
.CreationDate
,
202 &FCB
->entry
.Fat
.CreationTime
);
205 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
207 FsdSystemTimeToDosDateTime(DeviceExt
,
208 &BasicInfo
->LastAccessTime
,
209 &FCB
->entry
.Fat
.AccessDate
,
213 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
215 FsdSystemTimeToDosDateTime(DeviceExt
,
216 &BasicInfo
->LastWriteTime
,
217 &FCB
->entry
.Fat
.UpdateDate
,
218 &FCB
->entry
.Fat
.UpdateTime
);
222 if (BasicInfo
->FileAttributes
)
224 *FCB
->Attributes
= (unsigned char)((*FCB
->Attributes
&
225 (FILE_ATTRIBUTE_DIRECTORY
| 0x48)) |
226 (BasicInfo
->FileAttributes
&
227 (FILE_ATTRIBUTE_ARCHIVE
|
228 FILE_ATTRIBUTE_SYSTEM
|
229 FILE_ATTRIBUTE_HIDDEN
|
230 FILE_ATTRIBUTE_READONLY
)));
231 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
234 VfatUpdateEntry(FCB
);
236 return STATUS_SUCCESS
;
241 VfatGetBasicInformation(
242 PFILE_OBJECT FileObject
,
244 PDEVICE_OBJECT DeviceObject
,
245 PFILE_BASIC_INFORMATION BasicInfo
,
248 PDEVICE_EXTENSION DeviceExt
;
250 UNREFERENCED_PARAMETER(FileObject
);
252 DPRINT("VfatGetBasicInformation()\n");
254 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
256 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
257 return STATUS_BUFFER_OVERFLOW
;
259 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
261 FsdDosDateTimeToSystemTime(DeviceExt
,
262 FCB
->entry
.FatX
.CreationDate
,
263 FCB
->entry
.FatX
.CreationTime
,
264 &BasicInfo
->CreationTime
);
265 FsdDosDateTimeToSystemTime(DeviceExt
,
266 FCB
->entry
.FatX
.AccessDate
,
267 FCB
->entry
.FatX
.AccessTime
,
268 &BasicInfo
->LastAccessTime
);
269 FsdDosDateTimeToSystemTime(DeviceExt
,
270 FCB
->entry
.FatX
.UpdateDate
,
271 FCB
->entry
.FatX
.UpdateTime
,
272 &BasicInfo
->LastWriteTime
);
273 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
277 FsdDosDateTimeToSystemTime(DeviceExt
,
278 FCB
->entry
.Fat
.CreationDate
,
279 FCB
->entry
.Fat
.CreationTime
,
280 &BasicInfo
->CreationTime
);
281 FsdDosDateTimeToSystemTime(DeviceExt
,
282 FCB
->entry
.Fat
.AccessDate
,
284 &BasicInfo
->LastAccessTime
);
285 FsdDosDateTimeToSystemTime(DeviceExt
,
286 FCB
->entry
.Fat
.UpdateDate
,
287 FCB
->entry
.Fat
.UpdateTime
,
288 &BasicInfo
->LastWriteTime
);
289 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
292 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
293 /* Synthesize FILE_ATTRIBUTE_NORMAL */
294 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
295 FILE_ATTRIBUTE_ARCHIVE
|
296 FILE_ATTRIBUTE_SYSTEM
|
297 FILE_ATTRIBUTE_HIDDEN
|
298 FILE_ATTRIBUTE_READONLY
)))
300 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
301 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
303 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
305 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
306 return STATUS_SUCCESS
;
312 VfatSetDispositionInformation(
313 PFILE_OBJECT FileObject
,
315 PDEVICE_OBJECT DeviceObject
,
316 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
319 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
322 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
324 ASSERT(DeviceExt
!= NULL
);
325 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
328 if (!DispositionInfo
->DeleteFile
)
330 /* undelete the file */
331 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
332 FileObject
->DeletePending
= FALSE
;
333 return STATUS_SUCCESS
;
336 if (FCB
->Flags
& FCB_DELETE_PENDING
)
338 /* stream already marked for deletion. just update the file object */
339 FileObject
->DeletePending
= TRUE
;
340 return STATUS_SUCCESS
;
343 if (*FCB
->Attributes
& FILE_ATTRIBUTE_READONLY
)
345 return STATUS_CANNOT_DELETE
;
348 if (vfatFCBIsRoot(FCB
) ||
349 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
350 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
352 // we cannot delete a '.', '..' or the root directory
353 return STATUS_ACCESS_DENIED
;
357 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
359 /* can't delete a file if its mapped into a process */
361 DPRINT("MmFlushImageSection returned FALSE\n");
362 return STATUS_CANNOT_DELETE
;
365 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
367 /* can't delete a non-empty directory */
369 return STATUS_DIRECTORY_NOT_EMPTY
;
373 FCB
->Flags
|= FCB_DELETE_PENDING
;
374 FileObject
->DeletePending
= TRUE
;
376 return STATUS_SUCCESS
;
380 vfatPrepareTargetForRename(
381 IN PDEVICE_EXTENSION DeviceExt
,
382 IN PVFATFCB
* ParentFCB
,
383 IN PUNICODE_STRING NewName
,
384 IN BOOLEAN ReplaceIfExists
,
385 IN PUNICODE_STRING ParentName
,
386 OUT PBOOLEAN Deleted
)
391 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
394 /* Try to open target */
395 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
397 if (NT_SUCCESS(Status
))
399 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
400 /* Check whether we are allowed to replace */
403 /* If that's a directory or a read-only file, we're not allowed */
404 if (vfatFCBIsDirectory(TargetFcb
) || ((*TargetFcb
->Attributes
& FILE_ATTRIBUTE_READONLY
) == FILE_ATTRIBUTE_READONLY
))
406 DPRINT("And this is a readonly file!\n");
407 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
409 vfatReleaseFCB(DeviceExt
, TargetFcb
);
410 return STATUS_OBJECT_NAME_COLLISION
;
414 /* If we still have a file object, close it. */
415 if (TargetFcb
->FileObject
)
417 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
419 DPRINT("MmFlushImageSection failed.\n");
420 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
422 vfatReleaseFCB(DeviceExt
, TargetFcb
);
423 return STATUS_ACCESS_DENIED
;
426 TargetFcb
->FileObject
->DeletePending
= TRUE
;
427 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
430 /* If we are here, ensure the file isn't open by anyone! */
431 if (TargetFcb
->OpenHandleCount
!= 0)
433 DPRINT("There are still open handles for this file.\n");
434 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
436 vfatReleaseFCB(DeviceExt
, TargetFcb
);
437 return STATUS_ACCESS_DENIED
;
440 /* Effectively delete old file to allow renaming */
441 DPRINT("Effectively deleting the file.\n");
442 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
443 vfatReleaseFCB(DeviceExt
, TargetFcb
);
445 return STATUS_SUCCESS
;
449 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
451 vfatReleaseFCB(DeviceExt
, TargetFcb
);
452 return STATUS_OBJECT_NAME_COLLISION
;
455 else if (*ParentFCB
!= NULL
)
457 return STATUS_SUCCESS
;
465 * FUNCTION: Set the file name information
469 VfatSetRenameInformation(
470 PFILE_OBJECT FileObject
,
472 PDEVICE_EXTENSION DeviceExt
,
473 PFILE_RENAME_INFORMATION RenameInfo
,
474 PFILE_OBJECT TargetFileObject
)
476 #ifdef NASSERTS_RENAME
477 #pragma push_macro("ASSERT")
479 #define ASSERT(x) ((VOID) 0)
482 UNICODE_STRING NewName
;
483 UNICODE_STRING SourcePath
;
484 UNICODE_STRING SourceFile
;
485 UNICODE_STRING NewPath
;
486 UNICODE_STRING NewFile
;
487 PFILE_OBJECT RootFileObject
;
489 UNICODE_STRING RenameInfoString
;
491 IO_STATUS_BLOCK IoStatusBlock
;
492 OBJECT_ATTRIBUTES ObjectAttributes
;
494 BOOLEAN DeletedTarget
;
495 ULONG OldReferences
, NewReferences
;
498 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
500 /* Disallow renaming root */
501 if (vfatFCBIsRoot(FCB
))
503 return STATUS_INVALID_PARAMETER
;
506 OldReferences
= FCB
->parentFcb
->RefCount
;
507 #ifdef NASSERTS_RENAME
508 UNREFERENCED_PARAMETER(OldReferences
);
511 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
512 if (RenameInfo
->RootDirectory
!= NULL
)
514 /* We cannot tolerate relative opening with a full path */
515 if (RenameInfo
->FileName
[0] == L
'\\')
517 return STATUS_OBJECT_NAME_INVALID
;
520 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
524 (PVOID
*)&RootFileObject
,
526 if (!NT_SUCCESS(Status
))
531 RootFCB
= RootFileObject
->FsContext
;
536 if (TargetFileObject
== NULL
)
538 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
539 * information supplied by the user
542 /* First, setup a string we'll work on */
543 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
544 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
545 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
547 /* Check whether we have FQN */
548 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
550 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
551 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
552 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
553 RenameInfoString
.Buffer
[4] <= L
'Z'))
555 /* If so, open its target directory */
556 InitializeObjectAttributes(&ObjectAttributes
,
558 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
561 Status
= IoCreateFile(&TargetHandle
,
562 FILE_WRITE_DATA
| SYNCHRONIZE
,
566 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
568 FILE_OPEN_FOR_BACKUP_INTENT
,
572 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
573 if (!NT_SUCCESS(Status
))
578 /* Get its FO to get the FCB */
579 Status
= ObReferenceObjectByHandle(TargetHandle
,
583 (PVOID
*)&TargetFileObject
,
585 if (!NT_SUCCESS(Status
))
587 ZwClose(TargetHandle
);
591 /* Are we working on the same volume? */
592 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
594 ObDereferenceObject(TargetFileObject
);
595 ZwClose(TargetHandle
);
596 TargetFileObject
= NULL
;
597 Status
= STATUS_NOT_SAME_DEVICE
;
604 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
605 if (RenameInfo
->RootDirectory
!= NULL
)
607 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
609 else if (RenameInfo
->FileName
[0] != L
'\\')
611 /* We don't have full path, and we don't have root directory:
612 * => we move inside the same directory
614 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
616 else if (TargetFileObject
!= NULL
)
619 * => we need to use its correct path
621 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
624 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
625 if (NewName
.Buffer
== NULL
)
627 if (TargetFileObject
!= NULL
)
629 ObDereferenceObject(TargetFileObject
);
630 ZwClose(TargetHandle
);
631 TargetFileObject
= NULL
;
633 Status
= STATUS_INSUFFICIENT_RESOURCES
;
637 if (RenameInfo
->RootDirectory
!= NULL
)
639 /* Here, copy first absolute and then append relative */
640 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
641 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
642 NewName
.Length
+= sizeof(WCHAR
);
643 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
645 else if (RenameInfo
->FileName
[0] != L
'\\')
647 /* Here, copy first work directory and then append filename */
648 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
649 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
650 NewName
.Length
+= sizeof(WCHAR
);
651 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
653 else if (TargetFileObject
!= NULL
)
655 /* Here, copy first path name and then append filename */
656 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
657 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
658 NewName
.Length
+= sizeof(WCHAR
);
659 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
663 /* Here we should have full path, so simply copy it */
664 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
667 /* Do we have to cleanup some stuff? */
668 if (TargetFileObject
!= NULL
)
670 ObDereferenceObject(TargetFileObject
);
671 ZwClose(TargetHandle
);
672 TargetFileObject
= NULL
;
677 /* At that point, we shouldn't care about whether we are relative opening
678 * Target FO FCB should already have full path
681 /* Before constructing string, just make a sanity check (just to be sure!) */
682 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
684 Status
= STATUS_NOT_SAME_DEVICE
;
689 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
690 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
691 if (NewName
.Buffer
== NULL
)
693 Status
= STATUS_INSUFFICIENT_RESOURCES
;
697 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
698 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
699 NewName
.Length
+= sizeof(WCHAR
);
700 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
703 /* Explode our paths to get path & filename */
704 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
705 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
706 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
707 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
709 /* Are we working in place? */
710 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
712 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
714 Status
= STATUS_SUCCESS
;
715 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
719 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
721 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
722 &(DeviceExt
->NotifyList
),
723 (PSTRING
)&FCB
->PathNameU
,
724 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
727 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
728 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
729 FILE_ACTION_RENAMED_OLD_NAME
,
731 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
732 if (NT_SUCCESS(Status
))
734 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
735 &(DeviceExt
->NotifyList
),
736 (PSTRING
)&FCB
->PathNameU
,
737 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
740 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
741 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
742 FILE_ACTION_RENAMED_NEW_NAME
,
748 /* Try to find target */
749 ParentFCB
= FCB
->parentFcb
;
750 vfatGrabFCB(DeviceExt
, ParentFCB
);
751 Status
= vfatPrepareTargetForRename(DeviceExt
,
754 RenameInfo
->ReplaceIfExists
,
757 if (!NT_SUCCESS(Status
))
759 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
760 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
764 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
765 &(DeviceExt
->NotifyList
),
766 (PSTRING
)&FCB
->PathNameU
,
767 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
770 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
771 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
772 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
774 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
775 if (NT_SUCCESS(Status
))
779 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
780 &(DeviceExt
->NotifyList
),
781 (PSTRING
)&FCB
->PathNameU
,
782 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
785 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
786 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
787 FILE_ACTION_MODIFIED
,
792 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
793 &(DeviceExt
->NotifyList
),
794 (PSTRING
)&FCB
->PathNameU
,
795 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
798 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
799 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
800 FILE_ACTION_RENAMED_NEW_NAME
,
806 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
807 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
812 /* Try to find target */
814 OldParent
= FCB
->parentFcb
;
815 #ifdef NASSERTS_RENAME
816 UNREFERENCED_PARAMETER(OldParent
);
818 Status
= vfatPrepareTargetForRename(DeviceExt
,
821 RenameInfo
->ReplaceIfExists
,
824 if (!NT_SUCCESS(Status
))
826 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
830 NewReferences
= ParentFCB
->RefCount
;
831 #ifdef NASSERTS_RENAME
832 UNREFERENCED_PARAMETER(NewReferences
);
835 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
836 &(DeviceExt
->NotifyList
),
837 (PSTRING
)&FCB
->PathNameU
,
838 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
841 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
842 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
845 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
846 if (NT_SUCCESS(Status
))
850 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
851 &(DeviceExt
->NotifyList
),
852 (PSTRING
)&FCB
->PathNameU
,
853 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
856 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
857 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
858 FILE_ACTION_MODIFIED
,
863 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
864 &(DeviceExt
->NotifyList
),
865 (PSTRING
)&FCB
->PathNameU
,
866 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
869 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
870 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
877 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
878 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
880 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
881 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
882 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
885 #ifdef NASSERTS_RENAME
886 #pragma pop_macro("ASSERT")
891 * FUNCTION: Retrieve the file name information
895 VfatGetNameInformation(
896 PFILE_OBJECT FileObject
,
898 PDEVICE_OBJECT DeviceObject
,
899 PFILE_NAME_INFORMATION NameInfo
,
904 UNREFERENCED_PARAMETER(FileObject
);
905 UNREFERENCED_PARAMETER(DeviceObject
);
907 ASSERT(NameInfo
!= NULL
);
910 /* If buffer can't hold at least the file name length, bail out */
911 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
912 return STATUS_BUFFER_OVERFLOW
;
914 /* Save file name length, and as much file len, as buffer length allows */
915 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
917 /* Calculate amount of bytes to copy not to overflow the buffer */
918 BytesToCopy
= min(FCB
->PathNameU
.Length
,
919 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
921 /* Fill in the bytes */
922 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
924 /* Check if we could write more but are not able to */
925 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
927 /* Return number of bytes written */
928 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
929 return STATUS_BUFFER_OVERFLOW
;
932 /* We filled up as many bytes, as needed */
933 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
935 return STATUS_SUCCESS
;
940 VfatGetInternalInformation(
942 PFILE_INTERNAL_INFORMATION InternalInfo
,
945 ASSERT(InternalInfo
);
948 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
949 return STATUS_BUFFER_OVERFLOW
;
950 // FIXME: get a real index, that can be used in a create operation
951 InternalInfo
->IndexNumber
.QuadPart
= 0;
952 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
953 return STATUS_SUCCESS
;
958 * FUNCTION: Retrieve the file network open information
962 VfatGetNetworkOpenInformation(
964 PDEVICE_EXTENSION DeviceExt
,
965 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
971 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
972 return(STATUS_BUFFER_OVERFLOW
);
974 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
976 FsdDosDateTimeToSystemTime(DeviceExt
,
977 Fcb
->entry
.FatX
.CreationDate
,
978 Fcb
->entry
.FatX
.CreationTime
,
979 &NetworkInfo
->CreationTime
);
980 FsdDosDateTimeToSystemTime(DeviceExt
,
981 Fcb
->entry
.FatX
.AccessDate
,
982 Fcb
->entry
.FatX
.AccessTime
,
983 &NetworkInfo
->LastAccessTime
);
984 FsdDosDateTimeToSystemTime(DeviceExt
,
985 Fcb
->entry
.FatX
.UpdateDate
,
986 Fcb
->entry
.FatX
.UpdateTime
,
987 &NetworkInfo
->LastWriteTime
);
988 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
992 FsdDosDateTimeToSystemTime(DeviceExt
,
993 Fcb
->entry
.Fat
.CreationDate
,
994 Fcb
->entry
.Fat
.CreationTime
,
995 &NetworkInfo
->CreationTime
);
996 FsdDosDateTimeToSystemTime(DeviceExt
,
997 Fcb
->entry
.Fat
.AccessDate
,
999 &NetworkInfo
->LastAccessTime
);
1000 FsdDosDateTimeToSystemTime(DeviceExt
,
1001 Fcb
->entry
.Fat
.UpdateDate
,
1002 Fcb
->entry
.Fat
.UpdateTime
,
1003 &NetworkInfo
->LastWriteTime
);
1004 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1007 if (vfatFCBIsDirectory(Fcb
))
1009 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1010 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1014 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1015 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1018 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1019 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1020 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1021 FILE_ATTRIBUTE_ARCHIVE
|
1022 FILE_ATTRIBUTE_SYSTEM
|
1023 FILE_ATTRIBUTE_HIDDEN
|
1024 FILE_ATTRIBUTE_READONLY
)))
1026 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1027 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1030 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1031 return STATUS_SUCCESS
;
1037 VfatGetEaInformation(
1038 PFILE_OBJECT FileObject
,
1040 PDEVICE_OBJECT DeviceObject
,
1041 PFILE_EA_INFORMATION Info
,
1042 PULONG BufferLength
)
1044 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1046 UNREFERENCED_PARAMETER(FileObject
);
1047 UNREFERENCED_PARAMETER(Fcb
);
1049 /* FIXME - use SEH to access the buffer! */
1051 *BufferLength
-= sizeof(*Info
);
1052 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1053 DeviceExt
->FatInfo
.FatType
== FAT16
)
1056 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1058 return STATUS_SUCCESS
;
1063 * FUNCTION: Retrieve the all file information
1067 VfatGetAllInformation(
1068 PFILE_OBJECT FileObject
,
1070 PDEVICE_OBJECT DeviceObject
,
1071 PFILE_ALL_INFORMATION Info
,
1072 PULONG BufferLength
)
1075 ULONG InitialBufferLength
= *BufferLength
;
1080 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
))
1081 return(STATUS_BUFFER_OVERFLOW
);
1083 /* Basic Information */
1084 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
1085 if (!NT_SUCCESS(Status
)) return Status
;
1086 /* Standard Information */
1087 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1088 if (!NT_SUCCESS(Status
)) return Status
;
1089 /* Internal Information */
1090 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
1091 if (!NT_SUCCESS(Status
)) return Status
;
1092 /* EA Information */
1093 Info
->EaInformation
.EaSize
= 0;
1094 /* Access Information: The IO-Manager adds this information */
1095 /* Position Information */
1096 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
1097 if (!NT_SUCCESS(Status
)) return Status
;
1098 /* Mode Information: The IO-Manager adds this information */
1099 /* Alignment Information: The IO-Manager adds this information */
1100 /* Name Information */
1101 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
1102 if (!NT_SUCCESS(Status
)) return Status
;
1104 *BufferLength
= InitialBufferLength
- (sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
));
1106 return STATUS_SUCCESS
;
1112 PFILE_OBJECT FileObject
,
1119 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
1123 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1125 if (!vfatFCBIsDirectory(Fcb
))
1127 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1128 Fcb
->entry
.FatX
.FileSize
= Size
;
1130 Fcb
->entry
.Fat
.FileSize
= Size
;
1132 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1133 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1135 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1139 VfatSetAllocationSizeInformation(
1140 PFILE_OBJECT FileObject
,
1142 PDEVICE_EXTENSION DeviceExt
,
1143 PLARGE_INTEGER AllocationSize
)
1146 ULONG Cluster
, FirstCluster
;
1149 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1150 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1152 BOOLEAN AllocSizeChanged
= FALSE
;
1154 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1155 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1157 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1158 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1160 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1162 if (AllocationSize
->u
.HighPart
> 0)
1164 return STATUS_INVALID_PARAMETER
;
1167 if (OldSize
== NewSize
)
1169 return STATUS_SUCCESS
;
1172 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1174 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1176 AllocSizeChanged
= TRUE
;
1177 if (FirstCluster
== 0)
1179 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1180 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1181 if (!NT_SUCCESS(Status
))
1183 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1187 if (FirstCluster
== 0xffffffff)
1189 return STATUS_DISK_FULL
;
1192 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1193 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1195 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1198 NCluster
= Cluster
= FirstCluster
;
1199 Status
= STATUS_SUCCESS
;
1200 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1202 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1203 WriteCluster(DeviceExt
, Cluster
, 0);
1206 return STATUS_DISK_FULL
;
1209 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1211 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1215 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1217 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1218 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1222 ASSERT((FirstCluster
>> 16) == 0);
1223 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1229 if (Fcb
->LastCluster
> 0)
1231 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1233 Cluster
= Fcb
->LastCluster
;
1234 Status
= STATUS_SUCCESS
;
1238 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1239 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1245 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1246 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1250 if (!NT_SUCCESS(Status
))
1255 Fcb
->LastCluster
= Cluster
;
1256 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1258 /* FIXME: Check status */
1259 /* Cluster points now to the last cluster within the chain */
1260 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1261 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1263 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1267 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1268 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1270 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1272 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1273 WriteCluster(DeviceExt
, Cluster
, 0);
1276 return STATUS_DISK_FULL
;
1279 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1281 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1283 DPRINT("Check for the ability to set file size\n");
1284 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1285 (PLARGE_INTEGER
)AllocationSize
))
1287 DPRINT("Couldn't set file size!\n");
1288 return STATUS_USER_MAPPED_FILE
;
1290 DPRINT("Can set file size\n");
1292 AllocSizeChanged
= TRUE
;
1293 /* FIXME: Use the cached cluster/offset better way. */
1294 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1295 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1298 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1299 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1303 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1304 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1309 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1311 Fcb
->entry
.FatX
.FirstCluster
= 0;
1315 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1317 Fcb
->entry
.Fat
.FirstCluster
= 0;
1318 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1322 Fcb
->entry
.Fat
.FirstCluster
= 0;
1326 NCluster
= Cluster
= FirstCluster
;
1327 Status
= STATUS_SUCCESS
;
1330 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1332 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1333 WriteCluster(DeviceExt
, Cluster
, 0);
1339 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1342 /* Update the on-disk directory entry */
1343 Fcb
->Flags
|= FCB_IS_DIRTY
;
1344 if (AllocSizeChanged
)
1346 VfatUpdateEntry(Fcb
);
1348 return STATUS_SUCCESS
;
1352 * FUNCTION: Retrieve the specified file information
1355 VfatQueryInformation(
1356 PVFAT_IRP_CONTEXT IrpContext
)
1358 FILE_INFORMATION_CLASS FileInformationClass
;
1359 PVFATFCB FCB
= NULL
;
1361 NTSTATUS Status
= STATUS_SUCCESS
;
1368 /* INITIALIZATION */
1369 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1370 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1372 DPRINT("VfatQueryInformation is called for '%s'\n",
1373 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1376 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1377 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1379 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1381 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1382 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
1384 return VfatMarkIrpContextForQueue(IrpContext
);
1388 switch (FileInformationClass
)
1390 case FileStandardInformation
:
1391 Status
= VfatGetStandardInformation(FCB
,
1396 case FilePositionInformation
:
1397 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1399 IrpContext
->DeviceObject
,
1404 case FileBasicInformation
:
1405 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1407 IrpContext
->DeviceObject
,
1412 case FileNameInformation
:
1413 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1415 IrpContext
->DeviceObject
,
1420 case FileInternalInformation
:
1421 Status
= VfatGetInternalInformation(FCB
,
1426 case FileNetworkOpenInformation
:
1427 Status
= VfatGetNetworkOpenInformation(FCB
,
1428 IrpContext
->DeviceExt
,
1433 case FileAllInformation
:
1434 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1436 IrpContext
->DeviceObject
,
1441 case FileEaInformation
:
1442 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1444 IrpContext
->DeviceObject
,
1449 case FileAlternateNameInformation
:
1450 Status
= STATUS_NOT_IMPLEMENTED
;
1454 Status
= STATUS_INVALID_PARAMETER
;
1457 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1459 ExReleaseResourceLite(&FCB
->MainResource
);
1462 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1463 IrpContext
->Irp
->IoStatus
.Information
=
1464 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1466 IrpContext
->Irp
->IoStatus
.Information
= 0;
1472 * FUNCTION: Retrieve the specified file information
1476 PVFAT_IRP_CONTEXT IrpContext
)
1478 FILE_INFORMATION_CLASS FileInformationClass
;
1479 PVFATFCB FCB
= NULL
;
1480 NTSTATUS Status
= STATUS_SUCCESS
;
1486 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1488 /* INITIALIZATION */
1489 FileInformationClass
=
1490 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1491 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1492 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1494 DPRINT("VfatSetInformation is called for '%s'\n",
1495 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1497 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1498 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1500 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1501 the file size would be allowed. If not, we bail with the right error.
1502 We must do this before acquiring the lock. */
1503 if (FileInformationClass
== FileEndOfFileInformation
)
1505 DPRINT("Check for the ability to set file size\n");
1506 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1507 (PLARGE_INTEGER
)SystemBuffer
))
1509 DPRINT("Couldn't set file size!\n");
1510 IrpContext
->Irp
->IoStatus
.Information
= 0;
1511 return STATUS_USER_MAPPED_FILE
;
1513 DPRINT("Can set file size\n");
1516 if (FileInformationClass
== FileRenameInformation
)
1518 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1519 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
1521 return VfatMarkIrpContextForQueue(IrpContext
);
1525 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1527 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1528 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
1530 if (FileInformationClass
== FileRenameInformation
)
1532 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1535 return VfatMarkIrpContextForQueue(IrpContext
);
1539 switch (FileInformationClass
)
1541 case FilePositionInformation
:
1542 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1546 case FileDispositionInformation
:
1547 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1549 IrpContext
->DeviceObject
,
1553 case FileAllocationInformation
:
1554 case FileEndOfFileInformation
:
1555 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1557 IrpContext
->DeviceExt
,
1558 (PLARGE_INTEGER
)SystemBuffer
);
1561 case FileBasicInformation
:
1562 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1564 IrpContext
->DeviceExt
,
1568 case FileRenameInformation
:
1569 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1571 IrpContext
->DeviceExt
,
1573 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1577 Status
= STATUS_NOT_SUPPORTED
;
1580 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1582 ExReleaseResourceLite(&FCB
->MainResource
);
1585 if (FileInformationClass
== FileRenameInformation
)
1587 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1590 IrpContext
->Irp
->IoStatus
.Information
= 0;