check for failure of vfatAttachFCBToFileObject() during file creation
[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 /* $Id$
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/fs/vfat/create.c
23 * PURPOSE: VFAT Filesystem
24 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
25 * Hartmut Birr
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #define NDEBUG
31 #include "vfat.h"
32
33 /* FUNCTIONS *****************************************************************/
34
35 void 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->Filename, 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 (PDEVICE_EXTENSION DeviceExt,
180 PVFATFCB Parent,
181 PUNICODE_STRING FileToFindU,
182 PVFAT_DIRENTRY_CONTEXT DirContext,
183 BOOLEAN First)
184 /*
185 * FUNCTION: Find a file
186 */
187 {
188 PWCHAR PathNameBuffer;
189 USHORT PathNameBufferLength;
190 NTSTATUS Status;
191 PVOID Context = NULL;
192 PVOID Page;
193 PVFATFCB rcFcb;
194 BOOLEAN Found;
195 UNICODE_STRING PathNameU;
196 UNICODE_STRING FileToFindUpcase;
197 BOOLEAN WildCard;
198
199 DPRINT ("FindFile(Parent %x, FileToFind '%wZ', DirIndex: %d)\n",
200 Parent, FileToFindU, DirContext->DirIndex);
201 DPRINT ("FindFile: Path %wZ)\n",&Parent->PathNameU);
202
203 PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR);
204 PathNameBuffer = ExAllocatePool(NonPagedPool, PathNameBufferLength + sizeof(WCHAR));
205 if (!PathNameBuffer)
206 {
207 CHECKPOINT1;
208 return STATUS_INSUFFICIENT_RESOURCES;
209 }
210
211 PathNameU.Buffer = PathNameBuffer;
212 PathNameU.Length = 0;
213 PathNameU.MaximumLength = PathNameBufferLength;
214
215 DirContext->LongNameU.Length = 0;
216 DirContext->ShortNameU.Length = 0;
217
218 WildCard = FsRtlDoesNameContainWildCards(FileToFindU);
219
220 if (WildCard == FALSE)
221 {
222 /* if there is no '*?' in the search name, than look first for an existing fcb */
223 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
224 if (!vfatFCBIsRoot(Parent))
225 {
226 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
227 PathNameU.Length += sizeof(WCHAR);
228 }
229 RtlAppendUnicodeStringToString(&PathNameU, FileToFindU);
230 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
231 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
232 if (rcFcb)
233 {
234 ULONG startIndex = rcFcb->startIndex;
235 if ((rcFcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Parent))
236 {
237 startIndex += 2;
238 }
239 if(startIndex >= DirContext->DirIndex)
240 {
241 RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU);
242 RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU);
243 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
244 DirContext->StartIndex = rcFcb->startIndex;
245 DirContext->DirIndex = rcFcb->dirIndex;
246 DPRINT("FindFile: new Name %wZ, DirIndex %d (%d)\n",
247 &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex);
248 Status = STATUS_SUCCESS;
249 }
250 else
251 {
252 CHECKPOINT1;
253 Status = STATUS_UNSUCCESSFUL;
254 }
255 vfatReleaseFCB(DeviceExt, rcFcb);
256 ExFreePool(PathNameBuffer);
257 return Status;
258 }
259 }
260
261 /* FsRtlIsNameInExpression need the searched string to be upcase,
262 * even if IgnoreCase is specified */
263 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE);
264 if (!NT_SUCCESS(Status))
265 {
266 CHECKPOINT;
267 ExFreePool(PathNameBuffer);
268 return Status;
269 }
270
271 while(TRUE)
272 {
273 Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
274 First = FALSE;
275 if (Status == STATUS_NO_MORE_ENTRIES)
276 {
277 break;
278 }
279 if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
280 {
281 DirContext->DirIndex++;
282 continue;
283 }
284 if (WildCard)
285 {
286 Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) ||
287 FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL);
288 }
289 else
290 {
291 Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
292 FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
293 }
294
295 if (Found)
296 {
297 if (WildCard)
298 {
299 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
300 if (!vfatFCBIsRoot(Parent))
301 {
302 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
303 PathNameU.Length += sizeof(WCHAR);
304 }
305 RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU);
306 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
307 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
308 if (rcFcb != NULL)
309 {
310 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
311 vfatReleaseFCB(DeviceExt, rcFcb);
312 }
313 }
314 DPRINT("%d\n", DirContext->LongNameU.Length);
315 DPRINT("FindFile: new Name %wZ, DirIndex %d\n",
316 &DirContext->LongNameU, DirContext->DirIndex);
317
318 if (Context)
319 {
320 CcUnpinData(Context);
321 }
322 RtlFreeUnicodeString(&FileToFindUpcase);
323 ExFreePool(PathNameBuffer);
324 return STATUS_SUCCESS;
325 }
326 DirContext->DirIndex++;
327 }
328
329 if (Context)
330 {
331 CcUnpinData(Context);
332 }
333
334 RtlFreeUnicodeString(&FileToFindUpcase);
335 ExFreePool(PathNameBuffer);
336 return Status;
337 }
338
339 NTSTATUS
340 VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PVFATFCB* ParentFcb)
341 /*
342 * FUNCTION: Opens a file
343 */
344 {
345 PVFATFCB Fcb;
346 NTSTATUS Status;
347 UNICODE_STRING PathNameU;
348 WCHAR Buffer[260];
349
350 DPRINT ("VfatOpenFile(%08lx, %08lx, '%wZ')\n", DeviceExt, FileObject, &FileObject->FileName);
351
352 if (FileObject->RelatedFileObject)
353 {
354 DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
355
356 *ParentFcb = FileObject->RelatedFileObject->FsContext;
357 (*ParentFcb)->RefCount++;
358 }
359 else
360 {
361 *ParentFcb = NULL;
362 }
363
364 if (!DeviceExt->FatInfo.FixedMedia)
365 {
366 Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice,
367 IOCTL_DISK_CHECK_VERIFY,
368 NULL,
369 0,
370 NULL,
371 0,
372 FALSE);
373
374 if (Status == STATUS_VERIFY_REQUIRED)
375
376 {
377 PDEVICE_OBJECT DeviceToVerify;
378
379 DPRINT ("Media change detected!\n");
380 DPRINT ("Device %p\n", DeviceExt->StorageDevice);
381
382 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
383
384 IoSetDeviceToVerify (PsGetCurrentThread (),
385 NULL);
386 Status = IoVerifyVolume (DeviceExt->StorageDevice,
387 FALSE);
388 }
389 if (!NT_SUCCESS(Status))
390 {
391 DPRINT ("Status %lx\n", Status);
392 *ParentFcb = NULL;
393 return Status;
394 }
395 }
396
397 if (*ParentFcb)
398 {
399 (*ParentFcb)->RefCount++;
400 }
401
402 PathNameU.Buffer = Buffer;
403 PathNameU.Length = 0;
404 PathNameU.MaximumLength = sizeof(Buffer);
405 RtlCopyUnicodeString(&PathNameU, &FileObject->FileName);
406 if (PathNameU.Length > sizeof(WCHAR) &&
407 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR) - 1] == L'\\')
408 {
409 PathNameU.Length -= sizeof(WCHAR);
410 }
411 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
412
413 /* try first to find an existing FCB in memory */
414 DPRINT ("Checking for existing FCB in memory\n");
415
416 Status = vfatGetFCBForFile (DeviceExt, ParentFcb, &Fcb, &PathNameU);
417 if (!NT_SUCCESS (Status))
418 {
419 DPRINT ("Could not make a new FCB, status: %x\n", Status);
420 return Status;
421 }
422 if (Fcb->Flags & FCB_DELETE_PENDING)
423 {
424 vfatReleaseFCB (DeviceExt, Fcb);
425 return STATUS_DELETE_PENDING;
426 }
427 DPRINT ("Attaching FCB to fileObject\n");
428 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
429 if (!NT_SUCCESS(Status))
430 {
431 vfatReleaseFCB (DeviceExt, Fcb);
432 }
433 return Status;
434 }
435
436 NTSTATUS
437 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
438 /*
439 * FUNCTION: Create or open a file
440 */
441 {
442 PIO_STACK_LOCATION Stack;
443 PFILE_OBJECT FileObject;
444 NTSTATUS Status = STATUS_SUCCESS;
445 PDEVICE_EXTENSION DeviceExt;
446 ULONG RequestedDisposition, RequestedOptions;
447 PVFATCCB pCcb;
448 PVFATFCB pFcb;
449 PVFATFCB ParentFcb;
450 PWCHAR c, last;
451 BOOLEAN PagingFileCreate = FALSE;
452 LARGE_INTEGER AllocationSize;
453 BOOLEAN Dots;
454 UNICODE_STRING FileNameU;
455
456 /* Unpack the various parameters. */
457 Stack = IoGetCurrentIrpStackLocation (Irp);
458 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
459 RequestedOptions =
460 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
461 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
462 FileObject = Stack->FileObject;
463 DeviceExt = DeviceObject->DeviceExtension;
464
465 /* Check their validity. */
466 if (RequestedOptions & FILE_DIRECTORY_FILE &&
467 RequestedDisposition == FILE_SUPERSEDE)
468 {
469 return(STATUS_INVALID_PARAMETER);
470 }
471
472 /* This a open operation for the volume itself */
473 if (FileObject->FileName.Length == 0 &&
474 FileObject->RelatedFileObject == NULL)
475 {
476 if (RequestedDisposition == FILE_CREATE ||
477 RequestedDisposition == FILE_OVERWRITE_IF ||
478 RequestedDisposition == FILE_SUPERSEDE)
479 {
480 return(STATUS_ACCESS_DENIED);
481 }
482 if (RequestedOptions & FILE_DIRECTORY_FILE)
483 {
484 return(STATUS_NOT_A_DIRECTORY);
485 }
486 pFcb = DeviceExt->VolumeFcb;
487 pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
488 if (pCcb == NULL)
489 {
490 return (STATUS_INSUFFICIENT_RESOURCES);
491 }
492 RtlZeroMemory(pCcb, sizeof(VFATCCB));
493 FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
494 FileObject->FsContext = pFcb;
495 FileObject->FsContext2 = pCcb;
496 pFcb->RefCount++;
497
498 Irp->IoStatus.Information = FILE_OPENED;
499 return(STATUS_SUCCESS);
500 }
501
502 /*
503 * Check for illegal characters and illegale dot sequences in the file name
504 */
505 c = FileObject->FileName.Buffer + FileObject->FileName.Length / sizeof(WCHAR);
506 last = c - 1;
507 Dots = TRUE;
508 while (c-- > FileObject->FileName.Buffer)
509 {
510 if (*c == L'\\' || c == FileObject->FileName.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
530 /* Try opening the file. */
531 Status = VfatOpenFile (DeviceExt, FileObject, &ParentFcb);
532
533 /*
534 * If the directory containing the file to open doesn't exist then
535 * fail immediately
536 */
537 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
538 Status == STATUS_INVALID_PARAMETER ||
539 Status == STATUS_DELETE_PENDING)
540 {
541 if (ParentFcb)
542 {
543 vfatReleaseFCB (DeviceExt, ParentFcb);
544 }
545 return(Status);
546 }
547
548 /*
549 * If the file open failed then create the required file
550 */
551 if (!NT_SUCCESS (Status))
552 {
553 if (RequestedDisposition == FILE_CREATE ||
554 RequestedDisposition == FILE_OPEN_IF ||
555 RequestedDisposition == FILE_OVERWRITE_IF ||
556 RequestedDisposition == FILE_SUPERSEDE)
557 {
558 ULONG Attributes;
559 Attributes = Stack->Parameters.Create.FileAttributes;
560
561 vfatSplitPathName(&FileObject->FileName, NULL, &FileNameU);
562 Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
563 (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
564 vfatReleaseFCB (DeviceExt, ParentFcb);
565 if (NT_SUCCESS (Status))
566 {
567 Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject);
568 if ( !NT_SUCCESS(Status) )
569 {
570 vfatReleaseFCB (DeviceExt, pFcb);
571 return Status;
572 }
573
574 Irp->IoStatus.Information = FILE_CREATED;
575
576 VfatSetAllocationSizeInformation(FileObject,
577 pFcb,
578 DeviceExt,
579 &Irp->Overlay.AllocationSize);
580 VfatSetExtendedAttributes(FileObject,
581 Irp->AssociatedIrp.SystemBuffer,
582 Stack->Parameters.Create.EaLength);
583
584 if (PagingFileCreate)
585 {
586 pFcb->Flags |= FCB_IS_PAGE_FILE;
587 }
588 }
589 else
590 {
591 return(Status);
592 }
593 }
594 else
595 {
596 vfatReleaseFCB (DeviceExt, ParentFcb);
597 return(Status);
598 }
599 }
600 else
601 {
602 if (ParentFcb)
603 {
604 vfatReleaseFCB (DeviceExt, ParentFcb);
605 }
606 /* Otherwise fail if the caller wanted to create a new file */
607 if (RequestedDisposition == FILE_CREATE)
608 {
609 Irp->IoStatus.Information = FILE_EXISTS;
610 VfatCloseFile (DeviceExt, FileObject);
611 return(STATUS_OBJECT_NAME_COLLISION);
612 }
613
614 pFcb = FileObject->FsContext;
615
616 if (pFcb->OpenHandleCount != 0)
617 {
618 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
619 Stack->Parameters.Create.ShareAccess,
620 FileObject,
621 &pFcb->FCBShareAccess,
622 FALSE);
623 if (!NT_SUCCESS(Status))
624 {
625 VfatCloseFile (DeviceExt, FileObject);
626 return(Status);
627 }
628 }
629
630 /*
631 * Check the file has the requested attributes
632 */
633 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
634 *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
635 {
636 VfatCloseFile (DeviceExt, FileObject);
637 return(STATUS_FILE_IS_A_DIRECTORY);
638 }
639 if (RequestedOptions & FILE_DIRECTORY_FILE &&
640 !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
641 {
642 VfatCloseFile (DeviceExt, FileObject);
643 return(STATUS_NOT_A_DIRECTORY);
644 }
645
646 if (PagingFileCreate)
647 {
648 /* FIXME:
649 * Do more checking for page files. It is possible,
650 * that the file was opened and closed previously
651 * as a normal cached file. In this case, the cache
652 * manager has referenced the fileobject and the fcb
653 * is held in memory. Try to remove the fileobject
654 * from cache manager and use the fcb.
655 */
656 if (pFcb->RefCount > 1)
657 {
658 if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
659 {
660 VfatCloseFile(DeviceExt, FileObject);
661 return(STATUS_INVALID_PARAMETER);
662 }
663 }
664 else
665 {
666 pFcb->Flags |= FCB_IS_PAGE_FILE;
667 }
668 }
669 else
670 {
671 if (pFcb->Flags & FCB_IS_PAGE_FILE)
672 {
673 VfatCloseFile(DeviceExt, FileObject);
674 return(STATUS_INVALID_PARAMETER);
675 }
676 }
677
678
679 if (RequestedDisposition == FILE_OVERWRITE ||
680 RequestedDisposition == FILE_OVERWRITE_IF)
681 {
682 AllocationSize.QuadPart = 0;
683 Status = VfatSetAllocationSizeInformation (FileObject,
684 pFcb,
685 DeviceExt,
686 &AllocationSize);
687 if (!NT_SUCCESS (Status))
688 {
689 VfatCloseFile (DeviceExt, FileObject);
690 return(Status);
691 }
692 }
693
694
695 /* Supersede the file */
696 if (RequestedDisposition == FILE_SUPERSEDE)
697 {
698 LARGE_INTEGER AllocationSize;
699 AllocationSize.QuadPart = 0LL;
700 VfatSetAllocationSizeInformation(FileObject, pFcb, DeviceExt, &AllocationSize);
701 Irp->IoStatus.Information = FILE_SUPERSEDED;
702 }
703 else if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)
704 {
705 Irp->IoStatus.Information = FILE_OVERWRITTEN;
706 }
707 else
708 {
709 Irp->IoStatus.Information = FILE_OPENED;
710 }
711 }
712
713 if (pFcb->OpenHandleCount == 0)
714 {
715 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
716 Stack->Parameters.Create.ShareAccess,
717 FileObject,
718 &pFcb->FCBShareAccess);
719 }
720 else
721 {
722 IoUpdateShareAccess(
723 FileObject,
724 &pFcb->FCBShareAccess
725 );
726
727 }
728
729 pFcb->OpenHandleCount++;
730
731 /* FIXME : test write access if requested */
732
733 return(Status);
734 }
735
736
737 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
738 /*
739 * FUNCTION: Create or open a file
740 */
741 {
742 NTSTATUS Status;
743
744 ASSERT(IrpContext);
745
746 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
747 {
748 /* DeviceObject represents FileSystem instead of logical volume */
749 DPRINT ("FsdCreate called with file system\n");
750 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
751 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
752 IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
753 VfatFreeIrpContext(IrpContext);
754 return(STATUS_SUCCESS);
755 }
756
757 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
758 {
759 return(VfatQueueRequest (IrpContext));
760 }
761
762 IrpContext->Irp->IoStatus.Information = 0;
763 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
764 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
765 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
766
767 IrpContext->Irp->IoStatus.Status = Status;
768 IoCompleteRequest (IrpContext->Irp,
769 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
770 VfatFreeIrpContext(IrpContext);
771 return(Status);
772 }
773
774 /* EOF */