[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
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
610 /* Check for backslash at the end */
611 if (FileName.Length &&
612 FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] == L'\\')
613 {
614 /* Cut it out */
615 FileName.Length -= sizeof(WCHAR);
616
617 /* Remember we cut it */
618 EndBackslash = TRUE;
619 }
620
621 /* Ensure the name is set */
622 if (!ParentDcb->FullFileName.Buffer)
623 {
624 /* Set it if it's missing */
625 FatSetFullFileNameInFcb(IrpContext, ParentDcb);
626 }
627
628 /* Check max path length */
629 if (ParentDcb->FullFileName.Length + FileName.Length + sizeof(WCHAR) <= FileName.Length)
630 {
631 DPRINT1("Max length is way off\n");
632 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
633 ASSERT(FALSE);
634 }
635
636 /* Loop through FCBs to find a good one */
637 while (TRUE)
638 {
639 Fcb = ParentDcb;
640
641 /* Dissect the name */
642 RemainingPart = FileName;
643 while (RemainingPart.Length)
644 {
645 FsRtlDissectName(RemainingPart, &FirstName, &NextName);
646
647 /* Check for validity */
648 if ((NextName.Length && NextName.Buffer[0] == L'\\') ||
649 (NextName.Length > 255 * sizeof(WCHAR)))
650 {
651 /* The name is invalid */
652 DPRINT1("Invalid name found\n");
653 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
654 ASSERT(FALSE);
655 }
656
657 /* Convert the name to ANSI */
658 AnsiFirstName.Buffer = ExAllocatePool(PagedPool, FirstName.Length);
659 AnsiFirstName.Length = 0;
660 AnsiFirstName.MaximumLength = FirstName.Length;
661 Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName, &FirstName, FALSE);
662
663 if (!NT_SUCCESS(Status))
664 {
665 DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status);
666 ASSERT(FALSE);
667 NextFcb = NULL;
668 AnsiFirstName.Length = 0;
669 }
670 else
671 {
672 /* Find the coresponding FCB */
673 NextFcb = FatFindFcb(IrpContext,
674 &Fcb->Dcb.SplayLinksAnsi,
675 (PSTRING)&AnsiFirstName,
676 &OpenedAsDos);
677 }
678
679 /* If nothing found - try with unicode */
680 if (!NextFcb && Fcb->Dcb.SplayLinksUnicode)
681 {
682 FileNameUpcased.Buffer = FsRtlAllocatePool(PagedPool, FirstName.Length);
683 FileNameUpcased.Length = 0;
684 FileNameUpcased.MaximumLength = FirstName.Length;
685
686 /* Downcase and then upcase to normalize it */
687 Status = RtlDowncaseUnicodeString(&FileNameUpcased, &FirstName, FALSE);
688 Status = RtlUpcaseUnicodeString(&FileNameUpcased, &FileNameUpcased, FALSE);
689
690 /* Try to find FCB again using unicode name */
691 NextFcb = FatFindFcb(IrpContext,
692 &Fcb->Dcb.SplayLinksUnicode,
693 (PSTRING)&FileNameUpcased,
694 &OpenedAsDos);
695 }
696
697 /* Move to the next FCB */
698 if (NextFcb)
699 {
700 Fcb = NextFcb;
701 RemainingPart = NextName;
702 }
703
704 /* Break out of this loop if nothing can be found */
705 if (!NextFcb ||
706 NextName.Length == 0 ||
707 FatNodeType(NextFcb) == FAT_NTC_FCB)
708 {
709 break;
710 }
711 }
712
713 /* Ensure remaining name doesn't start from a backslash */
714 if (RemainingPart.Length &&
715 RemainingPart.Buffer[0] == L'\\')
716 {
717 /* Cut it */
718 RemainingPart.Buffer++;
719 RemainingPart.Length -= sizeof(WCHAR);
720 }
721
722 if (Fcb->Condition == FcbGood)
723 {
724 /* Good FCB, break out of the loop */
725 break;
726 }
727 else
728 {
729 ASSERT(FALSE);
730 }
731 }
732
733 /* We have a valid FCB now */
734 if (!RemainingPart.Length)
735 {
736 /* Check for target dir open */
737 if (OpenTargetDirectory)
738 {
739 DPRINT1("Opening target dir is missing\n");
740 ASSERT(FALSE);
741 }
742
743 /* Check this FCB's type */
744 if (FatNodeType(Fcb) == FAT_NTC_ROOT_DCB ||
745 FatNodeType(Fcb) == FAT_NTC_DCB)
746 {
747 /* Open a directory */
748 if (NonDirectoryFile)
749 {
750 /* Forbidden */
751 Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
752 ASSERT(FALSE);
753 return Iosb.Status;
754 }
755
756 /* Open existing DCB */
757 Iosb = FatiOpenExistingDcb(IrpContext,
758 FileObject,
759 Vcb,
760 Fcb,
761 DesiredAccess,
762 ShareAccess,
763 CreateDisposition,
764 NoEaKnowledge,
765 DeleteOnClose);
766
767 /* Save information */
768 Irp->IoStatus.Information = Iosb.Information;
769
770 /* Unlock VCB */
771 FatReleaseVcb(IrpContext, Vcb);
772
773 /* Complete the request */
774 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
775
776 return Iosb.Status;
777 }
778 else if (FatNodeType(Fcb) == FAT_NTC_FCB)
779 {
780 /* Open a file */
781 if (OpenDirectory)
782 {
783 /* Forbidden */
784 Iosb.Status = STATUS_NOT_A_DIRECTORY;
785 ASSERT(FALSE);
786 return Iosb.Status;
787 }
788
789 /* Check for trailing backslash */
790 if (EndBackslash)
791 {
792 /* Forbidden */
793 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
794 ASSERT(FALSE);
795 return Iosb.Status;
796 }
797
798 Iosb = FatiOpenExistingFcb(IrpContext,
799 FileObject,
800 Vcb,
801 Fcb,
802 DesiredAccess,
803 ShareAccess,
804 AllocationSize,
805 EaBuffer,
806 EaLength,
807 FileAttributes,
808 CreateDisposition,
809 NoEaKnowledge,
810 DeleteOnClose,
811 OpenedAsDos,
812 &OplockPostIrp);
813
814 /* Check if it's pending */
815 if (Iosb.Status != STATUS_PENDING)
816 {
817 /* In case of success set cache supported flag */
818 if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering)
819 {
820 SetFlag(FileObject->Flags, FO_CACHE_SUPPORTED);
821 }
822
823 /* Save information */
824 Irp->IoStatus.Information = Iosb.Information;
825
826 /* Unlock VCB */
827 FatReleaseVcb(IrpContext, Vcb);
828
829 /* Complete the request */
830 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
831
832 return Iosb.Status;
833 }
834 else
835 {
836 /* Queue this IRP */
837 UNIMPLEMENTED;
838 ASSERT(FALSE);
839 }
840 }
841 else
842 {
843 /* Unexpected FCB type */
844 KeBugCheckEx(/*FAT_FILE_SYSTEM*/0x23, __LINE__, (ULONG_PTR)Fcb, 0, 0);
845 }
846 }
847
848 /* During parsing we encountered a part which has no attached FCB/DCB.
849 Check that the parent is really DCB and not FCB */
850 if (FatNodeType(Fcb) != FAT_NTC_ROOT_DCB &&
851 FatNodeType(Fcb) != FAT_NTC_DCB)
852 {
853 DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb));
854 ASSERT(FALSE);
855 }
856
857 /* Create additional DCBs for all path items */
858 ParentDcb = Fcb;
859 while (TRUE)
860 {
861 FsRtlDissectName(RemainingPart, &FirstName, &RemainingPart);
862
863 /* Check for validity */
864 if ((RemainingPart.Length && RemainingPart.Buffer[0] == L'\\') ||
865 (NextName.Length > 255 * sizeof(WCHAR)))
866 {
867 /* The name is invalid */
868 DPRINT1("Invalid name found\n");
869 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
870 ASSERT(FALSE);
871 }
872
873 /* Convert the name to ANSI */
874 AnsiFirstName.Buffer = ExAllocatePool(PagedPool, FirstName.Length);
875 AnsiFirstName.Length = 0;
876 AnsiFirstName.MaximumLength = FirstName.Length;
877 Status = RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName, &FirstName, FALSE);
878
879 if (!NT_SUCCESS(Status))
880 {
881 ASSERT(FALSE);
882 }
883
884 DPRINT("FirstName %wZ, RemainingPart %wZ\n", &FirstName, &RemainingPart);
885
886 /* Break if came to the end */
887 if (!RemainingPart.Length) break;
888
889 /* Create a DCB for this entry */
890 ParentDcb = FatCreateDcb(IrpContext,
891 Vcb,
892 ParentDcb,
893 NULL);
894
895 /* Set its name */
896 FatSetFullNameInFcb(ParentDcb, &FirstName);
897 }
898
899 /* Try to open it and get a result, saying if this is a dir or a file */
900 FfError = FatiTryToOpen(FileObject, Vcb);
901
902 /* Check if we need to open target directory */
903 if (OpenTargetDirectory)
904 {
905 // TODO: Open target directory
906 UNIMPLEMENTED;
907 }
908
909 /* Check, if path is a directory or a file */
910 if (FfError == FF_ERR_FILE_OBJECT_IS_A_DIR)
911 {
912 if (NonDirectoryFile)
913 {
914 DPRINT1("Can't open dir as a file\n");
915
916 /* Unlock VCB */
917 FatReleaseVcb(IrpContext, Vcb);
918
919 /* Complete the request */
920 Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
921 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
922 return Iosb.Status;
923 }
924
925 /* Open this directory */
926 Iosb = FatiOpenExistingDir(IrpContext,
927 FileObject,
928 Vcb,
929 ParentDcb,
930 DesiredAccess,
931 ShareAccess,
932 AllocationSize,
933 EaBuffer,
934 EaLength,
935 FileAttributes,
936 CreateDisposition,
937 DeleteOnClose);
938
939 Irp->IoStatus.Information = Iosb.Information;
940
941 /* Unlock VCB */
942 FatReleaseVcb(IrpContext, Vcb);
943
944 /* Complete the request */
945 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
946
947 return Iosb.Status;
948 }
949
950 /* If end backslash here, then it's definately not permitted,
951 since we're opening files here */
952 if (EndBackslash)
953 {
954 /* Unlock VCB */
955 FatReleaseVcb(IrpContext, Vcb);
956
957 /* Complete the request */
958 Iosb.Status = STATUS_OBJECT_NAME_INVALID;
959 FatCompleteRequest(IrpContext, Irp, Iosb.Status);
960 return Iosb.Status;
961 }
962
963 /* Try to open the file */
964 Iosb = FatiOpenExistingFile(IrpContext,
965 FileObject,
966 Vcb,
967 ParentDcb,
968 DesiredAccess,
969 ShareAccess,
970 AllocationSize,
971 EaBuffer,
972 EaLength,
973 FileAttributes,
974 CreateDisposition,
975 FALSE,
976 DeleteOnClose,
977 OpenedAsDos);
978
979 Irp->IoStatus.Information = Iosb.Information;
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 */