2003-07-24 Casper S. Hornstrup <chorns@users.sourceforge.net>
[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.63 2003/07/24 20:52:58 chorns Exp $
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 */