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