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