- Removed the using of the media change count to recognize a median change.
[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.70 2004/07/05 21:39:02 hbirr 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 = FALSE;
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 NTSTATUS Status;
342
343
344 // PDEVICE_OBJECT DeviceObject = DeviceExt->StorageDevice->Vpb->DeviceObject;
345
346 DPRINT ("VfatOpenFile(%08lx, %08lx, '%wZ')\n", DeviceExt, FileObject, &FileObject->FileName);
347
348 if (FileObject->RelatedFileObject)
349 {
350 DPRINT ("Converting relative filename to absolute filename\n");
351
352 Fcb = FileObject->RelatedFileObject->FsContext;
353 RtlCopyUnicodeString(FileNameU, &Fcb->PathNameU);
354 if (!vfatFCBIsRoot(Fcb))
355 {
356 RtlAppendUnicodeToString(FileNameU, L"\\");
357 }
358 RtlAppendUnicodeStringToString(FileNameU, &FileObject->FileName);
359 }
360 else
361 {
362 RtlCopyUnicodeString(FileNameU, &FileObject->FileName);
363 }
364 if (FileNameU->Length > sizeof(WCHAR) &&
365 FileNameU->Buffer[FileNameU->Length / sizeof(WCHAR) - 1] == L'\\')
366 {
367 FileNameU->Length -= sizeof(WCHAR);
368 }
369 FileNameU->Buffer[FileNameU->Length / sizeof(WCHAR)] = 0;
370
371 DPRINT ("PathName to open: '%wZ'\n", FileNameU);
372
373 if (!DeviceExt->FatInfo.FixedMedia)
374 {
375 Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice,
376 IOCTL_DISK_CHECK_VERIFY,
377 NULL,
378 0,
379 NULL,
380 0,
381 FALSE);
382
383 if (Status == STATUS_VERIFY_REQUIRED)
384
385 {
386 PDEVICE_OBJECT DeviceToVerify;
387
388 DPRINT ("Media change detected!\n");
389 DPRINT ("Device %p\n", DeviceExt->StorageDevice);
390
391 DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
392
393 IoSetDeviceToVerify (PsGetCurrentThread (),
394 NULL);
395 Status = IoVerifyVolume (DeviceExt->StorageDevice,
396 FALSE);
397 }
398 if (!NT_SUCCESS(Status))
399 {
400 DPRINT ("Status %lx\n", Status);
401 return Status;
402 }
403 }
404
405
406 /* try first to find an existing FCB in memory */
407 DPRINT ("Checking for existing FCB in memory\n");
408 Fcb = vfatGrabFCBFromTable (DeviceExt, FileNameU);
409 if (Fcb == NULL)
410 {
411 DPRINT ("No existing FCB found, making a new one if file exists.\n");
412 Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileNameU);
413 if (ParentFcb != NULL)
414 {
415 vfatReleaseFCB (DeviceExt, ParentFcb);
416 }
417 if (!NT_SUCCESS (Status))
418 {
419 DPRINT ("Could not make a new FCB, status: %x\n", Status);
420 return Status;
421 }
422 }
423 else
424 {
425 RtlCopyUnicodeString(FileNameU, &Fcb->PathNameU);
426 }
427 if (Fcb->Flags & FCB_DELETE_PENDING)
428 {
429 vfatReleaseFCB (DeviceExt, Fcb);
430 return STATUS_DELETE_PENDING;
431 }
432 DPRINT ("Attaching FCB to fileObject\n");
433 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
434
435 return Status;
436 }
437
438 VOID STATIC
439 VfatSupersedeFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
440 PVFATFCB Fcb)
441 {
442 ULONG Cluster, NextCluster;
443 NTSTATUS Status;
444
445 Fcb->entry.FileSize = 0;
446 if (DeviceExt->FatInfo.FatType == FAT32)
447 {
448 Cluster = Fcb->entry.FirstCluster + Fcb->entry.FirstClusterHigh * 65536;
449 }
450 else
451 {
452 Cluster = Fcb->entry.FirstCluster;
453 }
454 Fcb->entry.FirstCluster = 0;
455 Fcb->entry.FirstClusterHigh = 0;
456 VfatUpdateEntry (Fcb);
457 if (Fcb->RFCB.FileSize.QuadPart > 0)
458 {
459 Fcb->RFCB.AllocationSize.QuadPart = 0;
460 Fcb->RFCB.FileSize.QuadPart = 0;
461 Fcb->RFCB.ValidDataLength.QuadPart = 0;
462 /* Notify cache manager about the change in file size if caching is
463 initialized on the file stream */
464 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
465 {
466 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
467 }
468 }
469 while (Cluster != 0xffffffff && Cluster > 1)
470 {
471 Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
472 WriteCluster (DeviceExt, Cluster, 0);
473 Cluster = NextCluster;
474 }
475 }
476
477 NTSTATUS
478 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
479 /*
480 * FUNCTION: Create or open a file
481 */
482 {
483 PIO_STACK_LOCATION Stack;
484 PFILE_OBJECT FileObject;
485 NTSTATUS Status = STATUS_SUCCESS;
486 PDEVICE_EXTENSION DeviceExt;
487 ULONG RequestedDisposition, RequestedOptions;
488 PVFATCCB pCcb;
489 PVFATFCB pFcb;
490 PWCHAR c, last;
491 BOOLEAN PagingFileCreate = FALSE;
492 LARGE_INTEGER AllocationSize;
493 BOOLEAN Dots;
494 UNICODE_STRING NameU;
495 WCHAR NameW[MAX_PATH];
496
497 /* Unpack the various parameters. */
498 Stack = IoGetCurrentIrpStackLocation (Irp);
499 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
500 RequestedOptions =
501 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
502 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
503 FileObject = Stack->FileObject;
504 DeviceExt = DeviceObject->DeviceExtension;
505
506 /* Check their validity. */
507 if (RequestedOptions & FILE_DIRECTORY_FILE &&
508 RequestedDisposition == FILE_SUPERSEDE)
509 {
510 return(STATUS_INVALID_PARAMETER);
511 }
512
513 /* This a open operation for the volume itself */
514 if (FileObject->FileName.Length == 0 &&
515 FileObject->RelatedFileObject == NULL)
516 {
517 if (RequestedDisposition == FILE_CREATE ||
518 RequestedDisposition == FILE_OVERWRITE_IF ||
519 RequestedDisposition == FILE_SUPERSEDE)
520 {
521 return(STATUS_ACCESS_DENIED);
522 }
523 if (RequestedOptions & FILE_DIRECTORY_FILE)
524 {
525 return(STATUS_NOT_A_DIRECTORY);
526 }
527 pFcb = DeviceExt->VolumeFcb;
528 pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
529 if (pCcb == NULL)
530 {
531 return (STATUS_INSUFFICIENT_RESOURCES);
532 }
533 memset(pCcb, 0, sizeof(VFATCCB));
534 FileObject->Flags |= FO_FCB_IS_VALID;
535 FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
536 FileObject->FsContext = pFcb;
537 FileObject->FsContext2 = pCcb;
538 pFcb->RefCount++;
539
540 Irp->IoStatus.Information = FILE_OPENED;
541 return(STATUS_SUCCESS);
542 }
543
544 /*
545 * Check for illegal characters and illegale dot sequences in the file name
546 */
547 c = FileObject->FileName.Buffer + FileObject->FileName.Length / sizeof(WCHAR);
548 last = c - 1;
549 Dots = TRUE;
550 while (c-- > FileObject->FileName.Buffer)
551 {
552 if (*c == L'\\' || c == FileObject->FileName.Buffer)
553 {
554 if (Dots && last > c)
555 {
556 return(STATUS_OBJECT_NAME_INVALID);
557 }
558 last = c - 1;
559 Dots = TRUE;
560 }
561 else if (*c != L'.')
562 {
563 Dots = FALSE;
564 }
565
566 if (*c != '\\' && vfatIsLongIllegal(*c))
567 {
568 return(STATUS_OBJECT_NAME_INVALID);
569 }
570 }
571
572 NameU.Buffer = NameW;
573 NameU.Length = 0;
574 NameU.MaximumLength = sizeof(NameW);
575
576 /* Try opening the file. */
577 Status = VfatOpenFile (DeviceExt, FileObject, &NameU);
578
579 /*
580 * If the directory containing the file to open doesn't exist then
581 * fail immediately
582 */
583 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
584 Status == STATUS_INVALID_PARAMETER ||
585 Status == STATUS_DELETE_PENDING)
586 {
587 return(Status);
588 }
589
590 /*
591 * If the file open failed then create the required file
592 */
593 if (!NT_SUCCESS (Status))
594 {
595 if (RequestedDisposition == FILE_CREATE ||
596 RequestedDisposition == FILE_OPEN_IF ||
597 RequestedDisposition == FILE_OVERWRITE_IF ||
598 RequestedDisposition == FILE_SUPERSEDE)
599 {
600 ULONG Attributes;
601 Attributes = Stack->Parameters.Create.FileAttributes;
602 Status = VfatAddEntry (DeviceExt, &NameU, FileObject, RequestedOptions,
603 (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
604 if (NT_SUCCESS (Status))
605 {
606 pFcb = FileObject->FsContext;
607
608 Irp->IoStatus.Information = FILE_CREATED;
609
610 VfatSetAllocationSizeInformation(FileObject,
611 pFcb,
612 DeviceExt,
613 &Irp->Overlay.AllocationSize);
614 VfatSetExtendedAttributes(FileObject,
615 Irp->AssociatedIrp.SystemBuffer,
616 Stack->Parameters.Create.EaLength);
617 IoSetShareAccess(0 /*DesiredAccess*/,
618 Stack->Parameters.Create.ShareAccess,
619 FileObject,
620 &pFcb->FCBShareAccess);
621
622 if (PagingFileCreate)
623 {
624 pFcb->Flags |= FCB_IS_PAGE_FILE;
625 }
626 }
627 else
628 {
629 return(Status);
630 }
631 }
632 else
633 {
634 return(Status);
635 }
636 }
637 else
638 {
639 /* Otherwise fail if the caller wanted to create a new file */
640 if (RequestedDisposition == FILE_CREATE)
641 {
642 Irp->IoStatus.Information = FILE_EXISTS;
643 VfatCloseFile (DeviceExt, FileObject);
644 return(STATUS_OBJECT_NAME_COLLISION);
645 }
646
647 pFcb = FileObject->FsContext;
648
649 /*
650 * Check the file has the requested attributes
651 */
652 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
653 pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
654 {
655 VfatCloseFile (DeviceExt, FileObject);
656 return(STATUS_FILE_IS_A_DIRECTORY);
657 }
658 if (RequestedOptions & FILE_DIRECTORY_FILE &&
659 !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
660 {
661 VfatCloseFile (DeviceExt, FileObject);
662 return(STATUS_NOT_A_DIRECTORY);
663 }
664
665 if (PagingFileCreate)
666 {
667 /* FIXME:
668 * Do more checking for page files. It is possible,
669 * that the file was opened and closed previously
670 * as a normal cached file. In this case, the cache
671 * manager has referenced the fileobject and the fcb
672 * is held in memory. Try to remove the fileobject
673 * from cache manager and use the fcb.
674 */
675 if (pFcb->RefCount > 1)
676 {
677 if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
678 {
679 VfatCloseFile(DeviceExt, FileObject);
680 return(STATUS_INVALID_PARAMETER);
681 }
682 }
683 else
684 {
685 pFcb->Flags |= FCB_IS_PAGE_FILE;
686 }
687 }
688 else
689 {
690 if (pFcb->Flags & FCB_IS_PAGE_FILE)
691 {
692 VfatCloseFile(DeviceExt, FileObject);
693 return(STATUS_INVALID_PARAMETER);
694 }
695 }
696
697
698 if (RequestedDisposition == FILE_OVERWRITE ||
699 RequestedDisposition == FILE_OVERWRITE_IF)
700 {
701 AllocationSize.QuadPart = 0;
702 Status = VfatSetAllocationSizeInformation (FileObject,
703 pFcb,
704 DeviceExt,
705 &AllocationSize);
706 if (!NT_SUCCESS (Status))
707 {
708 VfatCloseFile (DeviceExt, FileObject);
709 return(Status);
710 }
711 }
712
713
714 /* Supersede the file */
715 if (RequestedDisposition == FILE_SUPERSEDE)
716 {
717 VfatSupersedeFile(DeviceExt, FileObject, pFcb);
718 Irp->IoStatus.Information = FILE_SUPERSEDED;
719 }
720 else if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)
721 {
722 Irp->IoStatus.Information = FILE_OVERWRITTEN;
723 }
724 else
725 {
726 Irp->IoStatus.Information = FILE_OPENED;
727 }
728 }
729
730 /* FIXME : test share access */
731 /* FIXME : test write access if requested */
732
733 return(Status);
734 }
735
736
737 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
738 /*
739 * FUNCTION: Create or open a file
740 */
741 {
742 NTSTATUS Status;
743
744 assert (IrpContext);
745
746 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
747 {
748 /* DeviceObject represents FileSystem instead of logical volume */
749 DPRINT ("FsdCreate called with file system\n");
750 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
751 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
752 IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
753 VfatFreeIrpContext(IrpContext);
754 return(STATUS_SUCCESS);
755 }
756
757 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
758 {
759 return(VfatQueueRequest (IrpContext));
760 }
761
762 IrpContext->Irp->IoStatus.Information = 0;
763 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
764 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
765 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
766
767 IrpContext->Irp->IoStatus.Status = Status;
768 IoCompleteRequest (IrpContext->Irp,
769 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
770 VfatFreeIrpContext(IrpContext);
771 return(Status);
772 }
773
774 /* EOF */