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 /* Are we working in place? */
708 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
710 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
712 Status
= STATUS_SUCCESS
;
713 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
717 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
719 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
720 &(DeviceExt
->NotifyList
),
721 (PSTRING
)&FCB
->PathNameU
,
722 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
725 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
726 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
727 FILE_ACTION_RENAMED_OLD_NAME
,
729 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
730 if (NT_SUCCESS(Status
))
732 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
733 &(DeviceExt
->NotifyList
),
734 (PSTRING
)&FCB
->PathNameU
,
735 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
738 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
739 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
740 FILE_ACTION_RENAMED_NEW_NAME
,
746 /* Try to find target */
747 ParentFCB
= FCB
->parentFcb
;
748 vfatGrabFCB(DeviceExt
, ParentFCB
);
749 Status
= vfatPrepareTargetForRename(DeviceExt
,
752 RenameInfo
->ReplaceIfExists
,
755 if (!NT_SUCCESS(Status
))
757 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
758 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
762 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
763 &(DeviceExt
->NotifyList
),
764 (PSTRING
)&FCB
->PathNameU
,
765 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
768 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
769 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
770 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
772 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
773 if (NT_SUCCESS(Status
))
777 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
778 &(DeviceExt
->NotifyList
),
779 (PSTRING
)&FCB
->PathNameU
,
780 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
783 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
784 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
785 FILE_ACTION_MODIFIED
,
790 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
791 &(DeviceExt
->NotifyList
),
792 (PSTRING
)&FCB
->PathNameU
,
793 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
796 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
797 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
798 FILE_ACTION_RENAMED_NEW_NAME
,
804 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
805 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
810 /* Try to find target */
812 OldParent
= FCB
->parentFcb
;
813 #ifdef NASSERTS_RENAME
814 UNREFERENCED_PARAMETER(OldParent
);
816 Status
= vfatPrepareTargetForRename(DeviceExt
,
819 RenameInfo
->ReplaceIfExists
,
822 if (!NT_SUCCESS(Status
))
824 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
828 NewReferences
= ParentFCB
->RefCount
;
829 #ifdef NASSERTS_RENAME
830 UNREFERENCED_PARAMETER(NewReferences
);
833 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
834 &(DeviceExt
->NotifyList
),
835 (PSTRING
)&FCB
->PathNameU
,
836 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
839 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
840 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
843 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
844 if (NT_SUCCESS(Status
))
848 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
849 &(DeviceExt
->NotifyList
),
850 (PSTRING
)&FCB
->PathNameU
,
851 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
854 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
855 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
856 FILE_ACTION_MODIFIED
,
861 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
862 &(DeviceExt
->NotifyList
),
863 (PSTRING
)&FCB
->PathNameU
,
864 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
867 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
868 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
875 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
876 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
878 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
879 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
880 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
883 #ifdef NASSERTS_RENAME
884 #pragma pop_macro("ASSERT")
889 * FUNCTION: Retrieve the file name information
893 VfatGetNameInformation(
894 PFILE_OBJECT FileObject
,
896 PDEVICE_OBJECT DeviceObject
,
897 PFILE_NAME_INFORMATION NameInfo
,
902 UNREFERENCED_PARAMETER(FileObject
);
903 UNREFERENCED_PARAMETER(DeviceObject
);
905 ASSERT(NameInfo
!= NULL
);
908 /* If buffer can't hold at least the file name length, bail out */
909 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
910 return STATUS_BUFFER_OVERFLOW
;
912 /* Save file name length, and as much file len, as buffer length allows */
913 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
915 /* Calculate amount of bytes to copy not to overflow the buffer */
916 BytesToCopy
= min(FCB
->PathNameU
.Length
,
917 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
919 /* Fill in the bytes */
920 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
922 /* Check if we could write more but are not able to */
923 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
925 /* Return number of bytes written */
926 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
927 return STATUS_BUFFER_OVERFLOW
;
930 /* We filled up as many bytes, as needed */
931 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
933 return STATUS_SUCCESS
;
938 VfatGetInternalInformation(
940 PFILE_INTERNAL_INFORMATION InternalInfo
,
943 ASSERT(InternalInfo
);
946 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
947 return STATUS_BUFFER_OVERFLOW
;
948 // FIXME: get a real index, that can be used in a create operation
949 InternalInfo
->IndexNumber
.QuadPart
= 0;
950 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
951 return STATUS_SUCCESS
;
956 * FUNCTION: Retrieve the file network open information
960 VfatGetNetworkOpenInformation(
962 PDEVICE_EXTENSION DeviceExt
,
963 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
969 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
970 return(STATUS_BUFFER_OVERFLOW
);
972 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
974 FsdDosDateTimeToSystemTime(DeviceExt
,
975 Fcb
->entry
.FatX
.CreationDate
,
976 Fcb
->entry
.FatX
.CreationTime
,
977 &NetworkInfo
->CreationTime
);
978 FsdDosDateTimeToSystemTime(DeviceExt
,
979 Fcb
->entry
.FatX
.AccessDate
,
980 Fcb
->entry
.FatX
.AccessTime
,
981 &NetworkInfo
->LastAccessTime
);
982 FsdDosDateTimeToSystemTime(DeviceExt
,
983 Fcb
->entry
.FatX
.UpdateDate
,
984 Fcb
->entry
.FatX
.UpdateTime
,
985 &NetworkInfo
->LastWriteTime
);
986 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
990 FsdDosDateTimeToSystemTime(DeviceExt
,
991 Fcb
->entry
.Fat
.CreationDate
,
992 Fcb
->entry
.Fat
.CreationTime
,
993 &NetworkInfo
->CreationTime
);
994 FsdDosDateTimeToSystemTime(DeviceExt
,
995 Fcb
->entry
.Fat
.AccessDate
,
997 &NetworkInfo
->LastAccessTime
);
998 FsdDosDateTimeToSystemTime(DeviceExt
,
999 Fcb
->entry
.Fat
.UpdateDate
,
1000 Fcb
->entry
.Fat
.UpdateTime
,
1001 &NetworkInfo
->LastWriteTime
);
1002 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
1005 if (vfatFCBIsDirectory(Fcb
))
1007 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
1008 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
1012 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
1013 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
1016 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
1017 /* Synthesize FILE_ATTRIBUTE_NORMAL */
1018 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
1019 FILE_ATTRIBUTE_ARCHIVE
|
1020 FILE_ATTRIBUTE_SYSTEM
|
1021 FILE_ATTRIBUTE_HIDDEN
|
1022 FILE_ATTRIBUTE_READONLY
)))
1024 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
1025 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
1028 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1029 return STATUS_SUCCESS
;
1035 VfatGetEaInformation(
1036 PFILE_OBJECT FileObject
,
1038 PDEVICE_OBJECT DeviceObject
,
1039 PFILE_EA_INFORMATION Info
,
1040 PULONG BufferLength
)
1042 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1044 UNREFERENCED_PARAMETER(FileObject
);
1045 UNREFERENCED_PARAMETER(Fcb
);
1047 /* FIXME - use SEH to access the buffer! */
1049 *BufferLength
-= sizeof(*Info
);
1050 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1051 DeviceExt
->FatInfo
.FatType
== FAT16
)
1054 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1056 return STATUS_SUCCESS
;
1061 * FUNCTION: Retrieve the all file information
1065 VfatGetAllInformation(
1066 PFILE_OBJECT FileObject
,
1068 PDEVICE_OBJECT DeviceObject
,
1069 PFILE_ALL_INFORMATION Info
,
1070 PULONG BufferLength
)
1077 if (*BufferLength
< FIELD_OFFSET(FILE_ALL_INFORMATION
, NameInformation
.FileName
))
1078 return STATUS_BUFFER_OVERFLOW
;
1080 /* Basic Information */
1081 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
1082 if (!NT_SUCCESS(Status
)) return Status
;
1083 /* Standard Information */
1084 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1085 if (!NT_SUCCESS(Status
)) return Status
;
1086 /* Internal Information */
1087 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
1088 if (!NT_SUCCESS(Status
)) return Status
;
1089 /* EA Information */
1090 Status
= VfatGetEaInformation(FileObject
, Fcb
, DeviceObject
, &Info
->EaInformation
, BufferLength
);
1091 if (!NT_SUCCESS(Status
)) return Status
;
1092 /* Access Information: The IO-Manager adds this information */
1093 *BufferLength
-= sizeof(FILE_ACCESS_INFORMATION
);
1094 /* Position Information */
1095 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
1096 if (!NT_SUCCESS(Status
)) return Status
;
1097 /* Mode Information: The IO-Manager adds this information */
1098 *BufferLength
-= sizeof(FILE_MODE_INFORMATION
);
1099 /* Alignment Information: The IO-Manager adds this information */
1100 *BufferLength
-= sizeof(FILE_ALIGNMENT_INFORMATION
);
1101 /* Name Information */
1102 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
1110 PFILE_OBJECT FileObject
,
1117 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
1121 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1123 if (!vfatFCBIsDirectory(Fcb
))
1125 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1126 Fcb
->entry
.FatX
.FileSize
= Size
;
1128 Fcb
->entry
.Fat
.FileSize
= Size
;
1130 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1131 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1133 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1137 VfatSetAllocationSizeInformation(
1138 PFILE_OBJECT FileObject
,
1140 PDEVICE_EXTENSION DeviceExt
,
1141 PLARGE_INTEGER AllocationSize
)
1144 ULONG Cluster
, FirstCluster
;
1147 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1148 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1150 BOOLEAN AllocSizeChanged
= FALSE
;
1152 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1153 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1155 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1156 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1158 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1160 if (AllocationSize
->u
.HighPart
> 0)
1162 return STATUS_INVALID_PARAMETER
;
1165 if (OldSize
== NewSize
)
1167 return STATUS_SUCCESS
;
1170 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1172 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1174 AllocSizeChanged
= TRUE
;
1175 if (FirstCluster
== 0)
1177 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1178 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1179 if (!NT_SUCCESS(Status
))
1181 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1185 if (FirstCluster
== 0xffffffff)
1187 return STATUS_DISK_FULL
;
1190 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1191 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1193 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1196 NCluster
= Cluster
= FirstCluster
;
1197 Status
= STATUS_SUCCESS
;
1198 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1200 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1201 WriteCluster(DeviceExt
, Cluster
, 0);
1204 return STATUS_DISK_FULL
;
1207 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1209 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1213 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1215 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1216 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1220 ASSERT((FirstCluster
>> 16) == 0);
1221 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1227 if (Fcb
->LastCluster
> 0)
1229 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1231 Cluster
= Fcb
->LastCluster
;
1232 Status
= STATUS_SUCCESS
;
1236 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1237 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1243 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1244 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1248 if (!NT_SUCCESS(Status
))
1253 Fcb
->LastCluster
= Cluster
;
1254 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1256 /* FIXME: Check status */
1257 /* Cluster points now to the last cluster within the chain */
1258 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1259 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1261 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1265 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1266 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1268 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1270 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1271 WriteCluster(DeviceExt
, Cluster
, 0);
1274 return STATUS_DISK_FULL
;
1277 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1279 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1281 DPRINT("Check for the ability to set file size\n");
1282 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1283 (PLARGE_INTEGER
)AllocationSize
))
1285 DPRINT("Couldn't set file size!\n");
1286 return STATUS_USER_MAPPED_FILE
;
1288 DPRINT("Can set file size\n");
1290 AllocSizeChanged
= TRUE
;
1291 /* FIXME: Use the cached cluster/offset better way. */
1292 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1293 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1296 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1297 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1301 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1302 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1307 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1309 Fcb
->entry
.FatX
.FirstCluster
= 0;
1313 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1315 Fcb
->entry
.Fat
.FirstCluster
= 0;
1316 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1320 Fcb
->entry
.Fat
.FirstCluster
= 0;
1324 NCluster
= Cluster
= FirstCluster
;
1325 Status
= STATUS_SUCCESS
;
1328 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1330 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1331 WriteCluster(DeviceExt
, Cluster
, 0);
1337 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1340 /* Update the on-disk directory entry */
1341 Fcb
->Flags
|= FCB_IS_DIRTY
;
1342 if (AllocSizeChanged
)
1344 VfatUpdateEntry(Fcb
);
1346 return STATUS_SUCCESS
;
1350 * FUNCTION: Retrieve the specified file information
1353 VfatQueryInformation(
1354 PVFAT_IRP_CONTEXT IrpContext
)
1356 FILE_INFORMATION_CLASS FileInformationClass
;
1357 PVFATFCB FCB
= NULL
;
1359 NTSTATUS Status
= STATUS_SUCCESS
;
1366 /* INITIALIZATION */
1367 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1368 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1370 DPRINT("VfatQueryInformation is called for '%s'\n",
1371 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1374 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1375 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1377 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1379 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1380 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1382 return VfatMarkIrpContextForQueue(IrpContext
);
1386 switch (FileInformationClass
)
1388 case FileStandardInformation
:
1389 Status
= VfatGetStandardInformation(FCB
,
1394 case FilePositionInformation
:
1395 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1397 IrpContext
->DeviceObject
,
1402 case FileBasicInformation
:
1403 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1405 IrpContext
->DeviceObject
,
1410 case FileNameInformation
:
1411 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1413 IrpContext
->DeviceObject
,
1418 case FileInternalInformation
:
1419 Status
= VfatGetInternalInformation(FCB
,
1424 case FileNetworkOpenInformation
:
1425 Status
= VfatGetNetworkOpenInformation(FCB
,
1426 IrpContext
->DeviceExt
,
1431 case FileAllInformation
:
1432 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1434 IrpContext
->DeviceObject
,
1439 case FileEaInformation
:
1440 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1442 IrpContext
->DeviceObject
,
1447 case FileAlternateNameInformation
:
1448 Status
= STATUS_NOT_IMPLEMENTED
;
1452 Status
= STATUS_INVALID_PARAMETER
;
1455 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1457 ExReleaseResourceLite(&FCB
->MainResource
);
1460 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1461 IrpContext
->Irp
->IoStatus
.Information
=
1462 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1464 IrpContext
->Irp
->IoStatus
.Information
= 0;
1470 * FUNCTION: Retrieve the specified file information
1474 PVFAT_IRP_CONTEXT IrpContext
)
1476 FILE_INFORMATION_CLASS FileInformationClass
;
1477 PVFATFCB FCB
= NULL
;
1478 NTSTATUS Status
= STATUS_SUCCESS
;
1484 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1486 /* INITIALIZATION */
1487 FileInformationClass
=
1488 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1489 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1490 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1492 DPRINT("VfatSetInformation is called for '%s'\n",
1493 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1495 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1496 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1498 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1499 the file size would be allowed. If not, we bail with the right error.
1500 We must do this before acquiring the lock. */
1501 if (FileInformationClass
== FileEndOfFileInformation
)
1503 DPRINT("Check for the ability to set file size\n");
1504 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1505 (PLARGE_INTEGER
)SystemBuffer
))
1507 DPRINT("Couldn't set file size!\n");
1508 IrpContext
->Irp
->IoStatus
.Information
= 0;
1509 return STATUS_USER_MAPPED_FILE
;
1511 DPRINT("Can set file size\n");
1514 if (FileInformationClass
== FileRenameInformation
)
1516 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1517 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1519 return VfatMarkIrpContextForQueue(IrpContext
);
1523 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1525 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1526 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
1528 if (FileInformationClass
== FileRenameInformation
)
1530 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1533 return VfatMarkIrpContextForQueue(IrpContext
);
1537 switch (FileInformationClass
)
1539 case FilePositionInformation
:
1540 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1544 case FileDispositionInformation
:
1545 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1547 IrpContext
->DeviceObject
,
1551 case FileAllocationInformation
:
1552 case FileEndOfFileInformation
:
1553 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1555 IrpContext
->DeviceExt
,
1556 (PLARGE_INTEGER
)SystemBuffer
);
1559 case FileBasicInformation
:
1560 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1562 IrpContext
->DeviceExt
,
1566 case FileRenameInformation
:
1567 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1569 IrpContext
->DeviceExt
,
1571 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1575 Status
= STATUS_NOT_SUPPORTED
;
1578 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1580 ExReleaseResourceLite(&FCB
->MainResource
);
1583 if (FileInformationClass
== FileRenameInformation
)
1585 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1588 IrpContext
->Irp
->IoStatus
.Information
= 0;