Reverted latest changes.
[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.46 2002/09/08 10:22:12 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 (PAGESIZE / sizeof (FATDirEntry))
42
43 /* FUNCTIONS *****************************************************************/
44
45 BOOLEAN
46 IsLastEntry (PVOID Block, ULONG Offset)
47 /*
48 * FUNCTION: Determine if the given directory entry is the last
49 */
50 {
51 return (((FATDirEntry *) Block)[Offset].Filename[0] == 0);
52 }
53
54 BOOLEAN
55 IsVolEntry (PVOID Block, ULONG Offset)
56 /*
57 * FUNCTION: Determine if the given directory entry is a vol entry
58 */
59 {
60 if ((((FATDirEntry *) Block)[Offset].Attrib) == 0x28)
61 return TRUE;
62 else
63 return FALSE;
64 }
65
66 BOOLEAN
67 IsDeletedEntry (PVOID Block, ULONG Offset)
68 /*
69 * FUNCTION: Determines if the given entry is a deleted one
70 */
71 {
72 /* Checks special character */
73
74 return ((((FATDirEntry *) Block)[Offset].Filename[0] == 0xe5) ||
75 (((FATDirEntry *) Block)[Offset].Filename[0] == 0));
76 }
77
78 void vfat8Dot3ToString (PCHAR pBasename, PCHAR pExtension, PWSTR pName)
79 {
80 int fromIndex, toIndex;
81
82 fromIndex = toIndex = 0;
83 while (fromIndex < 8 && pBasename [fromIndex] != ' ')
84 {
85 pName [toIndex++] = pBasename [fromIndex++];
86 }
87 if (pExtension [0] != ' ')
88 {
89 pName [toIndex++] = L'.';
90 fromIndex = 0;
91 while (fromIndex < 3 && pExtension [fromIndex] != ' ')
92 {
93 pName [toIndex++] = pExtension [fromIndex++];
94 }
95 }
96 pName [toIndex] = L'\0';
97 }
98
99 static void vfat8Dot3ToVolumeLabel (PCHAR pBasename, PCHAR pExtension, PWSTR pName)
100 {
101 int fromIndex, toIndex;
102
103 fromIndex = toIndex = 0;
104 while (fromIndex < 8 && pBasename [fromIndex] != ' ')
105 {
106 pName [toIndex++] = pBasename [fromIndex++];
107 }
108 if (pExtension [0] != ' ')
109 {
110 fromIndex = 0;
111 while (fromIndex < 3 && pBasename [fromIndex] != ' ')
112 {
113 pName [toIndex++] = pExtension [fromIndex++];
114 }
115 }
116 pName [toIndex] = L'\0';
117 }
118
119 NTSTATUS
120 GetEntryName(PVOID *pContext,
121 PVOID *Block,
122 PFILE_OBJECT FileObject,
123 PWSTR Name,
124 PULONG pIndex,
125 PULONG pIndex2)
126 /*
127 * FUNCTION: Retrieves the file name, be it in short or long file name format
128 */
129 {
130 NTSTATUS Status;
131 FATDirEntry * test;
132 slot * test2;
133 ULONG cpos;
134 ULONG Offset = *pIndex % ENTRIES_PER_PAGE;
135 ULONG Read;
136 LARGE_INTEGER FileOffset;
137
138 *Name = 0;
139 while (TRUE)
140 {
141 test = (FATDirEntry *) *Block;
142 test2 = (slot *) *Block;
143 if (vfatIsDirEntryEndMarker(&test[Offset]))
144 {
145 return STATUS_NO_MORE_ENTRIES;
146 }
147 if (test2[Offset].attr == 0x0f && !vfatIsDirEntryDeleted(&test[Offset]))
148 {
149 *Name = 0;
150 if (pIndex2)
151 *pIndex2 = *pIndex; // start of dir entry
152
153 DPRINT (" long name entry found at %d\n", *pIndex);
154
155 DPRINT (" name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n",
156 5, test2 [Offset].name0_4,
157 6, test2 [Offset].name5_10,
158 2, test2 [Offset].name11_12);
159
160 vfat_initstr (Name, 255);
161 vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
162 vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
163 vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
164
165 DPRINT (" longName: [%S]\n", Name);
166 cpos = 0;
167 while ((test2[Offset].id != 0x41) && (test2[Offset].id != 0x01) &&
168 (test2[Offset].attr > 0))
169 {
170 (*pIndex)++;
171 Offset++;
172
173 if (Offset == ENTRIES_PER_PAGE)
174 {
175 Offset = 0;
176 CcUnpinData(*pContext);
177 FileOffset.QuadPart = *pIndex * sizeof(FATDirEntry);
178 if(!CcMapData(FileObject, &FileOffset, PAGESIZE, TRUE, pContext, Block))
179 {
180 *pContext = NULL;
181 return STATUS_NO_MORE_ENTRIES;
182 }
183 test2 = (slot *) *Block;
184 }
185 DPRINT (" long name entry found at %d\n", *pIndex);
186
187 DPRINT (" name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n",
188 5, test2 [Offset].name0_4,
189 6, test2 [Offset].name5_10,
190 2, test2 [Offset].name11_12);
191
192 cpos++;
193 vfat_movstr (Name, 13, 0, cpos * 13);
194 vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
195 vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
196 vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
197
198 DPRINT (" longName: [%S]\n", Name);
199 }
200 (*pIndex)++;
201 Offset++;
202 if (Offset == ENTRIES_PER_PAGE)
203 {
204 Offset = 0;
205 CcUnpinData(*pContext);
206 FileOffset.QuadPart = *pIndex * sizeof(FATDirEntry);
207 if(!CcMapData(FileObject, &FileOffset, PAGESIZE, TRUE, pContext, Block))
208 {
209 *pContext = NULL;
210 return STATUS_NO_MORE_ENTRIES;
211 }
212 test2 = (slot *) *Block;
213 test = (FATDirEntry*) *Block;
214 }
215 }
216 else
217 {
218 if (vfatIsDirEntryEndMarker(&test[Offset]))
219 return STATUS_NO_MORE_ENTRIES;
220 if (vfatIsDirEntryDeleted(&test[Offset]))
221 return STATUS_UNSUCCESSFUL;
222 if (*Name == 0)
223 {
224 vfat8Dot3ToString (test[Offset].Filename, test[Offset].Ext, Name);
225 if (pIndex2)
226 *pIndex2 = *pIndex;
227 }
228 break;
229 }
230 }
231 return STATUS_SUCCESS;
232 }
233
234 NTSTATUS
235 ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
236 /*
237 * FUNCTION: Read the volume label
238 */
239 {
240 PVOID Context = NULL;
241 ULONG Offset = 0;
242 ULONG DirIndex = 0;
243 FATDirEntry* Entry;
244 PVFATFCB pFcb;
245 LARGE_INTEGER FileOffset;
246
247 *(Vpb->VolumeLabel) = 0;
248 Vpb->VolumeLabelLength = 0;
249
250 pFcb = vfatOpenRootFCB (DeviceExt);
251
252 while (TRUE)
253 {
254 if (Context == NULL || Offset == ENTRIES_PER_PAGE)
255 {
256 if (Offset == ENTRIES_PER_PAGE)
257 {
258 Offset = 0;
259 }
260 if (Context)
261 {
262 CcUnpinData(Context);
263 }
264 FileOffset.u.HighPart = 0;
265 FileOffset.u.LowPart = (DirIndex - Offset) * sizeof(FATDirEntry);
266 if (!CcMapData(pFcb->FileObject, &FileOffset, PAGESIZE, TRUE, &Context, (PVOID*)&Entry))
267 {
268 Context = NULL;
269 break;
270 }
271 }
272 if (IsVolEntry(Entry, Offset))
273 {
274 /* copy volume label */
275 vfat8Dot3ToVolumeLabel (Entry[Offset].Filename, Entry[Offset].Ext, Vpb->VolumeLabel);
276 Vpb->VolumeLabelLength = wcslen (Vpb->VolumeLabel) * sizeof(WCHAR);
277 break;
278 }
279 if (IsLastEntry(Entry, Offset))
280 {
281 break;
282 }
283 Offset++;
284 DirIndex++;
285 }
286
287 if (Context)
288 {
289 CcUnpinData(Context);
290 }
291 vfatReleaseFCB (DeviceExt, pFcb);
292
293 return STATUS_SUCCESS;
294 }
295
296 NTSTATUS
297 FindFile (PDEVICE_EXTENSION DeviceExt,
298 PVFATFCB Fcb,
299 PVFATFCB Parent,
300 PWSTR FileToFind,
301 ULONG *pDirIndex,
302 ULONG *pDirIndex2)
303 /*
304 * FUNCTION: Find a file
305 */
306 {
307 WCHAR name[256];
308 WCHAR name2[14];
309 char * block;
310 WCHAR TempStr[2];
311 NTSTATUS Status;
312 ULONG len;
313 ULONG DirIndex;
314 ULONG Offset;
315 ULONG FirstCluster;
316 ULONG Read;
317 BOOL isRoot;
318 LARGE_INTEGER FileOffset;
319 PVOID Context = NULL;
320
321 DPRINT ("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n", Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
322 DPRINT ("FindFile: old Pathname %x, old Objectname %x)\n",Fcb->PathName, Fcb->ObjectName);
323
324 isRoot = FALSE;
325 DirIndex = 0;
326 if (wcslen (FileToFind) == 0)
327 {
328 CHECKPOINT;
329 TempStr[0] = (WCHAR) '.';
330 TempStr[1] = 0;
331 FileToFind = (PWSTR)&TempStr;
332 }
333 if (Parent)
334 {
335 FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Parent->entry);
336 if (DeviceExt->FatInfo.FatType == FAT32)
337 {
338 if (FirstCluster == DeviceExt->FatInfo.RootCluster)
339 isRoot = TRUE;
340 }
341 else
342 {
343 if (FirstCluster == 1)
344 isRoot = TRUE;
345 }
346 }
347 else
348 isRoot = TRUE;
349 if (isRoot)
350 {
351 if (DeviceExt->FatInfo.FatType == FAT32)
352 FirstCluster = DeviceExt->FatInfo.RootCluster;
353 else
354 FirstCluster = 1;
355
356 if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
357 || (FileToFind[0] == '.' && FileToFind[1] == 0))
358 {
359 /* it's root : complete essentials fields then return ok */
360 CHECKPOINT;
361 memset (Fcb, 0, sizeof (VFATFCB));
362 memset (Fcb->entry.Filename, ' ', 11);
363 CHECKPOINT;
364 Fcb->PathName[0]='\\';
365 Fcb->ObjectName = &Fcb->PathName[1];
366 Fcb->entry.FileSize = DeviceExt->FatInfo.rootDirectorySectors * DeviceExt->FatInfo.BytesPerSector;
367 Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
368 if (DeviceExt->FatInfo.FatType == FAT32)
369 {
370 Fcb->entry.FirstCluster = ((PUSHORT)FirstCluster)[0];
371 Fcb->entry.FirstClusterHigh = ((PUSHORT)FirstCluster)[1];
372 }
373 else
374 Fcb->entry.FirstCluster = 1;
375 if (pDirIndex)
376 *pDirIndex = 0;
377 if (pDirIndex2)
378 *pDirIndex2 = 0;
379 DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
380 return (STATUS_SUCCESS);
381 }
382 }
383 else
384 {
385 DPRINT ("Parent->entry.FileSize %x\n", Parent->entry.FileSize);
386 FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Parent->entry);
387 }
388 if (pDirIndex && (*pDirIndex))
389 DirIndex = *pDirIndex;
390
391 Offset = DirIndex % ENTRIES_PER_PAGE;
392 while(TRUE)
393 {
394 if (Context == NULL || Offset == ENTRIES_PER_PAGE)
395 {
396 if (Offset == ENTRIES_PER_PAGE)
397 Offset = 0;
398 if (Context)
399 {
400 CcUnpinData(Context);
401 }
402 FileOffset.QuadPart = (DirIndex - Offset) * sizeof(FATDirEntry);
403 if (!CcMapData(Parent->FileObject, &FileOffset, PAGESIZE, TRUE,
404 &Context, (PVOID*)&block))
405 {
406 Context = NULL;
407 break;
408 }
409 }
410 if (vfatIsDirEntryVolume(&((FATDirEntry*)block)[Offset]))
411 {
412 Offset++;
413 DirIndex++;
414 continue;
415 }
416 Status = GetEntryName (&Context, (PVOID*)&block, Parent->FileObject, name,
417 &DirIndex, pDirIndex2);
418 if (Status == STATUS_NO_MORE_ENTRIES)
419 break;
420 Offset = DirIndex % ENTRIES_PER_PAGE;
421 if (NT_SUCCESS(Status))
422 {
423 vfat8Dot3ToString(((FATDirEntry *) block)[Offset].Filename,((FATDirEntry *) block)[Offset].Ext, name2);
424 if (wstrcmpjoki (name, FileToFind) || wstrcmpjoki (name2, FileToFind))
425 {
426 if (Parent && Parent->PathName)
427 {
428 len = wcslen(Parent->PathName);
429 CHECKPOINT;
430 memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
431 Fcb->ObjectName=&Fcb->PathName[len];
432 if (len != 1 || Fcb->PathName[0] != '\\')
433 {
434 Fcb->ObjectName[0] = '\\';
435 Fcb->ObjectName = &Fcb->ObjectName[1];
436 }
437 }
438 else
439 {
440 Fcb->ObjectName=Fcb->PathName;
441 Fcb->ObjectName[0]='\\';
442 Fcb->ObjectName=&Fcb->ObjectName[1];
443 }
444
445 memcpy (&Fcb->entry, &((FATDirEntry *) block)[Offset],
446 sizeof (FATDirEntry));
447 vfat_wcsncpy (Fcb->ObjectName, name, MAX_PATH);
448 if (pDirIndex)
449 *pDirIndex = DirIndex;
450 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",Fcb->PathName, Fcb->ObjectName, DirIndex);
451 if (Context)
452 CcUnpinData(Context);
453 return STATUS_SUCCESS;
454 }
455 }
456 Offset++;
457 DirIndex++;
458 }
459 if (pDirIndex)
460 *pDirIndex = DirIndex;
461 if (Context)
462 CcUnpinData(Context);
463 return (STATUS_UNSUCCESSFUL);
464 }
465
466 NTSTATUS
467 vfatMakeAbsoluteFilename (PFILE_OBJECT pFileObject,
468 PWSTR pRelativeFileName,
469 PWSTR *pAbsoluteFilename)
470 {
471 PWSTR rcName;
472 PVFATFCB fcb;
473 PVFATCCB ccb;
474
475 DPRINT ("try related for %S\n", pRelativeFileName);
476 ccb = pFileObject->FsContext2;
477 assert (ccb);
478 fcb = ccb->pFcb;
479 assert (fcb);
480
481 /* verify related object is a directory and target name
482 don't start with \. */
483 if (!(fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
484 || (pRelativeFileName[0] == L'\\'))
485 {
486 return STATUS_INVALID_PARAMETER;
487 }
488
489 /* construct absolute path name */
490 assert (wcslen (fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1
491 <= MAX_PATH);
492 rcName = ExAllocatePool (NonPagedPool, MAX_PATH * sizeof(WCHAR));
493 if (!rcName)
494 {
495 return STATUS_INSUFFICIENT_RESOURCES;
496 }
497 wcscpy (rcName, fcb->PathName);
498 if (!vfatFCBIsRoot(fcb))
499 wcscat (rcName, L"\\");
500 wcscat (rcName, pRelativeFileName);
501 *pAbsoluteFilename = rcName;
502
503 return STATUS_SUCCESS;
504 }
505
506 NTSTATUS
507 VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
508 PWSTR FileName)
509 /*
510 * FUNCTION: Opens a file
511 */
512 {
513 PVFATFCB ParentFcb;
514 PVFATFCB Fcb;
515 NTSTATUS Status;
516 PWSTR AbsFileName = NULL;
517
518 DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
519
520 if (FileObject->RelatedFileObject)
521 {
522 DPRINT ("Converting relative filename to absolute filename\n");
523 Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject,
524 FileName,
525 &AbsFileName);
526 FileName = AbsFileName;
527 if (!NT_SUCCESS(Status))
528 {
529 return Status;
530 }
531 }
532
533 //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
534
535 DPRINT ("PathName to open: %S\n", FileName);
536
537 /* try first to find an existing FCB in memory */
538 DPRINT ("Checking for existing FCB in memory\n");
539 Fcb = vfatGrabFCBFromTable (DeviceExt, FileName);
540 if (Fcb == NULL)
541 {
542 DPRINT ("No existing FCB found, making a new one if file exists.\n");
543 Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileName);
544 if (ParentFcb != NULL)
545 {
546 vfatReleaseFCB (DeviceExt, ParentFcb);
547 }
548 if (!NT_SUCCESS (Status))
549 {
550 DPRINT ("Could not make a new FCB, status: %x\n", Status);
551
552 if (AbsFileName)
553 ExFreePool (AbsFileName);
554
555 return Status;
556 }
557 }
558 if (Fcb->Flags & FCB_DELETE_PENDING)
559 {
560 vfatReleaseFCB (DeviceExt, Fcb);
561 if (AbsFileName)
562 ExFreePool (AbsFileName);
563 return STATUS_DELETE_PENDING;
564 }
565 DPRINT ("Attaching FCB to fileObject\n");
566 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
567
568 if (AbsFileName)
569 ExFreePool (AbsFileName);
570
571 return Status;
572 }
573
574 VOID STATIC
575 VfatPagingFileCreate(PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb)
576 {
577 ULONG CurrentCluster, NextCluster, i;
578 NTSTATUS Status;
579
580 Fcb->Flags |= FCB_IS_PAGE_FILE;
581 Fcb->FatChainSize =
582 ((Fcb->entry.FileSize + DeviceExt->FatInfo.BytesPerCluster - 1) /
583 DeviceExt->FatInfo.BytesPerCluster);
584 if (Fcb->FatChainSize)
585 {
586 Fcb->FatChain =
587 ExAllocatePool(NonPagedPool, Fcb->FatChainSize * sizeof(ULONG));
588 }
589
590 if (DeviceExt->FatInfo.FatType == FAT32)
591 {
592 CurrentCluster = Fcb->entry.FirstCluster +
593 Fcb->entry.FirstClusterHigh * 65536;
594 }
595 else
596 {
597 CurrentCluster = Fcb->entry.FirstCluster;
598 }
599
600 i = 0;
601 if (Fcb->FatChainSize)
602 {
603 while (CurrentCluster != 0xffffffff)
604 {
605 Fcb->FatChain[i] = CurrentCluster;
606 Status = GetNextCluster (DeviceExt, CurrentCluster,
607 &NextCluster, FALSE);
608 i++;
609 CurrentCluster = NextCluster;
610 }
611 }
612 }
613
614 VOID STATIC
615 VfatSupersedeFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
616 PVFATFCB Fcb)
617 {
618 ULONG Cluster, NextCluster;
619 NTSTATUS Status;
620
621 Fcb->entry.FileSize = 0;
622 if (DeviceExt->FatInfo.FatType == FAT32)
623 {
624 Cluster = Fcb->entry.FirstCluster + Fcb->entry.FirstClusterHigh * 65536;
625 }
626 else
627 {
628 Cluster = Fcb->entry.FirstCluster;
629 }
630 Fcb->entry.FirstCluster = 0;
631 Fcb->entry.FirstClusterHigh = 0;
632 VfatUpdateEntry (DeviceExt, FileObject);
633 if (Fcb->RFCB.FileSize.QuadPart > 0)
634 {
635 Fcb->RFCB.AllocationSize.QuadPart = 0;
636 Fcb->RFCB.FileSize.QuadPart = 0;
637 Fcb->RFCB.ValidDataLength.QuadPart = 0;
638 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
639 }
640 while (Cluster != 0xffffffff && Cluster > 1)
641 {
642 Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
643 WriteCluster (DeviceExt, Cluster, 0);
644 Cluster = NextCluster;
645 }
646 }
647
648 NTSTATUS
649 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
650 /*
651 * FUNCTION: Create or open a file
652 */
653 {
654 PIO_STACK_LOCATION Stack;
655 PFILE_OBJECT FileObject;
656 NTSTATUS Status = STATUS_SUCCESS;
657 PDEVICE_EXTENSION DeviceExt;
658 ULONG RequestedDisposition, RequestedOptions;
659 PVFATCCB pCcb;
660 PVFATFCB pFcb;
661 PWCHAR c;
662 BOOLEAN PagingFileCreate = FALSE;
663
664 /* Unpack the various parameters. */
665 Stack = IoGetCurrentIrpStackLocation (Irp);
666 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
667 RequestedOptions =
668 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
669 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
670 FileObject = Stack->FileObject;
671 DeviceExt = DeviceObject->DeviceExtension;
672
673 /* Check their validity. */
674 if (RequestedOptions & FILE_DIRECTORY_FILE &&
675 RequestedDisposition == FILE_SUPERSEDE)
676 {
677 return(STATUS_INVALID_PARAMETER);
678 }
679
680 /* This a open operation for the volume itself */
681 if (FileObject->FileName.Length == 0 &&
682 FileObject->RelatedFileObject == NULL)
683 {
684 if (RequestedDisposition == FILE_CREATE ||
685 RequestedDisposition == FILE_OVERWRITE_IF ||
686 RequestedDisposition == FILE_SUPERSEDE)
687 {
688 return(STATUS_ACCESS_DENIED);
689 }
690 if (RequestedOptions & FILE_DIRECTORY_FILE)
691 {
692 return(STATUS_NOT_A_DIRECTORY);
693 }
694 pFcb = DeviceExt->VolumeFcb;
695 pCcb = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
696 if (pCcb == NULL)
697 {
698 return (STATUS_INSUFFICIENT_RESOURCES);
699 }
700 memset(pCcb, 0, sizeof(VFATCCB));
701 FileObject->Flags |= FO_FCB_IS_VALID;
702 FileObject->SectionObjectPointers = &pFcb->SectionObjectPointers;
703 FileObject->FsContext = (PVOID) &pFcb->RFCB;
704 FileObject->FsContext2 = pCcb;
705 pCcb->pFcb = pFcb;
706 pCcb->PtrFileObject = FileObject;
707 pFcb->pDevExt = DeviceExt;
708 pFcb->RefCount++;
709
710 Irp->IoStatus.Information = FILE_OPENED;
711 return(STATUS_SUCCESS);
712 }
713
714 /*
715 * Check for illegal characters in the file name
716 */
717 c = FileObject->FileName.Buffer;
718 while (*c != 0)
719 {
720 if (*c == L'*' || *c == L'?' || (*c == L'\\' && c[1] == L'\\'))
721 {
722 return(STATUS_OBJECT_NAME_INVALID);
723 }
724 c++;
725 }
726
727 /* Try opening the file. */
728 Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
729
730 /*
731 * If the directory containing the file to open doesn't exist then
732 * fail immediately
733 */
734 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
735 Status == STATUS_INVALID_PARAMETER ||
736 Status == STATUS_DELETE_PENDING)
737 {
738 return(Status);
739 }
740
741 /*
742 * If the file open failed then create the required file
743 */
744 if (!NT_SUCCESS (Status))
745 {
746 if (RequestedDisposition == FILE_CREATE ||
747 RequestedDisposition == FILE_OPEN_IF ||
748 RequestedDisposition == FILE_OVERWRITE_IF ||
749 RequestedDisposition == FILE_SUPERSEDE)
750 {
751 ULONG Attributes;
752 Attributes = Stack->Parameters.Create.FileAttributes;
753 Status = VfatAddEntry (DeviceExt, FileObject, RequestedOptions,
754 Attributes & FILE_ATTRIBUTE_VALID_FLAGS);
755 if (NT_SUCCESS (Status))
756 {
757 pCcb = FileObject->FsContext2;
758 pFcb = pCcb->pFcb;
759 Irp->IoStatus.Information = FILE_CREATED;
760 VfatSetAllocationSizeInformation(FileObject,
761 pFcb,
762 DeviceExt,
763 &Irp->Overlay.AllocationSize);
764 VfatSetExtendedAttributes(FileObject,
765 Irp->AssociatedIrp.SystemBuffer,
766 Stack->Parameters.Create.EaLength);
767 IoSetShareAccess(0 /*DesiredAccess*/,
768 Stack->Parameters.Create.ShareAccess,
769 FileObject,
770 &pFcb->FCBShareAccess);
771 }
772 else
773 {
774 return(Status);
775 }
776 }
777 else
778 {
779 return(Status);
780 }
781 }
782 else
783 {
784 /* Otherwise fail if the caller wanted to create a new file */
785 if (RequestedDisposition == FILE_CREATE)
786 {
787 Irp->IoStatus.Information = FILE_EXISTS;
788 return(STATUS_OBJECT_NAME_COLLISION);
789 }
790
791 pCcb = FileObject->FsContext2;
792 pFcb = pCcb->pFcb;
793
794 /*
795 * Check the file has the requested attributes
796 */
797 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
798 pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
799 {
800 VfatCloseFile (DeviceExt, FileObject);
801 return(STATUS_FILE_IS_A_DIRECTORY);
802 }
803 if (RequestedOptions & FILE_DIRECTORY_FILE &&
804 !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
805 {
806 VfatCloseFile (DeviceExt, FileObject);
807 return(STATUS_NOT_A_DIRECTORY);
808 }
809
810 /* Supersede the file */
811 if (RequestedDisposition == FILE_SUPERSEDE)
812 {
813 VfatSupersedeFile(DeviceExt, FileObject, pFcb);
814 Irp->IoStatus.Information = FILE_SUPERSEDED;
815 }
816 else
817 {
818 Irp->IoStatus.Information = FILE_OPENED;
819 }
820 }
821
822 /*
823 * If this create was for a paging file then make sure all the
824 * information needed to manipulate it is locked in memory.
825 */
826 if (PagingFileCreate)
827 {
828 VfatPagingFileCreate(DeviceExt, pFcb);
829 }
830
831 /* FIXME : test share access */
832 /* FIXME : test write access if requested */
833
834 return(Status);
835 }
836
837
838 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
839 /*
840 * FUNCTION: Create or open a file
841 */
842 {
843 NTSTATUS Status;
844
845 assert (IrpContext);
846
847 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
848 {
849 /* DeviceObject represents FileSystem instead of logical volume */
850 DPRINT ("FsdCreate called with file system\n");
851 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
852 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
853 IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
854 VfatFreeIrpContext(IrpContext);
855 return(STATUS_SUCCESS);
856 }
857
858 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
859 {
860 return(VfatQueueRequest (IrpContext));
861 }
862
863 IrpContext->Irp->IoStatus.Information = 0;
864 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
865 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
866 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
867
868 IrpContext->Irp->IoStatus.Status = Status;
869 IoCompleteRequest (IrpContext->Irp,
870 NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
871 VfatFreeIrpContext(IrpContext);
872 return(Status);
873 }
874
875 /* EOF */