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