- Change all FAT*FindAvailableCluster functions to new functions
[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.71 2004/08/01 21:57:17 navaraf 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 Fcb->LastOffset = Fcb->LastCluster = 0;
457 VfatUpdateEntry (Fcb);
458 if (Fcb->RFCB.FileSize.QuadPart > 0)
459 {
460 Fcb->RFCB.AllocationSize.QuadPart = 0;
461 Fcb->RFCB.FileSize.QuadPart = 0;
462 Fcb->RFCB.ValidDataLength.QuadPart = 0;
463 /* Notify cache manager about the change in file size if caching is
464 initialized on the file stream */
465 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
466 {
467 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
468 }
469 }
470 while (Cluster != 0xffffffff && Cluster > 1)
471 {
472 Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
473 WriteCluster (DeviceExt, Cluster, 0);
474 Cluster = NextCluster;
475 }
476 }
477
478 NTSTATUS
479 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
480 /*
481 * FUNCTION: Create or open a file
482 */
483 {
484 PIO_STACK_LOCATION Stack;
485 PFILE_OBJECT FileObject;
486 NTSTATUS Status = STATUS_SUCCESS;
487 PDEVICE_EXTENSION DeviceExt;
488 ULONG RequestedDisposition, RequestedOptions;
489 PVFATCCB pCcb;
490 PVFATFCB pFcb;
491 PWCHAR c, last;
492 BOOLEAN PagingFileCreate = FALSE;
493 LARGE_INTEGER AllocationSize;
494 BOOLEAN Dots;
495 UNICODE_STRING NameU;
496 WCHAR NameW[MAX_PATH];
497
498 /* Unpack the various parameters. */
499 Stack = IoGetCurrentIrpStackLocation (Irp);
500 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
501 RequestedOptions =
502 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
503 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
504 FileObject = Stack->FileObject;
505 DeviceExt = DeviceObject->DeviceExtension;
506
507 /* Check their validity. */
508 if (RequestedOptions & FILE_DIRECTORY_FILE &&
509 RequestedDisposition == FILE_SUPERSEDE)
510 {
511 return(STATUS_INVALID_PARAMETER);
512 }
513
514 /* This a open operation for the volume itself */
515 if (FileObject->FileName.Length == 0 &&
516 FileObject->RelatedFileObject == NULL)
517 {
518 if (RequestedDisposition == FILE_CREATE ||
519 RequestedDisposition == FILE_OVERWRITE_IF ||
520 RequestedDisposition == FILE_SUPERSEDE)
521 {
522 return(STATUS_ACCESS_DENIED);
523 }
524 if (RequestedOptions & FILE_DIRECTORY_FILE)
525 {
526 return(STATUS_NOT_A_DIRECTORY);
527 }
528 pFcb = DeviceExt->VolumeFcb;
529 pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
530 if (pCcb == NULL)
531 {
532 return (STATUS_INSUFFICIENT_RESOURCES);
533 }
534 memset(pCcb, 0, sizeof(VFATCCB));
535 FileObject->Flags |= FO_FCB_IS_VALID;
536 FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
537 FileObject->FsContext = pFcb;
538 FileObject->FsContext2 = pCcb;
539 pFcb->RefCount++;
540
541 Irp->IoStatus.Information = FILE_OPENED;
542 return(STATUS_SUCCESS);
543 }
544
545 /*
546 * Check for illegal characters and illegale dot sequences in the file name
547 */
548 c = FileObject->FileName.Buffer + FileObject->FileName.Length / sizeof(WCHAR);
549 last = c - 1;
550 Dots = TRUE;
551 while (c-- > FileObject->FileName.Buffer)
552 {
553 if (*c == L'\\' || c == FileObject->FileName.Buffer)
554 {
555 if (Dots && last > c)
556 {
557 return(STATUS_OBJECT_NAME_INVALID);
558 }
559 last = c - 1;
560 Dots = TRUE;
561 }
562 else if (*c != L'.')
563 {
564 Dots = FALSE;
565 }
566
567 if (*c != '\\' && vfatIsLongIllegal(*c))
568 {
569 return(STATUS_OBJECT_NAME_INVALID);
570 }
571 }
572
573 NameU.Buffer = NameW;
574 NameU.Length = 0;
575 NameU.MaximumLength = sizeof(NameW);
576
577 /* Try opening the file. */
578 Status = VfatOpenFile (DeviceExt, FileObject, &NameU);
579
580 /*
581 * If the directory containing the file to open doesn't exist then
582 * fail immediately
583 */
584 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
585 Status == STATUS_INVALID_PARAMETER ||
586 Status == STATUS_DELETE_PENDING)
587 {
588 return(Status);
589 }
590
591 /*
592 * If the file open failed then create the required file
593 */
594 if (!NT_SUCCESS (Status))
595 {
596 if (RequestedDisposition == FILE_CREATE ||
597 RequestedDisposition == FILE_OPEN_IF ||
598 RequestedDisposition == FILE_OVERWRITE_IF ||
599 RequestedDisposition == FILE_SUPERSEDE)
600 {
601 ULONG Attributes;
602 Attributes = Stack->Parameters.Create.FileAttributes;
603 Status = VfatAddEntry (DeviceExt, &NameU, FileObject, RequestedOptions,
604 (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
605 if (NT_SUCCESS (Status))
606 {
607 pFcb = FileObject->FsContext;
608
609 Irp->IoStatus.Information = FILE_CREATED;
610
611 VfatSetAllocationSizeInformation(FileObject,
612 pFcb,
613 DeviceExt,
614 &Irp->Overlay.AllocationSize);
615 VfatSetExtendedAttributes(FileObject,
616 Irp->AssociatedIrp.SystemBuffer,
617 Stack->Parameters.Create.EaLength);
618 IoSetShareAccess(0 /*DesiredAccess*/,
619 Stack->Parameters.Create.ShareAccess,
620 FileObject,
621 &pFcb->FCBShareAccess);
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 return(Status);
636 }
637 }
638 else
639 {
640 /* Otherwise fail if the caller wanted to create a new file */
641 if (RequestedDisposition == FILE_CREATE)
642 {
643 Irp->IoStatus.Information = FILE_EXISTS;
644 VfatCloseFile (DeviceExt, FileObject);
645 return(STATUS_OBJECT_NAME_COLLISION);
646 }
647
648 pFcb = FileObject->FsContext;
649
650 /*
651 * Check the file has the requested attributes
652 */
653 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
654 pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
655 {
656 VfatCloseFile (DeviceExt, FileObject);
657 return(STATUS_FILE_IS_A_DIRECTORY);
658 }
659 if (RequestedOptions & FILE_DIRECTORY_FILE &&
660 !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
661 {
662 VfatCloseFile (DeviceExt, FileObject);
663 return(STATUS_NOT_A_DIRECTORY);
664 }
665
666 if (PagingFileCreate)
667 {
668 /* FIXME:
669 * Do more checking for page files. It is possible,
670 * that the file was opened and closed previously
671 * as a normal cached file. In this case, the cache
672 * manager has referenced the fileobject and the fcb
673 * is held in memory. Try to remove the fileobject
674 * from cache manager and use the fcb.
675 */
676 if (pFcb->RefCount > 1)
677 {
678 if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
679 {
680 VfatCloseFile(DeviceExt, FileObject);
681 return(STATUS_INVALID_PARAMETER);
682 }
683 }
684 else
685 {
686 pFcb->Flags |= FCB_IS_PAGE_FILE;
687 }
688 }
689 else
690 {
691 if (pFcb->Flags & FCB_IS_PAGE_FILE)
692 {
693 VfatCloseFile(DeviceExt, FileObject);
694 return(STATUS_INVALID_PARAMETER);
695 }
696 }
697
698
699 if (RequestedDisposition == FILE_OVERWRITE ||
700 RequestedDisposition == FILE_OVERWRITE_IF)
701 {
702 AllocationSize.QuadPart = 0;
703 Status = VfatSetAllocationSizeInformation (FileObject,
704 pFcb,
705 DeviceExt,
706 &AllocationSize);
707 if (!NT_SUCCESS (Status))
708 {
709 VfatCloseFile (DeviceExt, FileObject);
710 return(Status);
711 }
712 }
713
714
715 /* Supersede the file */
716 if (RequestedDisposition == FILE_SUPERSEDE)
717 {
718 VfatSupersedeFile(DeviceExt, FileObject, pFcb);
719 Irp->IoStatus.Information = FILE_SUPERSEDED;
720 }
721 else if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)
722 {
723 Irp->IoStatus.Information = FILE_OVERWRITTEN;
724 }
725 else
726 {
727 Irp->IoStatus.Information = FILE_OPENED;
728 }
729 }
730
731 /* FIXME : test share access */
732 /* FIXME : test write access if requested */
733
734 return(Status);
735 }
736
737
738 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
739 /*
740 * FUNCTION: Create or open a file
741 */
742 {
743 NTSTATUS Status;
744
745 assert (IrpContext);
746
747 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
748 {
749 /* DeviceObject represents FileSystem instead of logical volume */
750 DPRINT ("FsdCreate called with file system\n");
751 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
752 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
753 IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
754 VfatFreeIrpContext(IrpContext);
755 return(STATUS_SUCCESS);
756 }
757
758 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
759 {
760 return(VfatQueueRequest (IrpContext));
761 }
762
763 IrpContext->Irp->IoStatus.Information = 0;
764 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
765 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
766 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
767
768 IrpContext->Irp->IoStatus.Status = Status;
769 IoCompleteRequest (IrpContext->Irp,
770 (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
771 VfatFreeIrpContext(IrpContext);
772 return(Status);
773 }
774
775 /* EOF */