c702a30e7e3f96122bc008ee362e60a843cff310
[reactos.git] / reactos / drivers / fs / vfat / create.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/fs/vfat/create.c
22 * PURPOSE: VFAT Filesystem
23 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
24 * Hartmut Birr
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #define NDEBUG
30 #include "vfat.h"
31
32 /* FUNCTIONS *****************************************************************/
33
34 void
35 vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
36 {
37 OEM_STRING StringA;
38 USHORT Length;
39 CHAR cString[12];
40
41 RtlCopyMemory(cString, pEntry->ShortName, 11);
42 cString[11] = 0;
43 if (cString[0] == 0x05)
44 {
45 cString[0] = 0xe5;
46 }
47
48 StringA.Buffer = cString;
49 for (StringA.Length = 0;
50 StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' ';
51 StringA.Length++);
52 StringA.MaximumLength = StringA.Length;
53
54 RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
55
56 if (pEntry->lCase & VFAT_CASE_LOWER_BASE)
57 {
58 RtlDowncaseUnicodeString(NameU, NameU, FALSE);
59 }
60 if (cString[8] != ' ')
61 {
62 Length = NameU->Length;
63 NameU->Buffer += Length / sizeof(WCHAR);
64 if (!FAT_ENTRY_VOLUME(pEntry))
65 {
66 Length += sizeof(WCHAR);
67 NameU->Buffer[0] = L'.';
68 NameU->Buffer++;
69 }
70 NameU->Length = 0;
71 NameU->MaximumLength -= Length;
72
73 StringA.Buffer = &cString[8];
74 for (StringA.Length = 0;
75 StringA.Length < 3 && StringA.Buffer[StringA.Length] != ' ';
76 StringA.Length++);
77 StringA.MaximumLength = StringA.Length;
78 RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
79 if (pEntry->lCase & VFAT_CASE_LOWER_EXT)
80 {
81 RtlDowncaseUnicodeString(NameU, NameU, FALSE);
82 }
83 NameU->Buffer -= Length / sizeof(WCHAR);
84 NameU->Length += Length;
85 NameU->MaximumLength += Length;
86 }
87 NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
88 DPRINT("'%wZ'\n", NameU);
89 }
90
91 NTSTATUS
92 ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
93 /*
94 * FUNCTION: Read the volume label
95 */
96 {
97 PVOID Context = NULL;
98 ULONG DirIndex = 0;
99 PDIR_ENTRY Entry;
100 PVFATFCB pFcb;
101 LARGE_INTEGER FileOffset;
102 UNICODE_STRING NameU;
103 ULONG SizeDirEntry;
104 ULONG EntriesPerPage;
105 OEM_STRING StringO;
106
107 NameU.Buffer = Vpb->VolumeLabel;
108 NameU.Length = 0;
109 NameU.MaximumLength = sizeof(Vpb->VolumeLabel);
110 *(Vpb->VolumeLabel) = 0;
111 Vpb->VolumeLabelLength = 0;
112
113 if (DeviceExt->Flags & VCB_IS_FATX)
114 {
115 SizeDirEntry = sizeof(FATX_DIR_ENTRY);
116 EntriesPerPage = FATX_ENTRIES_PER_PAGE;
117 }
118 else
119 {
120 SizeDirEntry = sizeof(FAT_DIR_ENTRY);
121 EntriesPerPage = FAT_ENTRIES_PER_PAGE;
122 }
123
124 ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
125 pFcb = vfatOpenRootFCB (DeviceExt);
126 ExReleaseResourceLite (&DeviceExt->DirResource);
127
128 FileOffset.QuadPart = 0;
129 if (CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
130 {
131 while (TRUE)
132 {
133 if (ENTRY_VOLUME(DeviceExt, Entry))
134 {
135 /* copy volume label */
136 if (DeviceExt->Flags & VCB_IS_FATX)
137 {
138 StringO.Buffer = (PCHAR)Entry->FatX.Filename;
139 StringO.MaximumLength = StringO.Length = Entry->FatX.FilenameLength;
140 RtlOemStringToUnicodeString(&NameU, &StringO, FALSE);
141 }
142 else
143 {
144 vfat8Dot3ToString (&Entry->Fat, &NameU);
145 }
146 Vpb->VolumeLabelLength = NameU.Length;
147 break;
148 }
149 if (ENTRY_END(DeviceExt, Entry))
150 {
151 break;
152 }
153 DirIndex++;
154 Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
155 if ((DirIndex % EntriesPerPage) == 0)
156 {
157 CcUnpinData(Context);
158 FileOffset.u.LowPart += PAGE_SIZE;
159 if (!CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
160 {
161 Context = NULL;
162 break;
163 }
164 }
165 }
166 if (Context)
167 {
168 CcUnpinData(Context);
169 }
170 }
171 ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
172 vfatReleaseFCB (DeviceExt, pFcb);
173 ExReleaseResourceLite (&DeviceExt->DirResource);
174
175 return STATUS_SUCCESS;
176 }
177
178 NTSTATUS
179 FindFile (
180 PDEVICE_EXTENSION DeviceExt,
181 PVFATFCB Parent,
182 PUNICODE_STRING FileToFindU,
183 PVFAT_DIRENTRY_CONTEXT DirContext,
184 BOOLEAN First)
185 /*
186 * FUNCTION: Find a file
187 */
188 {
189 PWCHAR PathNameBuffer;
190 USHORT PathNameBufferLength;
191 NTSTATUS Status;
192 PVOID Context = NULL;
193 PVOID Page;
194 PVFATFCB rcFcb;
195 BOOLEAN Found;
196 UNICODE_STRING PathNameU;
197 UNICODE_STRING FileToFindUpcase;
198 BOOLEAN WildCard;
199
200 DPRINT ("FindFile(Parent %x, FileToFind '%wZ', DirIndex: %d)\n",
201 Parent, FileToFindU, DirContext->DirIndex);
202 DPRINT ("FindFile: Path %wZ)\n",&Parent->PathNameU);
203
204 PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR);
205 PathNameBuffer = ExAllocatePool(NonPagedPool, PathNameBufferLength + sizeof(WCHAR));
206 if (!PathNameBuffer)
207 {
208 CHECKPOINT1;
209 return STATUS_INSUFFICIENT_RESOURCES;
210 }
211
212 PathNameU.Buffer = PathNameBuffer;
213 PathNameU.Length = 0;
214 PathNameU.MaximumLength = PathNameBufferLength;
215
216 DirContext->LongNameU.Length = 0;
217 DirContext->ShortNameU.Length = 0;
218
219 WildCard = FsRtlDoesNameContainWildCards(FileToFindU);
220
221 if (WildCard == FALSE)
222 {
223 /* if there is no '*?' in the search name, than look first for an existing fcb */
224 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
225 if (!vfatFCBIsRoot(Parent))
226 {
227 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
228 PathNameU.Length += sizeof(WCHAR);
229 }
230 RtlAppendUnicodeStringToString(&PathNameU, FileToFindU);
231 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
232 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
233 if (rcFcb)
234 {
235 ULONG startIndex = rcFcb->startIndex;
236 if ((rcFcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Parent))
237 {
238 startIndex += 2;
239 }
240 if(startIndex >= DirContext->DirIndex)
241 {
242 RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU);
243 RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU);
244 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
245 DirContext->StartIndex = rcFcb->startIndex;
246 DirContext->DirIndex = rcFcb->dirIndex;
247 DPRINT("FindFile: new Name %wZ, DirIndex %d (%d)\n",
248 &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex);
249 Status = STATUS_SUCCESS;
250 }
251 else
252 {
253 CHECKPOINT1;
254 Status = STATUS_UNSUCCESSFUL;
255 }
256 vfatReleaseFCB(DeviceExt, rcFcb);
257 ExFreePool(PathNameBuffer);
258 return Status;
259 }
260 }
261
262 /* FsRtlIsNameInExpression need the searched string to be upcase,
263 * even if IgnoreCase is specified */
264 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE);
265 if (!NT_SUCCESS(Status))
266 {
267 CHECKPOINT;
268 ExFreePool(PathNameBuffer);
269 return Status;
270 }
271
272 while(TRUE)
273 {
274 Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
275 First = FALSE;
276 if (Status == STATUS_NO_MORE_ENTRIES)
277 {
278 break;
279 }
280 if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
281 {
282 DirContext->DirIndex++;
283 continue;
284 }
285 if (WildCard)
286 {
287 Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) ||
288 FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL);
289 }
290 else
291 {
292 Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
293 FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
294 }
295
296 if (Found)
297 {
298 if (WildCard)
299 {
300 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
301 if (!vfatFCBIsRoot(Parent))
302 {
303 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
304 PathNameU.Length += sizeof(WCHAR);
305 }
306 RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU);
307 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
308 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
309 if (rcFcb != NULL)
310 {
311 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
312 vfatReleaseFCB(DeviceExt, rcFcb);
313 }
314 }
315 DPRINT("%d\n", DirContext->LongNameU.Length);
316 DPRINT("FindFile: new Name %wZ, DirIndex %d\n",
317 &DirContext->LongNameU, DirContext->DirIndex);
318
319 if (Context)
320 {
321 CcUnpinData(Context);
322 }
323 RtlFreeUnicodeString(&FileToFindUpcase);
324 ExFreePool(PathNameBuffer);
325 return STATUS_SUCCESS;
326 }
327 DirContext->DirIndex++;
328 }
329
330 if (Context)
331 {
332 CcUnpinData(Context);
333 }
334
335 RtlFreeUnicodeString(&FileToFindUpcase);
336 ExFreePool(PathNameBuffer);
337 return Status;
338 }
339
340 static
341 NTSTATUS
342 VfatOpenFile (
343 PDEVICE_EXTENSION DeviceExt,
344 PUNICODE_STRING PathNameU,
345 PFILE_OBJECT FileObject,
346 PVFATFCB* ParentFcb )
347 /*
348 * FUNCTION: Opens a file
349 */
350 {
351 PVFATFCB Fcb;
352 NTSTATUS Status;
353
354 DPRINT ("VfatOpenFile(%08lx, '%wZ', %08lx, %08lx)\n", DeviceExt, PathNameU, FileObject, ParentFcb);
355
356 if (FileObject->RelatedFileObject)
357 {
358 DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
359
360 *ParentFcb = FileObject->RelatedFileObject->FsContext;
361 (*ParentFcb)->RefCount++;
362 }
363 else
364 {
365 *ParentFcb = NULL;
366 }
367
368 if (!DeviceExt->FatInfo.FixedMedia)
369 {
370 Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice,
371 IOCTL_DISK_CHECK_VERIFY,
372 NULL,
373 0,
374 NULL,
375 0,
376 FALSE);
377
378 if (Status == STATUS_VERIFY_REQUIRED)
379
380 {
381 PDEVICE_OBJECT DeviceToVerify;
382
383 DPRINT ("Media change detected!\n");
384 DPRINT ("Device %p\n", DeviceExt->StorageDevice);
385
386 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
387
388 IoSetDeviceToVerify (PsGetCurrentThread (),
389 NULL);
390 Status = IoVerifyVolume (DeviceExt->StorageDevice,
391 FALSE);
392 }
393 if (!NT_SUCCESS(Status))
394 {
395 DPRINT ("Status %lx\n", Status);
396 *ParentFcb = NULL;
397 return Status;
398 }
399 }
400
401 if (*ParentFcb)
402 {
403 (*ParentFcb)->RefCount++;
404 }
405
406 /* try first to find an existing FCB in memory */
407 DPRINT ("Checking for existing FCB in memory\n");
408
409 Status = vfatGetFCBForFile (DeviceExt, ParentFcb, &Fcb, PathNameU);
410 if (!NT_SUCCESS (Status))
411 {
412 DPRINT ("Could not make a new FCB, status: %x\n", Status);
413 return Status;
414 }
415 if (Fcb->Flags & FCB_DELETE_PENDING)
416 {
417 vfatReleaseFCB (DeviceExt, Fcb);
418 return STATUS_DELETE_PENDING;
419 }
420 DPRINT ("Attaching FCB to fileObject\n");
421 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
422 if (!NT_SUCCESS(Status))
423 {
424 vfatReleaseFCB (DeviceExt, Fcb);
425 }
426 return Status;
427 }
428
429 static NTSTATUS
430 VfatCreateFile ( PDEVICE_OBJECT DeviceObject, PIRP Irp )
431 /*
432 * FUNCTION: Create or open a file
433 */
434 {
435 PIO_STACK_LOCATION Stack;
436 PFILE_OBJECT FileObject;
437 NTSTATUS Status = STATUS_SUCCESS;
438 PDEVICE_EXTENSION DeviceExt;
439 ULONG RequestedDisposition, RequestedOptions;
440 PVFATCCB pCcb;
441 PVFATFCB pFcb = NULL;
442 PVFATFCB ParentFcb;
443 PWCHAR c, last;
444 BOOLEAN PagingFileCreate = FALSE;
445 BOOLEAN Dots;
446 UNICODE_STRING FileNameU;
447 UNICODE_STRING PathNameU;
448
449 /* Unpack the various parameters. */
450 Stack = IoGetCurrentIrpStackLocation (Irp);
451 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
452 RequestedOptions =
453 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
454 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
455 FileObject = Stack->FileObject;
456 DeviceExt = DeviceObject->DeviceExtension;
457
458 /* Check their validity. */
459 if (RequestedOptions & FILE_DIRECTORY_FILE &&
460 RequestedDisposition == FILE_SUPERSEDE)
461 {
462 return(STATUS_INVALID_PARAMETER);
463 }
464
465 if (RequestedOptions & FILE_DIRECTORY_FILE &&
466 RequestedOptions & FILE_NON_DIRECTORY_FILE)
467 {
468 return(STATUS_INVALID_PARAMETER);
469 }
470
471 /* This a open operation for the volume itself */
472 if (FileObject->FileName.Length == 0 &&
473 FileObject->RelatedFileObject == NULL)
474 {
475 if (RequestedDisposition == FILE_CREATE ||
476 RequestedDisposition == FILE_OVERWRITE_IF ||
477 RequestedDisposition == FILE_SUPERSEDE)
478 {
479 return(STATUS_ACCESS_DENIED);
480 }
481 if (RequestedOptions & FILE_DIRECTORY_FILE)
482 {
483 return(STATUS_NOT_A_DIRECTORY);
484 }
485 pFcb = DeviceExt->VolumeFcb;
486 pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
487 if (pCcb == NULL)
488 {
489 return (STATUS_INSUFFICIENT_RESOURCES);
490 }
491 RtlZeroMemory(pCcb, sizeof(VFATCCB));
492 FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
493 FileObject->FsContext = pFcb;
494 FileObject->FsContext2 = pCcb;
495 pFcb->RefCount++;
496
497 Irp->IoStatus.Information = FILE_OPENED;
498 return(STATUS_SUCCESS);
499 }
500
501 /*
502 * Check for illegal characters and illegale dot sequences in the file name
503 */
504 PathNameU = FileObject->FileName;
505 c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR);
506 last = c - 1;
507 Dots = TRUE;
508 while (c-- > PathNameU.Buffer)
509 {
510 if (*c == L'\\' || c == PathNameU.Buffer)
511 {
512 if (Dots && last > c)
513 {
514 return(STATUS_OBJECT_NAME_INVALID);
515 }
516 last = c - 1;
517 Dots = TRUE;
518 }
519 else if (*c != L'.')
520 {
521 Dots = FALSE;
522 }
523
524 if (*c != '\\' && vfatIsLongIllegal(*c))
525 {
526 return(STATUS_OBJECT_NAME_INVALID);
527 }
528 }
529 if (FileObject->RelatedFileObject && PathNameU.Buffer[0] == L'\\')
530 {
531 return(STATUS_OBJECT_NAME_INVALID);
532 }
533 if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\')
534 {
535 PathNameU.Length -= sizeof(WCHAR);
536 }
537
538 /* Try opening the file. */
539 Status = VfatOpenFile (DeviceExt, &PathNameU, FileObject, &ParentFcb);
540
541 /*
542 * If the directory containing the file to open doesn't exist then
543 * fail immediately
544 */
545 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
546 Status == STATUS_INVALID_PARAMETER ||
547 Status == STATUS_DELETE_PENDING)
548 {
549 if (ParentFcb)
550 {
551 vfatReleaseFCB (DeviceExt, ParentFcb);
552 }
553 return(Status);
554 }
555
556 /*
557 * If the file open failed then create the required file
558 */
559 if (!NT_SUCCESS (Status))
560 {
561 if (RequestedDisposition == FILE_CREATE ||
562 RequestedDisposition == FILE_OPEN_IF ||
563 RequestedDisposition == FILE_OVERWRITE_IF ||
564 RequestedDisposition == FILE_SUPERSEDE)
565 {
566 ULONG Attributes;
567 if (ParentFcb == NULL)
568 {
569 ParentFcb = vfatOpenRootFCB (DeviceExt);
570 ASSERT(ParentFcb != NULL);
571 }
572 Attributes = Stack->Parameters.Create.FileAttributes;
573
574 vfatSplitPathName(&PathNameU, NULL, &FileNameU);
575 Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
576 (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
577 vfatReleaseFCB (DeviceExt, ParentFcb);
578 if (NT_SUCCESS (Status))
579 {
580 Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject);
581 if ( !NT_SUCCESS(Status) )
582 {
583 vfatReleaseFCB (DeviceExt, pFcb);
584 return Status;
585 }
586
587 Irp->IoStatus.Information = FILE_CREATED;
588 VfatSetAllocationSizeInformation(FileObject,
589 pFcb,
590 DeviceExt,
591 &Irp->Overlay.AllocationSize);
592 VfatSetExtendedAttributes(FileObject,
593 Irp->AssociatedIrp.SystemBuffer,
594 Stack->Parameters.Create.EaLength);
595
596 if (PagingFileCreate)
597 {
598 pFcb->Flags |= FCB_IS_PAGE_FILE;
599 }
600 }
601 else
602 {
603 return(Status);
604 }
605 }
606 else
607 {
608 if (ParentFcb)
609 {
610 vfatReleaseFCB (DeviceExt, ParentFcb);
611 }
612 return(Status);
613 }
614 }
615 else
616 {
617 if (ParentFcb)
618 {
619 vfatReleaseFCB (DeviceExt, ParentFcb);
620 }
621 /* Otherwise fail if the caller wanted to create a new file */
622 if (RequestedDisposition == FILE_CREATE)
623 {
624 Irp->IoStatus.Information = FILE_EXISTS;
625 VfatCloseFile (DeviceExt, FileObject);
626 return(STATUS_OBJECT_NAME_COLLISION);
627 }
628
629 pFcb = FileObject->FsContext;
630
631 if (pFcb->OpenHandleCount != 0)
632 {
633 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
634 Stack->Parameters.Create.ShareAccess,
635 FileObject,
636 &pFcb->FCBShareAccess,
637 FALSE);
638 if (!NT_SUCCESS(Status))
639 {
640 VfatCloseFile (DeviceExt, FileObject);
641 return(Status);
642 }
643 }
644
645 /*
646 * Check the file has the requested attributes
647 */
648 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
649 *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
650 {
651 VfatCloseFile (DeviceExt, FileObject);
652 return(STATUS_FILE_IS_A_DIRECTORY);
653 }
654 if (RequestedOptions & FILE_DIRECTORY_FILE &&
655 !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
656 {
657 VfatCloseFile (DeviceExt, FileObject);
658 return(STATUS_NOT_A_DIRECTORY);
659 }
660
661 if (PagingFileCreate)
662 {
663 /* FIXME:
664 * Do more checking for page files. It is possible,
665 * that the file was opened and closed previously
666 * as a normal cached file. In this case, the cache
667 * manager has referenced the fileobject and the fcb
668 * is held in memory. Try to remove the fileobject
669 * from cache manager and use the fcb.
670 */
671 if (pFcb->RefCount > 1)
672 {
673 if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
674 {
675 VfatCloseFile(DeviceExt, FileObject);
676 return(STATUS_INVALID_PARAMETER);
677 }
678 }
679 else
680 {
681 pFcb->Flags |= FCB_IS_PAGE_FILE;
682 }
683 }
684 else
685 {
686 if (pFcb->Flags & FCB_IS_PAGE_FILE)
687 {
688 VfatCloseFile(DeviceExt, FileObject);
689 return(STATUS_INVALID_PARAMETER);
690 }
691 }
692
693
694 if (RequestedDisposition == FILE_OVERWRITE ||
695 RequestedDisposition == FILE_OVERWRITE_IF ||
696 RequestedDisposition == FILE_SUPERSEDE)
697 {
698 ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE);
699 Status = VfatSetAllocationSizeInformation (FileObject,
700 pFcb,
701 DeviceExt,
702 &Irp->Overlay.AllocationSize);
703 ExReleaseResourceLite(&(pFcb->MainResource));
704 if (!NT_SUCCESS (Status))
705 {
706 VfatCloseFile (DeviceExt, FileObject);
707 return(Status);
708 }
709 }
710
711 if (RequestedDisposition == FILE_SUPERSEDE)
712 {
713 Irp->IoStatus.Information = FILE_SUPERSEDED;
714 }
715 else if (RequestedDisposition == FILE_OVERWRITE ||
716 RequestedDisposition == FILE_OVERWRITE_IF)
717 {
718 Irp->IoStatus.Information = FILE_OVERWRITTEN;
719 }
720 else
721 {
722 Irp->IoStatus.Information = FILE_OPENED;
723 }
724 }
725
726 if (pFcb->OpenHandleCount == 0)
727 {
728 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
729 Stack->Parameters.Create.ShareAccess,
730 FileObject,
731 &pFcb->FCBShareAccess);
732 }
733 else
734 {
735 IoUpdateShareAccess(
736 FileObject,
737 &pFcb->FCBShareAccess
738 );
739
740 }
741
742 pFcb->OpenHandleCount++;
743
744 /* FIXME : test write access if requested */
745
746 return(Status);
747 }
748
749
750 NTSTATUS
751 VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
752 /*
753 * FUNCTION: Create or open a file
754 */
755 {
756 NTSTATUS Status;
757
758 ASSERT(IrpContext);
759
760 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
761 {
762 /* DeviceObject represents FileSystem instead of logical volume */
763 DPRINT ("FsdCreate called with file system\n");
764 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
765 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
766 IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
767 VfatFreeIrpContext(IrpContext);
768 return(STATUS_SUCCESS);
769 }
770
771 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
772 {
773 return(VfatQueueRequest (IrpContext));
774 }
775
776 IrpContext->Irp->IoStatus.Information = 0;
777 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
778 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
779 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
780
781 IrpContext->Irp->IoStatus.Status = Status;
782 IoCompleteRequest (IrpContext->Irp,
783 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
784 VfatFreeIrpContext(IrpContext);
785 return(Status);
786 }
787
788 /* EOF */