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