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 */
70 Ccb
= FatCreateCcb(IrpContext
);
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 FatiOpenExistingDir(IN PFAT_IRP_CONTEXT IrpContext
,
123 IN PFILE_OBJECT FileObject
,
126 IN PACCESS_MASK DesiredAccess
,
127 IN USHORT ShareAccess
,
128 IN ULONG AllocationSize
,
129 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
131 IN UCHAR FileAttributes
,
132 IN ULONG CreateDisposition
,
133 IN BOOLEAN DeleteOnClose
)
135 IO_STATUS_BLOCK Iosb
= {{0}};
137 CHAR AnsiNameBuf
[512];
142 /* Only open is permitted */
143 if (CreateDisposition
!= FILE_OPEN
&&
144 CreateDisposition
!= FILE_OPEN_IF
)
146 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
150 // TODO: Check dir access
152 /* Convert the name to ANSI */
153 AnsiName
.Buffer
= AnsiNameBuf
;
155 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
156 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
157 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
158 if (!NT_SUCCESS(Status
))
163 /* Open the dir with FullFAT */
164 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_DIR
, NULL
);
168 Iosb
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // FIXME: A shortcut for now
172 /* Create a new DCB for this directory */
173 Fcb
= FatCreateDcb(IrpContext
, Vcb
, ParentDcb
, FileHandle
);
175 /* Set share access */
176 IoSetShareAccess(*DesiredAccess
, ShareAccess
, FileObject
, &Fcb
->ShareAccess
);
178 /* Set context and section object pointers */
179 FatSetFileObject(FileObject
,
184 Iosb
.Status
= STATUS_SUCCESS
;
185 Iosb
.Information
= FILE_OPENED
;
187 DPRINT1("Successfully opened dir %s\n", AnsiNameBuf
);
194 FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext
,
195 IN PFILE_OBJECT FileObject
,
198 IN PACCESS_MASK DesiredAccess
,
199 IN USHORT ShareAccess
,
200 IN ULONG AllocationSize
,
201 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
203 IN UCHAR FileAttributes
,
204 IN ULONG CreateDisposition
,
205 IN BOOLEAN IsPagingFile
,
206 IN BOOLEAN DeleteOnClose
,
207 IN BOOLEAN IsDosName
)
209 IO_STATUS_BLOCK Iosb
= {{0}};
211 CHAR AnsiNameBuf
[512];
216 /* Check for create file option and fail */
217 if (CreateDisposition
== FILE_CREATE
)
219 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
223 // TODO: Check more params
225 /* Convert the name to ANSI */
226 AnsiName
.Buffer
= AnsiNameBuf
;
228 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
229 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
230 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
231 if (!NT_SUCCESS(Status
))
236 /* Open the file with FullFAT */
237 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_READ
, NULL
);
241 Iosb
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // FIXME: A shortcut for now
245 /* Create a new FCB for this file */
246 Fcb
= FatCreateFcb(IrpContext
, Vcb
, ParentDcb
, FileHandle
);
248 // TODO: Check if overwrite is needed
250 // This is usual file open branch, without overwriting!
251 /* Set context and section object pointers */
252 FatSetFileObject(FileObject
,
256 FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
258 Iosb
.Status
= STATUS_SUCCESS
;
259 Iosb
.Information
= FILE_OPENED
;
266 FatiOpenVolume(IN PFAT_IRP_CONTEXT IrpContext
,
267 IN PFILE_OBJECT FileObject
,
269 IN PACCESS_MASK DesiredAccess
,
270 IN USHORT ShareAccess
,
271 IN ULONG CreateDisposition
)
274 IO_STATUS_BLOCK Iosb
= {{0}};
275 BOOLEAN VolumeFlushed
= FALSE
;
277 /* Check parameters */
278 if (CreateDisposition
!= FILE_OPEN
&&
279 CreateDisposition
!= FILE_OPEN_IF
)
282 Iosb
.Status
= STATUS_ACCESS_DENIED
;
285 /* Check if it's exclusive open */
286 if (!FlagOn(ShareAccess
, FILE_SHARE_WRITE
) &&
287 !FlagOn(ShareAccess
, FILE_SHARE_DELETE
))
289 // TODO: Check if exclusive read access requested
290 // and opened handles count is not 0
291 //if (!FlagOn(ShareAccess, FILE_SHARE_READ)
293 DPRINT1("Exclusive voume open\n");
295 // TODO: Flush the volume
296 VolumeFlushed
= TRUE
;
298 else if (FlagOn(*DesiredAccess
, FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
))
300 DPRINT1("Shared open\n");
302 // TODO: Flush the volume
303 VolumeFlushed
= TRUE
;
307 !FlagOn(Vcb
->State
, VCB_STATE_MOUNTED_DIRTY
) &&
308 FlagOn(Vcb
->State
, VCB_STATE_FLAG_DIRTY
) &&
309 CcIsThereDirtyData(Vcb
->Vpb
))
314 /* Set share access */
315 if (Vcb
->DirectOpenCount
> 0)
317 /* This volume has already been opened */
318 Iosb
.Status
= IoCheckShareAccess(*DesiredAccess
,
324 if (!NT_SUCCESS(Iosb
.Status
))
331 /* This is the first time open */
332 IoSetShareAccess(*DesiredAccess
,
338 /* Set file object pointers */
339 Ccb
= FatCreateCcb(IrpContext
);
340 FatSetFileObject(FileObject
, UserVolumeOpen
, Vcb
, Ccb
);
341 FileObject
->SectionObjectPointer
= &Vcb
->SectionObjectPointers
;
343 /* Increase direct open count */
344 Vcb
->DirectOpenCount
++;
345 Vcb
->OpenFileCount
++;
347 /* Set no buffering flag */
348 FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
350 // TODO: User's access check
352 Iosb
.Status
= STATUS_SUCCESS
;
353 Iosb
.Information
= FILE_OPENED
;
360 FatiCreate(IN PFAT_IRP_CONTEXT IrpContext
,
363 /* Boolean options */
364 BOOLEAN CreateDirectory
;
365 BOOLEAN SequentialOnly
;
366 BOOLEAN NoIntermediateBuffering
;
367 BOOLEAN OpenDirectory
;
368 BOOLEAN IsPagingFile
;
369 BOOLEAN OpenTargetDirectory
;
370 BOOLEAN DirectoryFile
;
371 BOOLEAN NonDirectoryFile
;
372 BOOLEAN NoEaKnowledge
;
373 BOOLEAN DeleteOnClose
;
374 BOOLEAN TemporaryFile
;
375 ULONG CreateDisposition
;
378 PVCB Vcb
, DecodedVcb
, RelatedVcb
;
379 PFCB Fcb
, NextFcb
, RelatedDcb
;
380 PCCB Ccb
, RelatedCcb
;
384 PFILE_OBJECT FileObject
;
385 PFILE_OBJECT RelatedFO
;
386 UNICODE_STRING FileName
;
387 ULONG AllocationSize
;
388 PFILE_FULL_EA_INFORMATION EaBuffer
;
389 PACCESS_MASK DesiredAccess
;
391 UCHAR FileAttributes
;
397 IO_STATUS_BLOCK Iosb
;
398 PIO_STACK_LOCATION IrpSp
;
399 BOOLEAN EndBackslash
= FALSE
, OpenedAsDos
;
400 UNICODE_STRING RemainingPart
, FirstName
, NextName
, FileNameUpcased
;
401 OEM_STRING AnsiFirstName
;
403 TYPE_OF_OPEN TypeOfOpen
;
404 BOOLEAN OplockPostIrp
= FALSE
;
406 Iosb
.Status
= STATUS_SUCCESS
;
408 /* Get current IRP stack location */
409 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
411 DPRINT("FatCommonCreate\n", 0 );
412 DPRINT("Irp = %08lx\n", Irp
);
413 DPRINT("\t->Flags = %08lx\n", Irp
->Flags
);
414 DPRINT("\t->FileObject = %08lx\n", IrpSp
->FileObject
);
415 DPRINT("\t->RelatedFileObject = %08lx\n", IrpSp
->FileObject
->RelatedFileObject
);
416 DPRINT("\t->FileName = %wZ\n", &IrpSp
->FileObject
->FileName
);
417 DPRINT("\t->AllocationSize.LowPart = %08lx\n", Irp
->Overlay
.AllocationSize
.LowPart
);
418 DPRINT("\t->AllocationSize.HighPart = %08lx\n", Irp
->Overlay
.AllocationSize
.HighPart
);
419 DPRINT("\t->SystemBuffer = %08lx\n", Irp
->AssociatedIrp
.SystemBuffer
);
420 DPRINT("\t->DesiredAccess = %08lx\n", IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
421 DPRINT("\t->Options = %08lx\n", IrpSp
->Parameters
.Create
.Options
);
422 DPRINT("\t->FileAttributes = %04x\n", IrpSp
->Parameters
.Create
.FileAttributes
);
423 DPRINT("\t->ShareAccess = %04x\n", IrpSp
->Parameters
.Create
.ShareAccess
);
424 DPRINT("\t->EaLength = %08lx\n", IrpSp
->Parameters
.Create
.EaLength
);
426 /* Apply a special hack for Win32, idea taken from FASTFAT reference driver from WDK */
427 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
428 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
429 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
431 /* Remove a leading slash */
432 IrpSp
->FileObject
->FileName
.Length
-= sizeof(WCHAR
);
433 RtlMoveMemory(&IrpSp
->FileObject
->FileName
.Buffer
[0],
434 &IrpSp
->FileObject
->FileName
.Buffer
[1],
435 IrpSp
->FileObject
->FileName
.Length
);
437 /* Check again: if there are still two leading slashes,
438 exit with an error */
439 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
440 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
441 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
443 FatCompleteRequest( IrpContext
, Irp
, STATUS_OBJECT_NAME_INVALID
);
445 DPRINT1("FatiCreate: STATUS_OBJECT_NAME_INVALID\n");
446 return STATUS_OBJECT_NAME_INVALID
;
450 /* Make sure we have SecurityContext */
451 ASSERT(IrpSp
->Parameters
.Create
.SecurityContext
!= NULL
);
453 /* Get necessary data out of IRP */
454 FileObject
= IrpSp
->FileObject
;
455 FileName
= FileObject
->FileName
;
456 RelatedFO
= FileObject
->RelatedFileObject
;
457 AllocationSize
= Irp
->Overlay
.AllocationSize
.LowPart
;
458 EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
459 DesiredAccess
= &IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
460 Options
= IrpSp
->Parameters
.Create
.Options
;
461 FileAttributes
= (UCHAR
)(IrpSp
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
);
462 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
463 EaLength
= IrpSp
->Parameters
.Create
.EaLength
;
465 /* Set VPB to related object's VPB if it exists */
467 FileObject
->Vpb
= RelatedFO
->Vpb
;
469 /* Prepare file attributes mask */
470 FileAttributes
&= (FILE_ATTRIBUTE_READONLY
|
471 FILE_ATTRIBUTE_HIDDEN
|
472 FILE_ATTRIBUTE_SYSTEM
|
473 FILE_ATTRIBUTE_ARCHIVE
);
475 /* Get the volume control object */
476 Vcb
= &((PVOLUME_DEVICE_OBJECT
)IrpSp
->DeviceObject
)->Vcb
;
479 DirectoryFile
= BooleanFlagOn(Options
, FILE_DIRECTORY_FILE
);
480 NonDirectoryFile
= BooleanFlagOn(Options
, FILE_NON_DIRECTORY_FILE
);
481 SequentialOnly
= BooleanFlagOn(Options
, FILE_SEQUENTIAL_ONLY
);
482 NoIntermediateBuffering
= BooleanFlagOn(Options
, FILE_NO_INTERMEDIATE_BUFFERING
);
483 NoEaKnowledge
= BooleanFlagOn(Options
, FILE_NO_EA_KNOWLEDGE
);
484 DeleteOnClose
= BooleanFlagOn(Options
, FILE_DELETE_ON_CLOSE
);
485 TemporaryFile
= BooleanFlagOn(IrpSp
->Parameters
.Create
.FileAttributes
,
486 FILE_ATTRIBUTE_TEMPORARY
);
487 IsPagingFile
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_PAGING_FILE
);
488 OpenTargetDirectory
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
490 /* Calculate create disposition */
491 CreateDisposition
= (Options
>> 24) & 0x000000ff;
493 /* Get Create/Open directory flags based on it */
494 CreateDirectory
= (BOOLEAN
)(DirectoryFile
&&
495 ((CreateDisposition
== FILE_CREATE
) ||
496 (CreateDisposition
== FILE_OPEN_IF
)));
498 OpenDirectory
= (BOOLEAN
)(DirectoryFile
&&
499 ((CreateDisposition
== FILE_OPEN
) ||
500 (CreateDisposition
== FILE_OPEN_IF
)));
502 /* Validate parameters: directory/nondirectory mismatch and
503 AllocationSize being more than 4GB */
504 if ((DirectoryFile
&& NonDirectoryFile
) ||
505 Irp
->Overlay
.AllocationSize
.HighPart
!= 0)
507 FatCompleteRequest(IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
509 DPRINT1("FatiCreate: STATUS_INVALID_PARAMETER\n", 0);
510 return STATUS_INVALID_PARAMETER
;
513 /* Acquire the VCB lock exclusively */
514 if (!FatAcquireExclusiveVcb(IrpContext
, Vcb
))
516 // TODO: Postpone the IRP for later processing
518 return STATUS_NOT_IMPLEMENTED
;
521 // TODO: Verify the VCB
523 /* If VCB is locked, then no file openings are possible */
524 if (Vcb
->State
& VCB_STATE_FLAG_LOCKED
)
526 DPRINT1("This volume is locked\n");
527 Status
= STATUS_ACCESS_DENIED
;
529 /* Cleanup and return */
530 FatReleaseVcb(IrpContext
, Vcb
);
534 // TODO: Check if the volume is write protected and disallow DELETE_ON_CLOSE
536 // TODO: Make sure EAs aren't supported on FAT32
538 /* Check if it's a volume open request */
539 if (FileName
.Length
== 0)
541 /* Test related FO to be sure */
543 FatDecodeFileObject(RelatedFO
, &DecodedVcb
, &Fcb
, &Ccb
) == UserVolumeOpen
)
545 /* Check parameters */
546 if (DirectoryFile
|| OpenTargetDirectory
)
548 Status
= DirectoryFile
? STATUS_NOT_A_DIRECTORY
: STATUS_INVALID_PARAMETER
;
551 FatReleaseVcb(IrpContext
, Vcb
);
553 /* Complete the request and return */
554 FatCompleteRequest(IrpContext
, Irp
, Status
);
558 /* It is indeed a volume open request */
559 Iosb
= FatiOpenVolume(IrpContext
,
566 /* Set resulting information */
567 Irp
->IoStatus
.Information
= Iosb
.Information
;
570 FatReleaseVcb(IrpContext
, Vcb
);
572 /* Complete the request and return */
573 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
578 /* Check if this is a relative open */
581 /* Decode the file object */
582 TypeOfOpen
= FatDecodeFileObject(RelatedFO
,
587 /* Check open type */
588 if (TypeOfOpen
!= UserFileOpen
&&
589 TypeOfOpen
!= UserDirectoryOpen
)
591 DPRINT1("Invalid file object!\n");
593 /* Cleanup and return */
594 FatReleaseVcb(IrpContext
, Vcb
);
595 return STATUS_OBJECT_PATH_NOT_FOUND
;
598 /* File path must be relative */
599 if (FileName
.Length
!= 0 &&
600 FileName
.Buffer
[0] == L
'\\')
602 /* The name is absolute, fail */
603 FatReleaseVcb(IrpContext
, Vcb
);
604 return STATUS_OBJECT_NAME_INVALID
;
607 /* Make sure volume is the same */
608 ASSERT(RelatedVcb
== Vcb
);
611 FileObject
->Vpb
= RelatedFO
->Vpb
;
614 ParentDcb
= RelatedDcb
;
616 DPRINT1("Opening file '%wZ' relatively to '%wZ'\n", &FileName
, &ParentDcb
->FullFileName
);
621 if ((FileName
.Length
== sizeof(WCHAR
)) &&
622 (FileName
.Buffer
[0] == L
'\\'))
624 /* Check if it's ok to open it */
625 if (NonDirectoryFile
)
627 DPRINT1("Trying to open root dir as a file\n");
629 /* Cleanup and return */
630 FatReleaseVcb(IrpContext
, Vcb
);
631 return STATUS_FILE_IS_A_DIRECTORY
;
634 /* Check delete on close on a root dir */
637 /* Cleanup and return */
638 FatReleaseVcb(IrpContext
, Vcb
);
639 return STATUS_CANNOT_DELETE
;
642 /* Call root directory open routine */
643 Iosb
= FatiOpenRootDcb(IrpContext
,
650 Irp
->IoStatus
.Information
= Iosb
.Information
;
652 /* Cleanup and return */
653 FatReleaseVcb(IrpContext
, Vcb
);
659 ParentDcb
= Vcb
->RootDcb
;
660 DPRINT("ParentDcb %p\n", ParentDcb
);
664 /* Check for backslash at the end */
665 if (FileName
.Length
&&
666 FileName
.Buffer
[FileName
.Length
/ sizeof(WCHAR
) - 1] == L
'\\')
669 FileName
.Length
-= sizeof(WCHAR
);
671 /* Remember we cut it */
675 /* Ensure the name is set */
676 if (!ParentDcb
->FullFileName
.Buffer
)
678 /* Set it if it's missing */
679 FatSetFullFileNameInFcb(IrpContext
, ParentDcb
);
682 /* Check max path length */
683 if (ParentDcb
->FullFileName
.Length
+ FileName
.Length
+ sizeof(WCHAR
) <= FileName
.Length
)
685 DPRINT1("Max length is way off\n");
686 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
690 /* Loop through FCBs to find a good one */
695 /* Dissect the name */
696 RemainingPart
= FileName
;
697 while (RemainingPart
.Length
)
699 FsRtlDissectName(RemainingPart
, &FirstName
, &NextName
);
701 /* Check for validity */
702 if ((NextName
.Length
&& NextName
.Buffer
[0] == L
'\\') ||
703 (NextName
.Length
> 255 * sizeof(WCHAR
)))
705 /* The name is invalid */
706 DPRINT1("Invalid name found\n");
707 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
711 /* Convert the name to ANSI */
712 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
713 AnsiFirstName
.Length
= 0;
714 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
715 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
717 if (!NT_SUCCESS(Status
))
719 DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status
);
722 AnsiFirstName
.Length
= 0;
726 /* Find the coresponding FCB */
727 NextFcb
= FatFindFcb(IrpContext
,
728 &Fcb
->Dcb
.SplayLinksAnsi
,
729 (PSTRING
)&AnsiFirstName
,
733 /* If nothing found - try with unicode */
734 if (!NextFcb
&& Fcb
->Dcb
.SplayLinksUnicode
)
736 FileNameUpcased
.Buffer
= FsRtlAllocatePool(PagedPool
, FirstName
.Length
);
737 FileNameUpcased
.Length
= 0;
738 FileNameUpcased
.MaximumLength
= FirstName
.Length
;
740 /* Downcase and then upcase to normalize it */
741 Status
= RtlDowncaseUnicodeString(&FileNameUpcased
, &FirstName
, FALSE
);
742 Status
= RtlUpcaseUnicodeString(&FileNameUpcased
, &FileNameUpcased
, FALSE
);
744 /* Try to find FCB again using unicode name */
745 NextFcb
= FatFindFcb(IrpContext
,
746 &Fcb
->Dcb
.SplayLinksUnicode
,
747 (PSTRING
)&FileNameUpcased
,
751 /* Move to the next FCB */
755 RemainingPart
= NextName
;
758 /* Break out of this loop if nothing can be found */
760 NextName
.Length
== 0 ||
761 FatNodeType(NextFcb
) == FAT_NTC_FCB
)
767 /* Ensure remaining name doesn't start from a backslash */
768 if (RemainingPart
.Length
&&
769 RemainingPart
.Buffer
[0] == L
'\\')
772 RemainingPart
.Buffer
++;
773 RemainingPart
.Length
-= sizeof(WCHAR
);
776 if (Fcb
->Condition
== FcbGood
)
778 /* Good FCB, break out of the loop */
787 /* We have a valid FCB now */
788 if (!RemainingPart
.Length
)
790 /* Check for target dir open */
791 if (OpenTargetDirectory
)
793 DPRINT1("Opening target dir is missing\n");
797 /* Check this FCB's type */
798 if (FatNodeType(Fcb
) == FAT_NTC_ROOT_DCB
||
799 FatNodeType(Fcb
) == FAT_NTC_DCB
)
801 /* Open a directory */
802 if (NonDirectoryFile
)
805 Iosb
.Status
= STATUS_FILE_IS_A_DIRECTORY
;
810 /* Open existing DCB */
811 Iosb
= FatiOpenExistingDcb(IrpContext
,
821 /* Save information */
822 Irp
->IoStatus
.Information
= Iosb
.Information
;
825 FatReleaseVcb(IrpContext
, Vcb
);
827 /* Complete the request */
828 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
832 else if (FatNodeType(Fcb
) == FAT_NTC_FCB
)
838 Iosb
.Status
= STATUS_NOT_A_DIRECTORY
;
843 /* Check for trailing backslash */
847 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
852 Iosb
= FatiOpenExistingFcb(IrpContext
,
868 /* Check if it's pending */
869 if (Iosb
.Status
!= STATUS_PENDING
)
871 /* In case of success set cache supported flag */
872 if (NT_SUCCESS(Iosb
.Status
) && !NoIntermediateBuffering
)
874 SetFlag(FileObject
->Flags
, FO_CACHE_SUPPORTED
);
877 /* Save information */
878 Irp
->IoStatus
.Information
= Iosb
.Information
;
881 FatReleaseVcb(IrpContext
, Vcb
);
883 /* Complete the request */
884 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
897 /* Unexpected FCB type */
898 KeBugCheckEx(/*FAT_FILE_SYSTEM*/0x23, __LINE__
, (ULONG_PTR
)Fcb
, 0, 0);
902 /* During parsing we encountered a part which has no attached FCB/DCB.
903 Check that the parent is really DCB and not FCB */
904 if (FatNodeType(Fcb
) != FAT_NTC_ROOT_DCB
&&
905 FatNodeType(Fcb
) != FAT_NTC_DCB
)
907 DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb
));
911 /* Create additional DCBs for all path items */
915 FsRtlDissectName(RemainingPart
, &FirstName
, &RemainingPart
);
917 /* Check for validity */
918 if ((RemainingPart
.Length
&& RemainingPart
.Buffer
[0] == L
'\\') ||
919 (NextName
.Length
> 255 * sizeof(WCHAR
)))
921 /* The name is invalid */
922 DPRINT1("Invalid name found\n");
923 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
927 /* Convert the name to ANSI */
928 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
929 AnsiFirstName
.Length
= 0;
930 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
931 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
933 if (!NT_SUCCESS(Status
))
938 DPRINT("FirstName %wZ, RemainingPart %wZ\n", &FirstName
, &RemainingPart
);
940 /* Break if came to the end */
941 if (!RemainingPart
.Length
) break;
943 /* Create a DCB for this entry */
944 ParentDcb
= FatCreateDcb(IrpContext
,
950 FatSetFullNameInFcb(ParentDcb
, &FirstName
);
953 /* Try to open it and get a result, saying if this is a dir or a file */
954 FfError
= FatiTryToOpen(FileObject
, Vcb
);
956 /* Check if we need to open target directory */
957 if (OpenTargetDirectory
)
959 // TODO: Open target directory
963 /* Check, if path is a directory or a file */
964 if (FfError
== FF_ERR_FILE_OBJECT_IS_A_DIR
)
966 if (NonDirectoryFile
)
968 DPRINT1("Can't open dir as a file\n");
971 FatReleaseVcb(IrpContext
, Vcb
);
973 /* Complete the request */
974 Iosb
.Status
= STATUS_FILE_IS_A_DIRECTORY
;
975 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
979 /* Open this directory */
980 Iosb
= FatiOpenExistingDir(IrpContext
,
993 Irp
->IoStatus
.Information
= Iosb
.Information
;
996 FatReleaseVcb(IrpContext
, Vcb
);
998 /* Complete the request */
999 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1004 /* If end backslash here, then it's definately not permitted,
1005 since we're opening files here */
1009 FatReleaseVcb(IrpContext
, Vcb
);
1011 /* Complete the request */
1012 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
1013 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1017 /* Try to open the file */
1018 Iosb
= FatiOpenExistingFile(IrpContext
,
1033 Irp
->IoStatus
.Information
= Iosb
.Information
;
1036 FatReleaseVcb(IrpContext
, Vcb
);
1038 /* Complete the request */
1039 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
1046 FatCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1048 PFAT_IRP_CONTEXT IrpContext
;
1051 /* If it's called with our Disk FS device object - it's always open */
1052 // TODO: Add check for CDROM FS device object
1053 if (DeviceObject
== FatGlobalData
.DiskDeviceObject
)
1055 /* Complete the request and return success */
1056 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1057 Irp
->IoStatus
.Information
= FILE_OPENED
;
1059 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1061 return STATUS_SUCCESS
;
1064 /* Enter FsRtl critical region */
1065 FsRtlEnterFileSystem();
1067 /* Build an irp context */
1068 IrpContext
= FatBuildIrpContext(Irp
, TRUE
);
1070 /* Call internal function */
1071 Status
= FatiCreate(IrpContext
, Irp
);
1073 /* Leave FsRtl critical region */
1074 FsRtlExitFileSystem();