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