update for HEAD-2003021201
[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   ULONG Read;
189   BOOL isRoot;
190   PVOID Context = NULL;
191   PVOID Page;
192   PVFATFCB rcFcb;
193
194   FATDirEntry fatDirEntry;
195
196   DPRINT ("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n", Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
197   DPRINT ("FindFile: old Pathname %x, old Objectname %x)\n",Fcb->PathName, Fcb->ObjectName);
198
199   isRoot = FALSE;
200   DirIndex = 0;
201   if (wcslen (FileToFind) == 0)
202   {
203     CHECKPOINT;
204     TempStr[0] = (WCHAR) '*';
205     TempStr[1] = 0;
206     FileToFind = (PWSTR)&TempStr;
207   }
208   if (Parent)
209   {
210     FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Parent->entry);
211     if (DeviceExt->FatInfo.FatType == FAT32)
212     {
213       if (FirstCluster == DeviceExt->FatInfo.RootCluster)
214         isRoot = TRUE;
215     }
216     else
217     {
218       if (FirstCluster == 1)
219         isRoot = TRUE;
220     }
221   }
222   else
223     isRoot = TRUE;
224   if (isRoot)
225   {
226     if (DeviceExt->FatInfo.FatType == FAT32)
227       FirstCluster = DeviceExt->FatInfo.RootCluster;
228     else
229       FirstCluster = 1;
230
231     if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
232             || (FileToFind[0] == '.' && FileToFind[1] == 0))
233     {
234        /* it's root : complete essentials fields then return ok */
235        CHECKPOINT;
236        memset (Fcb, 0, sizeof (VFATFCB));
237        memset (Fcb->entry.Filename, ' ', 11);
238        CHECKPOINT;
239        Fcb->PathName[0]='\\';
240        Fcb->ObjectName = &Fcb->PathName[1];
241        Fcb->entry.FileSize = DeviceExt->FatInfo.rootDirectorySectors * DeviceExt->FatInfo.BytesPerSector;
242        Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
243        if (DeviceExt->FatInfo.FatType == FAT32)
244        {
245           Fcb->entry.FirstCluster = ((PUSHORT)FirstCluster)[0];
246           Fcb->entry.FirstClusterHigh = ((PUSHORT)FirstCluster)[1];
247        }
248        else
249           Fcb->entry.FirstCluster = 1;
250        if (pDirIndex)
251           *pDirIndex = 0;
252        if (pDirIndex2)
253           *pDirIndex2 = 0;
254        DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
255        return (STATUS_SUCCESS);
256     }
257   }
258   else
259   {
260     DPRINT ("Parent->entry.FileSize %x\n", Parent->entry.FileSize);
261     FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Parent->entry);
262   }
263   if (pDirIndex && (*pDirIndex))
264     DirIndex = *pDirIndex;
265
266   if (NULL == wcschr(FileToFind, L'?') && NULL == wcschr(FileToFind, L'*'))
267   {
268      /* if there is no '*?' in the search name, than look first for an existing fcb */
269      len = wcslen(Parent->PathName);
270      memcpy(name, Parent->PathName, len * sizeof(WCHAR));
271      if (!vfatFCBIsRoot(Parent))
272      {
273         name[len++] = L'\\';
274      }
275      wcscpy(name + len, FileToFind);
276      rcFcb = vfatGrabFCBFromTable(DeviceExt, name);
277      if (rcFcb)
278      {
279         if(rcFcb->startIndex >= DirIndex)
280         {
281            wcscpy(Fcb->PathName, name);
282            Fcb->ObjectName = &Fcb->PathName[len];
283            memcpy(&Fcb->entry, &rcFcb->entry, sizeof(FATDirEntry));
284            if (pDirIndex)
285            {
286               *pDirIndex = rcFcb->dirIndex;
287            }
288            if (pDirIndex2)
289            {
290               *pDirIndex2 = rcFcb->startIndex;
291            }
292            DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d (%d)\n",Fcb->PathName, Fcb->ObjectName, rcFcb->dirIndex, rcFcb->startIndex);
293            vfatReleaseFCB(DeviceExt, rcFcb);
294            return STATUS_SUCCESS;
295         }
296         else
297         {
298            vfatReleaseFCB(DeviceExt, rcFcb);
299            return STATUS_UNSUCCESSFUL;
300         }
301         vfatReleaseFCB(DeviceExt, rcFcb);
302      }
303   }
304
305   while(TRUE)
306   {
307     Status = vfatGetNextDirEntry(&Context, &Page, Parent, &DirIndex, name, &fatDirEntry, pDirIndex2);
308     if (Status == STATUS_NO_MORE_ENTRIES)
309     {
310         break;
311     }
312     if (vfatIsDirEntryVolume(&fatDirEntry))
313     {
314       DirIndex++;
315       continue;
316     }
317     vfat8Dot3ToString(&fatDirEntry, name2);
318     if (wstrcmpjoki (name, FileToFind) || wstrcmpjoki (name2, FileToFind))
319     {
320        if (Parent && Parent->PathName)
321        {
322           len = wcslen(Parent->PathName);
323           CHECKPOINT;
324           memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
325           Fcb->ObjectName=&Fcb->PathName[len];
326           if (len != 1 || Fcb->PathName[0] != '\\')
327           {
328              Fcb->ObjectName[0] = '\\';
329              Fcb->ObjectName = &Fcb->ObjectName[1];
330           }
331        }
332        else
333        {
334           Fcb->ObjectName=Fcb->PathName;
335           Fcb->ObjectName[0]='\\';
336           Fcb->ObjectName=&Fcb->ObjectName[1];
337        }
338        memcpy(&Fcb->entry, &fatDirEntry, sizeof(FATDirEntry));
339        wcsncpy(Fcb->ObjectName, *name == 0 ? name2 : name, MAX_PATH);
340        if (pDirIndex)
341          *pDirIndex = DirIndex;
342        DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",Fcb->PathName, Fcb->ObjectName, DirIndex);
343
344        if (Context)
345           CcUnpinData(Context);
346
347        return STATUS_SUCCESS;
348     }
349     DirIndex++;
350   }
351   if (pDirIndex)
352      *pDirIndex = DirIndex;
353
354   if (Context)
355      CcUnpinData(Context);
356
357   return (STATUS_UNSUCCESSFUL);
358 }
359
360 NTSTATUS
361 vfatMakeAbsoluteFilename (PFILE_OBJECT pFileObject,
362                           PWSTR pRelativeFileName,
363                           PWSTR *pAbsoluteFilename)
364 {
365   PWSTR  rcName;
366   PVFATFCB  fcb;
367   PVFATCCB  ccb;
368
369   DPRINT ("try related for %S\n", pRelativeFileName);
370   ccb = pFileObject->FsContext2;
371   assert (ccb);
372   fcb = ccb->pFcb;
373   assert (fcb);
374
375   /* verify related object is a directory and target name
376      don't start with \. */
377   if (!(fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
378       || (pRelativeFileName[0] == L'\\'))
379   {
380     return  STATUS_INVALID_PARAMETER;
381   }
382
383   /* construct absolute path name */
384   assert (wcslen (fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1
385           <= MAX_PATH);
386   rcName = ExAllocatePool (NonPagedPool, MAX_PATH * sizeof(WCHAR));
387   if (!rcName)
388   {
389     return STATUS_INSUFFICIENT_RESOURCES;
390   }
391   wcscpy (rcName, fcb->PathName);
392   if (!vfatFCBIsRoot(fcb))
393     wcscat (rcName, L"\\");
394   wcscat (rcName, pRelativeFileName);
395   *pAbsoluteFilename = rcName;
396
397   return  STATUS_SUCCESS;
398 }
399
400 NTSTATUS
401 VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
402              PWSTR FileName)
403 /*
404  * FUNCTION: Opens a file
405  */
406 {
407   PVFATFCB ParentFcb;
408   PVFATFCB Fcb;
409   NTSTATUS Status;
410   PWSTR AbsFileName = NULL;
411
412   DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
413
414   if (FileObject->RelatedFileObject)
415     {
416       DPRINT ("Converting relative filename to absolute filename\n");
417       Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject,
418                                          FileName,
419                                          &AbsFileName);
420       FileName = AbsFileName;
421       if (!NT_SUCCESS(Status))
422       {
423         return Status;
424       }
425     }
426
427   //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
428
429   DPRINT ("PathName to open: %S\n", FileName);
430
431   /*  try first to find an existing FCB in memory  */
432   DPRINT ("Checking for existing FCB in memory\n");
433   Fcb = vfatGrabFCBFromTable (DeviceExt, FileName);
434   if (Fcb == NULL)
435   {
436     DPRINT ("No existing FCB found, making a new one if file exists.\n");
437     Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileName);
438     if (ParentFcb != NULL)
439     {
440       vfatReleaseFCB (DeviceExt, ParentFcb);
441     }
442     if (!NT_SUCCESS (Status))
443     {
444       DPRINT ("Could not make a new FCB, status: %x\n", Status);
445
446       if (AbsFileName)
447         ExFreePool (AbsFileName);
448
449       return  Status;
450     }
451   }
452   if (Fcb->Flags & FCB_DELETE_PENDING)
453   {
454     vfatReleaseFCB (DeviceExt, Fcb);
455     if (AbsFileName)
456       ExFreePool (AbsFileName);
457     return STATUS_DELETE_PENDING;
458   }
459   DPRINT ("Attaching FCB to fileObject\n");
460   Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
461
462   if (AbsFileName)
463     ExFreePool (AbsFileName);
464
465   return  Status;
466 }
467
468 VOID STATIC
469 VfatPagingFileCreate(PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb)
470 {
471   ULONG CurrentCluster, NextCluster, i;
472   NTSTATUS Status;
473
474   Fcb->Flags |= FCB_IS_PAGE_FILE;
475   Fcb->FatChainSize =
476     ((Fcb->entry.FileSize + DeviceExt->FatInfo.BytesPerCluster - 1) / 
477      DeviceExt->FatInfo.BytesPerCluster);
478   if (Fcb->FatChainSize)
479     {
480       Fcb->FatChain = 
481         ExAllocatePool(NonPagedPool, Fcb->FatChainSize * sizeof(ULONG));
482     }
483   
484   if (DeviceExt->FatInfo.FatType == FAT32)
485     {
486       CurrentCluster = Fcb->entry.FirstCluster + 
487         Fcb->entry.FirstClusterHigh * 65536;
488     }
489   else
490     {
491       CurrentCluster = Fcb->entry.FirstCluster;
492     }
493   
494   i = 0;
495   if (Fcb->FatChainSize)
496     {
497       while (CurrentCluster != 0xffffffff)
498         {
499           Fcb->FatChain[i] = CurrentCluster;    
500           Status = GetNextCluster (DeviceExt, CurrentCluster, 
501                                    &NextCluster, FALSE);
502           i++;
503           CurrentCluster = NextCluster;
504         }
505     }
506 }
507
508 VOID STATIC
509 VfatSupersedeFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
510                   PVFATFCB Fcb)
511 {
512   ULONG Cluster, NextCluster;
513   NTSTATUS Status;
514   
515   Fcb->entry.FileSize = 0;
516   if (DeviceExt->FatInfo.FatType == FAT32)
517     {
518       Cluster = Fcb->entry.FirstCluster + Fcb->entry.FirstClusterHigh * 65536;
519     }
520   else
521     {
522       Cluster = Fcb->entry.FirstCluster;
523     }
524   Fcb->entry.FirstCluster = 0;
525   Fcb->entry.FirstClusterHigh = 0;
526   VfatUpdateEntry (DeviceExt, FileObject);
527   if (Fcb->RFCB.FileSize.QuadPart > 0)
528     {
529       Fcb->RFCB.AllocationSize.QuadPart = 0;
530       Fcb->RFCB.FileSize.QuadPart = 0;
531       Fcb->RFCB.ValidDataLength.QuadPart = 0;
532       /* Notify cache manager about the change in file size if caching is
533          initialized on the file stream */
534       if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
535         {
536           CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
537         }
538     }
539   while (Cluster != 0xffffffff && Cluster > 1)
540     {
541       Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
542       WriteCluster (DeviceExt, Cluster, 0);
543       Cluster = NextCluster;
544     }
545 }
546
547 NTSTATUS
548 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
549 /*
550  * FUNCTION: Create or open a file
551  */
552 {
553   PIO_STACK_LOCATION Stack;
554   PFILE_OBJECT FileObject;
555   NTSTATUS Status = STATUS_SUCCESS;
556   PDEVICE_EXTENSION DeviceExt;
557   ULONG RequestedDisposition, RequestedOptions;
558   PVFATCCB pCcb;
559   PVFATFCB pFcb;
560   PWCHAR c;
561   BOOLEAN PagingFileCreate = FALSE;
562   LARGE_INTEGER AllocationSize;
563   
564   /* Unpack the various parameters. */
565   Stack = IoGetCurrentIrpStackLocation (Irp);
566   RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
567   RequestedOptions =
568     Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
569   PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;  
570   FileObject = Stack->FileObject;
571   DeviceExt = DeviceObject->DeviceExtension;
572
573   /* Check their validity. */
574   if (RequestedOptions & FILE_DIRECTORY_FILE &&
575       RequestedDisposition == FILE_SUPERSEDE)
576     {
577       return(STATUS_INVALID_PARAMETER);
578     }
579
580   /* This a open operation for the volume itself */
581   if (FileObject->FileName.Length == 0 && 
582       FileObject->RelatedFileObject == NULL)
583     {      
584       if (RequestedDisposition == FILE_CREATE ||
585           RequestedDisposition == FILE_OVERWRITE_IF ||
586           RequestedDisposition == FILE_SUPERSEDE)
587         {
588           return(STATUS_ACCESS_DENIED);
589         }
590       if (RequestedOptions & FILE_DIRECTORY_FILE)
591         {
592           return(STATUS_NOT_A_DIRECTORY);
593         }
594       pFcb = DeviceExt->VolumeFcb;
595       pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
596       if (pCcb == NULL)
597         {
598           return (STATUS_INSUFFICIENT_RESOURCES);
599         }
600       memset(pCcb, 0, sizeof(VFATCCB));
601       FileObject->Flags |= FO_FCB_IS_VALID;
602       FileObject->SectionObjectPointers = &pFcb->SectionObjectPointers;
603       FileObject->FsContext = (PVOID) &pFcb->RFCB;
604       FileObject->FsContext2 = pCcb;
605       pCcb->pFcb = pFcb;
606       pCcb->PtrFileObject = FileObject;
607       pFcb->pDevExt = DeviceExt;
608       pFcb->RefCount++;
609
610       Irp->IoStatus.Information = FILE_OPENED;
611       return(STATUS_SUCCESS);
612     }
613
614   /*
615    * Check for illegal characters in the file name
616    */
617   c = FileObject->FileName.Buffer;
618   while (*c != 0)
619     {
620       if (*c == L'*' || *c == L'?' || (*c == L'\\' && c[1] == L'\\'))
621         {
622           return(STATUS_OBJECT_NAME_INVALID);
623         }
624       c++;
625     }
626
627   /* Try opening the file. */
628   Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
629
630   /*
631    * If the directory containing the file to open doesn't exist then
632    * fail immediately
633    */
634   if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
635       Status == STATUS_INVALID_PARAMETER ||
636       Status == STATUS_DELETE_PENDING)
637     {
638       return(Status);
639     }
640
641   /*
642    * If the file open failed then create the required file
643    */
644   if (!NT_SUCCESS (Status))
645     {      
646       if (RequestedDisposition == FILE_CREATE ||
647           RequestedDisposition == FILE_OPEN_IF ||
648           RequestedDisposition == FILE_OVERWRITE_IF ||
649           RequestedDisposition == FILE_SUPERSEDE)
650         {
651           ULONG Attributes;
652           Attributes = Stack->Parameters.Create.FileAttributes;
653           Status = VfatAddEntry (DeviceExt, FileObject, RequestedOptions, 
654                                  Attributes & FILE_ATTRIBUTE_VALID_FLAGS);
655           if (NT_SUCCESS (Status))
656             {
657               pCcb = FileObject->FsContext2;
658               pFcb = pCcb->pFcb;
659               Irp->IoStatus.Information = FILE_CREATED;
660               VfatSetAllocationSizeInformation(FileObject, 
661                                                pFcb,
662                                                DeviceExt,
663                                                &Irp->Overlay.AllocationSize);
664               VfatSetExtendedAttributes(FileObject, 
665                                         Irp->AssociatedIrp.SystemBuffer,
666                                         Stack->Parameters.Create.EaLength);
667               IoSetShareAccess(0 /*DesiredAccess*/,
668                                Stack->Parameters.Create.ShareAccess,
669                                FileObject,
670                                &pFcb->FCBShareAccess);
671             }
672           else
673             {
674               return(Status);
675             }
676         }
677       else
678         {
679           return(Status);
680         }
681     }
682   else
683     {
684       /* Otherwise fail if the caller wanted to create a new file  */
685       if (RequestedDisposition == FILE_CREATE)
686         {
687           Irp->IoStatus.Information = FILE_EXISTS;
688           VfatCloseFile (DeviceExt, FileObject);
689           return(STATUS_OBJECT_NAME_COLLISION);
690         }
691
692       pCcb = FileObject->FsContext2;
693       pFcb = pCcb->pFcb;
694
695       /*
696        * Check the file has the requested attributes
697        */
698       if (RequestedOptions & FILE_NON_DIRECTORY_FILE && 
699           pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
700         {
701           VfatCloseFile (DeviceExt, FileObject);
702           return(STATUS_FILE_IS_A_DIRECTORY);
703         }
704       if (RequestedOptions & FILE_DIRECTORY_FILE && 
705           !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
706         {
707           VfatCloseFile (DeviceExt, FileObject);
708           return(STATUS_NOT_A_DIRECTORY);
709         }
710
711       if (RequestedDisposition == FILE_OVERWRITE ||
712           RequestedDisposition == FILE_OVERWRITE_IF)
713         {
714         AllocationSize.QuadPart = 0;
715         Status = VfatSetAllocationSizeInformation (FileObject,
716                                                    pFcb,
717                                                    DeviceExt,
718                                                    &AllocationSize);
719         if (!NT_SUCCESS (Status))
720           {
721           VfatCloseFile (DeviceExt, FileObject);
722           return(Status);
723           }
724         }
725         
726       
727       /* Supersede the file */
728       if (RequestedDisposition == FILE_SUPERSEDE)
729         {
730           VfatSupersedeFile(DeviceExt, FileObject, pFcb);
731           Irp->IoStatus.Information = FILE_SUPERSEDED;
732         }
733       else
734         {
735           Irp->IoStatus.Information = FILE_OPENED;
736         }
737     }
738   
739   /*
740    * If this create was for a paging file then make sure all the
741    * information needed to manipulate it is locked in memory.
742    */
743   if (PagingFileCreate)
744     {
745       VfatPagingFileCreate(DeviceExt, pFcb);
746     }
747
748   /* FIXME : test share access */
749   /* FIXME : test write access if requested */
750
751   return(Status);
752 }
753
754
755 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
756 /*
757  * FUNCTION: Create or open a file
758  */
759 {
760   NTSTATUS Status;
761   
762   assert (IrpContext);
763   
764   if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
765     {
766       /* DeviceObject represents FileSystem instead of logical volume */
767       DPRINT ("FsdCreate called with file system\n");
768       IrpContext->Irp->IoStatus.Information = FILE_OPENED;
769       IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
770       IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
771       VfatFreeIrpContext(IrpContext);
772       return(STATUS_SUCCESS);
773     }
774   
775   if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
776     {
777       return(VfatQueueRequest (IrpContext));
778     }
779   
780   IrpContext->Irp->IoStatus.Information = 0;
781   ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
782   Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
783   ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
784
785   IrpContext->Irp->IoStatus.Status = Status;
786   IoCompleteRequest (IrpContext->Irp, 
787                      NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
788   VfatFreeIrpContext(IrpContext);
789   return(Status);
790 }
791
792 /* EOF */