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