Sync with trunk (r48545)
[reactos.git] / 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 (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 (
179 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 %p, 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 = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength + sizeof(WCHAR), TAG_VFAT);
205 if (!PathNameBuffer)
206 {
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 DPRINT("FCB not found for %wZ\n", &PathNameU);
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 ExFreePool(PathNameBuffer);
266 return Status;
267 }
268
269 while(TRUE)
270 {
271 Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
272 First = FALSE;
273 if (Status == STATUS_NO_MORE_ENTRIES)
274 {
275 break;
276 }
277 if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
278 {
279 DirContext->DirIndex++;
280 continue;
281 }
282 if (WildCard)
283 {
284 Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) ||
285 FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL);
286 }
287 else
288 {
289 Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
290 FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
291 }
292
293 if (Found)
294 {
295 if (WildCard)
296 {
297 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
298 if (!vfatFCBIsRoot(Parent))
299 {
300 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
301 PathNameU.Length += sizeof(WCHAR);
302 }
303 RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU);
304 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
305 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
306 if (rcFcb != NULL)
307 {
308 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
309 vfatReleaseFCB(DeviceExt, rcFcb);
310 }
311 }
312 DPRINT("%d\n", DirContext->LongNameU.Length);
313 DPRINT("FindFile: new Name %wZ, DirIndex %d\n",
314 &DirContext->LongNameU, DirContext->DirIndex);
315
316 if (Context)
317 {
318 CcUnpinData(Context);
319 }
320 RtlFreeUnicodeString(&FileToFindUpcase);
321 ExFreePool(PathNameBuffer);
322 return STATUS_SUCCESS;
323 }
324 DirContext->DirIndex++;
325 }
326
327 if (Context)
328 {
329 CcUnpinData(Context);
330 }
331
332 RtlFreeUnicodeString(&FileToFindUpcase);
333 ExFreePool(PathNameBuffer);
334 return Status;
335 }
336
337 static
338 NTSTATUS
339 VfatOpenFile (
340 PDEVICE_EXTENSION DeviceExt,
341 PUNICODE_STRING PathNameU,
342 PFILE_OBJECT FileObject,
343 PVFATFCB* ParentFcb )
344 /*
345 * FUNCTION: Opens a file
346 */
347 {
348 PVFATFCB Fcb;
349 NTSTATUS Status;
350
351 DPRINT ("VfatOpenFile(%p, '%wZ', %p, %p)\n", DeviceExt, PathNameU, FileObject, ParentFcb);
352
353 if (FileObject->RelatedFileObject)
354 {
355 DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
356
357 *ParentFcb = FileObject->RelatedFileObject->FsContext;
358 (*ParentFcb)->RefCount++;
359 }
360 else
361 {
362 *ParentFcb = NULL;
363 }
364
365 if (!DeviceExt->FatInfo.FixedMedia)
366 {
367 Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice,
368 IOCTL_DISK_CHECK_VERIFY,
369 NULL,
370 0,
371 NULL,
372 0,
373 FALSE);
374
375 if (Status == STATUS_VERIFY_REQUIRED)
376
377 {
378 PDEVICE_OBJECT DeviceToVerify;
379
380 DPRINT ("Media change detected!\n");
381 DPRINT ("Device %p\n", DeviceExt->StorageDevice);
382
383 /* Find the device to verify and reset the thread field to empty value again. */
384 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
385 IoSetDeviceToVerify (PsGetCurrentThread (), NULL);
386 Status = IoVerifyVolume (DeviceToVerify,
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 /* try first to find an existing FCB in memory */
403 DPRINT ("Checking for existing FCB in memory\n");
404
405 Status = vfatGetFCBForFile (DeviceExt, ParentFcb, &Fcb, PathNameU);
406 if (!NT_SUCCESS (Status))
407 {
408 DPRINT ("Could not make a new FCB, status: %x\n", Status);
409 return Status;
410 }
411 if (Fcb->Flags & FCB_DELETE_PENDING)
412 {
413 vfatReleaseFCB (DeviceExt, Fcb);
414 return STATUS_DELETE_PENDING;
415 }
416 DPRINT ("Attaching FCB to fileObject\n");
417 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
418 if (!NT_SUCCESS(Status))
419 {
420 vfatReleaseFCB (DeviceExt, Fcb);
421 }
422 return Status;
423 }
424
425 static NTSTATUS
426 VfatCreateFile ( PDEVICE_OBJECT DeviceObject, PIRP Irp )
427 /*
428 * FUNCTION: Create or open a file
429 */
430 {
431 PIO_STACK_LOCATION Stack;
432 PFILE_OBJECT FileObject;
433 NTSTATUS Status = STATUS_SUCCESS;
434 PDEVICE_EXTENSION DeviceExt;
435 ULONG RequestedDisposition, RequestedOptions;
436 PVFATCCB pCcb;
437 PVFATFCB pFcb = NULL;
438 PVFATFCB ParentFcb = NULL;
439 PWCHAR c, last;
440 BOOLEAN PagingFileCreate = FALSE;
441 BOOLEAN Dots;
442 UNICODE_STRING FileNameU;
443 UNICODE_STRING PathNameU;
444
445 /* Unpack the various parameters. */
446 Stack = IoGetCurrentIrpStackLocation (Irp);
447 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
448 RequestedOptions =
449 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
450 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
451 FileObject = Stack->FileObject;
452 DeviceExt = DeviceObject->DeviceExtension;
453
454 /* Check their validity. */
455 if (RequestedOptions & FILE_DIRECTORY_FILE &&
456 RequestedDisposition == FILE_SUPERSEDE)
457 {
458 return(STATUS_INVALID_PARAMETER);
459 }
460
461 if (RequestedOptions & FILE_DIRECTORY_FILE &&
462 RequestedOptions & FILE_NON_DIRECTORY_FILE)
463 {
464 return(STATUS_INVALID_PARAMETER);
465 }
466
467 /* This a open operation for the volume itself */
468 if (FileObject->FileName.Length == 0 &&
469 (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL))
470 {
471 if (RequestedDisposition == FILE_CREATE ||
472 RequestedDisposition == FILE_OVERWRITE_IF ||
473 RequestedDisposition == FILE_SUPERSEDE)
474 {
475 return(STATUS_ACCESS_DENIED);
476 }
477 #if 0
478 /* In spite of what is shown in WDK, it seems that Windows FAT driver doesn't perform that test */
479 if (RequestedOptions & FILE_DIRECTORY_FILE)
480 {
481 return(STATUS_NOT_A_DIRECTORY);
482 }
483 #endif
484 pFcb = DeviceExt->VolumeFcb;
485 pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
486 if (pCcb == NULL)
487 {
488 return (STATUS_INSUFFICIENT_RESOURCES);
489 }
490 RtlZeroMemory(pCcb, sizeof(VFATCCB));
491 FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
492 FileObject->FsContext = pFcb;
493 FileObject->FsContext2 = pCcb;
494 pFcb->RefCount++;
495
496 Irp->IoStatus.Information = FILE_OPENED;
497 return(STATUS_SUCCESS);
498 }
499
500 /*
501 * Check for illegal characters and illegale dot sequences in the file name
502 */
503 PathNameU = FileObject->FileName;
504 c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR);
505 last = c - 1;
506 Dots = TRUE;
507 while (c-- > PathNameU.Buffer)
508 {
509 if (*c == L'\\' || c == PathNameU.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 if (FileObject->RelatedFileObject && PathNameU.Length >= sizeof(WCHAR) && PathNameU.Buffer[0] == L'\\')
529 {
530 return(STATUS_OBJECT_NAME_INVALID);
531 }
532 if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\')
533 {
534 PathNameU.Length -= sizeof(WCHAR);
535 }
536
537 /* Try opening the file. */
538 Status = VfatOpenFile (DeviceExt, &PathNameU, FileObject, &ParentFcb);
539
540 /*
541 * If the directory containing the file to open doesn't exist then
542 * fail immediately
543 */
544 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
545 Status == STATUS_INVALID_PARAMETER ||
546 Status == STATUS_DELETE_PENDING)
547 {
548 if (ParentFcb)
549 {
550 vfatReleaseFCB (DeviceExt, ParentFcb);
551 }
552 return(Status);
553 }
554 if (!NT_SUCCESS(Status) && ParentFcb == NULL)
555 {
556 DPRINT1("VfatOpenFile faild for '%wZ', status %x\n", &PathNameU, Status);
557 return Status;
558 }
559
560 /*
561 * If the file open failed then create the required file
562 */
563 if (!NT_SUCCESS (Status))
564 {
565 if (RequestedDisposition == FILE_CREATE ||
566 RequestedDisposition == FILE_OPEN_IF ||
567 RequestedDisposition == FILE_OVERWRITE_IF ||
568 RequestedDisposition == FILE_SUPERSEDE)
569 {
570 ULONG Attributes;
571 Attributes = Stack->Parameters.Create.FileAttributes;
572
573 vfatSplitPathName(&PathNameU, NULL, &FileNameU);
574 Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
575 (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
576 vfatReleaseFCB (DeviceExt, ParentFcb);
577 if (NT_SUCCESS (Status))
578 {
579 Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject);
580 if ( !NT_SUCCESS(Status) )
581 {
582 vfatReleaseFCB (DeviceExt, pFcb);
583 return Status;
584 }
585
586 Irp->IoStatus.Information = FILE_CREATED;
587 VfatSetAllocationSizeInformation(FileObject,
588 pFcb,
589 DeviceExt,
590 &Irp->Overlay.AllocationSize);
591 VfatSetExtendedAttributes(FileObject,
592 Irp->AssociatedIrp.SystemBuffer,
593 Stack->Parameters.Create.EaLength);
594
595 if (PagingFileCreate)
596 {
597 pFcb->Flags |= FCB_IS_PAGE_FILE;
598 }
599 }
600 else
601 {
602 return(Status);
603 }
604 }
605 else
606 {
607 if (ParentFcb)
608 {
609 vfatReleaseFCB (DeviceExt, ParentFcb);
610 }
611 return(Status);
612 }
613 }
614 else
615 {
616 if (ParentFcb)
617 {
618 vfatReleaseFCB (DeviceExt, ParentFcb);
619 }
620 /* Otherwise fail if the caller wanted to create a new file */
621 if (RequestedDisposition == FILE_CREATE)
622 {
623 Irp->IoStatus.Information = FILE_EXISTS;
624 VfatCloseFile (DeviceExt, FileObject);
625 return(STATUS_OBJECT_NAME_COLLISION);
626 }
627
628 pFcb = FileObject->FsContext;
629
630 if (pFcb->OpenHandleCount != 0)
631 {
632 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
633 Stack->Parameters.Create.ShareAccess,
634 FileObject,
635 &pFcb->FCBShareAccess,
636 FALSE);
637 if (!NT_SUCCESS(Status))
638 {
639 VfatCloseFile (DeviceExt, FileObject);
640 return(Status);
641 }
642 }
643
644 /*
645 * Check the file has the requested attributes
646 */
647 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
648 *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
649 {
650 VfatCloseFile (DeviceExt, FileObject);
651 return(STATUS_FILE_IS_A_DIRECTORY);
652 }
653 if (RequestedOptions & FILE_DIRECTORY_FILE &&
654 !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
655 {
656 VfatCloseFile (DeviceExt, FileObject);
657 return(STATUS_NOT_A_DIRECTORY);
658 }
659 #ifndef USE_ROS_CC_AND_FS
660 if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
661 {
662 if (Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA ||
663 RequestedDisposition == FILE_OVERWRITE ||
664 RequestedDisposition == FILE_OVERWRITE_IF)
665 {
666 if (!MmFlushImageSection(&pFcb->SectionObjectPointers, MmFlushForWrite))
667 {
668 DPRINT1("%wZ\n", &pFcb->PathNameU);
669 DPRINT1("%d %d %d\n", Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA,
670 RequestedDisposition == FILE_OVERWRITE, RequestedDisposition == FILE_OVERWRITE_IF);
671 VfatCloseFile (DeviceExt, FileObject);
672 return STATUS_SHARING_VIOLATION;
673 }
674 }
675 }
676 #endif
677 if (PagingFileCreate)
678 {
679 /* FIXME:
680 * Do more checking for page files. It is possible,
681 * that the file was opened and closed previously
682 * as a normal cached file. In this case, the cache
683 * manager has referenced the fileobject and the fcb
684 * is held in memory. Try to remove the fileobject
685 * from cache manager and use the fcb.
686 */
687 if (pFcb->RefCount > 1)
688 {
689 if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
690 {
691 VfatCloseFile(DeviceExt, FileObject);
692 return(STATUS_INVALID_PARAMETER);
693 }
694 }
695 else
696 {
697 pFcb->Flags |= FCB_IS_PAGE_FILE;
698 }
699 }
700 else
701 {
702 if (pFcb->Flags & FCB_IS_PAGE_FILE)
703 {
704 VfatCloseFile(DeviceExt, FileObject);
705 return(STATUS_INVALID_PARAMETER);
706 }
707 }
708
709
710 if (RequestedDisposition == FILE_OVERWRITE ||
711 RequestedDisposition == FILE_OVERWRITE_IF ||
712 RequestedDisposition == FILE_SUPERSEDE)
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(
752 FileObject,
753 &pFcb->FCBShareAccess
754 );
755
756 }
757
758 pFcb->OpenHandleCount++;
759
760 /* FIXME : test write access if requested */
761
762 return(Status);
763 }
764
765
766 NTSTATUS
767 VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
768 /*
769 * FUNCTION: Create or open a file
770 */
771 {
772 NTSTATUS Status;
773
774 ASSERT(IrpContext);
775
776 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
777 {
778 /* DeviceObject represents FileSystem instead of logical volume */
779 DPRINT ("FsdCreate called with file system\n");
780 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
781 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
782 IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
783 VfatFreeIrpContext(IrpContext);
784 return(STATUS_SUCCESS);
785 }
786
787 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
788 {
789 return(VfatQueueRequest (IrpContext));
790 }
791
792 IrpContext->Irp->IoStatus.Information = 0;
793 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
794 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
795 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
796
797 IrpContext->Irp->IoStatus.Status = Status;
798 IoCompleteRequest (IrpContext->Irp,
799 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
800 VfatFreeIrpContext(IrpContext);
801 return(Status);
802 }
803
804 /* EOF */