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
)
343 return STATUS_CANNOT_DELETE
;
346 if (vfatFCBIsRoot(FCB
) ||
347 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
348 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
350 /* we cannot delete a '.', '..' or the root directory */
351 return STATUS_ACCESS_DENIED
;
354 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
356 /* can't delete a file if its mapped into a process */
358 DPRINT("MmFlushImageSection returned FALSE\n");
359 return STATUS_CANNOT_DELETE
;
362 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
364 /* can't delete a non-empty directory */
366 return STATUS_DIRECTORY_NOT_EMPTY
;
370 FCB
->Flags
|= FCB_DELETE_PENDING
;
371 FileObject
->DeletePending
= TRUE
;
373 return STATUS_SUCCESS
;
377 vfatPrepareTargetForRename(
378 IN PDEVICE_EXTENSION DeviceExt
,
379 IN PVFATFCB
* ParentFCB
,
380 IN PUNICODE_STRING NewName
,
381 IN BOOLEAN ReplaceIfExists
,
382 IN PUNICODE_STRING ParentName
,
383 OUT PBOOLEAN Deleted
)
388 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
391 /* Try to open target */
392 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
394 if (NT_SUCCESS(Status
))
396 DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName
, TargetFcb
->Flags
);
397 /* Check whether we are allowed to replace */
400 /* If that's a directory or a read-only file, we're not allowed */
401 if (vfatFCBIsDirectory(TargetFcb
) || ((*TargetFcb
->Attributes
& FILE_ATTRIBUTE_READONLY
) == FILE_ATTRIBUTE_READONLY
))
403 DPRINT("And this is a readonly file!\n");
404 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
406 vfatReleaseFCB(DeviceExt
, TargetFcb
);
407 return STATUS_OBJECT_NAME_COLLISION
;
411 /* If we still have a file object, close it. */
412 if (TargetFcb
->FileObject
)
414 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
416 DPRINT("MmFlushImageSection failed.\n");
417 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
419 vfatReleaseFCB(DeviceExt
, TargetFcb
);
420 return STATUS_ACCESS_DENIED
;
423 TargetFcb
->FileObject
->DeletePending
= TRUE
;
424 VfatCloseFile(DeviceExt
, TargetFcb
->FileObject
);
427 /* If we are here, ensure the file isn't open by anyone! */
428 if (TargetFcb
->OpenHandleCount
!= 0)
430 DPRINT("There are still open handles for this file.\n");
431 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
433 vfatReleaseFCB(DeviceExt
, TargetFcb
);
434 return STATUS_ACCESS_DENIED
;
437 /* Effectively delete old file to allow renaming */
438 DPRINT("Effectively deleting the file.\n");
439 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
440 vfatReleaseFCB(DeviceExt
, TargetFcb
);
442 return STATUS_SUCCESS
;
446 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
448 vfatReleaseFCB(DeviceExt
, TargetFcb
);
449 return STATUS_OBJECT_NAME_COLLISION
;
452 else if (*ParentFCB
!= NULL
)
454 return STATUS_SUCCESS
;
462 * FUNCTION: Set the file name information
466 VfatSetRenameInformation(
467 PFILE_OBJECT FileObject
,
469 PDEVICE_EXTENSION DeviceExt
,
470 PFILE_RENAME_INFORMATION RenameInfo
,
471 PFILE_OBJECT TargetFileObject
)
473 #ifdef NASSERTS_RENAME
474 #pragma push_macro("ASSERT")
476 #define ASSERT(x) ((VOID) 0)
479 UNICODE_STRING NewName
;
480 UNICODE_STRING SourcePath
;
481 UNICODE_STRING SourceFile
;
482 UNICODE_STRING NewPath
;
483 UNICODE_STRING NewFile
;
484 PFILE_OBJECT RootFileObject
;
486 UNICODE_STRING RenameInfoString
;
488 IO_STATUS_BLOCK IoStatusBlock
;
489 OBJECT_ATTRIBUTES ObjectAttributes
;
491 BOOLEAN DeletedTarget
;
492 ULONG OldReferences
, NewReferences
;
495 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
497 /* Disallow renaming root */
498 if (vfatFCBIsRoot(FCB
))
500 return STATUS_INVALID_PARAMETER
;
503 OldReferences
= FCB
->parentFcb
->RefCount
;
504 #ifdef NASSERTS_RENAME
505 UNREFERENCED_PARAMETER(OldReferences
);
508 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
509 if (RenameInfo
->RootDirectory
!= NULL
)
511 /* We cannot tolerate relative opening with a full path */
512 if (RenameInfo
->FileName
[0] == L
'\\')
514 return STATUS_OBJECT_NAME_INVALID
;
517 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
521 (PVOID
*)&RootFileObject
,
523 if (!NT_SUCCESS(Status
))
528 RootFCB
= RootFileObject
->FsContext
;
531 RtlInitEmptyUnicodeString(&NewName
, NULL
, 0);
534 if (TargetFileObject
== NULL
)
536 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
537 * information supplied by the user
540 /* First, setup a string we'll work on */
541 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
542 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
543 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
545 /* Check whether we have FQN */
546 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
548 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
549 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
550 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
551 RenameInfoString
.Buffer
[4] <= L
'Z'))
553 /* If so, open its target directory */
554 InitializeObjectAttributes(&ObjectAttributes
,
556 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
559 Status
= IoCreateFile(&TargetHandle
,
560 FILE_WRITE_DATA
| SYNCHRONIZE
,
564 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
566 FILE_OPEN_FOR_BACKUP_INTENT
,
570 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
571 if (!NT_SUCCESS(Status
))
576 /* Get its FO to get the FCB */
577 Status
= ObReferenceObjectByHandle(TargetHandle
,
581 (PVOID
*)&TargetFileObject
,
583 if (!NT_SUCCESS(Status
))
585 ZwClose(TargetHandle
);
589 /* Are we working on the same volume? */
590 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
592 ObDereferenceObject(TargetFileObject
);
593 ZwClose(TargetHandle
);
594 TargetFileObject
= NULL
;
595 Status
= STATUS_NOT_SAME_DEVICE
;
602 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
603 if (RenameInfo
->RootDirectory
!= NULL
)
605 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
607 else if (RenameInfo
->FileName
[0] != L
'\\')
609 /* We don't have full path, and we don't have root directory:
610 * => we move inside the same directory
612 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
614 else if (TargetFileObject
!= NULL
)
617 * => we need to use its correct path
619 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
622 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
623 if (NewName
.Buffer
== NULL
)
625 if (TargetFileObject
!= NULL
)
627 ObDereferenceObject(TargetFileObject
);
628 ZwClose(TargetHandle
);
629 TargetFileObject
= NULL
;
631 Status
= STATUS_INSUFFICIENT_RESOURCES
;
635 if (RenameInfo
->RootDirectory
!= NULL
)
637 /* Here, copy first absolute and then append relative */
638 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
639 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
640 NewName
.Length
+= sizeof(WCHAR
);
641 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
643 else if (RenameInfo
->FileName
[0] != L
'\\')
645 /* Here, copy first work directory and then append filename */
646 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
647 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
648 NewName
.Length
+= sizeof(WCHAR
);
649 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
651 else if (TargetFileObject
!= NULL
)
653 /* Here, copy first path name and then append filename */
654 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
655 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
656 NewName
.Length
+= sizeof(WCHAR
);
657 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
661 /* Here we should have full path, so simply copy it */
662 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
665 /* Do we have to cleanup some stuff? */
666 if (TargetFileObject
!= NULL
)
668 ObDereferenceObject(TargetFileObject
);
669 ZwClose(TargetHandle
);
670 TargetFileObject
= NULL
;
675 /* At that point, we shouldn't care about whether we are relative opening
676 * Target FO FCB should already have full path
679 /* Before constructing string, just make a sanity check (just to be sure!) */
680 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
682 Status
= STATUS_NOT_SAME_DEVICE
;
687 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
688 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
689 if (NewName
.Buffer
== NULL
)
691 Status
= STATUS_INSUFFICIENT_RESOURCES
;
695 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
696 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
697 NewName
.Length
+= sizeof(WCHAR
);
698 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
701 /* Explode our paths to get path & filename */
702 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
703 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
704 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
705 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
707 if (vfatFCBIsDirectory(FCB
) && !IsListEmpty(&FCB
->ParentListHead
))
712 for (Entry
= FCB
->ParentListHead
.Flink
; Entry
!= &FCB
->ParentListHead
; Entry
= Entry
->Flink
)
714 VolFCB
= CONTAINING_RECORD(Entry
, VFATFCB
, ParentListEntry
);
715 if (VolFCB
->OpenHandleCount
!= 0)
717 ASSERT(VolFCB
->parentFCB
== FCB
);
718 DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB
->PathNameU
, VolFCB
->RefCount
, VolFCB
->OpenHandleCount
);
719 Status
= STATUS_ACCESS_DENIED
;
720 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
726 /* Are we working in place? */
727 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
729 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
731 Status
= STATUS_SUCCESS
;
732 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
736 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
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_OLD_NAME
,
748 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
749 if (NT_SUCCESS(Status
))
751 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
752 &(DeviceExt
->NotifyList
),
753 (PSTRING
)&FCB
->PathNameU
,
754 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
757 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
758 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
759 FILE_ACTION_RENAMED_NEW_NAME
,
765 /* Try to find target */
766 ParentFCB
= FCB
->parentFcb
;
767 vfatGrabFCB(DeviceExt
, ParentFCB
);
768 Status
= vfatPrepareTargetForRename(DeviceExt
,
771 RenameInfo
->ReplaceIfExists
,
774 if (!NT_SUCCESS(Status
))
776 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
777 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
781 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
782 &(DeviceExt
->NotifyList
),
783 (PSTRING
)&FCB
->PathNameU
,
784 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
787 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
788 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
789 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
791 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
792 if (NT_SUCCESS(Status
))
796 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
797 &(DeviceExt
->NotifyList
),
798 (PSTRING
)&FCB
->PathNameU
,
799 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
802 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
803 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
804 FILE_ACTION_MODIFIED
,
809 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
810 &(DeviceExt
->NotifyList
),
811 (PSTRING
)&FCB
->PathNameU
,
812 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
815 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
816 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
817 FILE_ACTION_RENAMED_NEW_NAME
,
823 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
824 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
829 /* Try to find target */
831 OldParent
= FCB
->parentFcb
;
832 #ifdef NASSERTS_RENAME
833 UNREFERENCED_PARAMETER(OldParent
);
835 Status
= vfatPrepareTargetForRename(DeviceExt
,
838 RenameInfo
->ReplaceIfExists
,
841 if (!NT_SUCCESS(Status
))
843 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
847 NewReferences
= ParentFCB
->RefCount
;
848 #ifdef NASSERTS_RENAME
849 UNREFERENCED_PARAMETER(NewReferences
);
852 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
853 &(DeviceExt
->NotifyList
),
854 (PSTRING
)&FCB
->PathNameU
,
855 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
858 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
859 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
862 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
863 if (NT_SUCCESS(Status
))
867 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
868 &(DeviceExt
->NotifyList
),
869 (PSTRING
)&FCB
->PathNameU
,
870 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
873 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
874 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
875 FILE_ACTION_MODIFIED
,
880 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
881 &(DeviceExt
->NotifyList
),
882 (PSTRING
)&FCB
->PathNameU
,
883 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
886 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
887 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
894 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
895 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
897 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
898 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
899 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
902 #ifdef NASSERTS_RENAME
903 #pragma pop_macro("ASSERT")
908 * FUNCTION: Retrieve the file name information
912 VfatGetNameInformation(
913 PFILE_OBJECT FileObject
,
915 PDEVICE_OBJECT DeviceObject
,
916 PFILE_NAME_INFORMATION NameInfo
,
921 UNREFERENCED_PARAMETER(FileObject
);
922 UNREFERENCED_PARAMETER(DeviceObject
);
924 ASSERT(NameInfo
!= NULL
);
927 /* If buffer can't hold at least the file name length, bail out */
928 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
929 return STATUS_BUFFER_OVERFLOW
;
931 /* Save file name length, and as much file len, as buffer length allows */
932 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
934 /* Calculate amount of bytes to copy not to overflow the buffer */
935 BytesToCopy
= min(FCB
->PathNameU
.Length
,
936 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
938 /* Fill in the bytes */
939 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
941 /* Check if we could write more but are not able to */
942 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
944 /* Return number of bytes written */
945 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
946 return STATUS_BUFFER_OVERFLOW
;
949 /* We filled up as many bytes, as needed */
950 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
952 return STATUS_SUCCESS
;
957 VfatGetInternalInformation(
959 PFILE_INTERNAL_INFORMATION InternalInfo
,
962 ASSERT(InternalInfo
);
965 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
966 return STATUS_BUFFER_OVERFLOW
;
967 // FIXME: get a real index, that can be used in a create operation
968 InternalInfo
->IndexNumber
.QuadPart
= 0;
969 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
970 return STATUS_SUCCESS
;
975 * FUNCTION: Retrieve the file network open information
979 VfatGetNetworkOpenInformation(
981 PDEVICE_EXTENSION DeviceExt
,
982 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
988 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
989 return(STATUS_BUFFER_OVERFLOW
);
991 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
993 FsdDosDateTimeToSystemTime(DeviceExt
,
994 Fcb
->entry
.FatX
.CreationDate
,
995 Fcb
->entry
.FatX
.CreationTime
,
996 &NetworkInfo
->CreationTime
);
997 FsdDosDateTimeToSystemTime(DeviceExt
,
998 Fcb
->entry
.FatX
.AccessDate
,
999 Fcb
->entry
.FatX
.AccessTime
,
1000 &NetworkInfo
->LastAccessTime
);
1001 FsdDosDateTimeToSystemTime(DeviceExt
,
1002 Fcb
->entry
.FatX
.UpdateDate
,
1003 Fcb
->entry
.FatX
.UpdateTime
,
1004 &NetworkInfo
->LastWriteTime
);
1005 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1009 FsdDosDateTimeToSystemTime(DeviceExt
,
1010 Fcb
->entry
.Fat
.CreationDate
,
1011 Fcb
->entry
.Fat
.CreationTime
,
1012 &NetworkInfo
->CreationTime
);
1013 FsdDosDateTimeToSystemTime(DeviceExt
,
1014 Fcb
->entry
.Fat
.AccessDate
,
1016 &NetworkInfo
->LastAccessTime
);
1017 FsdDosDateTimeToSystemTime(DeviceExt
,
1018 Fcb
->entry
.Fat
.UpdateDate
,
1019 Fcb
->entry
.Fat
.UpdateTime
,
1020 &NetworkInfo
->LastWriteTime
);
1021 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1024 if (vfatFCBIsDirectory(Fcb
))
1026 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1027 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1031 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1032 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1035 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1036 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1037 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1038 FILE_ATTRIBUTE_ARCHIVE
|
1039 FILE_ATTRIBUTE_SYSTEM
|
1040 FILE_ATTRIBUTE_HIDDEN
|
1041 FILE_ATTRIBUTE_READONLY
)))
1043 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1044 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1047 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1048 return STATUS_SUCCESS
;
1054 VfatGetEaInformation(
1055 PFILE_OBJECT FileObject
,
1057 PDEVICE_OBJECT DeviceObject
,
1058 PFILE_EA_INFORMATION Info
,
1059 PULONG BufferLength
)
1061 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1063 UNREFERENCED_PARAMETER(FileObject
);
1064 UNREFERENCED_PARAMETER(Fcb
);
1066 /* FIXME - use SEH to access the buffer! */
1068 *BufferLength
-= sizeof(*Info
);
1069 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1070 DeviceExt
->FatInfo
.FatType
== FAT16
)
1073 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1075 return STATUS_SUCCESS
;
1080 * FUNCTION: Retrieve the all file information
1084 VfatGetAllInformation(
1085 PFILE_OBJECT FileObject
,
1087 PDEVICE_OBJECT DeviceObject
,
1088 PFILE_ALL_INFORMATION Info
,
1089 PULONG BufferLength
)
1096 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1097 return STATUS_BUFFER_OVERFLOW
;
1099 /* Basic Information */
1100 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
1101 if (!NT_SUCCESS(Status
)) return Status
;
1102 /* Standard Information */
1103 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1104 if (!NT_SUCCESS(Status
)) return Status
;
1105 /* Internal Information */
1106 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
1107 if (!NT_SUCCESS(Status
)) return Status
;
1108 /* EA Information */
1109 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceObject
, &Info
->EaInformation
, BufferLength
);
1110 if (!NT_SUCCESS(Status
)) return Status
;
1111 /* Access Information: The IO-Manager adds this information */
1112 *BufferLength
-= sizeof(FILE_ACCESS_INFORMATION
);
1113 /* Position Information */
1114 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
1115 if (!NT_SUCCESS(Status
)) return Status
;
1116 /* Mode Information: The IO-Manager adds this information */
1117 *BufferLength
-= sizeof(FILE_MODE_INFORMATION
);
1118 /* Alignment Information: The IO-Manager adds this information */
1119 *BufferLength
-= sizeof(FILE_ALIGNMENT_INFORMATION
);
1120 /* Name Information */
1121 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
1129 PFILE_OBJECT FileObject
,
1136 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP_64(Size
, ClusterSize
);
1140 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1142 if (!vfatFCBIsDirectory(Fcb
))
1144 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1145 Fcb
->entry
.FatX
.FileSize
= Size
;
1147 Fcb
->entry
.Fat
.FileSize
= Size
;
1149 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1150 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1152 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1156 VfatSetAllocationSizeInformation(
1157 PFILE_OBJECT FileObject
,
1159 PDEVICE_EXTENSION DeviceExt
,
1160 PLARGE_INTEGER AllocationSize
)
1163 ULONG Cluster
, FirstCluster
;
1166 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1167 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1169 BOOLEAN AllocSizeChanged
= FALSE
;
1171 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1172 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1174 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1175 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1177 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1179 if (AllocationSize
->u
.HighPart
> 0)
1181 return STATUS_INVALID_PARAMETER
;
1184 if (OldSize
== NewSize
)
1186 return STATUS_SUCCESS
;
1189 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1191 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1193 AllocSizeChanged
= TRUE
;
1194 if (FirstCluster
== 0)
1196 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1197 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1198 if (!NT_SUCCESS(Status
))
1200 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1204 if (FirstCluster
== 0xffffffff)
1206 return STATUS_DISK_FULL
;
1209 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1210 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1212 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1215 NCluster
= Cluster
= FirstCluster
;
1216 Status
= STATUS_SUCCESS
;
1217 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1219 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1220 WriteCluster(DeviceExt
, Cluster
, 0);
1223 return STATUS_DISK_FULL
;
1226 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1228 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1232 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1234 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1235 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1239 ASSERT((FirstCluster
>> 16) == 0);
1240 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1246 if (Fcb
->LastCluster
> 0)
1248 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1250 Cluster
= Fcb
->LastCluster
;
1251 Status
= STATUS_SUCCESS
;
1255 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1256 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1262 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1263 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1267 if (!NT_SUCCESS(Status
))
1272 Fcb
->LastCluster
= Cluster
;
1273 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1275 /* FIXME: Check status */
1276 /* Cluster points now to the last cluster within the chain */
1277 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1278 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1280 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1284 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1285 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1287 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1289 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1290 WriteCluster(DeviceExt
, Cluster
, 0);
1293 return STATUS_DISK_FULL
;
1296 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1298 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1300 DPRINT("Check for the ability to set file size\n");
1301 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1302 (PLARGE_INTEGER
)AllocationSize
))
1304 DPRINT("Couldn't set file size!\n");
1305 return STATUS_USER_MAPPED_FILE
;
1307 DPRINT("Can set file size\n");
1309 AllocSizeChanged
= TRUE
;
1310 /* FIXME: Use the cached cluster/offset better way. */
1311 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1312 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1315 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1316 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1320 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1321 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1326 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1328 Fcb
->entry
.FatX
.FirstCluster
= 0;
1332 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1334 Fcb
->entry
.Fat
.FirstCluster
= 0;
1335 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1339 Fcb
->entry
.Fat
.FirstCluster
= 0;
1343 NCluster
= Cluster
= FirstCluster
;
1344 Status
= STATUS_SUCCESS
;
1347 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1349 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1350 WriteCluster(DeviceExt
, Cluster
, 0);
1356 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1359 /* Update the on-disk directory entry */
1360 Fcb
->Flags
|= FCB_IS_DIRTY
;
1361 if (AllocSizeChanged
)
1363 VfatUpdateEntry(Fcb
);
1365 return STATUS_SUCCESS
;
1369 * FUNCTION: Retrieve the specified file information
1372 VfatQueryInformation(
1373 PVFAT_IRP_CONTEXT IrpContext
)
1375 FILE_INFORMATION_CLASS FileInformationClass
;
1376 PVFATFCB FCB
= NULL
;
1378 NTSTATUS Status
= STATUS_SUCCESS
;
1385 /* INITIALIZATION */
1386 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1387 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1389 DPRINT("VfatQueryInformation is called for '%s'\n",
1390 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1393 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1394 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1396 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1398 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1399 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1401 return VfatMarkIrpContextForQueue(IrpContext
);
1405 switch (FileInformationClass
)
1407 case FileStandardInformation
:
1408 Status
= VfatGetStandardInformation(FCB
,
1413 case FilePositionInformation
:
1414 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1416 IrpContext
->DeviceObject
,
1421 case FileBasicInformation
:
1422 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1424 IrpContext
->DeviceObject
,
1429 case FileNameInformation
:
1430 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1432 IrpContext
->DeviceObject
,
1437 case FileInternalInformation
:
1438 Status
= VfatGetInternalInformation(FCB
,
1443 case FileNetworkOpenInformation
:
1444 Status
= VfatGetNetworkOpenInformation(FCB
,
1445 IrpContext
->DeviceExt
,
1450 case FileAllInformation
:
1451 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1453 IrpContext
->DeviceObject
,
1458 case FileEaInformation
:
1459 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1461 IrpContext
->DeviceObject
,
1466 case FileAlternateNameInformation
:
1467 Status
= STATUS_NOT_IMPLEMENTED
;
1471 Status
= STATUS_INVALID_PARAMETER
;
1474 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1476 ExReleaseResourceLite(&FCB
->MainResource
);
1479 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1480 IrpContext
->Irp
->IoStatus
.Information
=
1481 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1483 IrpContext
->Irp
->IoStatus
.Information
= 0;
1489 * FUNCTION: Retrieve the specified file information
1493 PVFAT_IRP_CONTEXT IrpContext
)
1495 FILE_INFORMATION_CLASS FileInformationClass
;
1496 PVFATFCB FCB
= NULL
;
1497 NTSTATUS Status
= STATUS_SUCCESS
;
1503 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1505 /* INITIALIZATION */
1506 FileInformationClass
=
1507 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1508 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1509 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1511 DPRINT("VfatSetInformation is called for '%s'\n",
1512 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1514 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1515 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1517 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1518 the file size would be allowed. If not, we bail with the right error.
1519 We must do this before acquiring the lock. */
1520 if (FileInformationClass
== FileEndOfFileInformation
)
1522 DPRINT("Check for the ability to set file size\n");
1523 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1524 (PLARGE_INTEGER
)SystemBuffer
))
1526 DPRINT("Couldn't set file size!\n");
1527 IrpContext
->Irp
->IoStatus
.Information
= 0;
1528 return STATUS_USER_MAPPED_FILE
;
1530 DPRINT("Can set file size\n");
1533 if (FileInformationClass
== FileRenameInformation
)
1535 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1536 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1538 return VfatMarkIrpContextForQueue(IrpContext
);
1542 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1544 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1545 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1547 if (FileInformationClass
== FileRenameInformation
)
1549 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1552 return VfatMarkIrpContextForQueue(IrpContext
);
1556 switch (FileInformationClass
)
1558 case FilePositionInformation
:
1559 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1563 case FileDispositionInformation
:
1564 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1566 IrpContext
->DeviceObject
,
1570 case FileAllocationInformation
:
1571 case FileEndOfFileInformation
:
1572 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1574 IrpContext
->DeviceExt
,
1575 (PLARGE_INTEGER
)SystemBuffer
);
1578 case FileBasicInformation
:
1579 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1581 IrpContext
->DeviceExt
,
1585 case FileRenameInformation
:
1586 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1588 IrpContext
->DeviceExt
,
1590 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1594 Status
= STATUS_NOT_SUPPORTED
;
1597 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1599 ExReleaseResourceLite(&FCB
->MainResource
);
1602 if (FileInformationClass
== FileRenameInformation
)
1604 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1607 IrpContext
->Irp
->IoStatus
.Information
= 0;