[fastfat_new]
[reactos.git] / reactos / drivers / filesystems / fastfat_new / create.c
1 /*
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)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* FUNCTIONS *****************************************************************/
15
16 IO_STATUS_BLOCK
17 NTAPI
18 FatiOpenRootDcb(IN PFAT_IRP_CONTEXT IrpContext,
19 IN PFILE_OBJECT FileObject,
20 IN PVCB Vcb,
21 IN PACCESS_MASK DesiredAccess,
22 IN USHORT ShareAccess,
23 IN ULONG CreateDisposition)
24 {
25 IO_STATUS_BLOCK Iosb;
26 PFCB Dcb;
27 NTSTATUS Status;
28 PCCB Ccb;
29
30 /* Reference our DCB */
31 Dcb = Vcb->RootDcb;
32
33 DPRINT("Opening root directory\n");
34
35 /* Exclusively lock this DCB */
36 (VOID)FatAcquireExclusiveFcb(IrpContext, Dcb);
37
38 do
39 {
40 /* Validate parameters */
41 if (CreateDisposition != FILE_OPEN &&
42 CreateDisposition != FILE_OPEN_IF)
43 {
44 Iosb.Status = STATUS_ACCESS_DENIED;
45 break;
46 }
47
48 // TODO: Check file access
49
50 /* Is it a first time open? */
51 if (Dcb->OpenCount == 0)
52 {
53 /* Set share access */
54 IoSetShareAccess(*DesiredAccess,
55 ShareAccess,
56 FileObject,
57 &Dcb->ShareAccess);
58 }
59 else
60 {
61 /* Check share access */
62 Status = IoCheckShareAccess(*DesiredAccess,
63 ShareAccess,
64 FileObject,
65 &Dcb->ShareAccess,
66 TRUE);
67 }
68
69 /* Set file object pointers */
70 Ccb = FatCreateCcb(IrpContext);
71 FatSetFileObject(FileObject, UserDirectoryOpen, Dcb, Ccb);
72
73 /* Increment counters */
74 Dcb->OpenCount++;
75 Vcb->OpenFileCount++;
76
77 /* Set success statuses */
78 Iosb.Status = STATUS_SUCCESS;
79 Iosb.Information = FILE_OPENED;
80 } while (FALSE);
81
82 /* Release the DCB lock */
83 FatReleaseFcb(IrpContext, Dcb);
84
85 return Iosb;
86 }
87
88 FF_ERROR
89 NTAPI
90 FatiTryToOpen(IN PFILE_OBJECT FileObject,
91 IN PVCB Vcb)
92 {
93 OEM_STRING AnsiName;
94 CHAR AnsiNameBuf[512];
95 FF_ERROR Error;
96 NTSTATUS Status;
97 FF_FILE *FileHandle;
98
99 /* Convert the name to ANSI */
100 AnsiName.Buffer = AnsiNameBuf;
101 AnsiName.Length = 0;
102 AnsiName.MaximumLength = sizeof(AnsiNameBuf);
103 RtlZeroMemory(AnsiNameBuf, sizeof(AnsiNameBuf));
104 Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiName, &FileObject->FileName, FALSE);
105 if (!NT_SUCCESS(Status))
106 {
107 ASSERT(FALSE);
108 }
109
110 /* Open the file with FullFAT */
111 FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_READ, &Error);
112
113 /* Close the handle */
114 if (FileHandle) FF_Close(FileHandle);
115
116 /* Return status */
117 return Error;
118 }
119
120 IO_STATUS_BLOCK
121 NTAPI
122 FatiOpenExistingDir(IN PFAT_IRP_CONTEXT IrpContext,
123 IN PFILE_OBJECT FileObject,
124 IN PVCB Vcb,
125 IN PFCB ParentDcb,
126 IN PACCESS_MASK DesiredAccess,
127 IN USHORT ShareAccess,
128 IN ULONG AllocationSize,
129 IN PFILE_FULL_EA_INFORMATION EaBuffer,
130 IN ULONG EaLength,
131 IN UCHAR FileAttributes,
132 IN ULONG CreateDisposition,
133 IN BOOLEAN DeleteOnClose)
134 {
135 IO_STATUS_BLOCK Iosb = {{0}};
136 OEM_STRING AnsiName;
137 CHAR AnsiNameBuf[512];
138 PFCB Fcb;
139 NTSTATUS Status;
140 FF_FILE *FileHandle;
141
142 /* Only open is permitted */
143 if (CreateDisposition != FILE_OPEN &&
144 CreateDisposition != FILE_OPEN_IF)
145 {
146 Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
147 return Iosb;
148 }
149
150 // TODO: Check dir access
151
152 /* Convert the name to ANSI */
153 AnsiName.Buffer = AnsiNameBuf;
154 AnsiName.Length = 0;
155 AnsiName.MaximumLength = sizeof(AnsiNameBuf);
156 RtlZeroMemory(AnsiNameBuf, sizeof(AnsiNameBuf));
157 Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiName, &FileObject->FileName, FALSE);
158 if (!NT_SUCCESS(Status))
159 {
160 ASSERT(FALSE);
161 }
162
163 /* Open the dir with FullFAT */
164 FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_DIR, NULL);
165
166 if (!FileHandle)
167 {
168 Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND; // FIXME: A shortcut for now
169 return Iosb;
170 }
171
172 /* Create a new DCB for this directory */
173 Fcb = FatCreateDcb(IrpContext, Vcb, ParentDcb, FileHandle);
174
175 /* Set share access */
176 IoSetShareAccess(*DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess);
177
178 /* Set context and section object pointers */
179 FatSetFileObject(FileObject,
180 UserDirectoryOpen,
181 Fcb,
182 FatCreateCcb());
183
184 Iosb.Status = STATUS_SUCCESS;
185 Iosb.Information = FILE_OPENED;
186
187 DPRINT1("Successfully opened dir %s\n", AnsiNameBuf);
188
189 return Iosb;
190 }
191
192 IO_STATUS_BLOCK
193 NTAPI
194 FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext,
195 IN PFILE_OBJECT FileObject,
196 IN PVCB Vcb,
197 IN PFCB ParentDcb,
198 IN PACCESS_MASK DesiredAccess,
199 IN USHORT ShareAccess,
200 IN ULONG AllocationSize,
201 IN PFILE_FULL_EA_INFORMATION EaBuffer,
202 IN ULONG EaLength,
203 IN UCHAR FileAttributes,
204 IN ULONG CreateDisposition,
205 IN BOOLEAN IsPagingFile,
206 IN BOOLEAN DeleteOnClose,
207 IN BOOLEAN IsDosName)
208 {
209 IO_STATUS_BLOCK Iosb = {{0}};
210 OEM_STRING AnsiName;
211 CHAR AnsiNameBuf[512];
212 PFCB Fcb;
213 NTSTATUS Status;
214 FF_FILE *FileHandle;
215
216 /* Check for create file option and fail */
217 if (CreateDisposition == FILE_CREATE)
218 {
219 Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
220 return Iosb;
221 }
222
223 // TODO: Check more params
224
225 /* Convert the name to ANSI */
226 AnsiName.Buffer = AnsiNameBuf;
227 AnsiName.Length = 0;
228 AnsiName.MaximumLength = sizeof(AnsiNameBuf);
229 RtlZeroMemory(AnsiNameBuf, sizeof(AnsiNameBuf));
230 Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiName, &FileObject->FileName, FALSE);
231 if (!NT_SUCCESS(Status))
232 {
233 ASSERT(FALSE);
234 }
235
236 /* Open the file with FullFAT */
237 FileHandle = FF_Open(Vcb->Ioman, AnsiName.Buffer, FF_MODE_READ, NULL);
238
239 if (!FileHandle)
240 {
241 Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND; // FIXME: A shortcut for now
242 return Iosb;
243 }
244
245 /* Create a new FCB for this file */
246 Fcb = FatCreateFcb(IrpContext, Vcb, ParentDcb, FileHandle);
247
248 // TODO: Check if overwrite is needed
249
250 // This is usual file open branch, without overwriting!
251 /* Set context and section object pointers */
252 FatSetFileObject(FileObject,
253 UserFileOpen,
254 Fcb,
255 FatCreateCcb());
256 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
257
258 Iosb.Status = STATUS_SUCCESS;
259 Iosb.Information = FILE_OPENED;
260
261 return Iosb;
262 }
263
264 IO_STATUS_BLOCK
265 NTAPI
266 FatiOpenVolume(IN PFAT_IRP_CONTEXT IrpContext,
267 IN PFILE_OBJECT FileObject,
268 IN PVCB Vcb,
269 IN PACCESS_MASK DesiredAccess,
270 IN USHORT ShareAccess,
271 IN ULONG CreateDisposition)
272 {
273 PCCB Ccb;
274 IO_STATUS_BLOCK Iosb = {{0}};
275 BOOLEAN VolumeFlushed = FALSE;
276
277 /* Check parameters */
278 if (CreateDisposition != FILE_OPEN &&
279 CreateDisposition != FILE_OPEN_IF)
280 {
281 /* Deny access */
282 Iosb.Status = STATUS_ACCESS_DENIED;
283 }
284
285 /* Check if it's exclusive open */
286 if (!FlagOn(ShareAccess, FILE_SHARE_WRITE) &&
287 !FlagOn(ShareAccess, FILE_SHARE_DELETE))
288 {
289 // TODO: Check if exclusive read access requested
290 // and opened handles count is not 0
291 //if (!FlagOn(ShareAccess, FILE_SHARE_READ)
292
293 DPRINT1("Exclusive voume open\n");
294
295 // TODO: Flush the volume
296 VolumeFlushed = TRUE;
297 }
298 else if (FlagOn(*DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA))
299 {
300 DPRINT1("Shared open\n");
301
302 // TODO: Flush the volume
303 VolumeFlushed = TRUE;
304 }
305
306 if (VolumeFlushed &&
307 !FlagOn(Vcb->State, VCB_STATE_MOUNTED_DIRTY) &&
308 FlagOn(Vcb->State, VCB_STATE_FLAG_DIRTY) &&
309 CcIsThereDirtyData(Vcb->Vpb))
310 {
311 UNIMPLEMENTED;
312 }
313
314 /* Set share access */
315 if (Vcb->DirectOpenCount > 0)
316 {
317 /* This volume has already been opened */
318 Iosb.Status = IoCheckShareAccess(*DesiredAccess,
319 ShareAccess,
320 FileObject,
321 &Vcb->ShareAccess,
322 TRUE);
323
324 if (!NT_SUCCESS(Iosb.Status))
325 {
326 ASSERT(FALSE);
327 }
328 }
329 else
330 {
331 /* This is the first time open */
332 IoSetShareAccess(*DesiredAccess,
333 ShareAccess,
334 FileObject,
335 &Vcb->ShareAccess);
336 }
337
338 /* Set file object pointers */
339 Ccb = FatCreateCcb(IrpContext);
340 FatSetFileObject(FileObject, UserVolumeOpen, Vcb, Ccb);
341 FileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
342
343 /* Increase direct open count */
344 Vcb->DirectOpenCount++;
345 Vcb->OpenFileCount++;
346
347 /* Set no buffering flag */
348 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
349
350 // TODO: User's access check
351
352 Iosb.Status = STATUS_SUCCESS;
353 Iosb.Information = FILE_OPENED;
354
355 return Iosb;
356 }
357
358 NTSTATUS
359 NTAPI
360 FatiCreate(IN PFAT_IRP_CONTEXT IrpContext,
361 IN PIRP Irp)
362 {
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;
376
377 /* Control blocks */
378 PVCB Vcb, DecodedVcb, RelatedVcb;
379 PFCB Fcb, NextFcb, RelatedDcb;
380 PCCB Ccb, RelatedCcb;
381 PFCB ParentDcb;
382
383 /* IRP data */
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;
390 ULONG Options;
391 UCHAR FileAttributes;
392 USHORT ShareAccess;
393 ULONG EaLength;
394
395 /* Misc */
396 NTSTATUS Status;
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;
402 FF_ERROR FfError;
403 TYPE_OF_OPEN TypeOfOpen;
404 BOOLEAN OplockPostIrp = FALSE;
405
406 Iosb.Status = STATUS_SUCCESS;
407
408 /* Get current IRP stack location */
409 IrpSp = IoGetCurrentIrpStackLocation(Irp);
410
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 );
425
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'\\'))
430 {
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 );
436
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'\\'))
442 {
443 FatCompleteRequest( IrpContext, Irp, STATUS_OBJECT_NAME_INVALID );
444
445 DPRINT1("FatiCreate: STATUS_OBJECT_NAME_INVALID\n");
446 return STATUS_OBJECT_NAME_INVALID;
447 }
448 }
449
450 /* Make sure we have SecurityContext */
451 ASSERT(IrpSp->Parameters.Create.SecurityContext != NULL);
452
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;
464
465 /* Set VPB to related object's VPB if it exists */
466 if (RelatedFO)
467 FileObject->Vpb = RelatedFO->Vpb;
468
469 /* Prepare file attributes mask */
470 FileAttributes &= (FILE_ATTRIBUTE_READONLY |
471 FILE_ATTRIBUTE_HIDDEN |
472 FILE_ATTRIBUTE_SYSTEM |
473 FILE_ATTRIBUTE_ARCHIVE);
474
475 /* Get the volume control object */
476 Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
477
478 /* Get options */
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);
489
490 /* Calculate create disposition */
491 CreateDisposition = (Options >> 24) & 0x000000ff;
492
493 /* Get Create/Open directory flags based on it */
494 CreateDirectory = (BOOLEAN)(DirectoryFile &&
495 ((CreateDisposition == FILE_CREATE) ||
496 (CreateDisposition == FILE_OPEN_IF)));
497
498 OpenDirectory = (BOOLEAN)(DirectoryFile &&
499 ((CreateDisposition == FILE_OPEN) ||
500 (CreateDisposition == FILE_OPEN_IF)));
501
502 /* Validate parameters: directory/nondirectory mismatch and
503 AllocationSize being more than 4GB */
504 if ((DirectoryFile && NonDirectoryFile) ||
505 Irp->Overlay.AllocationSize.HighPart != 0)
506 {
507 FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER);
508
509 DPRINT1("FatiCreate: STATUS_INVALID_PARAMETER\n", 0);
510 return STATUS_INVALID_PARAMETER;
511 }
512
513 /* Acquire the VCB lock exclusively */
514 if (!FatAcquireExclusiveVcb(IrpContext, Vcb))
515 {
516 // TODO: Postpone the IRP for later processing
517 ASSERT(FALSE);
518 return STATUS_NOT_IMPLEMENTED;
519 }
520
521 // TODO: Verify the VCB
522
523 /* If VCB is locked, then no file openings are possible */
524 if (Vcb->State & VCB_STATE_FLAG_LOCKED)
525 {
526 DPRINT1("This volume is locked\n");
527 Status = STATUS_ACCESS_DENIED;
528
529 /* Cleanup and return */
530 FatReleaseVcb(IrpContext, Vcb);
531 return Status;
532 }
533
534 // TODO: Check if the volume is write protected and disallow DELETE_ON_CLOSE
535
536 // TODO: Make sure EAs aren't supported on FAT32
537
538 /* Check if it's a volume open request */
539 if (FileName.Length == 0)
540 {
541 /* Test related FO to be sure */
542 if (!RelatedFO ||
543 FatDecodeFileObject(RelatedFO, &DecodedVcb, &Fcb, &Ccb) == UserVolumeOpen)
544 {
545 /* Check parameters */
546 if (DirectoryFile || OpenTargetDirectory)
547 {
548 Status = DirectoryFile ? STATUS_NOT_A_DIRECTORY : STATUS_INVALID_PARAMETER;
549
550 /* Unlock VCB */
551 FatReleaseVcb(IrpContext, Vcb);
552
553 /* Complete the request and return */
554 FatCompleteRequest(IrpContext, Irp, Status);
555 return Status;
556 }
557
558 /* It is indeed a volume open request */
559 Iosb = FatiOpenVolume(IrpContext,
560 FileObject,
561 Vcb,
562 DesiredAccess,
563 ShareAccess,
564 CreateDisposition);
565
566 /* Set resulting information */
567 Irp->IoStatus.Information = Iosb.Information;
568
569 /* Unlock VCB */
570 FatReleaseVcb(IrpContext, Vcb);
571
572 /* Complete the request and return */
573 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
574 return Iosb.Status;
575 }
576 }
577
578 /* Check if this is a relative open */
579 if (RelatedFO)
580 {
581 /* Decode the file object */
582 TypeOfOpen = FatDecodeFileObject(RelatedFO,
583 &RelatedVcb,
584 &RelatedDcb,
585 &RelatedCcb);
586
587 /* Check open type */
588 if (TypeOfOpen != UserFileOpen &&
589 TypeOfOpen != UserDirectoryOpen)
590 {
591 DPRINT1("Invalid file object!\n");
592
593 /* Cleanup and return */
594 FatReleaseVcb(IrpContext, Vcb);
595 return STATUS_OBJECT_PATH_NOT_FOUND;
596 }
597
598 /* File path must be relative */
599 if (FileName.Length != 0 &&
600 FileName.Buffer[0] == L'\\')
601 {
602 /* The name is absolute, fail */
603 FatReleaseVcb(IrpContext, Vcb);
604 return STATUS_OBJECT_NAME_INVALID;
605 }
606
607 /* Make sure volume is the same */
608 ASSERT(RelatedVcb == Vcb);
609
610 /* Save VPB */
611 FileObject->Vpb = RelatedFO->Vpb;
612
613 /* Set parent DCB */
614 ParentDcb = RelatedDcb;
615
616 DPRINT1("Opening file '%wZ' relatively to '%wZ'\n", &FileName, &ParentDcb->FullFileName);
617 }
618 else
619 {
620 /* Absolute open */
621 if ((FileName.Length == sizeof(WCHAR)) &&
622 (FileName.Buffer[0] == L'\\'))
623 {
624 /* Check if it's ok to open it */
625 if (NonDirectoryFile)
626 {
627 DPRINT1("Trying to open root dir as a file\n");
628
629 /* Cleanup and return */
630 FatReleaseVcb(IrpContext, Vcb);
631 return STATUS_FILE_IS_A_DIRECTORY;
632 }
633
634 /* Check delete on close on a root dir */
635 if (DeleteOnClose)
636 {
637 /* Cleanup and return */
638 FatReleaseVcb(IrpContext, Vcb);
639 return STATUS_CANNOT_DELETE;
640 }
641
642 /* Call root directory open routine */
643 Iosb = FatiOpenRootDcb(IrpContext,
644 FileObject,
645 Vcb,
646 DesiredAccess,
647 ShareAccess,
648 CreateDisposition);
649
650 Irp->IoStatus.Information = Iosb.Information;
651
652 /* Cleanup and return */
653 FatReleaseVcb(IrpContext, Vcb);
654 return Iosb.Status;
655 }
656 else
657 {
658 /* Not a root dir */
659 ParentDcb = Vcb->RootDcb;
660 DPRINT("ParentDcb %p\n", ParentDcb);
661 }
662 }
663
664 /* Check for backslash at the end */
665 if (FileName.Length &&
666 FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] == L'\\')
667 {
668 /* Cut it out */
669 FileName.Length -= sizeof(WCHAR);
670
671 /* Remember we cut it */
672 EndBackslash = TRUE;
673 }
674
675 /* Ensure the name is set */
676 if (!ParentDcb->FullFileName.Buffer)
677 {
678 /* Set it if it's missing */
679 FatSetFullFileNameInFcb(IrpContext, ParentDcb);
680 }
681
682 /* Check max path length */
683 if (ParentDcb->FullFileName.Length + FileName.Length + sizeof(WCHAR) <= FileName.Length)
684 {
685 DPRINT1("Max length is way off\n");
686 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
687 ASSERT(FALSE);
688 }
689
690 /* Loop through FCBs to find a good one */
691 while (TRUE)
692 {
693 Fcb = ParentDcb;
694
695 /* Dissect the name */
696 RemainingPart = FileName;
697 while (RemainingPart.Length)
698 {
699 FsRtlDissectName(RemainingPart, &FirstName, &NextName);
700
701 /* Check for validity */
702 if ((NextName.Length && NextName.Buffer[0] == L'\\') ||
703 (NextName.Length > 255 * sizeof(WCHAR)))
704 {
705 /* The name is invalid */
706 DPRINT1("Invalid name found\n");
707 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
708 ASSERT(FALSE);
709 }
710
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);
716
717 if (!NT_SUCCESS(Status))
718 {
719 DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status);
720 ASSERT(FALSE);
721 NextFcb = NULL;
722 AnsiFirstName.Length = 0;
723 }
724 else
725 {
726 /* Find the coresponding FCB */
727 NextFcb = FatFindFcb(IrpContext,
728 &Fcb->Dcb.SplayLinksAnsi,
729 (PSTRING)&AnsiFirstName,
730 &OpenedAsDos);
731 }
732
733 /* If nothing found - try with unicode */
734 if (!NextFcb && Fcb->Dcb.SplayLinksUnicode)
735 {
736 FileNameUpcased.Buffer = FsRtlAllocatePool(PagedPool, FirstName.Length);
737 FileNameUpcased.Length = 0;
738 FileNameUpcased.MaximumLength = FirstName.Length;
739
740 /* Downcase and then upcase to normalize it */
741 Status = RtlDowncaseUnicodeString(&FileNameUpcased, &FirstName, FALSE);
742 Status = RtlUpcaseUnicodeString(&FileNameUpcased, &FileNameUpcased, FALSE);
743
744 /* Try to find FCB again using unicode name */
745 NextFcb = FatFindFcb(IrpContext,
746 &Fcb->Dcb.SplayLinksUnicode,
747 (PSTRING)&FileNameUpcased,
748 &OpenedAsDos);
749 }
750
751 /* Move to the next FCB */
752 if (NextFcb)
753 {
754 Fcb = NextFcb;
755 RemainingPart = NextName;
756 }
757
758 /* Break out of this loop if nothing can be found */
759 if (!NextFcb ||
760 NextName.Length == 0 ||
761 FatNodeType(NextFcb) == FAT_NTC_FCB)
762 {
763 break;
764 }
765 }
766
767 /* Ensure remaining name doesn't start from a backslash */
768 if (RemainingPart.Length &&
769 RemainingPart.Buffer[0] == L'\\')
770 {
771 /* Cut it */
772 RemainingPart.Buffer++;
773 RemainingPart.Length -= sizeof(WCHAR);
774 }
775
776 if (Fcb->Condition == FcbGood)
777 {
778 /* Good FCB, break out of the loop */
779 break;
780 }
781 else
782 {
783 ASSERT(FALSE);
784 }
785 }
786
787 /* We have a valid FCB now */
788 if (!RemainingPart.Length)
789 {
790 /* Check for target dir open */
791 if (OpenTargetDirectory)
792 {
793 DPRINT1("Opening target dir is missing\n");
794 ASSERT(FALSE);
795 }
796
797 /* Check this FCB's type */
798 if (FatNodeType(Fcb) == FAT_NTC_ROOT_DCB ||
799 FatNodeType(Fcb) == FAT_NTC_DCB)
800 {
801 /* Open a directory */
802 if (NonDirectoryFile)
803 {
804 /* Forbidden */
805 Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
806 ASSERT(FALSE);
807 return Iosb.Status;
808 }
809
810 /* Open existing DCB */
811 Iosb = FatiOpenExistingDcb(IrpContext,
812 FileObject,
813 Vcb,
814 Fcb,
815 DesiredAccess,
816 ShareAccess,
817 CreateDisposition,
818 NoEaKnowledge,
819 DeleteOnClose);
820
821 /* Save information */
822 Irp->IoStatus.Information = Iosb.Information;
823
824 /* Unlock VCB */
825 FatReleaseVcb(IrpContext, Vcb);
826
827 /* Complete the request */
828 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
829
830 return Iosb.Status;
831 }
832 else if (FatNodeType(Fcb) == FAT_NTC_FCB)
833 {
834 /* Open a file */
835 if (OpenDirectory)
836 {
837 /* Forbidden */
838 Iosb.Status = STATUS_NOT_A_DIRECTORY;
839 ASSERT(FALSE);
840 return Iosb.Status;
841 }
842
843 /* Check for trailing backslash */
844 if (EndBackslash)
845 {
846 /* Forbidden */
847 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
848 ASSERT(FALSE);
849 return Iosb.Status;
850 }
851
852 Iosb = FatiOpenExistingFcb(IrpContext,
853 FileObject,
854 Vcb,
855 Fcb,
856 DesiredAccess,
857 ShareAccess,
858 AllocationSize,
859 EaBuffer,
860 EaLength,
861 FileAttributes,
862 CreateDisposition,
863 NoEaKnowledge,
864 DeleteOnClose,
865 OpenedAsDos,
866 &OplockPostIrp);
867
868 /* Check if it's pending */
869 if (Iosb.Status != STATUS_PENDING)
870 {
871 /* In case of success set cache supported flag */
872 if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering)
873 {
874 SetFlag(FileObject->Flags, FO_CACHE_SUPPORTED);
875 }
876
877 /* Save information */
878 Irp->IoStatus.Information = Iosb.Information;
879
880 /* Unlock VCB */
881 FatReleaseVcb(IrpContext, Vcb);
882
883 /* Complete the request */
884 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
885
886 return Iosb.Status;
887 }
888 else
889 {
890 /* Queue this IRP */
891 UNIMPLEMENTED;
892 ASSERT(FALSE);
893 }
894 }
895 else
896 {
897 /* Unexpected FCB type */
898 KeBugCheckEx(/*FAT_FILE_SYSTEM*/0x23, __LINE__, (ULONG_PTR)Fcb, 0, 0);
899 }
900 }
901
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)
906 {
907 DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb));
908 ASSERT(FALSE);
909 }
910
911 /* Create additional DCBs for all path items */
912 ParentDcb = Fcb;
913 while (TRUE)
914 {
915 FsRtlDissectName(RemainingPart, &FirstName, &RemainingPart);
916
917 /* Check for validity */
918 if ((RemainingPart.Length && RemainingPart.Buffer[0] == L'\\') ||
919 (NextName.Length > 255 * sizeof(WCHAR)))
920 {
921 /* The name is invalid */
922 DPRINT1("Invalid name found\n");
923 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
924 ASSERT(FALSE);
925 }
926
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);
932
933 if (!NT_SUCCESS(Status))
934 {
935 ASSERT(FALSE);
936 }
937
938 DPRINT("FirstName %wZ, RemainingPart %wZ\n", &FirstName, &RemainingPart);
939
940 /* Break if came to the end */
941 if (!RemainingPart.Length) break;
942
943 /* Create a DCB for this entry */
944 ParentDcb = FatCreateDcb(IrpContext,
945 Vcb,
946 ParentDcb,
947 NULL);
948
949 /* Set its name */
950 FatSetFullNameInFcb(ParentDcb, &FirstName);
951 }
952
953 /* Try to open it and get a result, saying if this is a dir or a file */
954 FfError = FatiTryToOpen(FileObject, Vcb);
955
956 /* Check if we need to open target directory */
957 if (OpenTargetDirectory)
958 {
959 // TODO: Open target directory
960 UNIMPLEMENTED;
961 }
962
963 /* Check, if path is a directory or a file */
964 if (FfError == FF_ERR_FILE_OBJECT_IS_A_DIR)
965 {
966 if (NonDirectoryFile)
967 {
968 DPRINT1("Can't open dir as a file\n");
969
970 /* Unlock VCB */
971 FatReleaseVcb(IrpContext, Vcb);
972
973 /* Complete the request */
974 Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
975 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
976 return Iosb.Status;
977 }
978
979 /* Open this directory */
980 Iosb = FatiOpenExistingDir(IrpContext,
981 FileObject,
982 Vcb,
983 ParentDcb,
984 DesiredAccess,
985 ShareAccess,
986 AllocationSize,
987 EaBuffer,
988 EaLength,
989 FileAttributes,
990 CreateDisposition,
991 DeleteOnClose);
992
993 Irp->IoStatus.Information = Iosb.Information;
994
995 /* Unlock VCB */
996 FatReleaseVcb(IrpContext, Vcb);
997
998 /* Complete the request */
999 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
1000
1001 return Iosb.Status;
1002 }
1003
1004 /* If end backslash here, then it's definately not permitted,
1005 since we're opening files here */
1006 if (EndBackslash)
1007 {
1008 /* Unlock VCB */
1009 FatReleaseVcb(IrpContext, Vcb);
1010
1011 /* Complete the request */
1012 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
1013 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
1014 return Iosb.Status;
1015 }
1016
1017 /* Try to open the file */
1018 Iosb = FatiOpenExistingFile(IrpContext,
1019 FileObject,
1020 Vcb,
1021 ParentDcb,
1022 DesiredAccess,
1023 ShareAccess,
1024 AllocationSize,
1025 EaBuffer,
1026 EaLength,
1027 FileAttributes,
1028 CreateDisposition,
1029 FALSE,
1030 DeleteOnClose,
1031 OpenedAsDos);
1032
1033 Irp->IoStatus.Information = Iosb.Information;
1034
1035 /* Unlock VCB */
1036 FatReleaseVcb(IrpContext, Vcb);
1037
1038 /* Complete the request */
1039 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
1040
1041 return Iosb.Status;
1042 }
1043
1044 NTSTATUS
1045 NTAPI
1046 FatCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1047 {
1048 PFAT_IRP_CONTEXT IrpContext;
1049 NTSTATUS Status;
1050
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)
1054 {
1055 /* Complete the request and return success */
1056 Irp->IoStatus.Status = STATUS_SUCCESS;
1057 Irp->IoStatus.Information = FILE_OPENED;
1058
1059 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1060
1061 return STATUS_SUCCESS;
1062 }
1063
1064 /* Enter FsRtl critical region */
1065 FsRtlEnterFileSystem();
1066
1067 /* Build an irp context */
1068 IrpContext = FatBuildIrpContext(Irp, TRUE);
1069
1070 /* Call internal function */
1071 Status = FatiCreate(IrpContext, Irp);
1072
1073 /* Leave FsRtl critical region */
1074 FsRtlExitFileSystem();
1075
1076 return Status;
1077 }
1078
1079 /* EOF */