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