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