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 /* GLOBALS ******************************************************************/
21 const char* FileInformationClassNames
[] =
24 "FileDirectoryInformation",
25 "FileFullDirectoryInformation",
26 "FileBothDirectoryInformation",
27 "FileBasicInformation",
28 "FileStandardInformation",
29 "FileInternalInformation",
31 "FileAccessInformation",
32 "FileNameInformation",
33 "FileRenameInformation",
34 "FileLinkInformation",
35 "FileNamesInformation",
36 "FileDispositionInformation",
37 "FilePositionInformation",
38 "FileFullEaInformation",
39 "FileModeInformation",
40 "FileAlignmentInformation",
42 "FileAllocationInformation",
43 "FileEndOfFileInformation",
44 "FileAlternateNameInformation",
45 "FileStreamInformation",
46 "FilePipeInformation",
47 "FilePipeLocalInformation",
48 "FilePipeRemoteInformation",
49 "FileMailslotQueryInformation",
50 "FileMailslotSetInformation",
51 "FileCompressionInformation",
52 "FileObjectIdInformation",
53 "FileCompletionInformation",
54 "FileMoveClusterInformation",
55 "FileQuotaInformation",
56 "FileReparsePointInformation",
57 "FileNetworkOpenInformation",
58 "FileAttributeTagInformation",
59 "FileTrackingInformation",
60 "FileIdBothDirectoryInformation",
61 "FileIdFullDirectoryInformation",
62 "FileValidDataLengthInformation",
63 "FileShortNameInformation",
64 "FileMaximumInformation"
67 /* FUNCTIONS ****************************************************************/
70 * FUNCTION: Retrieve the standard file information
74 VfatGetStandardInformation(
76 PFILE_STANDARD_INFORMATION StandardInfo
,
79 if (*BufferLength
< sizeof(FILE_STANDARD_INFORMATION
))
80 return STATUS_BUFFER_OVERFLOW
;
83 ASSERT(StandardInfo
!= NULL
);
86 if (vfatFCBIsDirectory(FCB
))
88 StandardInfo
->AllocationSize
.QuadPart
= 0;
89 StandardInfo
->EndOfFile
.QuadPart
= 0;
90 StandardInfo
->Directory
= TRUE
;
94 StandardInfo
->AllocationSize
= FCB
->RFCB
.AllocationSize
;
95 StandardInfo
->EndOfFile
= FCB
->RFCB
.FileSize
;
96 StandardInfo
->Directory
= FALSE
;
98 StandardInfo
->NumberOfLinks
= 1;
99 StandardInfo
->DeletePending
= FCB
->Flags
& FCB_DELETE_PENDING
? TRUE
: FALSE
;
101 *BufferLength
-= sizeof(FILE_STANDARD_INFORMATION
);
102 return STATUS_SUCCESS
;
107 VfatSetPositionInformation(
108 PFILE_OBJECT FileObject
,
109 PFILE_POSITION_INFORMATION PositionInfo
)
111 DPRINT("FsdSetPositionInformation()\n");
113 DPRINT("PositionInfo %p\n", PositionInfo
);
114 DPRINT("Setting position %u\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
116 FileObject
->CurrentByteOffset
.QuadPart
=
117 PositionInfo
->CurrentByteOffset
.QuadPart
;
119 return STATUS_SUCCESS
;
124 VfatGetPositionInformation(
125 PFILE_OBJECT FileObject
,
127 PDEVICE_OBJECT DeviceObject
,
128 PFILE_POSITION_INFORMATION PositionInfo
,
131 UNREFERENCED_PARAMETER(FileObject
);
132 UNREFERENCED_PARAMETER(FCB
);
133 UNREFERENCED_PARAMETER(DeviceObject
);
135 DPRINT("VfatGetPositionInformation()\n");
137 if (*BufferLength
< sizeof(FILE_POSITION_INFORMATION
))
138 return STATUS_BUFFER_OVERFLOW
;
140 PositionInfo
->CurrentByteOffset
.QuadPart
=
141 FileObject
->CurrentByteOffset
.QuadPart
;
143 DPRINT("Getting position %I64x\n",
144 PositionInfo
->CurrentByteOffset
.QuadPart
);
146 *BufferLength
-= sizeof(FILE_POSITION_INFORMATION
);
147 return STATUS_SUCCESS
;
152 VfatSetBasicInformation(
153 PFILE_OBJECT FileObject
,
155 PDEVICE_EXTENSION DeviceExt
,
156 PFILE_BASIC_INFORMATION BasicInfo
)
158 DPRINT("VfatSetBasicInformation()\n");
160 ASSERT(NULL
!= FileObject
);
162 ASSERT(NULL
!= DeviceExt
);
163 ASSERT(NULL
!= BasicInfo
);
164 /* Check volume label bit */
165 ASSERT(0 == (*FCB
->Attributes
& _A_VOLID
));
167 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
169 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
171 FsdSystemTimeToDosDateTime(DeviceExt
,
172 &BasicInfo
->CreationTime
,
173 &FCB
->entry
.FatX
.CreationDate
,
174 &FCB
->entry
.FatX
.CreationTime
);
177 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
179 FsdSystemTimeToDosDateTime(DeviceExt
,
180 &BasicInfo
->LastAccessTime
,
181 &FCB
->entry
.FatX
.AccessDate
,
182 &FCB
->entry
.FatX
.AccessTime
);
185 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
187 FsdSystemTimeToDosDateTime(DeviceExt
,
188 &BasicInfo
->LastWriteTime
,
189 &FCB
->entry
.FatX
.UpdateDate
,
190 &FCB
->entry
.FatX
.UpdateTime
);
195 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
197 FsdSystemTimeToDosDateTime(DeviceExt
,
198 &BasicInfo
->CreationTime
,
199 &FCB
->entry
.Fat
.CreationDate
,
200 &FCB
->entry
.Fat
.CreationTime
);
203 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
205 FsdSystemTimeToDosDateTime(DeviceExt
,
206 &BasicInfo
->LastAccessTime
,
207 &FCB
->entry
.Fat
.AccessDate
,
211 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
213 FsdSystemTimeToDosDateTime(DeviceExt
,
214 &BasicInfo
->LastWriteTime
,
215 &FCB
->entry
.Fat
.UpdateDate
,
216 &FCB
->entry
.Fat
.UpdateTime
);
220 if (BasicInfo
->FileAttributes
)
222 *FCB
->Attributes
= (unsigned char)((*FCB
->Attributes
&
223 (FILE_ATTRIBUTE_DIRECTORY
| 0x48)) |
224 (BasicInfo
->FileAttributes
&
225 (FILE_ATTRIBUTE_ARCHIVE
|
226 FILE_ATTRIBUTE_SYSTEM
|
227 FILE_ATTRIBUTE_HIDDEN
|
228 FILE_ATTRIBUTE_READONLY
)));
229 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
232 VfatUpdateEntry(FCB
);
234 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
;
355 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
357 /* can't delete a file if its mapped into a process */
359 DPRINT("MmFlushImageSection returned FALSE\n");
360 return STATUS_CANNOT_DELETE
;
363 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
365 /* can't delete a non-empty directory */
367 return STATUS_DIRECTORY_NOT_EMPTY
;
371 FCB
->Flags
|= FCB_DELETE_PENDING
;
372 FileObject
->DeletePending
= TRUE
;
374 return STATUS_SUCCESS
;
378 vfatPrepareTargetForRename(
379 IN PDEVICE_EXTENSION DeviceExt
,
380 IN PVFATFCB
* ParentFCB
,
381 IN PUNICODE_STRING NewName
,
382 IN BOOLEAN ReplaceIfExists
,
383 IN PUNICODE_STRING ParentName
,
384 OUT PBOOLEAN Deleted
)
389 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt
, ParentFCB
, NewName
, ReplaceIfExists
, ParentName
);
392 /* Try to open target */
393 Status
= vfatGetFCBForFile(DeviceExt
, ParentFCB
, &TargetFcb
, NewName
);
395 if (NT_SUCCESS(Status
))
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 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
405 vfatReleaseFCB(DeviceExt
, TargetFcb
);
406 return STATUS_OBJECT_NAME_COLLISION
;
409 /* Attempt to flush (might close the file) */
410 if (!MmFlushImageSection(TargetFcb
->FileObject
->SectionObjectPointer
, MmFlushForDelete
))
412 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
414 vfatReleaseFCB(DeviceExt
, TargetFcb
);
415 return STATUS_ACCESS_DENIED
;
418 /* If we are, ensure the file isn't open by anyone! */
419 if (TargetFcb
->OpenHandleCount
!= 0)
421 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
423 vfatReleaseFCB(DeviceExt
, TargetFcb
);
424 return STATUS_ACCESS_DENIED
;
427 /* Effectively delete old file to allow renaming */
428 VfatDelEntry(DeviceExt
, TargetFcb
, NULL
);
429 vfatGrabFCB(DeviceExt
, *ParentFCB
);
430 vfatReleaseFCB(DeviceExt
, TargetFcb
);
435 vfatReleaseFCB(DeviceExt
, *ParentFCB
);
437 vfatReleaseFCB(DeviceExt
, TargetFcb
);
438 return STATUS_OBJECT_NAME_COLLISION
;
441 else if (*ParentFCB
!= NULL
)
443 return STATUS_SUCCESS
;
451 * FUNCTION: Set the file name information
455 VfatSetRenameInformation(
456 PFILE_OBJECT FileObject
,
458 PDEVICE_EXTENSION DeviceExt
,
459 PFILE_RENAME_INFORMATION RenameInfo
,
460 PFILE_OBJECT TargetFileObject
)
463 UNICODE_STRING NewName
;
464 UNICODE_STRING SourcePath
;
465 UNICODE_STRING SourceFile
;
466 UNICODE_STRING NewPath
;
467 UNICODE_STRING NewFile
;
468 PFILE_OBJECT RootFileObject
;
470 UNICODE_STRING RenameInfoString
;
472 IO_STATUS_BLOCK IoStatusBlock
;
473 OBJECT_ATTRIBUTES ObjectAttributes
;
475 BOOLEAN DeletedTarget
;
476 ULONG OldReferences
, NewReferences
;
479 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject
, FCB
, DeviceExt
, RenameInfo
, TargetFileObject
);
481 /* Disallow renaming root */
482 if (vfatFCBIsRoot(FCB
))
484 return STATUS_INVALID_PARAMETER
;
487 OldReferences
= FCB
->parentFcb
->RefCount
;
489 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
490 if (RenameInfo
->RootDirectory
!= NULL
)
492 /* We cannot tolerate relative opening with a full path */
493 if (RenameInfo
->FileName
[0] == L
'\\')
495 return STATUS_OBJECT_NAME_INVALID
;
498 Status
= ObReferenceObjectByHandle(RenameInfo
->RootDirectory
,
502 (PVOID
*)&RootFileObject
,
504 if (!NT_SUCCESS(Status
))
509 RootFCB
= RootFileObject
->FsContext
;
514 if (TargetFileObject
== NULL
)
516 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
517 * information supplied by the user
520 /* First, setup a string we'll work on */
521 RenameInfoString
.Length
= RenameInfo
->FileNameLength
;
522 RenameInfoString
.MaximumLength
= RenameInfo
->FileNameLength
;
523 RenameInfoString
.Buffer
= RenameInfo
->FileName
;
525 /* Check whether we have FQN */
526 if (RenameInfoString
.Length
> 6 * sizeof(WCHAR
))
528 if (RenameInfoString
.Buffer
[0] == L
'\\' && RenameInfoString
.Buffer
[1] == L
'?' &&
529 RenameInfoString
.Buffer
[2] == L
'?' && RenameInfoString
.Buffer
[3] == L
'\\' &&
530 RenameInfoString
.Buffer
[5] == L
':' && (RenameInfoString
.Buffer
[4] >= L
'A' &&
531 RenameInfoString
.Buffer
[4] <= L
'Z'))
533 /* If so, open its target directory */
534 InitializeObjectAttributes(&ObjectAttributes
,
536 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
539 Status
= IoCreateFile(&TargetHandle
,
540 FILE_WRITE_DATA
| SYNCHRONIZE
,
544 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
546 FILE_OPEN_FOR_BACKUP_INTENT
,
550 IO_FORCE_ACCESS_CHECK
| IO_OPEN_TARGET_DIRECTORY
);
551 if (!NT_SUCCESS(Status
))
556 /* Get its FO to get the FCB */
557 Status
= ObReferenceObjectByHandle(TargetHandle
,
561 (PVOID
*)&TargetFileObject
,
563 if (!NT_SUCCESS(Status
))
565 ZwClose(TargetHandle
);
569 /* Are we working on the same volume? */
570 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
572 ObDereferenceObject(TargetFileObject
);
573 ZwClose(TargetHandle
);
574 TargetFileObject
= NULL
;
575 Status
= STATUS_NOT_SAME_DEVICE
;
582 NewName
.MaximumLength
= RenameInfo
->FileNameLength
;
583 if (RenameInfo
->RootDirectory
!= NULL
)
585 NewName
.MaximumLength
+= sizeof(WCHAR
) + RootFCB
->PathNameU
.Length
;
587 else if (RenameInfo
->FileName
[0] != L
'\\')
589 /* We don't have full path, and we don't have root directory:
590 * => we move inside the same directory
592 NewName
.MaximumLength
+= sizeof(WCHAR
) + FCB
->DirNameU
.Length
;
594 else if (TargetFileObject
!= NULL
)
597 * => we need to use its correct path
599 NewName
.MaximumLength
+= sizeof(WCHAR
) + ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
;
602 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
603 if (NewName
.Buffer
== NULL
)
605 if (TargetFileObject
!= NULL
)
607 ObDereferenceObject(TargetFileObject
);
608 ZwClose(TargetHandle
);
609 TargetFileObject
= NULL
;
611 Status
= STATUS_INSUFFICIENT_RESOURCES
;
615 if (RenameInfo
->RootDirectory
!= NULL
)
617 /* Here, copy first absolute and then append relative */
618 RtlCopyUnicodeString(&NewName
, &RootFCB
->PathNameU
);
619 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
620 NewName
.Length
+= sizeof(WCHAR
);
621 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
623 else if (RenameInfo
->FileName
[0] != L
'\\')
625 /* Here, copy first work directory and then append filename */
626 RtlCopyUnicodeString(&NewName
, &FCB
->DirNameU
);
627 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
628 NewName
.Length
+= sizeof(WCHAR
);
629 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
631 else if (TargetFileObject
!= NULL
)
633 /* Here, copy first path name and then append filename */
634 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
635 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
636 NewName
.Length
+= sizeof(WCHAR
);
637 RtlAppendUnicodeStringToString(&NewName
, &RenameInfoString
);
641 /* Here we should have full path, so simply copy it */
642 RtlCopyUnicodeString(&NewName
, &RenameInfoString
);
645 /* Do we have to cleanup some stuff? */
646 if (TargetFileObject
!= NULL
)
648 ObDereferenceObject(TargetFileObject
);
649 ZwClose(TargetHandle
);
650 TargetFileObject
= NULL
;
655 /* At that point, we shouldn't care about whether we are relative opening
656 * Target FO FCB should already have full path
659 /* Before constructing string, just make a sanity check (just to be sure!) */
660 if (IoGetRelatedDeviceObject(TargetFileObject
) != IoGetRelatedDeviceObject(FileObject
))
662 Status
= STATUS_NOT_SAME_DEVICE
;
667 NewName
.MaximumLength
= TargetFileObject
->FileName
.Length
+ ((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
.Length
+ sizeof(WCHAR
);
668 NewName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, NewName
.MaximumLength
, TAG_VFAT
);
669 if (NewName
.Buffer
== NULL
)
671 Status
= STATUS_INSUFFICIENT_RESOURCES
;
675 RtlCopyUnicodeString(&NewName
, &((PVFATFCB
)TargetFileObject
->FsContext
)->PathNameU
);
676 NewName
.Buffer
[NewName
.Length
/ sizeof(WCHAR
)] = L
'\\';
677 NewName
.Length
+= sizeof(WCHAR
);
678 RtlAppendUnicodeStringToString(&NewName
, &TargetFileObject
->FileName
);
681 /* Explode our paths to get path & filename */
682 vfatSplitPathName(&FCB
->PathNameU
, &SourcePath
, &SourceFile
);
683 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath
, &SourceFile
);
684 vfatSplitPathName(&NewName
, &NewPath
, &NewFile
);
685 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath
, &NewFile
);
687 /* Are we working in place? */
688 if (FsRtlAreNamesEqual(&SourcePath
, &NewPath
, TRUE
, NULL
))
690 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, FALSE
, NULL
))
692 Status
= STATUS_SUCCESS
;
693 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
697 if (FsRtlAreNamesEqual(&SourceFile
, &NewFile
, TRUE
, NULL
))
699 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
700 &(DeviceExt
->NotifyList
),
701 (PSTRING
)&FCB
->PathNameU
,
702 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
705 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
706 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
707 FILE_ACTION_RENAMED_OLD_NAME
,
709 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, TRUE
);
710 if (NT_SUCCESS(Status
))
712 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
713 &(DeviceExt
->NotifyList
),
714 (PSTRING
)&FCB
->PathNameU
,
715 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
718 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
719 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
720 FILE_ACTION_RENAMED_NEW_NAME
,
726 /* Try to find target */
727 ParentFCB
= FCB
->parentFcb
;
728 vfatGrabFCB(DeviceExt
, ParentFCB
);
729 Status
= vfatPrepareTargetForRename(DeviceExt
,
732 RenameInfo
->ReplaceIfExists
,
735 if (!NT_SUCCESS(Status
))
737 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1);
738 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1);
742 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
743 &(DeviceExt
->NotifyList
),
744 (PSTRING
)&FCB
->PathNameU
,
745 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
748 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
749 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
750 (DeletedTarget
? FILE_ACTION_REMOVED
: FILE_ACTION_RENAMED_OLD_NAME
),
752 Status
= vfatRenameEntry(DeviceExt
, FCB
, &NewFile
, FALSE
);
753 if (NT_SUCCESS(Status
))
757 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
758 &(DeviceExt
->NotifyList
),
759 (PSTRING
)&FCB
->PathNameU
,
760 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
763 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
764 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
765 FILE_ACTION_MODIFIED
,
770 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
771 &(DeviceExt
->NotifyList
),
772 (PSTRING
)&FCB
->PathNameU
,
773 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
776 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
777 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
778 FILE_ACTION_RENAMED_NEW_NAME
,
784 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
- 1); // extra grab
785 ASSERT(OldReferences
== ParentFCB
->RefCount
- 1); // extra grab
790 /* Try to find target */
792 OldParent
= FCB
->parentFcb
;
793 Status
= vfatPrepareTargetForRename(DeviceExt
,
796 RenameInfo
->ReplaceIfExists
,
799 if (!NT_SUCCESS(Status
))
801 ASSERT(OldReferences
== FCB
->parentFcb
->RefCount
);
805 NewReferences
= ParentFCB
->RefCount
;
807 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
808 &(DeviceExt
->NotifyList
),
809 (PSTRING
)&FCB
->PathNameU
,
810 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
813 ((*FCB
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
814 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
817 Status
= VfatMoveEntry(DeviceExt
, FCB
, &NewFile
, ParentFCB
);
818 if (NT_SUCCESS(Status
))
822 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
823 &(DeviceExt
->NotifyList
),
824 (PSTRING
)&FCB
->PathNameU
,
825 FCB
->PathNameU
.Length
- FCB
->LongNameU
.Length
,
828 FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE
829 | FILE_NOTIFY_CHANGE_LAST_ACCESS
| FILE_NOTIFY_CHANGE_CREATION
| FILE_NOTIFY_CHANGE_EA
,
830 FILE_ACTION_MODIFIED
,
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
),
849 ASSERT(OldReferences
== OldParent
->RefCount
+ 1); // removed file
850 ASSERT(NewReferences
== ParentFCB
->RefCount
- 1); // new file
852 if (ParentFCB
!= NULL
) vfatReleaseFCB(DeviceExt
, ParentFCB
);
853 if (NewName
.Buffer
!= NULL
) ExFreePoolWithTag(NewName
.Buffer
, TAG_VFAT
);
854 if (RenameInfo
->RootDirectory
!= NULL
) ObDereferenceObject(RootFileObject
);
860 * FUNCTION: Retrieve the file name information
864 VfatGetNameInformation(
865 PFILE_OBJECT FileObject
,
867 PDEVICE_OBJECT DeviceObject
,
868 PFILE_NAME_INFORMATION NameInfo
,
873 UNREFERENCED_PARAMETER(FileObject
);
874 UNREFERENCED_PARAMETER(DeviceObject
);
876 ASSERT(NameInfo
!= NULL
);
879 /* If buffer can't hold at least the file name length, bail out */
880 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
881 return STATUS_BUFFER_OVERFLOW
;
883 /* Save file name length, and as much file len, as buffer length allows */
884 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
886 /* Calculate amount of bytes to copy not to overflow the buffer */
887 BytesToCopy
= min(FCB
->PathNameU
.Length
,
888 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
890 /* Fill in the bytes */
891 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
893 /* Check if we could write more but are not able to */
894 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
896 /* Return number of bytes written */
897 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
898 return STATUS_BUFFER_OVERFLOW
;
901 /* We filled up as many bytes, as needed */
902 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
904 return STATUS_SUCCESS
;
909 VfatGetInternalInformation(
911 PFILE_INTERNAL_INFORMATION InternalInfo
,
914 ASSERT(InternalInfo
);
917 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
918 return STATUS_BUFFER_OVERFLOW
;
919 // FIXME: get a real index, that can be used in a create operation
920 InternalInfo
->IndexNumber
.QuadPart
= 0;
921 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
922 return STATUS_SUCCESS
;
927 * FUNCTION: Retrieve the file network open information
931 VfatGetNetworkOpenInformation(
933 PDEVICE_EXTENSION DeviceExt
,
934 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
940 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
941 return(STATUS_BUFFER_OVERFLOW
);
943 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
945 FsdDosDateTimeToSystemTime(DeviceExt
,
946 Fcb
->entry
.FatX
.CreationDate
,
947 Fcb
->entry
.FatX
.CreationTime
,
948 &NetworkInfo
->CreationTime
);
949 FsdDosDateTimeToSystemTime(DeviceExt
,
950 Fcb
->entry
.FatX
.AccessDate
,
951 Fcb
->entry
.FatX
.AccessTime
,
952 &NetworkInfo
->LastAccessTime
);
953 FsdDosDateTimeToSystemTime(DeviceExt
,
954 Fcb
->entry
.FatX
.UpdateDate
,
955 Fcb
->entry
.FatX
.UpdateTime
,
956 &NetworkInfo
->LastWriteTime
);
957 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
961 FsdDosDateTimeToSystemTime(DeviceExt
,
962 Fcb
->entry
.Fat
.CreationDate
,
963 Fcb
->entry
.Fat
.CreationTime
,
964 &NetworkInfo
->CreationTime
);
965 FsdDosDateTimeToSystemTime(DeviceExt
,
966 Fcb
->entry
.Fat
.AccessDate
,
968 &NetworkInfo
->LastAccessTime
);
969 FsdDosDateTimeToSystemTime(DeviceExt
,
970 Fcb
->entry
.Fat
.UpdateDate
,
971 Fcb
->entry
.Fat
.UpdateTime
,
972 &NetworkInfo
->LastWriteTime
);
973 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
976 if (vfatFCBIsDirectory(Fcb
))
978 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
979 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
983 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
984 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
987 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
988 /* Synthesize FILE_ATTRIBUTE_NORMAL */
989 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
990 FILE_ATTRIBUTE_ARCHIVE
|
991 FILE_ATTRIBUTE_SYSTEM
|
992 FILE_ATTRIBUTE_HIDDEN
|
993 FILE_ATTRIBUTE_READONLY
)))
995 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
996 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
999 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
1000 return STATUS_SUCCESS
;
1006 VfatGetEaInformation(
1007 PFILE_OBJECT FileObject
,
1009 PDEVICE_OBJECT DeviceObject
,
1010 PFILE_EA_INFORMATION Info
,
1011 PULONG BufferLength
)
1013 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1015 UNREFERENCED_PARAMETER(FileObject
);
1016 UNREFERENCED_PARAMETER(Fcb
);
1018 /* FIXME - use SEH to access the buffer! */
1020 *BufferLength
-= sizeof(*Info
);
1021 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
1022 DeviceExt
->FatInfo
.FatType
== FAT16
)
1025 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1027 return STATUS_SUCCESS
;
1032 * FUNCTION: Retrieve the all file information
1036 VfatGetAllInformation(
1037 PFILE_OBJECT FileObject
,
1039 PDEVICE_OBJECT DeviceObject
,
1040 PFILE_ALL_INFORMATION Info
,
1041 PULONG BufferLength
)
1044 ULONG InitialBufferLength
= *BufferLength
;
1049 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
))
1050 return(STATUS_BUFFER_OVERFLOW
);
1052 /* Basic Information */
1053 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
1054 if (!NT_SUCCESS(Status
)) return Status
;
1055 /* Standard Information */
1056 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
1057 if (!NT_SUCCESS(Status
)) return Status
;
1058 /* Internal Information */
1059 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
1060 if (!NT_SUCCESS(Status
)) return Status
;
1061 /* EA Information */
1062 Info
->EaInformation
.EaSize
= 0;
1063 /* Access Information: The IO-Manager adds this information */
1064 /* Position Information */
1065 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
1066 if (!NT_SUCCESS(Status
)) return Status
;
1067 /* Mode Information: The IO-Manager adds this information */
1068 /* Alignment Information: The IO-Manager adds this information */
1069 /* Name Information */
1070 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
1071 if (!NT_SUCCESS(Status
)) return Status
;
1073 *BufferLength
= InitialBufferLength
- (sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
));
1075 return STATUS_SUCCESS
;
1081 PFILE_OBJECT FileObject
,
1088 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
1092 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
1094 if (!vfatFCBIsDirectory(Fcb
))
1096 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1097 Fcb
->entry
.FatX
.FileSize
= Size
;
1099 Fcb
->entry
.Fat
.FileSize
= Size
;
1101 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
1102 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
1104 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
1108 VfatSetAllocationSizeInformation(
1109 PFILE_OBJECT FileObject
,
1111 PDEVICE_EXTENSION DeviceExt
,
1112 PLARGE_INTEGER AllocationSize
)
1115 ULONG Cluster
, FirstCluster
;
1118 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
1119 ULONG NewSize
= AllocationSize
->u
.LowPart
;
1121 BOOLEAN AllocSizeChanged
= FALSE
;
1123 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1124 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
1126 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1127 OldSize
= Fcb
->entry
.FatX
.FileSize
;
1129 OldSize
= Fcb
->entry
.Fat
.FileSize
;
1131 if (AllocationSize
->u
.HighPart
> 0)
1133 return STATUS_INVALID_PARAMETER
;
1136 if (OldSize
== NewSize
)
1138 return STATUS_SUCCESS
;
1141 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
1143 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1145 AllocSizeChanged
= TRUE
;
1146 if (FirstCluster
== 0)
1148 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1149 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
1150 if (!NT_SUCCESS(Status
))
1152 DPRINT1("NextCluster failed. Status = %x\n", Status
);
1156 if (FirstCluster
== 0xffffffff)
1158 return STATUS_DISK_FULL
;
1161 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1162 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1164 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1167 NCluster
= Cluster
= FirstCluster
;
1168 Status
= STATUS_SUCCESS
;
1169 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1171 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1172 WriteCluster(DeviceExt
, Cluster
, 0);
1175 return STATUS_DISK_FULL
;
1178 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1180 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
1184 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1186 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1187 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
1191 ASSERT((FirstCluster
>> 16) == 0);
1192 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
1198 if (Fcb
->LastCluster
> 0)
1200 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
1202 Cluster
= Fcb
->LastCluster
;
1203 Status
= STATUS_SUCCESS
;
1207 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
1208 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
1214 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1215 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
1219 if (!NT_SUCCESS(Status
))
1224 Fcb
->LastCluster
= Cluster
;
1225 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
1227 /* FIXME: Check status */
1228 /* Cluster points now to the last cluster within the chain */
1229 Status
= OffsetToCluster(DeviceExt
, Cluster
,
1230 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
1232 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
1236 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1237 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1239 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
1241 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1242 WriteCluster(DeviceExt
, Cluster
, 0);
1245 return STATUS_DISK_FULL
;
1248 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1250 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
1252 DPRINT("Check for the ability to set file size\n");
1253 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
1254 (PLARGE_INTEGER
)AllocationSize
))
1256 DPRINT("Couldn't set file size!\n");
1257 return STATUS_USER_MAPPED_FILE
;
1259 DPRINT("Can set file size\n");
1261 AllocSizeChanged
= TRUE
;
1262 /* FIXME: Use the cached cluster/offset better way. */
1263 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
1264 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1267 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
1268 ROUND_DOWN(NewSize
- 1, ClusterSize
),
1272 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1273 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
1278 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
1280 Fcb
->entry
.FatX
.FirstCluster
= 0;
1284 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
1286 Fcb
->entry
.Fat
.FirstCluster
= 0;
1287 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
1291 Fcb
->entry
.Fat
.FirstCluster
= 0;
1295 NCluster
= Cluster
= FirstCluster
;
1296 Status
= STATUS_SUCCESS
;
1299 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
1301 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
1302 WriteCluster(DeviceExt
, Cluster
, 0);
1308 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
1311 /* Update the on-disk directory entry */
1312 Fcb
->Flags
|= FCB_IS_DIRTY
;
1313 if (AllocSizeChanged
)
1315 VfatUpdateEntry(Fcb
);
1317 return STATUS_SUCCESS
;
1321 * FUNCTION: Retrieve the specified file information
1324 VfatQueryInformation(
1325 PVFAT_IRP_CONTEXT IrpContext
)
1327 FILE_INFORMATION_CLASS FileInformationClass
;
1328 PVFATFCB FCB
= NULL
;
1330 NTSTATUS Status
= STATUS_SUCCESS
;
1337 /* INITIALIZATION */
1338 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
1339 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1341 DPRINT("VfatQueryInformation is called for '%s'\n",
1342 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
1345 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1346 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
1348 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1350 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
1351 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
1353 return VfatQueueRequest(IrpContext
);
1357 switch (FileInformationClass
)
1359 case FileStandardInformation
:
1360 Status
= VfatGetStandardInformation(FCB
,
1365 case FilePositionInformation
:
1366 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
1368 IrpContext
->DeviceObject
,
1373 case FileBasicInformation
:
1374 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
1376 IrpContext
->DeviceObject
,
1381 case FileNameInformation
:
1382 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
1384 IrpContext
->DeviceObject
,
1389 case FileInternalInformation
:
1390 Status
= VfatGetInternalInformation(FCB
,
1395 case FileNetworkOpenInformation
:
1396 Status
= VfatGetNetworkOpenInformation(FCB
,
1397 IrpContext
->DeviceExt
,
1402 case FileAllInformation
:
1403 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
1405 IrpContext
->DeviceObject
,
1410 case FileEaInformation
:
1411 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
1413 IrpContext
->DeviceObject
,
1418 case FileAlternateNameInformation
:
1419 Status
= STATUS_NOT_IMPLEMENTED
;
1423 Status
= STATUS_INVALID_PARAMETER
;
1426 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1428 ExReleaseResourceLite(&FCB
->MainResource
);
1431 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1432 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
1433 IrpContext
->Irp
->IoStatus
.Information
=
1434 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
1436 IrpContext
->Irp
->IoStatus
.Information
= 0;
1437 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1438 VfatFreeIrpContext(IrpContext
);
1444 * FUNCTION: Retrieve the specified file information
1448 PVFAT_IRP_CONTEXT IrpContext
)
1450 FILE_INFORMATION_CLASS FileInformationClass
;
1451 PVFATFCB FCB
= NULL
;
1452 NTSTATUS Status
= STATUS_SUCCESS
;
1458 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
1460 /* INITIALIZATION */
1461 FileInformationClass
=
1462 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
1463 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
1464 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
1466 DPRINT("VfatSetInformation is called for '%s'\n",
1467 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
1469 DPRINT("FileInformationClass %d\n", FileInformationClass
);
1470 DPRINT("SystemBuffer %p\n", SystemBuffer
);
1472 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1473 the file size would be allowed. If not, we bail with the right error.
1474 We must do this before acquiring the lock. */
1475 if (FileInformationClass
== FileEndOfFileInformation
)
1477 DPRINT("Check for the ability to set file size\n");
1478 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
1479 (PLARGE_INTEGER
)SystemBuffer
))
1481 DPRINT("Couldn't set file size!\n");
1482 IrpContext
->Irp
->IoStatus
.Status
= STATUS_USER_MAPPED_FILE
;
1483 IrpContext
->Irp
->IoStatus
.Information
= 0;
1484 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1485 VfatFreeIrpContext(IrpContext
);
1486 return STATUS_USER_MAPPED_FILE
;
1488 DPRINT("Can set file size\n");
1491 if (FileInformationClass
== FileRenameInformation
)
1493 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
1494 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
1496 return VfatQueueRequest(IrpContext
);
1500 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1502 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1503 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
1505 if (FileInformationClass
== FileRenameInformation
)
1507 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1509 return VfatQueueRequest(IrpContext
);
1513 switch (FileInformationClass
)
1515 case FilePositionInformation
:
1516 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1520 case FileDispositionInformation
:
1521 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1523 IrpContext
->DeviceObject
,
1527 case FileAllocationInformation
:
1528 case FileEndOfFileInformation
:
1529 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1531 IrpContext
->DeviceExt
,
1532 (PLARGE_INTEGER
)SystemBuffer
);
1535 case FileBasicInformation
:
1536 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1538 IrpContext
->DeviceExt
,
1542 case FileRenameInformation
:
1543 Status
= VfatSetRenameInformation(IrpContext
->FileObject
,
1545 IrpContext
->DeviceExt
,
1547 IrpContext
->Stack
->Parameters
.SetFile
.FileObject
);
1551 Status
= STATUS_NOT_SUPPORTED
;
1554 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1556 ExReleaseResourceLite(&FCB
->MainResource
);
1559 if (FileInformationClass
== FileRenameInformation
)
1561 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
1564 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1565 IrpContext
->Irp
->IoStatus
.Information
= 0;
1566 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1567 VfatFreeIrpContext(IrpContext
);