Hide dependency files
[reactos.git] / reactos / drivers / fs / vfat / create.c
1 /* $Id: create.c,v 1.18 2001/03/06 17:28:25 dwelch Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/create.c
6 * PURPOSE: VFAT Filesystem
7 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
8
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <wchar.h>
15 #include <limits.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 #include "vfat.h"
21
22 /* FUNCTIONS ****************************************************************/
23
24 BOOLEAN
25 IsLastEntry (PVOID Block, ULONG Offset)
26 /*
27 * FUNCTION: Determine if the given directory entry is the last
28 */
29 {
30 return (((FATDirEntry *) Block)[Offset].Filename[0] == 0);
31 }
32
33 BOOLEAN
34 IsVolEntry (PVOID Block, ULONG Offset)
35 /*
36 * FUNCTION: Determine if the given directory entry is a vol entry
37 */
38 {
39 if ((((FATDirEntry *) Block)[Offset].Attrib) == 0x28)
40 return TRUE;
41 else
42 return FALSE;
43 }
44
45 BOOLEAN
46 IsDeletedEntry (PVOID Block, ULONG Offset)
47 /*
48 * FUNCTION: Determines if the given entry is a deleted one
49 */
50 {
51 /* Checks special character */
52
53 return ((((FATDirEntry *) Block)[Offset].Filename[0] == 0xe5) ||
54 (((FATDirEntry *) Block)[Offset].Filename[0] == 0));
55 }
56
57 BOOLEAN
58 GetEntryName (PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
59 PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
60 /*
61 * FUNCTION: Retrieves the file name, be it in short or long file name format
62 */
63 {
64 FATDirEntry *test;
65 slot *test2;
66 ULONG Offset = *_Offset;
67 ULONG StartingSector = *_StartingSector;
68 ULONG jloop = *_jloop;
69 ULONG cpos;
70
71 test = (FATDirEntry *) Block;
72 test2 = (slot *) Block;
73
74 *Name = 0;
75
76 if (IsDeletedEntry (Block, Offset))
77 {
78 return (FALSE);
79 }
80
81 if (test2[Offset].attr == 0x0f)
82 {
83 vfat_initstr (Name, 256);
84 vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
85 vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
86 vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
87
88 cpos = 0;
89 while ((test2[Offset].id != 0x41) && (test2[Offset].id != 0x01) &&
90 (test2[Offset].attr > 0))
91 {
92 Offset++;
93 if (Offset == ENTRIES_PER_SECTOR)
94 {
95 Offset = 0;
96 /* FIXME: Check status */
97 GetNextSector (DeviceExt, StartingSector, &StartingSector, FALSE);
98 jloop++;
99 /* FIXME: Check status */
100 VfatReadSectors (DeviceExt->StorageDevice,
101 StartingSector, 1, Block);
102 test2 = (slot *) Block;
103 }
104 cpos++;
105 vfat_movstr (Name, 13, 0, cpos * 13);
106 vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
107 vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
108 vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
109
110 }
111
112 if (IsDeletedEntry (Block, Offset + 1))
113 {
114 Offset++;
115 *_Offset = Offset;
116 *_jloop = jloop;
117 *_StartingSector = StartingSector;
118 return (FALSE);
119 }
120
121 *_Offset = Offset;
122 *_jloop = jloop;
123 *_StartingSector = StartingSector;
124
125 return (TRUE);
126 }
127
128 RtlAnsiToUnicode (Name, test[Offset].Filename, 8);
129 if (test[Offset].Ext[0] != ' ')
130 {
131 RtlCatAnsiToUnicode (Name, ".", 1);
132 }
133 RtlCatAnsiToUnicode (Name, test[Offset].Ext, 3);
134
135 *_Offset = Offset;
136
137 return (TRUE);
138 }
139
140 NTSTATUS
141 ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
142 /*
143 * FUNCTION: Read the volume label
144 */
145 {
146 ULONG i = 0;
147 ULONG j;
148 ULONG Size;
149 char *block;
150 ULONG StartingSector;
151 ULONG NextCluster;
152 NTSTATUS Status;
153
154 Size = DeviceExt->rootDirectorySectors; /* FIXME : in fat32, no limit */
155 StartingSector = DeviceExt->rootStart;
156 NextCluster = 0;
157
158 block = ExAllocatePool (NonPagedPool, BLOCKSIZE);
159 DPRINT ("FindFile : start at sector %lx, entry %ld\n", StartingSector, i);
160 for (j = 0; j < Size; j++)
161 {
162 /* FIXME: Check status */
163 VfatReadSectors (DeviceExt->StorageDevice, StartingSector, 1, block);
164
165 for (i = 0; i < ENTRIES_PER_SECTOR; i++)
166 {
167 if (IsVolEntry ((PVOID) block, i))
168 {
169 FATDirEntry *test = (FATDirEntry *) block;
170
171 /* copy volume label */
172 RtlAnsiToUnicode (Vpb->VolumeLabel, test[i].Filename, 8);
173 RtlCatAnsiToUnicode (Vpb->VolumeLabel, test[i].Ext, 3);
174 Vpb->VolumeLabelLength = wcslen (Vpb->VolumeLabel);
175
176 ExFreePool (block);
177 return (STATUS_SUCCESS);
178 }
179 if (IsLastEntry ((PVOID) block, i))
180 {
181 *(Vpb->VolumeLabel) = 0;
182 Vpb->VolumeLabelLength = 0;
183 ExFreePool (block);
184 return (STATUS_UNSUCCESSFUL);
185 }
186 }
187 /* not found in this sector, try next : */
188
189 /* directory can be fragmented although it is best to keep them
190 unfragmented.*/
191 StartingSector++;
192
193 if (DeviceExt->FatType == FAT32)
194 {
195 if (StartingSector == ClusterToSector (DeviceExt, NextCluster + 1))
196 {
197 Status = GetNextCluster (DeviceExt, NextCluster, &NextCluster,
198 FALSE);
199 if (NextCluster == 0 || NextCluster == 0xffffffff)
200 {
201 *(Vpb->VolumeLabel) = 0;
202 Vpb->VolumeLabelLength = 0;
203 ExFreePool (block);
204 return (STATUS_UNSUCCESSFUL);
205 }
206 StartingSector = ClusterToSector (DeviceExt, NextCluster);
207 }
208 }
209 }
210 *(Vpb->VolumeLabel) = 0;
211 Vpb->VolumeLabelLength = 0;
212 ExFreePool (block);
213 return (STATUS_UNSUCCESSFUL);
214 }
215
216
217 NTSTATUS
218 FindFile (PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb,
219 PVFATFCB Parent, PWSTR FileToFind, ULONG * StartSector,
220 ULONG * Entry)
221 /*
222 * FUNCTION: Find a file
223 */
224 {
225 ULONG i, j;
226 ULONG Size;
227 char *block;
228 WCHAR name[256];
229 ULONG StartingSector;
230 ULONG NextCluster;
231 WCHAR TempStr[2];
232 NTSTATUS Status;
233
234 DPRINT ("FindFile(Parent %x, FileToFind '%S')\n", Parent, FileToFind);
235
236 if (wcslen (FileToFind) == 0)
237 {
238 CHECKPOINT;
239 TempStr[0] = (WCHAR) '.';
240 TempStr[1] = 0;
241 FileToFind = (PWSTR)&TempStr;
242 }
243
244 if (Parent == NULL || Parent->entry.FirstCluster == 1)
245 {
246 Size = DeviceExt->rootDirectorySectors; /* FIXME : in fat32, no limit */
247 StartingSector = DeviceExt->rootStart;
248 NextCluster = 0;
249 if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
250 || (FileToFind[0] == '.' && FileToFind[1] == 0))
251 {
252 /* it's root : complete essentials fields then return ok */
253 memset (Fcb, 0, sizeof (VFATFCB));
254 memset (Fcb->entry.Filename, ' ', 11);
255 Fcb->entry.FileSize = DeviceExt->rootDirectorySectors * BLOCKSIZE;
256 Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
257 if (DeviceExt->FatType == FAT32)
258 Fcb->entry.FirstCluster = 2;
259 else
260 Fcb->entry.FirstCluster = 1;
261 if (StartSector)
262 *StartSector = StartingSector;
263 if (Entry)
264 *Entry = 0;
265 return (STATUS_SUCCESS);
266 }
267 }
268 else
269 {
270 DPRINT ("Parent->entry.FileSize %x\n", Parent->entry.FileSize);
271
272 Size = ULONG_MAX;
273 if (DeviceExt->FatType == FAT32)
274 NextCluster = Parent->entry.FirstCluster
275 + Parent->entry.FirstClusterHigh * 65536;
276 else
277 NextCluster = Parent->entry.FirstCluster;
278 StartingSector = ClusterToSector (DeviceExt, NextCluster);
279 if (Parent->entry.FirstCluster == 1 && DeviceExt->FatType != FAT32)
280 {
281 /* read of root directory in FAT16 or FAT12 */
282 StartingSector = DeviceExt->rootStart;
283 }
284 }
285 block = ExAllocatePool (NonPagedPool, BLOCKSIZE);
286 if (StartSector && (*StartSector))
287 StartingSector = *StartSector;
288 i = (Entry) ? (*Entry) : 0;
289 for (j = 0; j < Size; j++)
290 {
291 /* FIXME: Check status */
292 VfatReadSectors (DeviceExt->StorageDevice, StartingSector, 1, block);
293
294 for (i = (Entry) ? (*Entry) : 0; i < ENTRIES_PER_SECTOR; i++)
295 {
296 if (IsVolEntry ((PVOID) block, i))
297 continue;
298 if (IsLastEntry ((PVOID) block, i))
299 {
300 if (StartSector)
301 *StartSector = StartingSector;
302 if (Entry)
303 *Entry = i;
304 ExFreePool (block);
305 return (STATUS_UNSUCCESSFUL);
306 }
307 if (GetEntryName
308 ((PVOID) block, &i, name, &j, DeviceExt, &StartingSector))
309 {
310 if (wstrcmpjoki (name, FileToFind))
311 {
312 /* In the case of a long filename, the firstcluster is
313 stored in the next record -- where it's short name is */
314 if (((FATDirEntry *) block)[i].Attrib == 0x0f)
315 i++;
316 if (i == (ENTRIES_PER_SECTOR))
317 {
318 /* FIXME: Check status */
319 GetNextSector (DeviceExt, StartingSector, &StartingSector, FALSE);
320
321 /* FIXME: Check status */
322 VfatReadSectors (DeviceExt->StorageDevice,
323 StartingSector, 1, block);
324 i = 0;
325 }
326 memcpy (&Fcb->entry, &((FATDirEntry *) block)[i],
327 sizeof (FATDirEntry));
328 vfat_wcsncpy (Fcb->ObjectName, name, MAX_PATH);
329 if (StartSector)
330 *StartSector = StartingSector;
331 if (Entry)
332 *Entry = i;
333 ExFreePool (block);
334 return (STATUS_SUCCESS);
335 }
336 }
337 }
338 /* not found in this sector, try next : */
339
340 /* directory can be fragmented although it is best to keep them
341 unfragmented. Should we change this to also use GetNextSector?
342 GetNextSector was originally implemented to handle the case above */
343 if (Entry)
344 *Entry = 0;
345 StartingSector++;
346 if ((Parent != NULL && Parent->entry.FirstCluster != 1)
347 || DeviceExt->FatType == FAT32)
348 {
349 if (StartingSector == ClusterToSector (DeviceExt, NextCluster + 1))
350 {
351 Status = GetNextCluster (DeviceExt, NextCluster, &NextCluster,
352 FALSE);
353 if (NextCluster == 0 || NextCluster == 0xffffffff)
354 {
355 if (StartSector)
356 *StartSector = StartingSector;
357 if (Entry)
358 *Entry = i;
359 ExFreePool (block);
360 return (STATUS_UNSUCCESSFUL);
361 }
362 StartingSector = ClusterToSector (DeviceExt, NextCluster);
363 }
364 }
365 }
366 if (StartSector)
367 *StartSector = StartingSector;
368 if (Entry)
369 *Entry = i;
370 ExFreePool (block);
371 return (STATUS_UNSUCCESSFUL);
372 }
373
374
375
376 NTSTATUS
377 VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
378 PWSTR FileName)
379 /*
380 * FUNCTION: Opens a file
381 */
382 {
383 PWSTR current = NULL;
384 PWSTR next;
385 PWSTR string;
386 PVFATFCB ParentFcb;
387 PVFATFCB Fcb, pRelFcb;
388 PVFATFCB Temp;
389 PVFATCCB newCCB, pRelCcb;
390 NTSTATUS Status;
391 PFILE_OBJECT pRelFileObject;
392 PWSTR AbsFileName = NULL;
393 short i, j;
394 PLIST_ENTRY current_entry;
395 KIRQL oldIrql;
396 ULONG BytesPerCluster;
397
398 DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
399
400 /* FIXME : treat relative name */
401 if (FileObject->RelatedFileObject)
402 {
403 DbgPrint ("try related for %S\n", FileName);
404 pRelFileObject = FileObject->RelatedFileObject;
405 pRelCcb = pRelFileObject->FsContext2;
406 assert (pRelCcb);
407 pRelFcb = pRelCcb->pFcb;
408 assert (pRelFcb);
409 /*
410 * verify related object is a directory and target name don't start with
411 * \.
412 */
413 if (!(pRelFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
414 || (FileName[0] != '\\'))
415 {
416 Status = STATUS_INVALID_PARAMETER;
417 return Status;
418 }
419 /* construct absolute path name */
420 AbsFileName = ExAllocatePool (NonPagedPool, MAX_PATH);
421 for (i = 0; pRelFcb->PathName[i]; i++)
422 AbsFileName[i] = pRelFcb->PathName[i];
423 AbsFileName[i++] = '\\';
424 for (j = 0; FileName[j] && i < MAX_PATH; j++)
425 AbsFileName[i++] = FileName[j];
426 assert (i < MAX_PATH);
427 AbsFileName[i] = 0;
428 FileName = AbsFileName;
429 }
430
431 /*
432 * try first to find an existing FCB in memory
433 */
434 CHECKPOINT;
435
436 KeAcquireSpinLock (&DeviceExt->FcbListLock, &oldIrql);
437 current_entry = DeviceExt->FcbListHead.Flink;
438 while (current_entry != &DeviceExt->FcbListHead)
439 {
440 Fcb = CONTAINING_RECORD (current_entry, VFATFCB, FcbListEntry);
441
442 DPRINT ("Scanning %x\n", Fcb);
443 DPRINT ("Scanning %S\n", Fcb->PathName);
444
445 if (DeviceExt == Fcb->pDevExt && wstrcmpi (FileName, Fcb->PathName))
446 {
447 Fcb->RefCount++;
448 KeReleaseSpinLock (&DeviceExt->FcbListLock, oldIrql);
449 FileObject->FsContext = (PVOID)&Fcb->RFCB;
450 newCCB = ExAllocatePool (NonPagedPool, sizeof (VFATCCB));
451 memset (newCCB, 0, sizeof (VFATCCB));
452 FileObject->Flags = FileObject->Flags |
453 FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
454 FileObject->SectionObjectPointers =
455 &Fcb->SectionObjectPointers;
456 FileObject->FsContext2 = newCCB;
457 newCCB->pFcb = Fcb;
458 newCCB->PtrFileObject = FileObject;
459 if (AbsFileName)
460 ExFreePool (AbsFileName);
461 return (STATUS_SUCCESS);
462 }
463
464 current_entry = current_entry->Flink;
465 }
466 KeReleaseSpinLock (&DeviceExt->FcbListLock, oldIrql);
467
468 CHECKPOINT;
469 DPRINT ("FileName %S\n", FileName);
470
471 string = FileName;
472 ParentFcb = NULL;
473 Fcb = ExAllocatePool (NonPagedPool, sizeof (VFATFCB));
474 memset (Fcb, 0, sizeof (VFATFCB));
475 Fcb->ObjectName = Fcb->PathName;
476 next = &string[0];
477
478 CHECKPOINT;
479 if (*next == 0) // root
480 {
481 memset (Fcb->entry.Filename, ' ', 11);
482 Fcb->entry.FileSize = DeviceExt->rootDirectorySectors * BLOCKSIZE;
483 Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
484 if (DeviceExt->FatType == FAT32)
485 Fcb->entry.FirstCluster = 2;
486 else
487 Fcb->entry.FirstCluster = 1;
488 /* FIXME : is 1 the good value for mark root? */
489 ParentFcb = Fcb;
490 Fcb = NULL;
491 }
492 else
493 {
494 while (TRUE)
495 {
496 CHECKPOINT;
497 *next = '\\';
498 current = next + 1;
499 next = wcschr (next + 1, '\\');
500 if (next != NULL)
501 {
502 *next = 0;
503 }
504 else
505 {
506 /* reached the last path component */
507 DPRINT ("exiting: current '%S'\n", current);
508 break;
509 }
510
511 DPRINT ("current '%S'\n", current);
512 Status = FindFile (DeviceExt, Fcb, ParentFcb, current, NULL, NULL);
513 if (Status != STATUS_SUCCESS)
514 {
515 CHECKPOINT;
516 if (Fcb != NULL)
517 ExFreePool (Fcb);
518 if (ParentFcb != NULL)
519 ExFreePool (ParentFcb);
520 if (AbsFileName)
521 ExFreePool (AbsFileName);
522
523 DPRINT ("error STATUS_OBJECT_PATH_NOT_FOUND\n");
524 return STATUS_OBJECT_PATH_NOT_FOUND;
525 }
526 Temp = Fcb;
527 CHECKPOINT;
528 if (ParentFcb == NULL)
529 {
530 CHECKPOINT;
531 Fcb = ExAllocatePool (NonPagedPool, sizeof (VFATFCB));
532 memset (Fcb, 0, sizeof (VFATFCB));
533 Fcb->ObjectName = Fcb->PathName;
534 }
535 else
536 Fcb = ParentFcb;
537 CHECKPOINT;
538 ParentFcb = Temp;
539 }
540
541 /* searching for last path component */
542 DPRINT ("current '%S'\n", current);
543 Status = FindFile (DeviceExt, Fcb, ParentFcb, current, NULL, NULL);
544 if (Status != STATUS_SUCCESS)
545 {
546 /* file does not exist */
547 CHECKPOINT;
548 if (Fcb != NULL)
549 ExFreePool (Fcb);
550 if (ParentFcb != NULL)
551 ExFreePool (ParentFcb);
552 if (AbsFileName)
553 ExFreePool (AbsFileName);
554
555 return STATUS_OBJECT_NAME_NOT_FOUND;
556 }
557
558 Temp = Fcb;
559 if (ParentFcb == NULL)
560 {
561 CHECKPOINT;
562 Fcb = ExAllocatePool (NonPagedPool, sizeof (VFATFCB));
563 memset (Fcb, 0, sizeof (VFATFCB));
564 Fcb->ObjectName = Fcb->PathName;
565 }
566 else
567 Fcb = ParentFcb;
568 ParentFcb = Temp;
569 }
570
571 FileObject->Flags = FileObject->Flags |
572 FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
573 FileObject->SectionObjectPointers = &ParentFcb->SectionObjectPointers;
574 memset(FileObject->SectionObjectPointers, 0,
575 sizeof(SECTION_OBJECT_POINTERS));
576 FileObject->FsContext = (PVOID)&ParentFcb->RFCB;
577 newCCB = ExAllocatePool (NonPagedPool, sizeof (VFATCCB));
578 memset (newCCB, 0, sizeof (VFATCCB));
579 FileObject->FsContext2 = newCCB;
580 newCCB->pFcb = ParentFcb;
581 newCCB->PtrFileObject = FileObject;
582 ParentFcb->RefCount++;
583 /* FIXME : initialize all fields in FCB and CCB */
584
585 KeAcquireSpinLock (&DeviceExt->FcbListLock, &oldIrql);
586 InsertTailList (&DeviceExt->FcbListHead, &ParentFcb->FcbListEntry);
587 KeReleaseSpinLock (&DeviceExt->FcbListLock, oldIrql);
588
589 vfat_wcsncpy (ParentFcb->PathName, FileName, MAX_PATH);
590 ParentFcb->ObjectName = ParentFcb->PathName + (current - FileName);
591 ParentFcb->pDevExt = DeviceExt;
592 BytesPerCluster = DeviceExt->Boot->SectorsPerCluster * BLOCKSIZE;
593 if (BytesPerCluster >= PAGESIZE)
594 {
595 Status = CcInitializeFileCache(FileObject, &ParentFcb->RFCB.Bcb,
596 BytesPerCluster);
597 }
598 else
599 {
600 Status = CcInitializeFileCache(FileObject, &ParentFcb->RFCB.Bcb,
601 PAGESIZE);
602 }
603 if (!NT_SUCCESS(Status))
604 {
605 DbgPrint("CcInitializeFileCache failed\n");
606 KeBugCheck(0);
607 }
608 DPRINT ("file open, fcb=%x\n", ParentFcb);
609 DPRINT ("FileSize %d\n", ParentFcb->entry.FileSize);
610 if (Fcb)
611 ExFreePool (Fcb);
612 if (AbsFileName)
613 ExFreePool (AbsFileName);
614 CHECKPOINT;
615
616 return (STATUS_SUCCESS);
617 }
618
619
620 NTSTATUS
621 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
622 /*
623 * FUNCTION: Create or open a file
624 */
625 {
626 PIO_STACK_LOCATION Stack;
627 PFILE_OBJECT FileObject;
628 NTSTATUS Status = STATUS_SUCCESS;
629 PDEVICE_EXTENSION DeviceExt;
630 ULONG RequestedDisposition, RequestedOptions;
631 PVFATCCB pCcb;
632 PVFATFCB pFcb;
633 PWCHAR c;
634
635 Stack = IoGetCurrentIrpStackLocation (Irp);
636 assert (Stack);
637 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
638 RequestedOptions =
639 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
640 if ((RequestedOptions & FILE_DIRECTORY_FILE)
641 && RequestedDisposition == FILE_SUPERSEDE)
642 return STATUS_INVALID_PARAMETER;
643 FileObject = Stack->FileObject;
644 DeviceExt = DeviceObject->DeviceExtension;
645 assert (DeviceExt);
646
647 /*
648 * Check for illegal characters in the file name
649 */
650 c = FileObject->FileName.Buffer;
651 while (*c != 0)
652 {
653 if (*c == L'*' || *c == L'?')
654 {
655 Irp->IoStatus.Information = 0;
656 Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
657 return(Status);
658 }
659 c++;
660 }
661
662 Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
663
664 /*
665 * If the directory containing the file to open doesn't exist then
666 * fail immediately
667 */
668 Irp->IoStatus.Information = 0;
669 if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
670 {
671 Irp->IoStatus.Status = Status;
672 return Status;
673 }
674
675 if (!NT_SUCCESS (Status))
676 {
677 /*
678 * If the file open failed then create the required file
679 */
680 if (RequestedDisposition == FILE_CREATE ||
681 RequestedDisposition == FILE_OPEN_IF ||
682 RequestedDisposition == FILE_OVERWRITE_IF ||
683 RequestedDisposition == FILE_SUPERSEDE)
684 {
685 CHECKPOINT;
686 Status =
687 addEntry (DeviceExt, FileObject, RequestedOptions,
688 (Stack->Parameters.
689 Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
690 if (NT_SUCCESS (Status))
691 Irp->IoStatus.Information = FILE_CREATED;
692 /* FIXME set size if AllocationSize requested */
693 /* FIXME set extended attributes? */
694 /* FIXME set share access */
695 /* IoSetShareAccess(DesiredAccess,ShareAccess,FileObject,
696 * ((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
697 */
698 }
699 }
700 else
701 {
702 /*
703 * Otherwise fail if the caller wanted to create a new file
704 */
705 if (RequestedDisposition == FILE_CREATE)
706 {
707 Irp->IoStatus.Information = FILE_EXISTS;
708 Status = STATUS_OBJECT_NAME_COLLISION;
709 }
710 pCcb = FileObject->FsContext2;
711 pFcb = pCcb->pFcb;
712 /*
713 * If requested then delete the file and create a new one with the
714 * same name
715 */
716 if (RequestedDisposition == FILE_SUPERSEDE)
717 {
718 ULONG Cluster, NextCluster;
719 /* FIXME set size to 0 and free clusters */
720 pFcb->entry.FileSize = 0;
721 if (DeviceExt->FatType == FAT32)
722 Cluster = pFcb->entry.FirstCluster
723 + pFcb->entry.FirstClusterHigh * 65536;
724 else
725 Cluster = pFcb->entry.FirstCluster;
726 pFcb->entry.FirstCluster = 0;
727 pFcb->entry.FirstClusterHigh = 0;
728 updEntry (DeviceExt, FileObject);
729 while (Cluster != 0xffffffff && Cluster > 1)
730 {
731 Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, TRUE);
732 WriteCluster (DeviceExt, Cluster, 0);
733 Cluster = NextCluster;
734 }
735 }
736
737 /*
738 * Check the file has the requested attributes
739 */
740 if ((RequestedOptions & FILE_NON_DIRECTORY_FILE)
741 && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
742 {
743 Status = STATUS_FILE_IS_A_DIRECTORY;
744 }
745 if ((RequestedOptions & FILE_DIRECTORY_FILE)
746 && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
747 {
748 Status = STATUS_NOT_A_DIRECTORY;
749 }
750 /* FIXME : test share access */
751 /* FIXME : test write access if requested */
752 if (!NT_SUCCESS (Status))
753 VfatCloseFile (DeviceExt, FileObject);
754 else
755 Irp->IoStatus.Information = FILE_OPENED;
756 /* FIXME : make supersed or overwrite if requested */
757 }
758
759 Irp->IoStatus.Status = Status;
760
761 return Status;
762 }
763
764
765 NTSTATUS STDCALL
766 VfatCreate (PDEVICE_OBJECT DeviceObject, PIRP Irp)
767 /*
768 * FUNCTION: Create or open a file
769 */
770 {
771 NTSTATUS Status = STATUS_SUCCESS;
772 PDEVICE_EXTENSION DeviceExt;
773
774 assert (DeviceObject);
775 assert (Irp);
776
777 if (DeviceObject->Size == sizeof (DEVICE_OBJECT))
778 {
779 /* DeviceObject represents FileSystem instead of logical volume */
780 DbgPrint ("FsdCreate called with file system\n");
781 Irp->IoStatus.Status = Status;
782 Irp->IoStatus.Information = FILE_OPENED;
783 IoCompleteRequest (Irp, IO_NO_INCREMENT);
784 return (Status);
785 }
786
787 DeviceExt = DeviceObject->DeviceExtension;
788 assert (DeviceExt);
789 ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
790
791 Status = VfatCreateFile (DeviceObject, Irp);
792
793 ExReleaseResourceLite (&DeviceExt->DirResource);
794
795 Irp->IoStatus.Status = Status;
796 IoCompleteRequest (Irp, IO_NO_INCREMENT);
797
798 return Status;
799 }
800
801 /* EOF */