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