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 /* Set success statuses */
78 Iosb
.Status
= STATUS_SUCCESS
;
79 Iosb
.Information
= FILE_OPENED
;
82 /* Release the DCB lock */
83 FatReleaseFcb(IrpContext
, Dcb
);
90 FatiTryToOpen(IN PFILE_OBJECT FileObject
,
94 CHAR AnsiNameBuf
[512];
99 /* Convert the name to ANSI */
100 AnsiName
.Buffer
= AnsiNameBuf
;
102 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
103 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
104 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
105 if (!NT_SUCCESS(Status
))
110 /* Open the file with FullFAT */
111 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_READ
, &Error
);
113 /* Close the handle */
114 if (FileHandle
) FF_Close(FileHandle
);
122 FatiOverwriteFile(PFAT_IRP_CONTEXT IrpContext
,
123 PFILE_OBJECT FileObject
,
125 ULONG AllocationSize
,
126 PFILE_FULL_EA_INFORMATION EaBuffer
,
128 UCHAR FileAttributes
,
129 ULONG CreateDisposition
,
130 BOOLEAN NoEaKnowledge
)
132 IO_STATUS_BLOCK Iosb
= {{0}};
139 /* Check Ea mismatch first */
140 if (NoEaKnowledge
&& EaLength
> 0)
142 Iosb
.Status
= STATUS_ACCESS_DENIED
;
148 /* Check if it's not still mapped */
149 if (!MmCanFileBeTruncated(&Fcb
->SectionObjectPointers
,
153 Iosb
.Status
= STATUS_USER_MAPPED_FILE
;
157 /* Set file object pointers */
158 Ccb
= FatCreateCcb();
159 FatSetFileObject(FileObject
,
164 FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
166 /* Indicate that create is in progress */
167 Fcb
->Vcb
->State
|= VCB_STATE_CREATE_IN_PROGRESS
;
169 /* Purge the cache section */
170 CcPurgeCacheSection(&Fcb
->SectionObjectPointers
, NULL
, 0, FALSE
);
178 /* Acquire the paging resource */
179 (VOID
)ExAcquireResourceExclusiveLite(Fcb
->Header
.PagingIoResource
, TRUE
);
181 /* Initialize FCB header */
182 Fcb
->Header
.FileSize
.QuadPart
= 0;
183 Fcb
->Header
.ValidDataLength
.QuadPart
= 0;
185 /* Let CC know about changed file size */
186 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
188 // TODO: Actually truncate the file
189 DPRINT1("TODO: Actually truncate the file with a fullfat handle %x\n", Fcb
->FatHandle
);
191 /* Release the paging resource */
192 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
194 /* Specify truncate on close */
195 Fcb
->State
|= FCB_STATE_TRUNCATE_ON_CLOSE
;
197 // TODO: Delete previous EA if needed
199 /* Send notification about changes */
200 NotifyFilter
= FILE_NOTIFY_CHANGE_LAST_WRITE
|
201 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
202 FILE_NOTIFY_CHANGE_SIZE
;
204 FsRtlNotifyFullReportChange(Fcb
->Vcb
->NotifySync
,
205 &Fcb
->Vcb
->NotifyList
,
206 (PSTRING
)&Fcb
->FullFileName
,
207 Fcb
->FullFileName
.Length
- Fcb
->FileNameLength
,
211 FILE_ACTION_MODIFIED
,
214 /* Set success status */
215 Iosb
.Status
= STATUS_SUCCESS
;
217 /* Set correct information code */
218 Iosb
.Information
= (CreateDisposition
== FILE_SUPERSEDE
) ? FILE_SUPERSEDED
: FILE_OVERWRITTEN
;
221 /* Remove the create in progress flag */
222 ClearFlag(Fcb
->Vcb
->State
, VCB_STATE_CREATE_IN_PROGRESS
);
229 FatiOpenExistingDir(IN PFAT_IRP_CONTEXT IrpContext
,
230 IN PFILE_OBJECT FileObject
,
233 IN PACCESS_MASK DesiredAccess
,
234 IN USHORT ShareAccess
,
235 IN ULONG AllocationSize
,
236 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
238 IN UCHAR FileAttributes
,
239 IN ULONG CreateDisposition
,
240 IN BOOLEAN DeleteOnClose
)
242 IO_STATUS_BLOCK Iosb
= {{0}};
244 CHAR AnsiNameBuf
[512];
249 /* Only open is permitted */
250 if (CreateDisposition
!= FILE_OPEN
&&
251 CreateDisposition
!= FILE_OPEN_IF
)
253 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
257 // TODO: Check dir access
259 /* Convert the name to ANSI */
260 AnsiName
.Buffer
= AnsiNameBuf
;
262 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
263 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
264 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
265 if (!NT_SUCCESS(Status
))
270 /* Open the dir with FullFAT */
271 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_DIR
, NULL
);
275 Iosb
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // FIXME: A shortcut for now
279 /* Create a new DCB for this directory */
280 Fcb
= FatCreateDcb(IrpContext
, Vcb
, ParentDcb
, FileHandle
);
282 /* Set share access */
283 IoSetShareAccess(*DesiredAccess
, ShareAccess
, FileObject
, &Fcb
->ShareAccess
);
285 /* Set context and section object pointers */
286 FatSetFileObject(FileObject
,
291 Iosb
.Status
= STATUS_SUCCESS
;
292 Iosb
.Information
= FILE_OPENED
;
294 DPRINT1("Successfully opened dir %s\n", AnsiNameBuf
);
301 FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext
,
302 IN PFILE_OBJECT FileObject
,
305 IN PACCESS_MASK DesiredAccess
,
306 IN USHORT ShareAccess
,
307 IN ULONG AllocationSize
,
308 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
310 IN UCHAR FileAttributes
,
311 IN ULONG CreateDisposition
,
312 IN BOOLEAN IsPagingFile
,
313 IN BOOLEAN DeleteOnClose
,
314 IN BOOLEAN IsDosName
)
316 IO_STATUS_BLOCK Iosb
= {{0}};
318 CHAR AnsiNameBuf
[512];
323 /* Check for create file option and fail */
324 if (CreateDisposition
== FILE_CREATE
)
326 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
330 // TODO: Check more params
332 /* Convert the name to ANSI */
333 AnsiName
.Buffer
= AnsiNameBuf
;
335 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
336 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
337 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
338 if (!NT_SUCCESS(Status
))
343 /* Open the file with FullFAT */
344 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_READ
, NULL
);
348 Iosb
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // FIXME: A shortcut for now
352 /* Create a new FCB for this file */
353 Fcb
= FatCreateFcb(IrpContext
, Vcb
, ParentDcb
, FileHandle
);
355 // TODO: Check if overwrite is needed
357 // This is usual file open branch, without overwriting!
358 /* Set context and section object pointers */
359 FatSetFileObject(FileObject
,
363 FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
365 Iosb
.Status
= STATUS_SUCCESS
;
366 Iosb
.Information
= FILE_OPENED
;
373 FatiOpenVolume(IN PFAT_IRP_CONTEXT IrpContext
,
374 IN PFILE_OBJECT FileObject
,
376 IN PACCESS_MASK DesiredAccess
,
377 IN USHORT ShareAccess
,
378 IN ULONG CreateDisposition
)
381 IO_STATUS_BLOCK Iosb
= {{0}};
382 BOOLEAN VolumeFlushed
= FALSE
;
384 /* Check parameters */
385 if (CreateDisposition
!= FILE_OPEN
&&
386 CreateDisposition
!= FILE_OPEN_IF
)
389 Iosb
.Status
= STATUS_ACCESS_DENIED
;
392 /* Check if it's exclusive open */
393 if (!FlagOn(ShareAccess
, FILE_SHARE_WRITE
) &&
394 !FlagOn(ShareAccess
, FILE_SHARE_DELETE
))
396 // TODO: Check if exclusive read access requested
397 // and opened handles count is not 0
398 //if (!FlagOn(ShareAccess, FILE_SHARE_READ)
400 DPRINT1("Exclusive voume open\n");
402 // TODO: Flush the volume
403 VolumeFlushed
= TRUE
;
405 else if (FlagOn(*DesiredAccess
, FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
))
407 DPRINT1("Shared open\n");
409 // TODO: Flush the volume
410 VolumeFlushed
= TRUE
;
414 !FlagOn(Vcb
->State
, VCB_STATE_MOUNTED_DIRTY
) &&
415 FlagOn(Vcb
->State
, VCB_STATE_FLAG_DIRTY
) &&
416 CcIsThereDirtyData(Vcb
->Vpb
))
421 /* Set share access */
422 if (Vcb
->DirectOpenCount
> 0)
424 /* This volume has already been opened */
425 Iosb
.Status
= IoCheckShareAccess(*DesiredAccess
,
431 if (!NT_SUCCESS(Iosb
.Status
))
438 /* This is the first time open */
439 IoSetShareAccess(*DesiredAccess
,
445 /* Set file object pointers */
446 Ccb
= FatCreateCcb();
447 FatSetFileObject(FileObject
, UserVolumeOpen
, Vcb
, Ccb
);
448 FileObject
->SectionObjectPointer
= &Vcb
->SectionObjectPointers
;
450 /* Increase direct open count */
451 Vcb
->DirectOpenCount
++;
452 Vcb
->OpenFileCount
++;
454 /* Set no buffering flag */
455 FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
457 // TODO: User's access check
459 Iosb
.Status
= STATUS_SUCCESS
;
460 Iosb
.Information
= FILE_OPENED
;
467 FatiCreate(IN PFAT_IRP_CONTEXT IrpContext
,
470 /* Boolean options */
471 BOOLEAN CreateDirectory
;
472 BOOLEAN SequentialOnly
;
473 BOOLEAN NoIntermediateBuffering
;
474 BOOLEAN OpenDirectory
;
475 BOOLEAN IsPagingFile
;
476 BOOLEAN OpenTargetDirectory
;
477 BOOLEAN DirectoryFile
;
478 BOOLEAN NonDirectoryFile
;
479 BOOLEAN NoEaKnowledge
;
480 BOOLEAN DeleteOnClose
;
481 BOOLEAN TemporaryFile
;
482 ULONG CreateDisposition
;
485 PVCB Vcb
, DecodedVcb
, RelatedVcb
;
486 PFCB Fcb
, NextFcb
, RelatedDcb
;
487 PCCB Ccb
, RelatedCcb
;
491 PFILE_OBJECT FileObject
;
492 PFILE_OBJECT RelatedFO
;
493 UNICODE_STRING FileName
;
494 ULONG AllocationSize
;
495 PFILE_FULL_EA_INFORMATION EaBuffer
;
496 PACCESS_MASK DesiredAccess
;
498 UCHAR FileAttributes
;
504 IO_STATUS_BLOCK Iosb
;
505 PIO_STACK_LOCATION IrpSp
;
506 BOOLEAN EndBackslash
= FALSE
, OpenedAsDos
;
507 UNICODE_STRING RemainingPart
, FirstName
, NextName
, FileNameUpcased
;
508 OEM_STRING AnsiFirstName
;
510 TYPE_OF_OPEN TypeOfOpen
;
511 BOOLEAN OplockPostIrp
= FALSE
;
513 Iosb
.Status
= STATUS_SUCCESS
;
515 /* Get current IRP stack location */
516 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
518 DPRINT("FatCommonCreate\n", 0 );
519 DPRINT("Irp = %08lx\n", Irp
);
520 DPRINT("\t->Flags = %08lx\n", Irp
->Flags
);
521 DPRINT("\t->FileObject = %08lx\n", IrpSp
->FileObject
);
522 DPRINT("\t->RelatedFileObject = %08lx\n", IrpSp
->FileObject
->RelatedFileObject
);
523 DPRINT("\t->FileName = %wZ\n", &IrpSp
->FileObject
->FileName
);
524 DPRINT("\t->AllocationSize.LowPart = %08lx\n", Irp
->Overlay
.AllocationSize
.LowPart
);
525 DPRINT("\t->AllocationSize.HighPart = %08lx\n", Irp
->Overlay
.AllocationSize
.HighPart
);
526 DPRINT("\t->SystemBuffer = %08lx\n", Irp
->AssociatedIrp
.SystemBuffer
);
527 DPRINT("\t->DesiredAccess = %08lx\n", IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
528 DPRINT("\t->Options = %08lx\n", IrpSp
->Parameters
.Create
.Options
);
529 DPRINT("\t->FileAttributes = %04x\n", IrpSp
->Parameters
.Create
.FileAttributes
);
530 DPRINT("\t->ShareAccess = %04x\n", IrpSp
->Parameters
.Create
.ShareAccess
);
531 DPRINT("\t->EaLength = %08lx\n", IrpSp
->Parameters
.Create
.EaLength
);
533 /* Apply a special hack for Win32, idea taken from FASTFAT reference driver from WDK */
534 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
535 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
536 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
538 /* Remove a leading slash */
539 IrpSp
->FileObject
->FileName
.Length
-= sizeof(WCHAR
);
540 RtlMoveMemory(&IrpSp
->FileObject
->FileName
.Buffer
[0],
541 &IrpSp
->FileObject
->FileName
.Buffer
[1],
542 IrpSp
->FileObject
->FileName
.Length
);
544 /* Check again: if there are still two leading slashes,
545 exit with an error */
546 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
547 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
548 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
550 FatCompleteRequest( IrpContext
, Irp
, STATUS_OBJECT_NAME_INVALID
);
552 DPRINT1("FatiCreate: STATUS_OBJECT_NAME_INVALID\n");
553 return STATUS_OBJECT_NAME_INVALID
;
557 /* Make sure we have SecurityContext */
558 ASSERT(IrpSp
->Parameters
.Create
.SecurityContext
!= NULL
);
560 /* Get necessary data out of IRP */
561 FileObject
= IrpSp
->FileObject
;
562 FileName
= FileObject
->FileName
;
563 RelatedFO
= FileObject
->RelatedFileObject
;
564 AllocationSize
= Irp
->Overlay
.AllocationSize
.LowPart
;
565 EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
566 DesiredAccess
= &IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
567 Options
= IrpSp
->Parameters
.Create
.Options
;
568 FileAttributes
= (UCHAR
)(IrpSp
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
);
569 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
570 EaLength
= IrpSp
->Parameters
.Create
.EaLength
;
572 /* Set VPB to related object's VPB if it exists */
574 FileObject
->Vpb
= RelatedFO
->Vpb
;
576 /* Prepare file attributes mask */
577 FileAttributes
&= (FILE_ATTRIBUTE_READONLY
|
578 FILE_ATTRIBUTE_HIDDEN
|
579 FILE_ATTRIBUTE_SYSTEM
|
580 FILE_ATTRIBUTE_ARCHIVE
);
582 /* Get the volume control object */
583 Vcb
= &((PVOLUME_DEVICE_OBJECT
)IrpSp
->DeviceObject
)->Vcb
;
586 DirectoryFile
= BooleanFlagOn(Options
, FILE_DIRECTORY_FILE
);
587 NonDirectoryFile
= BooleanFlagOn(Options
, FILE_NON_DIRECTORY_FILE
);
588 SequentialOnly
= BooleanFlagOn(Options
, FILE_SEQUENTIAL_ONLY
);
589 NoIntermediateBuffering
= BooleanFlagOn(Options
, FILE_NO_INTERMEDIATE_BUFFERING
);
590 NoEaKnowledge
= BooleanFlagOn(Options
, FILE_NO_EA_KNOWLEDGE
);
591 DeleteOnClose
= BooleanFlagOn(Options
, FILE_DELETE_ON_CLOSE
);
592 TemporaryFile
= BooleanFlagOn(IrpSp
->Parameters
.Create
.FileAttributes
,
593 FILE_ATTRIBUTE_TEMPORARY
);
594 IsPagingFile
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_PAGING_FILE
);
595 OpenTargetDirectory
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
597 /* Calculate create disposition */
598 CreateDisposition
= (Options
>> 24) & 0x000000ff;
600 /* Get Create/Open directory flags based on it */
601 CreateDirectory
= (BOOLEAN
)(DirectoryFile
&&
602 ((CreateDisposition
== FILE_CREATE
) ||
603 (CreateDisposition
== FILE_OPEN_IF
)));
605 OpenDirectory
= (BOOLEAN
)(DirectoryFile
&&
606 ((CreateDisposition
== FILE_OPEN
) ||
607 (CreateDisposition
== FILE_OPEN_IF
)));
609 /* Validate parameters: directory/nondirectory mismatch and
610 AllocationSize being more than 4GB */
611 if ((DirectoryFile
&& NonDirectoryFile
) ||
612 Irp
->Overlay
.AllocationSize
.HighPart
!= 0)
614 FatCompleteRequest(IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
616 DPRINT1("FatiCreate: STATUS_INVALID_PARAMETER\n", 0);
617 return STATUS_INVALID_PARAMETER
;
620 /* Acquire the VCB lock exclusively */
621 if (!FatAcquireExclusiveVcb(IrpContext
, Vcb
))
623 // TODO: Postpone the IRP for later processing
625 return STATUS_NOT_IMPLEMENTED
;
628 // TODO: Verify the VCB
630 /* If VCB is locked, then no file openings are possible */
631 if (Vcb
->State
& VCB_STATE_FLAG_LOCKED
)
633 DPRINT1("This volume is locked\n");
634 Status
= STATUS_ACCESS_DENIED
;
636 /* Cleanup and return */
637 FatReleaseVcb(IrpContext
, Vcb
);
641 // TODO: Check if the volume is write protected and disallow DELETE_ON_CLOSE
643 // TODO: Make sure EAs aren't supported on FAT32
645 /* Check if it's a volume open request */
646 if (FileName
.Length
== 0)
648 /* Test related FO to be sure */
650 FatDecodeFileObject(RelatedFO
, &DecodedVcb
, &Fcb
, &Ccb
) == UserVolumeOpen
)
652 /* Check parameters */
653 if (DirectoryFile
|| OpenTargetDirectory
)
655 Status
= DirectoryFile
? STATUS_NOT_A_DIRECTORY
: STATUS_INVALID_PARAMETER
;
658 FatReleaseVcb(IrpContext
, Vcb
);
660 /* Complete the request and return */
661 FatCompleteRequest(IrpContext
, Irp
, Status
);
665 /* It is indeed a volume open request */
666 Iosb
= FatiOpenVolume(IrpContext
,
673 /* Set resulting information */
674 Irp
->IoStatus
.Information
= Iosb
.Information
;
677 FatReleaseVcb(IrpContext
, Vcb
);
679 /* Complete the request and return */
680 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
685 /* Check if this is a relative open */
688 /* Decode the file object */
689 TypeOfOpen
= FatDecodeFileObject(RelatedFO
,
694 /* Check open type */
695 if (TypeOfOpen
!= UserFileOpen
&&
696 TypeOfOpen
!= UserDirectoryOpen
)
698 DPRINT1("Invalid file object!\n");
700 /* Cleanup and return */
701 FatReleaseVcb(IrpContext
, Vcb
);
702 return STATUS_OBJECT_PATH_NOT_FOUND
;
705 /* File path must be relative */
706 if (FileName
.Length
!= 0 &&
707 FileName
.Buffer
[0] == L
'\\')
709 /* The name is absolute, fail */
710 FatReleaseVcb(IrpContext
, Vcb
);
711 return STATUS_OBJECT_NAME_INVALID
;
714 /* Make sure volume is the same */
715 ASSERT(RelatedVcb
== Vcb
);
718 FileObject
->Vpb
= RelatedFO
->Vpb
;
721 ParentDcb
= RelatedDcb
;
723 DPRINT1("Opening file '%wZ' relatively to '%wZ'\n", &FileName
, &ParentDcb
->FullFileName
);
728 if ((FileName
.Length
== sizeof(WCHAR
)) &&
729 (FileName
.Buffer
[0] == L
'\\'))
731 /* Check if it's ok to open it */
732 if (NonDirectoryFile
)
734 DPRINT1("Trying to open root dir as a file\n");
736 /* Cleanup and return */
737 FatReleaseVcb(IrpContext
, Vcb
);
738 return STATUS_FILE_IS_A_DIRECTORY
;
741 /* Check delete on close on a root dir */
744 /* Cleanup and return */
745 FatReleaseVcb(IrpContext
, Vcb
);
746 return STATUS_CANNOT_DELETE
;
749 /* Call root directory open routine */
750 Iosb
= FatiOpenRootDcb(IrpContext
,
757 Irp
->IoStatus
.Information
= Iosb
.Information
;
759 /* Cleanup and return */
760 FatReleaseVcb(IrpContext
, Vcb
);
766 ParentDcb
= Vcb
->RootDcb
;
767 DPRINT("ParentDcb %p\n", ParentDcb
);
771 /* Check for backslash at the end */
772 if (FileName
.Length
&&
773 FileName
.Buffer
[FileName
.Length
/ sizeof(WCHAR
) - 1] == L
'\\')
776 FileName
.Length
-= sizeof(WCHAR
);
778 /* Remember we cut it */
782 /* Ensure the name is set */
783 if (!ParentDcb
->FullFileName
.Buffer
)
785 /* Set it if it's missing */
786 FatSetFullFileNameInFcb(IrpContext
, ParentDcb
);
789 /* Check max path length */
790 if (ParentDcb
->FullFileName
.Length
+ FileName
.Length
+ sizeof(WCHAR
) <= FileName
.Length
)
792 DPRINT1("Max length is way off\n");
793 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
797 /* Loop through FCBs to find a good one */
802 /* Dissect the name */
803 RemainingPart
= FileName
;
804 while (RemainingPart
.Length
)
806 FsRtlDissectName(RemainingPart
, &FirstName
, &NextName
);
808 /* Check for validity */
809 if ((NextName
.Length
&& NextName
.Buffer
[0] == L
'\\') ||
810 (NextName
.Length
> 255 * sizeof(WCHAR
)))
812 /* The name is invalid */
813 DPRINT1("Invalid name found\n");
814 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
818 /* Convert the name to ANSI */
819 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
820 AnsiFirstName
.Length
= 0;
821 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
822 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
824 if (!NT_SUCCESS(Status
))
826 DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status
);
829 AnsiFirstName
.Length
= 0;
833 /* Find the coresponding FCB */
834 NextFcb
= FatFindFcb(IrpContext
,
835 &Fcb
->Dcb
.SplayLinksAnsi
,
836 (PSTRING
)&AnsiFirstName
,
840 /* If nothing found - try with unicode */
841 if (!NextFcb
&& Fcb
->Dcb
.SplayLinksUnicode
)
843 FileNameUpcased
.Buffer
= FsRtlAllocatePool(PagedPool
, FirstName
.Length
);
844 FileNameUpcased
.Length
= 0;
845 FileNameUpcased
.MaximumLength
= FirstName
.Length
;
847 /* Downcase and then upcase to normalize it */
848 Status
= RtlDowncaseUnicodeString(&FileNameUpcased
, &FirstName
, FALSE
);
849 Status
= RtlUpcaseUnicodeString(&FileNameUpcased
, &FileNameUpcased
, FALSE
);
851 /* Try to find FCB again using unicode name */
852 NextFcb
= FatFindFcb(IrpContext
,
853 &Fcb
->Dcb
.SplayLinksUnicode
,
854 (PSTRING
)&FileNameUpcased
,
858 /* Move to the next FCB */
862 RemainingPart
= NextName
;
865 /* Break out of this loop if nothing can be found */
867 NextName
.Length
== 0 ||
868 FatNodeType(NextFcb
) == FAT_NTC_FCB
)
874 /* Ensure remaining name doesn't start from a backslash */
875 if (RemainingPart
.Length
&&
876 RemainingPart
.Buffer
[0] == L
'\\')
879 RemainingPart
.Buffer
++;
880 RemainingPart
.Length
-= sizeof(WCHAR
);
883 if (Fcb
->Condition
== FcbGood
)
885 /* Good FCB, break out of the loop */
894 /* We have a valid FCB now */
895 if (!RemainingPart
.Length
)
897 /* Check for target dir open */
898 if (OpenTargetDirectory
)
900 DPRINT1("Opening target dir is missing\n");
904 /* Check this FCB's type */
905 if (FatNodeType(Fcb
) == FAT_NTC_ROOT_DCB
||
906 FatNodeType(Fcb
) == FAT_NTC_DCB
)
908 /* Open a directory */
909 if (NonDirectoryFile
)
912 Iosb
.Status
= STATUS_FILE_IS_A_DIRECTORY
;
917 /* Open existing DCB */
918 Iosb
= FatiOpenExistingDcb(IrpContext
,
928 /* Save information */
929 Irp
->IoStatus
.Information
= Iosb
.Information
;
932 FatReleaseVcb(IrpContext
, Vcb
);
934 /* Complete the request */
935 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
939 else if (FatNodeType(Fcb
) == FAT_NTC_FCB
)
945 Iosb
.Status
= STATUS_NOT_A_DIRECTORY
;
950 /* Check for trailing backslash */
954 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
959 Iosb
= FatiOpenExistingFcb(IrpContext
,
975 /* Check if it's pending */
976 if (Iosb
.Status
!= STATUS_PENDING
)
978 /* In case of success set cache supported flag */
979 if (NT_SUCCESS(Iosb
.Status
) && !NoIntermediateBuffering
)
981 SetFlag(FileObject
->Flags
, FO_CACHE_SUPPORTED
);
984 /* Save information */
985 Irp
->IoStatus
.Information
= Iosb
.Information
;
988 FatReleaseVcb(IrpContext
, Vcb
);
990 /* Complete the request */
991 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1004 /* Unexpected FCB type */
1005 KeBugCheckEx(FAT_FILE_SYSTEM
, __LINE__
, (ULONG_PTR
)Fcb
, 0, 0);
1009 /* During parsing we encountered a part which has no attached FCB/DCB.
1010 Check that the parent is really DCB and not FCB */
1011 if (FatNodeType(Fcb
) != FAT_NTC_ROOT_DCB
&&
1012 FatNodeType(Fcb
) != FAT_NTC_DCB
)
1014 DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb
));
1018 /* Create additional DCBs for all path items */
1022 FsRtlDissectName(RemainingPart
, &FirstName
, &RemainingPart
);
1024 /* Check for validity */
1025 if ((RemainingPart
.Length
&& RemainingPart
.Buffer
[0] == L
'\\') ||
1026 (NextName
.Length
> 255 * sizeof(WCHAR
)))
1028 /* The name is invalid */
1029 DPRINT1("Invalid name found\n");
1030 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
1034 /* Convert the name to ANSI */
1035 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
1036 AnsiFirstName
.Length
= 0;
1037 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
1038 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
1040 if (!NT_SUCCESS(Status
))
1045 DPRINT("FirstName %wZ, RemainingPart %wZ\n", &FirstName
, &RemainingPart
);
1047 /* Break if came to the end */
1048 if (!RemainingPart
.Length
) break;
1050 /* Create a DCB for this entry */
1051 ParentDcb
= FatCreateDcb(IrpContext
,
1057 FatSetFullNameInFcb(ParentDcb
, &FirstName
);
1060 /* Try to open it and get a result, saying if this is a dir or a file */
1061 FfError
= FatiTryToOpen(FileObject
, Vcb
);
1063 /* Check if we need to open target directory */
1064 if (OpenTargetDirectory
)
1066 // TODO: Open target directory
1070 /* Check, if path is a directory or a file */
1071 if (FfError
== FF_ERR_FILE_OBJECT_IS_A_DIR
)
1073 if (NonDirectoryFile
)
1075 DPRINT1("Can't open dir as a file\n");
1078 FatReleaseVcb(IrpContext
, Vcb
);
1080 /* Complete the request */
1081 Iosb
.Status
= STATUS_FILE_IS_A_DIRECTORY
;
1082 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1086 /* Open this directory */
1087 Iosb
= FatiOpenExistingDir(IrpContext
,
1100 Irp
->IoStatus
.Information
= Iosb
.Information
;
1103 FatReleaseVcb(IrpContext
, Vcb
);
1105 /* Complete the request */
1106 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1111 /* If end backslash here, then it's definately not permitted,
1112 since we're opening files here */
1116 FatReleaseVcb(IrpContext
, Vcb
);
1118 /* Complete the request */
1119 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
1120 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1124 /* Try to open the file */
1125 Iosb
= FatiOpenExistingFile(IrpContext
,
1140 Irp
->IoStatus
.Information
= Iosb
.Information
;
1143 FatReleaseVcb(IrpContext
, Vcb
);
1145 /* Complete the request */
1146 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1153 FatCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1155 PFAT_IRP_CONTEXT IrpContext
;
1158 /* If it's called with our Disk FS device object - it's always open */
1159 // TODO: Add check for CDROM FS device object
1160 if (DeviceObject
== FatGlobalData
.DiskDeviceObject
)
1162 /* Complete the request and return success */
1163 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1164 Irp
->IoStatus
.Information
= FILE_OPENED
;
1166 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1168 return STATUS_SUCCESS
;
1171 /* Enter FsRtl critical region */
1172 FsRtlEnterFileSystem();
1174 /* Build an irp context */
1175 IrpContext
= FatBuildIrpContext(Irp
, TRUE
);
1177 /* Call internal function */
1178 Status
= FatiCreate(IrpContext
, Irp
);
1180 /* Leave FsRtl critical region */
1181 FsRtlExitFileSystem();