Don't check the share access for directories.
[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 vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
35 {
36 OEM_STRING StringA;
37 USHORT Length;
38 CHAR cString[12];
39
40 RtlCopyMemory(cString, pEntry->ShortName, 11);
41 cString[11] = 0;
42 if (cString[0] == 0x05)
43 {
44 cString[0] = 0xe5;
45 }
46
47 StringA.Buffer = cString;
48 for (StringA.Length = 0;
49 StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' ';
50 StringA.Length++);
51 StringA.MaximumLength = StringA.Length;
52
53 RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
54
55 if (pEntry->lCase & VFAT_CASE_LOWER_BASE)
56 {
57 RtlDowncaseUnicodeString(NameU, NameU, FALSE);
58 }
59 if (cString[8] != ' ')
60 {
61 Length = NameU->Length;
62 NameU->Buffer += Length / sizeof(WCHAR);
63 if (!FAT_ENTRY_VOLUME(pEntry))
64 {
65 Length += sizeof(WCHAR);
66 NameU->Buffer[0] = L'.';
67 NameU->Buffer++;
68 }
69 NameU->Length = 0;
70 NameU->MaximumLength -= Length;
71
72 StringA.Buffer = &cString[8];
73 for (StringA.Length = 0;
74 StringA.Length < 3 && StringA.Buffer[StringA.Length] != ' ';
75 StringA.Length++);
76 StringA.MaximumLength = StringA.Length;
77 RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
78 if (pEntry->lCase & VFAT_CASE_LOWER_EXT)
79 {
80 RtlDowncaseUnicodeString(NameU, NameU, FALSE);
81 }
82 NameU->Buffer -= Length / sizeof(WCHAR);
83 NameU->Length += Length;
84 NameU->MaximumLength += Length;
85 }
86 NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
87 DPRINT("'%wZ'\n", NameU);
88 }
89
90 NTSTATUS
91 ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
92 /*
93 * FUNCTION: Read the volume label
94 */
95 {
96 PVOID Context = NULL;
97 ULONG DirIndex = 0;
98 PDIR_ENTRY Entry;
99 PVFATFCB pFcb;
100 LARGE_INTEGER FileOffset;
101 UNICODE_STRING NameU;
102 ULONG SizeDirEntry;
103 ULONG EntriesPerPage;
104 OEM_STRING StringO;
105
106 NameU.Buffer = Vpb->VolumeLabel;
107 NameU.Length = 0;
108 NameU.MaximumLength = sizeof(Vpb->VolumeLabel);
109 *(Vpb->VolumeLabel) = 0;
110 Vpb->VolumeLabelLength = 0;
111
112 if (DeviceExt->Flags & VCB_IS_FATX)
113 {
114 SizeDirEntry = sizeof(FATX_DIR_ENTRY);
115 EntriesPerPage = FATX_ENTRIES_PER_PAGE;
116 }
117 else
118 {
119 SizeDirEntry = sizeof(FAT_DIR_ENTRY);
120 EntriesPerPage = FAT_ENTRIES_PER_PAGE;
121 }
122
123 ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
124 pFcb = vfatOpenRootFCB (DeviceExt);
125 ExReleaseResourceLite (&DeviceExt->DirResource);
126
127 FileOffset.QuadPart = 0;
128 if (CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
129 {
130 while (TRUE)
131 {
132 if (ENTRY_VOLUME(DeviceExt, Entry))
133 {
134 /* copy volume label */
135 if (DeviceExt->Flags & VCB_IS_FATX)
136 {
137 StringO.Buffer = (PCHAR)Entry->FatX.Filename;
138 StringO.MaximumLength = StringO.Length = Entry->FatX.FilenameLength;
139 RtlOemStringToUnicodeString(&NameU, &StringO, FALSE);
140 }
141 else
142 {
143 vfat8Dot3ToString (&Entry->Fat, &NameU);
144 }
145 Vpb->VolumeLabelLength = NameU.Length;
146 break;
147 }
148 if (ENTRY_END(DeviceExt, Entry))
149 {
150 break;
151 }
152 DirIndex++;
153 Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
154 if ((DirIndex % EntriesPerPage) == 0)
155 {
156 CcUnpinData(Context);
157 FileOffset.u.LowPart += PAGE_SIZE;
158 if (!CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
159 {
160 Context = NULL;
161 break;
162 }
163 }
164 }
165 if (Context)
166 {
167 CcUnpinData(Context);
168 }
169 }
170 ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
171 vfatReleaseFCB (DeviceExt, pFcb);
172 ExReleaseResourceLite (&DeviceExt->DirResource);
173
174 return STATUS_SUCCESS;
175 }
176
177 NTSTATUS
178 FindFile (PDEVICE_EXTENSION DeviceExt,
179 PVFATFCB Parent,
180 PUNICODE_STRING FileToFindU,
181 PVFAT_DIRENTRY_CONTEXT DirContext,
182 BOOLEAN First)
183 /*
184 * FUNCTION: Find a file
185 */
186 {
187 PWCHAR PathNameBuffer;
188 USHORT PathNameBufferLength;
189 NTSTATUS Status;
190 PVOID Context = NULL;
191 PVOID Page;
192 PVFATFCB rcFcb;
193 BOOLEAN Found;
194 UNICODE_STRING PathNameU;
195 UNICODE_STRING FileToFindUpcase;
196 BOOLEAN WildCard;
197
198 DPRINT ("FindFile(Parent %x, FileToFind '%wZ', DirIndex: %d)\n",
199 Parent, FileToFindU, DirContext->DirIndex);
200 DPRINT ("FindFile: Path %wZ)\n",&Parent->PathNameU);
201
202 PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR);
203 PathNameBuffer = ExAllocatePool(NonPagedPool, PathNameBufferLength + sizeof(WCHAR));
204 if (!PathNameBuffer)
205 {
206 CHECKPOINT1;
207 return STATUS_INSUFFICIENT_RESOURCES;
208 }
209
210 PathNameU.Buffer = PathNameBuffer;
211 PathNameU.Length = 0;
212 PathNameU.MaximumLength = PathNameBufferLength;
213
214 DirContext->LongNameU.Length = 0;
215 DirContext->ShortNameU.Length = 0;
216
217 WildCard = FsRtlDoesNameContainWildCards(FileToFindU);
218
219 if (WildCard == FALSE)
220 {
221 /* if there is no '*?' in the search name, than look first for an existing fcb */
222 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
223 if (!vfatFCBIsRoot(Parent))
224 {
225 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
226 PathNameU.Length += sizeof(WCHAR);
227 }
228 RtlAppendUnicodeStringToString(&PathNameU, FileToFindU);
229 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
230 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
231 if (rcFcb)
232 {
233 ULONG startIndex = rcFcb->startIndex;
234 if ((rcFcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Parent))
235 {
236 startIndex += 2;
237 }
238 if(startIndex >= DirContext->DirIndex)
239 {
240 RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU);
241 RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU);
242 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
243 DirContext->StartIndex = rcFcb->startIndex;
244 DirContext->DirIndex = rcFcb->dirIndex;
245 DPRINT("FindFile: new Name %wZ, DirIndex %d (%d)\n",
246 &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex);
247 Status = STATUS_SUCCESS;
248 }
249 else
250 {
251 CHECKPOINT1;
252 Status = STATUS_UNSUCCESSFUL;
253 }
254 vfatReleaseFCB(DeviceExt, rcFcb);
255 ExFreePool(PathNameBuffer);
256 return Status;
257 }
258 }
259
260 /* FsRtlIsNameInExpression need the searched string to be upcase,
261 * even if IgnoreCase is specified */
262 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE);
263 if (!NT_SUCCESS(Status))
264 {
265 CHECKPOINT;
266 ExFreePool(PathNameBuffer);
267 return Status;
268 }
269
270 while(TRUE)
271 {
272 Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
273 First = FALSE;
274 if (Status == STATUS_NO_MORE_ENTRIES)
275 {
276 break;
277 }
278 if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
279 {
280 DirContext->DirIndex++;
281 continue;
282 }
283 if (WildCard)
284 {
285 Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) ||
286 FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL);
287 }
288 else
289 {
290 Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
291 FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
292 }
293
294 if (Found)
295 {
296 if (WildCard)
297 {
298 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
299 if (!vfatFCBIsRoot(Parent))
300 {
301 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
302 PathNameU.Length += sizeof(WCHAR);
303 }
304 RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU);
305 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
306 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
307 if (rcFcb != NULL)
308 {
309 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
310 vfatReleaseFCB(DeviceExt, rcFcb);
311 }
312 }
313 DPRINT("%d\n", DirContext->LongNameU.Length);
314 DPRINT("FindFile: new Name %wZ, DirIndex %d\n",
315 &DirContext->LongNameU, DirContext->DirIndex);
316
317 if (Context)
318 {
319 CcUnpinData(Context);
320 }
321 RtlFreeUnicodeString(&FileToFindUpcase);
322 ExFreePool(PathNameBuffer);
323 return STATUS_SUCCESS;
324 }
325 DirContext->DirIndex++;
326 }
327
328 if (Context)
329 {
330 CcUnpinData(Context);
331 }
332
333 RtlFreeUnicodeString(&FileToFindUpcase);
334 ExFreePool(PathNameBuffer);
335 return Status;
336 }
337
338 NTSTATUS
339 VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PVFATFCB* ParentFcb)
340 /*
341 * FUNCTION: Opens a file
342 */
343 {
344 PVFATFCB Fcb;
345 NTSTATUS Status;
346 UNICODE_STRING PathNameU;
347 WCHAR Buffer[260];
348
349 DPRINT ("VfatOpenFile(%08lx, %08lx, '%wZ')\n", DeviceExt, FileObject, &FileObject->FileName);
350
351 if (FileObject->RelatedFileObject)
352 {
353 DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
354
355 *ParentFcb = FileObject->RelatedFileObject->FsContext;
356 (*ParentFcb)->RefCount++;
357 }
358 else
359 {
360 *ParentFcb = NULL;
361 }
362
363 if (!DeviceExt->FatInfo.FixedMedia)
364 {
365 Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice,
366 IOCTL_DISK_CHECK_VERIFY,
367 NULL,
368 0,
369 NULL,
370 0,
371 FALSE);
372
373 if (Status == STATUS_VERIFY_REQUIRED)
374
375 {
376 PDEVICE_OBJECT DeviceToVerify;
377
378 DPRINT ("Media change detected!\n");
379 DPRINT ("Device %p\n", DeviceExt->StorageDevice);
380
381 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
382
383 IoSetDeviceToVerify (PsGetCurrentThread (),
384 NULL);
385 Status = IoVerifyVolume (DeviceExt->StorageDevice,
386 FALSE);
387 }
388 if (!NT_SUCCESS(Status))
389 {
390 DPRINT ("Status %lx\n", Status);
391 *ParentFcb = NULL;
392 return Status;
393 }
394 }
395
396 if (*ParentFcb)
397 {
398 (*ParentFcb)->RefCount++;
399 }
400
401 PathNameU.Buffer = Buffer;
402 PathNameU.Length = 0;
403 PathNameU.MaximumLength = sizeof(Buffer);
404 RtlCopyUnicodeString(&PathNameU, &FileObject->FileName);
405 if (PathNameU.Length > sizeof(WCHAR) &&
406 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR) - 1] == L'\\')
407 {
408 PathNameU.Length -= sizeof(WCHAR);
409 }
410 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
411
412 /* try first to find an existing FCB in memory */
413 DPRINT ("Checking for existing FCB in memory\n");
414
415 Status = vfatGetFCBForFile (DeviceExt, ParentFcb, &Fcb, &PathNameU);
416 if (!NT_SUCCESS (Status))
417 {
418 DPRINT ("Could not make a new FCB, status: %x\n", Status);
419 return Status;
420 }
421 if (Fcb->Flags & FCB_DELETE_PENDING)
422 {
423 vfatReleaseFCB (DeviceExt, Fcb);
424 return STATUS_DELETE_PENDING;
425 }
426 DPRINT ("Attaching FCB to fileObject\n");
427 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
428 if (!NT_SUCCESS(Status))
429 {
430 vfatReleaseFCB (DeviceExt, Fcb);
431 }
432 return Status;
433 }
434
435 NTSTATUS
436 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
437 /*
438 * FUNCTION: Create or open a file
439 */
440 {
441 PIO_STACK_LOCATION Stack;
442 PFILE_OBJECT FileObject;
443 NTSTATUS Status = STATUS_SUCCESS;
444 PDEVICE_EXTENSION DeviceExt;
445 ULONG RequestedDisposition, RequestedOptions;
446 PVFATCCB pCcb;
447 PVFATFCB pFcb;
448 PVFATFCB ParentFcb;
449 PWCHAR c, last;
450 BOOLEAN PagingFileCreate = FALSE;
451 LARGE_INTEGER AllocationSize;
452 BOOLEAN Dots;
453 UNICODE_STRING FileNameU;
454
455 /* Unpack the various parameters. */
456 Stack = IoGetCurrentIrpStackLocation (Irp);
457 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
458 RequestedOptions =
459 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
460 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
461 FileObject = Stack->FileObject;
462 DeviceExt = DeviceObject->DeviceExtension;
463
464 /* Check their validity. */
465 if (RequestedOptions & FILE_DIRECTORY_FILE &&
466 RequestedDisposition == FILE_SUPERSEDE)
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 c = FileObject->FileName.Buffer + FileObject->FileName.Length / sizeof(WCHAR);
505 last = c - 1;
506 Dots = TRUE;
507 while (c-- > FileObject->FileName.Buffer)
508 {
509 if (*c == L'\\' || c == FileObject->FileName.Buffer)
510 {
511 if (Dots && last > c)
512 {
513 return(STATUS_OBJECT_NAME_INVALID);
514 }
515 last = c - 1;
516 Dots = TRUE;
517 }
518 else if (*c != L'.')
519 {
520 Dots = FALSE;
521 }
522
523 if (*c != '\\' && vfatIsLongIllegal(*c))
524 {
525 return(STATUS_OBJECT_NAME_INVALID);
526 }
527 }
528
529 /* Try opening the file. */
530 Status = VfatOpenFile (DeviceExt, FileObject, &ParentFcb);
531
532 /*
533 * If the directory containing the file to open doesn't exist then
534 * fail immediately
535 */
536 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
537 Status == STATUS_INVALID_PARAMETER ||
538 Status == STATUS_DELETE_PENDING)
539 {
540 if (ParentFcb)
541 {
542 vfatReleaseFCB (DeviceExt, ParentFcb);
543 }
544 return(Status);
545 }
546
547 /*
548 * If the file open failed then create the required file
549 */
550 if (!NT_SUCCESS (Status))
551 {
552 if (RequestedDisposition == FILE_CREATE ||
553 RequestedDisposition == FILE_OPEN_IF ||
554 RequestedDisposition == FILE_OVERWRITE_IF ||
555 RequestedDisposition == FILE_SUPERSEDE)
556 {
557 ULONG Attributes;
558 Attributes = Stack->Parameters.Create.FileAttributes;
559
560 vfatSplitPathName(&FileObject->FileName, NULL, &FileNameU);
561 Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
562 (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
563 vfatReleaseFCB (DeviceExt, ParentFcb);
564 if (NT_SUCCESS (Status))
565 {
566 Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject);
567 if ( !NT_SUCCESS(Status) )
568 {
569 vfatReleaseFCB (DeviceExt, pFcb);
570 return Status;
571 }
572
573 Irp->IoStatus.Information = FILE_CREATED;
574
575 VfatSetAllocationSizeInformation(FileObject,
576 pFcb,
577 DeviceExt,
578 &Irp->Overlay.AllocationSize);
579 VfatSetExtendedAttributes(FileObject,
580 Irp->AssociatedIrp.SystemBuffer,
581 Stack->Parameters.Create.EaLength);
582
583 if (PagingFileCreate)
584 {
585 pFcb->Flags |= FCB_IS_PAGE_FILE;
586 }
587 }
588 else
589 {
590 return(Status);
591 }
592 }
593 else
594 {
595 vfatReleaseFCB (DeviceExt, ParentFcb);
596 return(Status);
597 }
598 }
599 else
600 {
601 if (ParentFcb)
602 {
603 vfatReleaseFCB (DeviceExt, ParentFcb);
604 }
605 /* Otherwise fail if the caller wanted to create a new file */
606 if (RequestedDisposition == FILE_CREATE)
607 {
608 Irp->IoStatus.Information = FILE_EXISTS;
609 VfatCloseFile (DeviceExt, FileObject);
610 return(STATUS_OBJECT_NAME_COLLISION);
611 }
612
613 pFcb = FileObject->FsContext;
614
615 if (pFcb->OpenHandleCount != 0 &&
616 !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
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 AllocationSize.QuadPart = 0;
699 VfatSetAllocationSizeInformation(FileObject, pFcb, DeviceExt, &AllocationSize);
700 Irp->IoStatus.Information = FILE_SUPERSEDED;
701 }
702 else if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)
703 {
704 Irp->IoStatus.Information = FILE_OVERWRITTEN;
705 }
706 else
707 {
708 Irp->IoStatus.Information = FILE_OPENED;
709 }
710 }
711
712 if (pFcb->OpenHandleCount == 0 &&
713 !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
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 */