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