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