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