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