2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/create.c
5 * PURPOSE: Create routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9 /* INCLUDES *****************************************************************/
14 /* FUNCTIONS *****************************************************************/
18 FatiOpenRootDcb(IN PFAT_IRP_CONTEXT IrpContext
,
19 IN PFILE_OBJECT FileObject
,
21 IN PACCESS_MASK DesiredAccess
,
22 IN USHORT ShareAccess
,
23 IN ULONG CreateDisposition
)
30 /* Reference our DCB */
33 DPRINT("Opening root directory\n");
35 /* Exclusively lock this DCB */
36 (VOID
)FatAcquireExclusiveFcb(IrpContext
, Dcb
);
40 /* Validate parameters */
41 if (CreateDisposition
!= FILE_OPEN
&&
42 CreateDisposition
!= FILE_OPEN_IF
)
44 Iosb
.Status
= STATUS_ACCESS_DENIED
;
48 // TODO: Check file access
50 /* Is it a first time open? */
51 if (Dcb
->OpenCount
== 0)
53 /* Set share access */
54 IoSetShareAccess(*DesiredAccess
,
61 /* Check share access */
62 Status
= IoCheckShareAccess(*DesiredAccess
,
69 /* Set file object pointers */
71 FatSetFileObject(FileObject
, UserDirectoryOpen
, Dcb
, Ccb
);
73 /* Increment counters */
77 if (IsFileObjectReadOnly(FileObject
)) Vcb
->ReadOnlyCount
++;
79 /* Set success statuses */
80 Iosb
.Status
= STATUS_SUCCESS
;
81 Iosb
.Information
= FILE_OPENED
;
84 /* Release the DCB lock */
85 FatReleaseFcb(IrpContext
, Dcb
);
92 FatiTryToOpen(IN PFILE_OBJECT FileObject
,
96 CHAR AnsiNameBuf
[512];
101 /* Convert the name to ANSI */
102 AnsiName
.Buffer
= AnsiNameBuf
;
104 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
105 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
106 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
107 if (!NT_SUCCESS(Status
))
112 /* Open the file with FullFAT */
113 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_READ
, &Error
);
115 /* Close the handle */
116 if (FileHandle
) FF_Close(FileHandle
);
124 FatiOverwriteFile(PFAT_IRP_CONTEXT IrpContext
,
125 PFILE_OBJECT FileObject
,
127 ULONG AllocationSize
,
128 PFILE_FULL_EA_INFORMATION EaBuffer
,
130 UCHAR FileAttributes
,
131 ULONG CreateDisposition
,
132 BOOLEAN NoEaKnowledge
)
134 IO_STATUS_BLOCK Iosb
= {{0}};
141 /* Check Ea mismatch first */
142 if (NoEaKnowledge
&& EaLength
> 0)
144 Iosb
.Status
= STATUS_ACCESS_DENIED
;
150 /* Check if it's not still mapped */
151 if (!MmCanFileBeTruncated(&Fcb
->SectionObjectPointers
,
155 Iosb
.Status
= STATUS_USER_MAPPED_FILE
;
159 /* Set file object pointers */
160 Ccb
= FatCreateCcb();
161 FatSetFileObject(FileObject
,
166 FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
168 /* Indicate that create is in progress */
169 Fcb
->Vcb
->State
|= VCB_STATE_CREATE_IN_PROGRESS
;
171 /* Purge the cache section */
172 CcPurgeCacheSection(&Fcb
->SectionObjectPointers
, NULL
, 0, FALSE
);
180 /* Acquire the paging resource */
181 (VOID
)ExAcquireResourceExclusiveLite(Fcb
->Header
.PagingIoResource
, TRUE
);
183 /* Initialize FCB header */
184 Fcb
->Header
.FileSize
.QuadPart
= 0;
185 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
187 /* Let CC know about changed file size */
188 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
190 // TODO: Actually truncate the file
191 DPRINT1("TODO: Actually truncate file '%wZ' with a fullfat handle %x\n", &Fcb
->FullFileName
, Fcb
->FatHandle
);
193 /* Release the paging resource */
194 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
196 /* Specify truncate on close */
197 Fcb
->State
|= FCB_STATE_TRUNCATE_ON_CLOSE
;
199 // TODO: Delete previous EA if needed
201 /* Send notification about changes */
202 NotifyFilter
= FILE_NOTIFY_CHANGE_LAST_WRITE
|
203 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
204 FILE_NOTIFY_CHANGE_SIZE
;
206 FsRtlNotifyFullReportChange(Fcb
->Vcb
->NotifySync
,
207 &Fcb
->Vcb
->NotifyList
,
208 (PSTRING
)&Fcb
->FullFileName
,
209 Fcb
->FullFileName
.Length
- Fcb
->FileNameLength
,
213 FILE_ACTION_MODIFIED
,
216 /* Set success status */
217 Iosb
.Status
= STATUS_SUCCESS
;
219 /* Set correct information code */
220 Iosb
.Information
= (CreateDisposition
== FILE_SUPERSEDE
) ? FILE_SUPERSEDED
: FILE_OVERWRITTEN
;
223 /* Remove the create in progress flag */
224 ClearFlag(Fcb
->Vcb
->State
, VCB_STATE_CREATE_IN_PROGRESS
);
231 FatiOpenExistingDir(IN PFAT_IRP_CONTEXT IrpContext
,
232 IN PFILE_OBJECT FileObject
,
235 IN PACCESS_MASK DesiredAccess
,
236 IN USHORT ShareAccess
,
237 IN ULONG AllocationSize
,
238 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
240 IN UCHAR FileAttributes
,
241 IN ULONG CreateDisposition
,
242 IN BOOLEAN DeleteOnClose
)
244 IO_STATUS_BLOCK Iosb
= {{0}};
246 CHAR AnsiNameBuf
[512];
251 /* Only open is permitted */
252 if (CreateDisposition
!= FILE_OPEN
&&
253 CreateDisposition
!= FILE_OPEN_IF
)
255 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
259 // TODO: Check dir access
261 /* Convert the name to ANSI */
262 AnsiName
.Buffer
= AnsiNameBuf
;
264 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
265 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
266 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
267 if (!NT_SUCCESS(Status
))
272 /* Open the dir with FullFAT */
273 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_DIR
, NULL
);
277 Iosb
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // FIXME: A shortcut for now
281 /* Create a new DCB for this directory */
282 Fcb
= FatCreateDcb(IrpContext
, Vcb
, ParentDcb
, FileHandle
);
284 /* Set share access */
285 IoSetShareAccess(*DesiredAccess
, ShareAccess
, FileObject
, &Fcb
->ShareAccess
);
287 /* Set context and section object pointers */
288 FatSetFileObject(FileObject
,
293 /* Increase counters */
296 Vcb
->OpenFileCount
++;
297 if (IsFileObjectReadOnly(FileObject
)) Vcb
->ReadOnlyCount
++;
299 Iosb
.Status
= STATUS_SUCCESS
;
300 Iosb
.Information
= FILE_OPENED
;
302 DPRINT1("Successfully opened dir %s\n", AnsiNameBuf
);
309 FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext
,
310 IN PFILE_OBJECT FileObject
,
313 IN PACCESS_MASK DesiredAccess
,
314 IN USHORT ShareAccess
,
315 IN ULONG AllocationSize
,
316 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
318 IN UCHAR FileAttributes
,
319 IN ULONG CreateDisposition
,
320 IN BOOLEAN IsPagingFile
,
321 IN BOOLEAN DeleteOnClose
,
322 IN BOOLEAN IsDosName
)
324 IO_STATUS_BLOCK Iosb
= {{0}};
326 CHAR AnsiNameBuf
[512];
332 /* Check for create file option and fail */
333 if (CreateDisposition
== FILE_CREATE
)
335 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
339 // TODO: Check more params
341 /* Convert the name to ANSI */
342 AnsiName
.Buffer
= AnsiNameBuf
;
344 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
345 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
346 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
347 if (!NT_SUCCESS(Status
))
352 /* Open the file with FullFAT */
353 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_READ
, &FfError
);
357 DPRINT1("Failed to open file '%s', error %ld\n", AnsiName
.Buffer
, FfError
);
358 Iosb
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // FIXME: A shortcut for now
361 DPRINT1("Succeeded opening file '%s'\n", AnsiName
.Buffer
);
363 /* Create a new FCB for this file */
364 Fcb
= FatCreateFcb(IrpContext
, Vcb
, ParentDcb
, FileHandle
);
366 // TODO: Check if overwrite is needed
368 // TODO: This is usual file open branch, without overwriting!
369 /* Set context and section object pointers */
370 FatSetFileObject(FileObject
,
374 FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
376 Iosb
.Status
= STATUS_SUCCESS
;
377 Iosb
.Information
= FILE_OPENED
;
380 /* Increase counters */
383 if (FlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
)) Fcb
->NonCachedUncleanCount
++;
384 if (IsFileObjectReadOnly(FileObject
)) Vcb
->ReadOnlyCount
++;
391 FatiOpenVolume(IN PFAT_IRP_CONTEXT IrpContext
,
392 IN PFILE_OBJECT FileObject
,
394 IN PACCESS_MASK DesiredAccess
,
395 IN USHORT ShareAccess
,
396 IN ULONG CreateDisposition
)
399 IO_STATUS_BLOCK Iosb
= {{0}};
400 BOOLEAN VolumeFlushed
= FALSE
;
402 /* Check parameters */
403 if (CreateDisposition
!= FILE_OPEN
&&
404 CreateDisposition
!= FILE_OPEN_IF
)
407 Iosb
.Status
= STATUS_ACCESS_DENIED
;
410 /* Check if it's exclusive open */
411 if (!FlagOn(ShareAccess
, FILE_SHARE_WRITE
) &&
412 !FlagOn(ShareAccess
, FILE_SHARE_DELETE
))
414 // TODO: Check if exclusive read access requested
415 // and opened handles count is not 0
416 //if (!FlagOn(ShareAccess, FILE_SHARE_READ)
418 DPRINT1("Exclusive volume open\n");
420 // TODO: Flush the volume
421 VolumeFlushed
= TRUE
;
423 else if (FlagOn(*DesiredAccess
, FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
))
425 DPRINT1("Shared open\n");
427 // TODO: Flush the volume
428 VolumeFlushed
= TRUE
;
432 !FlagOn(Vcb
->State
, VCB_STATE_MOUNTED_DIRTY
) &&
433 FlagOn(Vcb
->State
, VCB_STATE_FLAG_DIRTY
) &&
434 CcIsThereDirtyData(Vcb
->Vpb
))
439 /* Set share access */
440 if (Vcb
->DirectOpenCount
> 0)
442 /* This volume has already been opened */
443 Iosb
.Status
= IoCheckShareAccess(*DesiredAccess
,
449 if (!NT_SUCCESS(Iosb
.Status
))
456 /* This is the first time open */
457 IoSetShareAccess(*DesiredAccess
,
463 /* Set file object pointers */
464 Ccb
= FatCreateCcb();
465 FatSetFileObject(FileObject
, UserVolumeOpen
, Vcb
, Ccb
);
466 FileObject
->SectionObjectPointer
= &Vcb
->SectionObjectPointers
;
468 /* Increase direct open count */
469 Vcb
->DirectOpenCount
++;
470 Vcb
->OpenFileCount
++;
471 if (IsFileObjectReadOnly(FileObject
)) Vcb
->ReadOnlyCount
++;
473 /* Set no buffering flag */
474 FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
476 // TODO: User's access check
478 Iosb
.Status
= STATUS_SUCCESS
;
479 Iosb
.Information
= FILE_OPENED
;
486 FatiCreate(IN PFAT_IRP_CONTEXT IrpContext
,
489 /* Boolean options */
490 BOOLEAN CreateDirectory
;
491 BOOLEAN SequentialOnly
;
492 BOOLEAN NoIntermediateBuffering
;
493 BOOLEAN OpenDirectory
;
494 BOOLEAN IsPagingFile
;
495 BOOLEAN OpenTargetDirectory
;
496 BOOLEAN DirectoryFile
;
497 BOOLEAN NonDirectoryFile
;
498 BOOLEAN NoEaKnowledge
;
499 BOOLEAN DeleteOnClose
;
500 BOOLEAN TemporaryFile
;
501 ULONG CreateDisposition
;
504 PVCB Vcb
, DecodedVcb
, RelatedVcb
;
505 PFCB Fcb
, NextFcb
, RelatedDcb
;
506 PCCB Ccb
, RelatedCcb
;
510 PFILE_OBJECT FileObject
;
511 PFILE_OBJECT RelatedFO
;
512 UNICODE_STRING FileName
;
513 ULONG AllocationSize
;
514 PFILE_FULL_EA_INFORMATION EaBuffer
;
515 PACCESS_MASK DesiredAccess
;
517 UCHAR FileAttributes
;
523 IO_STATUS_BLOCK Iosb
;
524 PIO_STACK_LOCATION IrpSp
;
525 BOOLEAN EndBackslash
= FALSE
, OpenedAsDos
, FirstRun
= TRUE
;
526 UNICODE_STRING RemainingPart
, FirstName
, NextName
, FileNameUpcased
;
527 OEM_STRING AnsiFirstName
;
529 TYPE_OF_OPEN TypeOfOpen
;
530 BOOLEAN OplockPostIrp
= FALSE
;
532 Iosb
.Status
= STATUS_SUCCESS
;
534 /* Get current IRP stack location */
535 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
537 DPRINT("FatCommonCreate\n", 0 );
538 DPRINT("Irp = %08lx\n", Irp
);
539 DPRINT("\t->Flags = %08lx\n", Irp
->Flags
);
540 DPRINT("\t->FileObject = %08lx\n", IrpSp
->FileObject
);
541 DPRINT("\t->RelatedFileObject = %08lx\n", IrpSp
->FileObject
->RelatedFileObject
);
542 DPRINT("\t->FileName = %wZ\n", &IrpSp
->FileObject
->FileName
);
543 DPRINT("\t->AllocationSize.LowPart = %08lx\n", Irp
->Overlay
.AllocationSize
.LowPart
);
544 DPRINT("\t->AllocationSize.HighPart = %08lx\n", Irp
->Overlay
.AllocationSize
.HighPart
);
545 DPRINT("\t->SystemBuffer = %08lx\n", Irp
->AssociatedIrp
.SystemBuffer
);
546 DPRINT("\t->DesiredAccess = %08lx\n", IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
547 DPRINT("\t->Options = %08lx\n", IrpSp
->Parameters
.Create
.Options
);
548 DPRINT("\t->FileAttributes = %04x\n", IrpSp
->Parameters
.Create
.FileAttributes
);
549 DPRINT("\t->ShareAccess = %04x\n", IrpSp
->Parameters
.Create
.ShareAccess
);
550 DPRINT("\t->EaLength = %08lx\n", IrpSp
->Parameters
.Create
.EaLength
);
552 /* Apply a special hack for Win32, idea taken from FASTFAT reference driver from WDK */
553 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
554 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
555 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
557 /* Remove a leading slash */
558 IrpSp
->FileObject
->FileName
.Length
-= sizeof(WCHAR
);
559 RtlMoveMemory(&IrpSp
->FileObject
->FileName
.Buffer
[0],
560 &IrpSp
->FileObject
->FileName
.Buffer
[1],
561 IrpSp
->FileObject
->FileName
.Length
);
563 /* Check again: if there are still two leading slashes,
564 exit with an error */
565 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
566 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
567 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
569 FatCompleteRequest( IrpContext
, Irp
, STATUS_OBJECT_NAME_INVALID
);
571 DPRINT1("FatiCreate: STATUS_OBJECT_NAME_INVALID\n");
572 return STATUS_OBJECT_NAME_INVALID
;
576 /* Make sure we have SecurityContext */
577 ASSERT(IrpSp
->Parameters
.Create
.SecurityContext
!= NULL
);
579 /* Get necessary data out of IRP */
580 FileObject
= IrpSp
->FileObject
;
581 FileName
= FileObject
->FileName
;
582 RelatedFO
= FileObject
->RelatedFileObject
;
583 AllocationSize
= Irp
->Overlay
.AllocationSize
.LowPart
;
584 EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
585 DesiredAccess
= &IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
586 Options
= IrpSp
->Parameters
.Create
.Options
;
587 FileAttributes
= (UCHAR
)(IrpSp
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
);
588 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
589 EaLength
= IrpSp
->Parameters
.Create
.EaLength
;
591 /* Set VPB to related object's VPB if it exists */
593 FileObject
->Vpb
= RelatedFO
->Vpb
;
595 /* Reject open by id */
596 if (Options
& FILE_OPEN_BY_FILE_ID
)
598 FatCompleteRequest(IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
599 return STATUS_INVALID_PARAMETER
;
602 /* Prepare file attributes mask */
603 FileAttributes
&= (FILE_ATTRIBUTE_READONLY
|
604 FILE_ATTRIBUTE_HIDDEN
|
605 FILE_ATTRIBUTE_SYSTEM
|
606 FILE_ATTRIBUTE_ARCHIVE
);
608 /* Get the volume control object */
609 Vcb
= &((PVOLUME_DEVICE_OBJECT
)IrpSp
->DeviceObject
)->Vcb
;
612 DirectoryFile
= BooleanFlagOn(Options
, FILE_DIRECTORY_FILE
);
613 NonDirectoryFile
= BooleanFlagOn(Options
, FILE_NON_DIRECTORY_FILE
);
614 SequentialOnly
= BooleanFlagOn(Options
, FILE_SEQUENTIAL_ONLY
);
615 NoIntermediateBuffering
= BooleanFlagOn(Options
, FILE_NO_INTERMEDIATE_BUFFERING
);
616 NoEaKnowledge
= BooleanFlagOn(Options
, FILE_NO_EA_KNOWLEDGE
);
617 DeleteOnClose
= BooleanFlagOn(Options
, FILE_DELETE_ON_CLOSE
);
618 TemporaryFile
= BooleanFlagOn(IrpSp
->Parameters
.Create
.FileAttributes
,
619 FILE_ATTRIBUTE_TEMPORARY
);
620 IsPagingFile
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_PAGING_FILE
);
621 OpenTargetDirectory
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
623 /* Calculate create disposition */
624 CreateDisposition
= (Options
>> 24) & 0x000000ff;
626 /* Get Create/Open directory flags based on it */
627 CreateDirectory
= (BOOLEAN
)(DirectoryFile
&&
628 ((CreateDisposition
== FILE_CREATE
) ||
629 (CreateDisposition
== FILE_OPEN_IF
)));
631 OpenDirectory
= (BOOLEAN
)(DirectoryFile
&&
632 ((CreateDisposition
== FILE_OPEN
) ||
633 (CreateDisposition
== FILE_OPEN_IF
)));
635 /* Validate parameters: directory/nondirectory mismatch and
636 AllocationSize being more than 4GB */
637 if ((DirectoryFile
&& NonDirectoryFile
) ||
638 Irp
->Overlay
.AllocationSize
.HighPart
!= 0)
640 FatCompleteRequest(IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
642 DPRINT1("FatiCreate: STATUS_INVALID_PARAMETER\n", 0);
643 return STATUS_INVALID_PARAMETER
;
646 /* Acquire the VCB lock exclusively */
647 if (!FatAcquireExclusiveVcb(IrpContext
, Vcb
))
649 // TODO: Postpone the IRP for later processing
651 return STATUS_NOT_IMPLEMENTED
;
654 // TODO: Verify the VCB
656 /* If VCB is locked, then no file openings are possible */
657 if (Vcb
->State
& VCB_STATE_FLAG_LOCKED
)
659 DPRINT1("This volume is locked\n");
660 Status
= STATUS_ACCESS_DENIED
;
662 /* Set volume dismount status */
663 if (Vcb
->Condition
!= VcbGood
)
664 Status
= STATUS_VOLUME_DISMOUNTED
;
666 /* Cleanup and return */
667 FatReleaseVcb(IrpContext
, Vcb
);
668 FatCompleteRequest(IrpContext
, Irp
, Status
);
672 /* Check if the volume is write protected and disallow DELETE_ON_CLOSE */
673 if (DeleteOnClose
& FlagOn(Vcb
->State
, VCB_STATE_FLAG_WRITE_PROTECTED
))
676 return STATUS_NOT_IMPLEMENTED
;
679 // TODO: Make sure EAs aren't supported on FAT32
681 /* Check if it's a volume open request */
682 if (FileName
.Length
== 0)
684 /* Test related FO to be sure */
686 FatDecodeFileObject(RelatedFO
, &DecodedVcb
, &Fcb
, &Ccb
) == UserVolumeOpen
)
688 /* Check parameters */
689 if (DirectoryFile
|| OpenTargetDirectory
)
691 Status
= DirectoryFile
? STATUS_NOT_A_DIRECTORY
: STATUS_INVALID_PARAMETER
;
694 FatReleaseVcb(IrpContext
, Vcb
);
696 /* Complete the request and return */
697 FatCompleteRequest(IrpContext
, Irp
, Status
);
701 /* It is indeed a volume open request */
702 Iosb
= FatiOpenVolume(IrpContext
,
709 /* Set resulting information */
710 Irp
->IoStatus
.Information
= Iosb
.Information
;
713 FatReleaseVcb(IrpContext
, Vcb
);
715 /* Complete the request and return */
716 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
721 /* Check if this is a relative open */
724 /* Decode the file object */
725 TypeOfOpen
= FatDecodeFileObject(RelatedFO
,
730 /* Check open type */
731 if (TypeOfOpen
!= UserFileOpen
&&
732 TypeOfOpen
!= UserDirectoryOpen
)
734 DPRINT1("Invalid file object!\n");
736 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
738 /* Cleanup and return */
739 FatReleaseVcb(IrpContext
, Vcb
);
740 FatCompleteRequest(IrpContext
, Irp
, Status
);
744 /* File path must be relative */
745 if (FileName
.Length
!= 0 &&
746 FileName
.Buffer
[0] == L
'\\')
748 Status
= STATUS_OBJECT_NAME_INVALID
;
750 /* The name is absolute, fail */
751 FatReleaseVcb(IrpContext
, Vcb
);
752 FatCompleteRequest(IrpContext
, Irp
, Status
);
756 /* Make sure volume is the same */
757 ASSERT(RelatedVcb
== Vcb
);
760 FileObject
->Vpb
= RelatedFO
->Vpb
;
763 ParentDcb
= RelatedDcb
;
765 DPRINT("Opening file '%wZ' relatively to '%wZ'\n", &FileName
, &ParentDcb
->FullFileName
);
770 if ((FileName
.Length
== sizeof(WCHAR
)) &&
771 (FileName
.Buffer
[0] == L
'\\'))
773 /* Check if it's ok to open it */
774 if (NonDirectoryFile
)
776 DPRINT1("Trying to open root dir as a file\n");
777 Status
= STATUS_FILE_IS_A_DIRECTORY
;
779 /* Cleanup and return */
780 FatReleaseVcb(IrpContext
, Vcb
);
781 FatCompleteRequest(IrpContext
, Irp
, Status
);
785 /* Check for target directory on a root dir */
786 if (OpenTargetDirectory
)
788 Status
= STATUS_INVALID_PARAMETER
;
790 /* Cleanup and return */
791 FatReleaseVcb(IrpContext
, Vcb
);
792 FatCompleteRequest(IrpContext
, Irp
, Status
);
796 /* Check delete on close on a root dir */
799 Status
= STATUS_CANNOT_DELETE
;
801 /* Cleanup and return */
802 FatReleaseVcb(IrpContext
, Vcb
);
803 FatCompleteRequest(IrpContext
, Irp
, Status
);
807 /* Call root directory open routine */
808 Iosb
= FatiOpenRootDcb(IrpContext
,
815 Irp
->IoStatus
.Information
= Iosb
.Information
;
817 /* Cleanup and return */
818 FatReleaseVcb(IrpContext
, Vcb
);
819 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
825 ParentDcb
= Vcb
->RootDcb
;
826 DPRINT("ParentDcb %p\n", ParentDcb
);
830 /* Check for backslash at the end */
831 if (FileName
.Length
&&
832 FileName
.Buffer
[FileName
.Length
/ sizeof(WCHAR
) - 1] == L
'\\')
835 FileName
.Length
-= sizeof(WCHAR
);
837 /* Remember we cut it */
841 /* Ensure the name is set */
842 if (!ParentDcb
->FullFileName
.Buffer
)
844 /* Set it if it's missing */
845 FatSetFullFileNameInFcb(IrpContext
, ParentDcb
);
848 /* Check max path length */
849 if (ParentDcb
->FullFileName
.Length
+ FileName
.Length
+ sizeof(WCHAR
) <= FileName
.Length
)
851 DPRINT1("Max length is way off\n");
852 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
856 /* Loop through FCBs to find a good one */
861 /* Dissect the name */
862 RemainingPart
= FileName
;
863 while (RemainingPart
.Length
)
865 FsRtlDissectName(RemainingPart
, &FirstName
, &NextName
);
867 /* Check for validity */
868 if ((NextName
.Length
&& NextName
.Buffer
[0] == L
'\\') ||
869 (NextName
.Length
> 255 * sizeof(WCHAR
)))
871 /* The name is invalid */
872 DPRINT1("Invalid name found\n");
873 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
877 /* Convert the name to ANSI */
878 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
879 AnsiFirstName
.Length
= 0;
880 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
881 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
883 if (!NT_SUCCESS(Status
))
885 DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status
);
888 AnsiFirstName
.Length
= 0;
892 /* Find the coresponding FCB */
893 NextFcb
= FatFindFcb(IrpContext
,
894 &Fcb
->Dcb
.SplayLinksAnsi
,
895 (PSTRING
)&AnsiFirstName
,
899 /* If nothing found - try with unicode */
900 if (!NextFcb
&& Fcb
->Dcb
.SplayLinksUnicode
)
902 FileNameUpcased
.Buffer
= FsRtlAllocatePool(PagedPool
, FirstName
.Length
);
903 FileNameUpcased
.Length
= 0;
904 FileNameUpcased
.MaximumLength
= FirstName
.Length
;
906 /* Downcase and then upcase to normalize it */
907 Status
= RtlDowncaseUnicodeString(&FileNameUpcased
, &FirstName
, FALSE
);
908 Status
= RtlUpcaseUnicodeString(&FileNameUpcased
, &FileNameUpcased
, FALSE
);
910 /* Try to find FCB again using unicode name */
911 NextFcb
= FatFindFcb(IrpContext
,
912 &Fcb
->Dcb
.SplayLinksUnicode
,
913 (PSTRING
)&FileNameUpcased
,
917 /* Move to the next FCB */
921 RemainingPart
= NextName
;
924 /* Break out of this loop if nothing can be found */
926 NextName
.Length
== 0 ||
927 FatNodeType(NextFcb
) == FAT_NTC_FCB
)
933 /* Ensure remaining name doesn't start from a backslash */
934 if (RemainingPart
.Length
&&
935 RemainingPart
.Buffer
[0] == L
'\\')
938 RemainingPart
.Buffer
++;
939 RemainingPart
.Length
-= sizeof(WCHAR
);
942 if (Fcb
->Condition
== FcbGood
)
944 /* Good FCB, break out of the loop */
953 /* Treat page file in a special way */
957 // FIXME: System file too
960 /* Make sure there is no pending delete on a higher-level FCB */
961 if (Fcb
->State
& FCB_STATE_DELETE_ON_CLOSE
)
963 Iosb
.Status
= STATUS_DELETE_PENDING
;
965 /* Cleanup and return */
966 FatReleaseVcb(IrpContext
, Vcb
);
968 /* Complete the request */
969 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
974 /* We have a valid FCB now */
975 if (!RemainingPart
.Length
)
977 /* Check for target dir open */
978 if (OpenTargetDirectory
)
980 DPRINT1("Opening target dir is missing\n");
984 /* Check this FCB's type */
985 if (FatNodeType(Fcb
) == FAT_NTC_ROOT_DCB
||
986 FatNodeType(Fcb
) == FAT_NTC_DCB
)
988 /* Open a directory */
989 if (NonDirectoryFile
)
992 Iosb
.Status
= STATUS_FILE_IS_A_DIRECTORY
;
997 /* Open existing DCB */
998 Iosb
= FatiOpenExistingDcb(IrpContext
,
1008 /* Save information */
1009 Irp
->IoStatus
.Information
= Iosb
.Information
;
1012 FatReleaseVcb(IrpContext
, Vcb
);
1014 /* Complete the request */
1015 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1019 else if (FatNodeType(Fcb
) == FAT_NTC_FCB
)
1025 Iosb
.Status
= STATUS_NOT_A_DIRECTORY
;
1030 /* Check for trailing backslash */
1034 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
1039 Iosb
= FatiOpenExistingFcb(IrpContext
,
1055 /* Check if it's pending */
1056 if (Iosb
.Status
!= STATUS_PENDING
)
1058 /* In case of success set cache supported flag */
1059 if (NT_SUCCESS(Iosb
.Status
) && !NoIntermediateBuffering
)
1061 SetFlag(FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1064 /* Save information */
1065 Irp
->IoStatus
.Information
= Iosb
.Information
;
1068 FatReleaseVcb(IrpContext
, Vcb
);
1070 /* Complete the request */
1071 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1077 /* Queue this IRP */
1084 /* Unexpected FCB type */
1085 KeBugCheckEx(FAT_FILE_SYSTEM
, __LINE__
, (ULONG_PTR
)Fcb
, 0, 0);
1089 /* During parsing we encountered a part which has no attached FCB/DCB.
1090 Check that the parent is really DCB and not FCB */
1091 if (FatNodeType(Fcb
) != FAT_NTC_ROOT_DCB
&&
1092 FatNodeType(Fcb
) != FAT_NTC_DCB
)
1094 DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb
));
1098 /* Create additional DCBs for all path items */
1104 RemainingPart
= NextName
;
1105 if (AnsiFirstName
.Length
)
1106 Status
= STATUS_SUCCESS
;
1108 Status
= STATUS_UNMAPPABLE_CHARACTER
;
1112 FsRtlDissectName(RemainingPart
, &FirstName
, &RemainingPart
);
1114 /* Check for validity */
1115 if ((RemainingPart
.Length
&& RemainingPart
.Buffer
[0] == L
'\\') ||
1116 (NextName
.Length
> 255 * sizeof(WCHAR
)))
1118 /* The name is invalid */
1119 DPRINT1("Invalid name found\n");
1120 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
1124 /* Convert the name to ANSI */
1125 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
1126 AnsiFirstName
.Length
= 0;
1127 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
1128 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
1131 if (!NT_SUCCESS(Status
))
1136 DPRINT("FirstName %wZ, RemainingPart %wZ\n", &FirstName
, &RemainingPart
);
1138 /* Break if came to the end */
1139 if (!RemainingPart
.Length
) break;
1141 /* Create a DCB for this entry */
1142 ParentDcb
= FatCreateDcb(IrpContext
,
1148 FatSetFullNameInFcb(ParentDcb
, &FirstName
);
1151 /* Try to open it and get a result, saying if this is a dir or a file */
1152 FfError
= FatiTryToOpen(FileObject
, Vcb
);
1154 /* Check if we need to open target directory */
1155 if (OpenTargetDirectory
)
1157 // TODO: Open target directory
1161 /* Check, if path is a directory or a file */
1162 if (FfError
== FF_ERR_FILE_OBJECT_IS_A_DIR
||
1163 FfError
== FF_ERR_NONE
)
1165 if (FfError
== FF_ERR_FILE_OBJECT_IS_A_DIR
)
1167 if (NonDirectoryFile
)
1169 DPRINT1("Can't open dir as a file\n");
1172 FatReleaseVcb(IrpContext
, Vcb
);
1174 /* Complete the request */
1175 Iosb
.Status
= STATUS_FILE_IS_A_DIRECTORY
;
1176 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1180 /* Open this directory */
1181 Iosb
= FatiOpenExistingDir(IrpContext
,
1194 Irp
->IoStatus
.Information
= Iosb
.Information
;
1197 FatReleaseVcb(IrpContext
, Vcb
);
1199 /* Complete the request */
1200 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1206 /* This is opening an existing file */
1209 /* But caller wanted a dir */
1210 Status
= STATUS_NOT_A_DIRECTORY
;
1213 FatReleaseVcb(IrpContext
, Vcb
);
1215 /* Complete the request */
1216 FatCompleteRequest(IrpContext
, Irp
, Status
);
1221 /* If end backslash here, then it's definately not permitted,
1222 since we're opening files here */
1226 FatReleaseVcb(IrpContext
, Vcb
);
1228 /* Complete the request */
1229 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
1230 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1234 /* Try to open the file */
1235 Iosb
= FatiOpenExistingFile(IrpContext
,
1250 /* In case of success set cache supported flag */
1251 if (NT_SUCCESS(Iosb
.Status
) && !NoIntermediateBuffering
)
1253 SetFlag(FileObject
->Flags
, FO_CACHE_SUPPORTED
);
1256 Irp
->IoStatus
.Information
= Iosb
.Information
;
1259 FatReleaseVcb(IrpContext
, Vcb
);
1261 /* Complete the request */
1262 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1268 /* We come here only in the case when a new file is created */
1274 FatCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1276 PFAT_IRP_CONTEXT IrpContext
;
1279 /* If it's called with our Disk FS device object - it's always open */
1280 // TODO: Add check for CDROM FS device object
1281 if (DeviceObject
== FatGlobalData
.DiskDeviceObject
)
1283 /* Complete the request and return success */
1284 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1285 Irp
->IoStatus
.Information
= FILE_OPENED
;
1287 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1289 return STATUS_SUCCESS
;
1292 /* Enter FsRtl critical region */
1293 FsRtlEnterFileSystem();
1295 /* Build an irp context */
1296 IrpContext
= FatBuildIrpContext(Irp
, TRUE
);
1298 /* Call internal function */
1299 Status
= FatiCreate(IrpContext
, Irp
);
1301 /* Leave FsRtl critical region */
1302 FsRtlExitFileSystem();