833deaaf8db61566f9ddee2c98bd7a6d93cb5584
[reactos.git] / reactos / drivers / fs / vfat / create.c
1 /* $Id: create.c,v 1.38 2002/02/08 02:57:09 chorns 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 DPRINT ("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] == L'\\'))
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 * sizeof(WCHAR));
496 if (!rcName)
497 {
498 return STATUS_INSUFFICIENT_RESOURCES;
499 }
500 wcscpy (rcName, fcb->PathName);
501 if (!vfatFCBIsRoot(fcb))
502 wcscat (rcName, L"\\");
503 wcscat (rcName, pRelativeFileName);
504 *pAbsoluteFilename = rcName;
505
506 return STATUS_SUCCESS;
507 }
508
509 NTSTATUS
510 VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
511 PWSTR FileName)
512 /*
513 * FUNCTION: Opens a file
514 */
515 {
516 PVFATFCB ParentFcb;
517 PVFATFCB Fcb;
518 NTSTATUS Status;
519 PWSTR AbsFileName = NULL;
520
521 DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
522
523 if (FileObject->RelatedFileObject)
524 {
525 DPRINT ("Converting relative filename to absolute filename\n");
526 Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject,
527 FileName,
528 &AbsFileName);
529 FileName = AbsFileName;
530 if (!NT_SUCCESS(Status))
531 {
532 return Status;
533 }
534 }
535
536 //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
537
538 DPRINT ("PathName to open: %S\n", FileName);
539
540 /* try first to find an existing FCB in memory */
541 DPRINT ("Checking for existing FCB in memory\n");
542 Fcb = vfatGrabFCBFromTable (DeviceExt, FileName);
543 if (Fcb == NULL)
544 {
545 DPRINT ("No existing FCB found, making a new one if file exists.\n");
546 Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileName);
547 if (ParentFcb != NULL)
548 {
549 vfatReleaseFCB (DeviceExt, ParentFcb);
550 }
551 if (!NT_SUCCESS (Status))
552 {
553 DPRINT ("Could not make a new FCB, status: %x\n", Status);
554
555 if (AbsFileName)
556 ExFreePool (AbsFileName);
557
558 return Status;
559 }
560 }
561 if (Fcb->Flags & FCB_DELETE_PENDING)
562 {
563 vfatReleaseFCB (DeviceExt, Fcb);
564 if (AbsFileName)
565 ExFreePool (AbsFileName);
566 return STATUS_DELETE_PENDING;
567 }
568 DPRINT ("Attaching FCB to fileObject\n");
569 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
570
571 if (AbsFileName)
572 ExFreePool (AbsFileName);
573
574 return Status;
575 }
576
577 NTSTATUS
578 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
579 /*
580 * FUNCTION: Create or open a file
581 */
582 {
583 PIO_STACK_LOCATION Stack;
584 PFILE_OBJECT FileObject;
585 NTSTATUS Status = STATUS_SUCCESS;
586 PDEVICE_EXTENSION DeviceExt;
587 ULONG RequestedDisposition, RequestedOptions;
588 PVFATCCB pCcb;
589 PVFATFCB pFcb;
590 PWCHAR c;
591 BOOLEAN PagingFileCreate = FALSE;
592
593 Stack = IoGetCurrentIrpStackLocation (Irp);
594 assert (Stack);
595 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
596 RequestedOptions =
597 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
598 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
599 if ((RequestedOptions & FILE_DIRECTORY_FILE)
600 && RequestedDisposition == FILE_SUPERSEDE)
601 return STATUS_INVALID_PARAMETER;
602 FileObject = Stack->FileObject;
603 DeviceExt = DeviceObject->DeviceExtension;
604 assert (DeviceExt);
605
606 /*
607 * Check for illegal characters in the file name
608 */
609 c = FileObject->FileName.Buffer;
610 while (*c != 0)
611 {
612 if (*c == L'*' || *c == L'?' || (*c == L'\\' && c[1] == L'\\'))
613 {
614 Irp->IoStatus.Information = 0;
615 Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
616 return(STATUS_OBJECT_NAME_INVALID);
617 }
618 c++;
619 }
620
621 Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
622
623 /*
624 * If the directory containing the file to open doesn't exist then
625 * fail immediately
626 */
627 Irp->IoStatus.Information = 0;
628 if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
629 {
630 Irp->IoStatus.Status = Status;
631 return Status;
632 }
633
634 if (Status == STATUS_DELETE_PENDING)
635 {
636 Irp->IoStatus.Status = Status;
637 return Status;
638 }
639 if (!NT_SUCCESS (Status))
640 {
641 /*
642 * If the file open failed then create the required file
643 */
644 if (RequestedDisposition == FILE_CREATE ||
645 RequestedDisposition == FILE_OPEN_IF ||
646 RequestedDisposition == FILE_OVERWRITE_IF ||
647 RequestedDisposition == FILE_SUPERSEDE)
648 {
649 CHECKPOINT;
650 Status =
651 addEntry (DeviceExt, FileObject, RequestedOptions,
652 (Stack->Parameters.
653 Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
654 if (NT_SUCCESS (Status))
655 {
656 if (PagingFileCreate)
657 {
658 DPRINT("Creating a new paging file.\n");
659 pCcb = FileObject->FsContext2;
660 pFcb = pCcb->pFcb;
661 pFcb->Flags |= FCB_IS_PAGE_FILE;
662 pFcb->FatChainSize = 0;
663 pFcb->FatChain = NULL;
664 }
665
666 Irp->IoStatus.Information = FILE_CREATED;
667 }
668 /* FIXME set size if AllocationSize requested */
669 /* FIXME set extended attributes? */
670 /* FIXME set share access */
671 /* IoSetShareAccess(DesiredAccess,ShareAccess,FileObject,
672 * ((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
673 */
674 }
675 }
676 else
677 {
678 /*
679 * Otherwise fail if the caller wanted to create a new file
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 /*
689 * If requested then delete the file and create a new one with the
690 * same name
691 */
692 if (RequestedDisposition == FILE_SUPERSEDE)
693 {
694 ULONG Cluster, NextCluster;
695 /* FIXME set size to 0 and free clusters */
696 pFcb->entry.FileSize = 0;
697 if (DeviceExt->FatType == FAT32)
698 Cluster = pFcb->entry.FirstCluster
699 + pFcb->entry.FirstClusterHigh * 65536;
700 else
701 Cluster = pFcb->entry.FirstCluster;
702 pFcb->entry.FirstCluster = 0;
703 pFcb->entry.FirstClusterHigh = 0;
704 updEntry (DeviceExt, FileObject);
705 if ((ULONG)pFcb->RFCB.FileSize.QuadPart > 0)
706 {
707 pFcb->RFCB.AllocationSize.QuadPart = 0;
708 pFcb->RFCB.FileSize.QuadPart = 0;
709 pFcb->RFCB.ValidDataLength.QuadPart = 0;
710 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&pFcb->RFCB.AllocationSize);
711 }
712 while (Cluster != 0xffffffff && Cluster > 1)
713 {
714 Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
715 WriteCluster (DeviceExt, Cluster, 0);
716 Cluster = NextCluster;
717 }
718 }
719
720 /*
721 * If this create was for a paging file then make sure all the
722 * information needed to manipulate it is locked in memory.
723 */
724 if (PagingFileCreate)
725 {
726 ULONG CurrentCluster, NextCluster, i;
727 DPRINT("Open an existing paging file\n");
728 pFcb->Flags |= FCB_IS_PAGE_FILE;
729 pFcb->FatChainSize =
730 ((pFcb->entry.FileSize + DeviceExt->BytesPerCluster - 1) / DeviceExt->BytesPerCluster);
731 if (pFcb->FatChainSize)
732 {
733 pFcb->FatChain = ExAllocatePool(NonPagedPool,
734 pFcb->FatChainSize * sizeof(ULONG));
735 }
736
737 if (DeviceExt->FatType == FAT32)
738 {
739 CurrentCluster = pFcb->entry.FirstCluster +
740 pFcb->entry.FirstClusterHigh * 65536;
741 }
742 else
743 {
744 CurrentCluster = pFcb->entry.FirstCluster;
745 }
746
747 i = 0;
748 if (pFcb->FatChainSize)
749 {
750 while (CurrentCluster != 0xffffffff)
751 {
752 pFcb->FatChain[i] = CurrentCluster;
753 Status = GetNextCluster (DeviceExt, CurrentCluster, &NextCluster,
754 FALSE);
755 i++;
756 CurrentCluster = NextCluster;
757 }
758 }
759 }
760
761 /*
762 * Check the file has the requested attributes
763 */
764 if ((RequestedOptions & FILE_NON_DIRECTORY_FILE)
765 && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
766 {
767 Status = STATUS_FILE_IS_A_DIRECTORY;
768 }
769 if ((RequestedOptions & FILE_DIRECTORY_FILE)
770 && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
771 {
772 Status = STATUS_NOT_A_DIRECTORY;
773 }
774 /* FIXME : test share access */
775 /* FIXME : test write access if requested */
776 if (!NT_SUCCESS (Status))
777 VfatCloseFile (DeviceExt, FileObject);
778 else
779 Irp->IoStatus.Information = FILE_OPENED;
780 /* FIXME : make supersed or overwrite if requested */
781 }
782
783 Irp->IoStatus.Status = Status;
784
785 return Status;
786 }
787
788
789 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
790 /*
791 * FUNCTION: Create or open a file
792 */
793 {
794 NTSTATUS Status;
795
796 assert (IrpContext);
797
798 if (IrpContext->DeviceObject->Size == sizeof (DEVICE_OBJECT))
799 {
800 /* DeviceObject represents FileSystem instead of logical volume */
801 DPRINT ("FsdCreate called with file system\n");
802 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
803 Status = STATUS_SUCCESS;
804 goto ByeBye;
805 }
806
807 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
808 {
809 return VfatQueueRequest (IrpContext);
810 }
811
812 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
813 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
814 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
815
816 ByeBye:
817 IrpContext->Irp->IoStatus.Status = Status;
818 IoCompleteRequest (IrpContext->Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
819 VfatFreeIrpContext(IrpContext);
820 return Status;
821 }
822
823 /* EOF */