- Ntoskrnl uses for all access to internal structures the SectionObjectPointers from...
[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.54 2003/02/13 22:24:16 hbirr 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 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
368 DPRINT ("try related for %S\n", pRelativeFileName);
369 fcb = pFileObject->FsContext;
370 assert (fcb);
371
372 /* verify related object is a directory and target name
373 don't start with \. */
374 if (!(fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
375 || (pRelativeFileName[0] == L'\\'))
376 {
377 return STATUS_INVALID_PARAMETER;
378 }
379
380 /* construct absolute path name */
381 assert (wcslen (fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1
382 <= MAX_PATH);
383 rcName = ExAllocatePool (NonPagedPool, MAX_PATH * sizeof(WCHAR));
384 if (!rcName)
385 {
386 return STATUS_INSUFFICIENT_RESOURCES;
387 }
388 wcscpy (rcName, fcb->PathName);
389 if (!vfatFCBIsRoot(fcb))
390 wcscat (rcName, L"\\");
391 wcscat (rcName, pRelativeFileName);
392 *pAbsoluteFilename = rcName;
393
394 return STATUS_SUCCESS;
395 }
396
397 NTSTATUS
398 VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
399 PWSTR FileName)
400 /*
401 * FUNCTION: Opens a file
402 */
403 {
404 PVFATFCB ParentFcb;
405 PVFATFCB Fcb;
406 NTSTATUS Status;
407 PWSTR AbsFileName = NULL;
408
409 DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
410
411 if (FileObject->RelatedFileObject)
412 {
413 DPRINT ("Converting relative filename to absolute filename\n");
414 Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject,
415 FileName,
416 &AbsFileName);
417 FileName = AbsFileName;
418 if (!NT_SUCCESS(Status))
419 {
420 return Status;
421 }
422 }
423
424 //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
425
426 DPRINT ("PathName to open: %S\n", FileName);
427
428 /* try first to find an existing FCB in memory */
429 DPRINT ("Checking for existing FCB in memory\n");
430 Fcb = vfatGrabFCBFromTable (DeviceExt, FileName);
431 if (Fcb == NULL)
432 {
433 DPRINT ("No existing FCB found, making a new one if file exists.\n");
434 Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileName);
435 if (ParentFcb != NULL)
436 {
437 vfatReleaseFCB (DeviceExt, ParentFcb);
438 }
439 if (!NT_SUCCESS (Status))
440 {
441 DPRINT ("Could not make a new FCB, status: %x\n", Status);
442
443 if (AbsFileName)
444 ExFreePool (AbsFileName);
445
446 return Status;
447 }
448 }
449 if (Fcb->Flags & FCB_DELETE_PENDING)
450 {
451 vfatReleaseFCB (DeviceExt, Fcb);
452 if (AbsFileName)
453 ExFreePool (AbsFileName);
454 return STATUS_DELETE_PENDING;
455 }
456 DPRINT ("Attaching FCB to fileObject\n");
457 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
458
459 if (AbsFileName)
460 ExFreePool (AbsFileName);
461
462 return Status;
463 }
464
465 VOID STATIC
466 VfatPagingFileCreate(PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb)
467 {
468 ULONG CurrentCluster, NextCluster, i;
469 NTSTATUS Status;
470
471 Fcb->Flags |= FCB_IS_PAGE_FILE;
472 Fcb->FatChainSize =
473 ((Fcb->entry.FileSize + DeviceExt->FatInfo.BytesPerCluster - 1) /
474 DeviceExt->FatInfo.BytesPerCluster);
475 if (Fcb->FatChainSize)
476 {
477 Fcb->FatChain =
478 ExAllocatePool(NonPagedPool, Fcb->FatChainSize * sizeof(ULONG));
479 }
480
481 if (DeviceExt->FatInfo.FatType == FAT32)
482 {
483 CurrentCluster = Fcb->entry.FirstCluster +
484 Fcb->entry.FirstClusterHigh * 65536;
485 }
486 else
487 {
488 CurrentCluster = Fcb->entry.FirstCluster;
489 }
490
491 i = 0;
492 if (Fcb->FatChainSize)
493 {
494 while (CurrentCluster != 0xffffffff)
495 {
496 Fcb->FatChain[i] = CurrentCluster;
497 Status = GetNextCluster (DeviceExt, CurrentCluster,
498 &NextCluster, FALSE);
499 i++;
500 CurrentCluster = NextCluster;
501 }
502 }
503 }
504
505 VOID STATIC
506 VfatSupersedeFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
507 PVFATFCB Fcb)
508 {
509 ULONG Cluster, NextCluster;
510 NTSTATUS Status;
511
512 Fcb->entry.FileSize = 0;
513 if (DeviceExt->FatInfo.FatType == FAT32)
514 {
515 Cluster = Fcb->entry.FirstCluster + Fcb->entry.FirstClusterHigh * 65536;
516 }
517 else
518 {
519 Cluster = Fcb->entry.FirstCluster;
520 }
521 Fcb->entry.FirstCluster = 0;
522 Fcb->entry.FirstClusterHigh = 0;
523 VfatUpdateEntry (DeviceExt, FileObject);
524 if (Fcb->RFCB.FileSize.QuadPart > 0)
525 {
526 Fcb->RFCB.AllocationSize.QuadPart = 0;
527 Fcb->RFCB.FileSize.QuadPart = 0;
528 Fcb->RFCB.ValidDataLength.QuadPart = 0;
529 /* Notify cache manager about the change in file size if caching is
530 initialized on the file stream */
531 if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
532 {
533 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
534 }
535 }
536 while (Cluster != 0xffffffff && Cluster > 1)
537 {
538 Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
539 WriteCluster (DeviceExt, Cluster, 0);
540 Cluster = NextCluster;
541 }
542 }
543
544 NTSTATUS
545 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
546 /*
547 * FUNCTION: Create or open a file
548 */
549 {
550 PIO_STACK_LOCATION Stack;
551 PFILE_OBJECT FileObject;
552 NTSTATUS Status = STATUS_SUCCESS;
553 PDEVICE_EXTENSION DeviceExt;
554 ULONG RequestedDisposition, RequestedOptions;
555 PVFATCCB pCcb;
556 PVFATFCB pFcb;
557 PWCHAR c;
558 BOOLEAN PagingFileCreate = FALSE;
559 LARGE_INTEGER AllocationSize;
560
561 /* Unpack the various parameters. */
562 Stack = IoGetCurrentIrpStackLocation (Irp);
563 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
564 RequestedOptions =
565 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
566 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
567 FileObject = Stack->FileObject;
568 DeviceExt = DeviceObject->DeviceExtension;
569
570 /* Check their validity. */
571 if (RequestedOptions & FILE_DIRECTORY_FILE &&
572 RequestedDisposition == FILE_SUPERSEDE)
573 {
574 return(STATUS_INVALID_PARAMETER);
575 }
576
577 /* This a open operation for the volume itself */
578 if (FileObject->FileName.Length == 0 &&
579 FileObject->RelatedFileObject == NULL)
580 {
581 if (RequestedDisposition == FILE_CREATE ||
582 RequestedDisposition == FILE_OVERWRITE_IF ||
583 RequestedDisposition == FILE_SUPERSEDE)
584 {
585 return(STATUS_ACCESS_DENIED);
586 }
587 if (RequestedOptions & FILE_DIRECTORY_FILE)
588 {
589 return(STATUS_NOT_A_DIRECTORY);
590 }
591 pFcb = DeviceExt->VolumeFcb;
592 pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
593 if (pCcb == NULL)
594 {
595 return (STATUS_INSUFFICIENT_RESOURCES);
596 }
597 memset(pCcb, 0, sizeof(VFATCCB));
598 FileObject->Flags |= FO_FCB_IS_VALID;
599 FileObject->SectionObjectPointers = &pFcb->SectionObjectPointers;
600 FileObject->FsContext = pFcb;
601 FileObject->FsContext2 = pCcb;
602 pFcb->RefCount++;
603
604 Irp->IoStatus.Information = FILE_OPENED;
605 return(STATUS_SUCCESS);
606 }
607
608 /*
609 * Check for illegal characters in the file name
610 */
611 c = FileObject->FileName.Buffer;
612 while (*c != 0)
613 {
614 if (*c == L'*' || *c == L'?' || (*c == L'\\' && c[1] == L'\\'))
615 {
616 return(STATUS_OBJECT_NAME_INVALID);
617 }
618 c++;
619 }
620
621 /* Try opening the file. */
622 Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
623
624 /*
625 * If the directory containing the file to open doesn't exist then
626 * fail immediately
627 */
628 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
629 Status == STATUS_INVALID_PARAMETER ||
630 Status == STATUS_DELETE_PENDING)
631 {
632 return(Status);
633 }
634
635 /*
636 * If the file open failed then create the required file
637 */
638 if (!NT_SUCCESS (Status))
639 {
640 if (RequestedDisposition == FILE_CREATE ||
641 RequestedDisposition == FILE_OPEN_IF ||
642 RequestedDisposition == FILE_OVERWRITE_IF ||
643 RequestedDisposition == FILE_SUPERSEDE)
644 {
645 ULONG Attributes;
646 Attributes = Stack->Parameters.Create.FileAttributes;
647 Status = VfatAddEntry (DeviceExt, FileObject, RequestedOptions,
648 Attributes & FILE_ATTRIBUTE_VALID_FLAGS);
649 if (NT_SUCCESS (Status))
650 {
651 pFcb = FileObject->FsContext;
652 Irp->IoStatus.Information = FILE_CREATED;
653 VfatSetAllocationSizeInformation(FileObject,
654 pFcb,
655 DeviceExt,
656 &Irp->Overlay.AllocationSize);
657 VfatSetExtendedAttributes(FileObject,
658 Irp->AssociatedIrp.SystemBuffer,
659 Stack->Parameters.Create.EaLength);
660 IoSetShareAccess(0 /*DesiredAccess*/,
661 Stack->Parameters.Create.ShareAccess,
662 FileObject,
663 &pFcb->FCBShareAccess);
664 }
665 else
666 {
667 return(Status);
668 }
669 }
670 else
671 {
672 return(Status);
673 }
674 }
675 else
676 {
677 /* Otherwise fail if the caller wanted to create a new file */
678 if (RequestedDisposition == FILE_CREATE)
679 {
680 Irp->IoStatus.Information = FILE_EXISTS;
681 VfatCloseFile (DeviceExt, FileObject);
682 return(STATUS_OBJECT_NAME_COLLISION);
683 }
684
685 pFcb = FileObject->FsContext;
686
687 /*
688 * Check the file has the requested attributes
689 */
690 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
691 pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
692 {
693 VfatCloseFile (DeviceExt, FileObject);
694 return(STATUS_FILE_IS_A_DIRECTORY);
695 }
696 if (RequestedOptions & FILE_DIRECTORY_FILE &&
697 !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
698 {
699 VfatCloseFile (DeviceExt, FileObject);
700 return(STATUS_NOT_A_DIRECTORY);
701 }
702
703 if (RequestedDisposition == FILE_OVERWRITE ||
704 RequestedDisposition == FILE_OVERWRITE_IF)
705 {
706 AllocationSize.QuadPart = 0;
707 Status = VfatSetAllocationSizeInformation (FileObject,
708 pFcb,
709 DeviceExt,
710 &AllocationSize);
711 if (!NT_SUCCESS (Status))
712 {
713 VfatCloseFile (DeviceExt, FileObject);
714 return(Status);
715 }
716 }
717
718
719 /* Supersede the file */
720 if (RequestedDisposition == FILE_SUPERSEDE)
721 {
722 VfatSupersedeFile(DeviceExt, FileObject, pFcb);
723 Irp->IoStatus.Information = FILE_SUPERSEDED;
724 }
725 else
726 {
727 Irp->IoStatus.Information = FILE_OPENED;
728 }
729 }
730
731 /*
732 * If this create was for a paging file then make sure all the
733 * information needed to manipulate it is locked in memory.
734 */
735 if (PagingFileCreate)
736 {
737 VfatPagingFileCreate(DeviceExt, pFcb);
738 }
739
740 /* FIXME : test share access */
741 /* FIXME : test write access if requested */
742
743 return(Status);
744 }
745
746
747 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
748 /*
749 * FUNCTION: Create or open a file
750 */
751 {
752 NTSTATUS Status;
753
754 assert (IrpContext);
755
756 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
757 {
758 /* DeviceObject represents FileSystem instead of logical volume */
759 DPRINT ("FsdCreate called with file system\n");
760 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
761 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
762 IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
763 VfatFreeIrpContext(IrpContext);
764 return(STATUS_SUCCESS);
765 }
766
767 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
768 {
769 return(VfatQueueRequest (IrpContext));
770 }
771
772 IrpContext->Irp->IoStatus.Information = 0;
773 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
774 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
775 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
776
777 IrpContext->Irp->IoStatus.Status = Status;
778 IoCompleteRequest (IrpContext->Irp,
779 NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
780 VfatFreeIrpContext(IrpContext);
781 return(Status);
782 }
783
784 /* EOF */