Added support for accessing the raw volume.
[reactos.git] / reactos / drivers / fs / vfat / create.c
1 /* $Id: create.c,v 1.40 2002/05/05 20:18:33 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 PVOID Context = NULL;
224 ULONG Offset = 0;
225 ULONG DirIndex = 0;
226 FATDirEntry* Entry;
227 PVFATFCB pFcb;
228 LARGE_INTEGER FileOffset;
229
230 *(Vpb->VolumeLabel) = 0;
231 Vpb->VolumeLabelLength = 0;
232
233 pFcb = vfatOpenRootFCB (DeviceExt);
234
235 while (TRUE)
236 {
237 if (Context == NULL || Offset == ENTRIES_PER_PAGE)
238 {
239 if (Offset == ENTRIES_PER_PAGE)
240 {
241 Offset = 0;
242 }
243 if (Context)
244 {
245 CcUnpinData(Context);
246 }
247 FileOffset.u.HighPart = 0;
248 FileOffset.u.LowPart = (DirIndex - Offset) * sizeof(FATDirEntry);
249 if (!CcMapData(pFcb->FileObject, &FileOffset, PAGESIZE, TRUE, &Context, (PVOID*)&Entry))
250 {
251 Context = NULL;
252 break;
253 }
254 }
255 if (IsVolEntry(Entry, Offset))
256 {
257 /* copy volume label */
258 vfat8Dot3ToVolumeLabel (Entry[Offset].Filename, Entry[Offset].Ext, Vpb->VolumeLabel);
259 Vpb->VolumeLabelLength = wcslen (Vpb->VolumeLabel) * sizeof(WCHAR);
260 break;
261 }
262 if (IsLastEntry(Entry, Offset))
263 {
264 break;
265 }
266 Offset++;
267 DirIndex++;
268 }
269
270 if (Context)
271 {
272 CcUnpinData(Context);
273 }
274 vfatReleaseFCB (DeviceExt, pFcb);
275
276 return STATUS_SUCCESS;
277 }
278
279 NTSTATUS
280 FindFile (PDEVICE_EXTENSION DeviceExt,
281 PVFATFCB Fcb,
282 PVFATFCB Parent,
283 PWSTR FileToFind,
284 ULONG *pDirIndex,
285 ULONG *pDirIndex2)
286 /*
287 * FUNCTION: Find a file
288 */
289 {
290 WCHAR name[256];
291 WCHAR name2[14];
292 char * block;
293 WCHAR TempStr[2];
294 NTSTATUS Status;
295 ULONG len;
296 ULONG DirIndex;
297 ULONG Offset;
298 ULONG FirstCluster;
299 ULONG Read;
300 BOOL isRoot;
301 LARGE_INTEGER FileOffset;
302 PVOID Context = NULL;
303
304 DPRINT ("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n", Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
305 DPRINT ("FindFile: old Pathname %x, old Objectname %x)\n",Fcb->PathName, Fcb->ObjectName);
306
307 isRoot = FALSE;
308 DirIndex = 0;
309 if (wcslen (FileToFind) == 0)
310 {
311 CHECKPOINT;
312 TempStr[0] = (WCHAR) '.';
313 TempStr[1] = 0;
314 FileToFind = (PWSTR)&TempStr;
315 }
316 if (Parent)
317 {
318 FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Parent->entry);
319 if (DeviceExt->FatInfo.FatType == FAT32)
320 {
321 if (FirstCluster == DeviceExt->FatInfo.RootCluster)
322 isRoot = TRUE;
323 }
324 else
325 {
326 if (FirstCluster == 1)
327 isRoot = TRUE;
328 }
329 }
330 else
331 isRoot = TRUE;
332 if (isRoot)
333 {
334 if (DeviceExt->FatInfo.FatType == FAT32)
335 FirstCluster = DeviceExt->FatInfo.RootCluster;
336 else
337 FirstCluster = 1;
338
339 if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
340 || (FileToFind[0] == '.' && FileToFind[1] == 0))
341 {
342 /* it's root : complete essentials fields then return ok */
343 CHECKPOINT;
344 memset (Fcb, 0, sizeof (VFATFCB));
345 memset (Fcb->entry.Filename, ' ', 11);
346 CHECKPOINT;
347 Fcb->PathName[0]='\\';
348 Fcb->ObjectName = &Fcb->PathName[1];
349 Fcb->entry.FileSize = DeviceExt->FatInfo.rootDirectorySectors * BLOCKSIZE;
350 Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
351 if (DeviceExt->FatInfo.FatType == FAT32)
352 {
353 Fcb->entry.FirstCluster = ((PUSHORT)FirstCluster)[0];
354 Fcb->entry.FirstClusterHigh = ((PUSHORT)FirstCluster)[1];
355 }
356 else
357 Fcb->entry.FirstCluster = 1;
358 if (pDirIndex)
359 *pDirIndex = 0;
360 if (pDirIndex2)
361 *pDirIndex2 = 0;
362 DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
363 return (STATUS_SUCCESS);
364 }
365 }
366 else
367 {
368 DPRINT ("Parent->entry.FileSize %x\n", Parent->entry.FileSize);
369 FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Parent->entry);
370 }
371 if (pDirIndex && (*pDirIndex))
372 DirIndex = *pDirIndex;
373
374 Offset = DirIndex % ENTRIES_PER_PAGE;
375 while(TRUE)
376 {
377 if (Context == NULL || Offset == ENTRIES_PER_PAGE)
378 {
379 if (Offset == ENTRIES_PER_PAGE)
380 Offset = 0;
381 if (Context)
382 {
383 CcUnpinData(Context);
384 }
385 FileOffset.QuadPart = (DirIndex - Offset) * sizeof(FATDirEntry);
386 if (!CcMapData(Parent->FileObject, &FileOffset, PAGESIZE, TRUE,
387 &Context, (PVOID*)&block))
388 {
389 Context = NULL;
390 break;
391 }
392 }
393 if (vfatIsDirEntryVolume(&((FATDirEntry*)block)[Offset]))
394 {
395 Offset++;
396 DirIndex++;
397 continue;
398 }
399 Status = GetEntryName (&Context, (PVOID*)&block, Parent->FileObject, name,
400 &DirIndex, pDirIndex2);
401 if (Status == STATUS_NO_MORE_ENTRIES)
402 break;
403 Offset = DirIndex % ENTRIES_PER_PAGE;
404 if (NT_SUCCESS(Status))
405 {
406 vfat8Dot3ToString(((FATDirEntry *) block)[Offset].Filename,((FATDirEntry *) block)[Offset].Ext, name2);
407 if (wstrcmpjoki (name, FileToFind) || wstrcmpjoki (name2, FileToFind))
408 {
409 if (Parent && Parent->PathName)
410 {
411 len = wcslen(Parent->PathName);
412 CHECKPOINT;
413 memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
414 Fcb->ObjectName=&Fcb->PathName[len];
415 if (len != 1 || Fcb->PathName[0] != '\\')
416 {
417 Fcb->ObjectName[0] = '\\';
418 Fcb->ObjectName = &Fcb->ObjectName[1];
419 }
420 }
421 else
422 {
423 Fcb->ObjectName=Fcb->PathName;
424 Fcb->ObjectName[0]='\\';
425 Fcb->ObjectName=&Fcb->ObjectName[1];
426 }
427
428 memcpy (&Fcb->entry, &((FATDirEntry *) block)[Offset],
429 sizeof (FATDirEntry));
430 vfat_wcsncpy (Fcb->ObjectName, name, MAX_PATH);
431 if (pDirIndex)
432 *pDirIndex = DirIndex;
433 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",Fcb->PathName, Fcb->ObjectName, DirIndex);
434 if (Context)
435 CcUnpinData(Context);
436 return STATUS_SUCCESS;
437 }
438 }
439 Offset++;
440 DirIndex++;
441 }
442 if (pDirIndex)
443 *pDirIndex = DirIndex;
444 if (Context)
445 CcUnpinData(Context);
446 return (STATUS_UNSUCCESSFUL);
447 }
448
449 NTSTATUS
450 vfatMakeAbsoluteFilename (PFILE_OBJECT pFileObject,
451 PWSTR pRelativeFileName,
452 PWSTR *pAbsoluteFilename)
453 {
454 PWSTR rcName;
455 PVFATFCB fcb;
456 PVFATCCB ccb;
457
458 DPRINT ("try related for %S\n", pRelativeFileName);
459 ccb = pFileObject->FsContext2;
460 assert (ccb);
461 fcb = ccb->pFcb;
462 assert (fcb);
463
464 /* verify related object is a directory and target name
465 don't start with \. */
466 if (!(fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
467 || (pRelativeFileName[0] == L'\\'))
468 {
469 return STATUS_INVALID_PARAMETER;
470 }
471
472 /* construct absolute path name */
473 assert (wcslen (fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1
474 <= MAX_PATH);
475 rcName = ExAllocatePool (NonPagedPool, MAX_PATH * sizeof(WCHAR));
476 if (!rcName)
477 {
478 return STATUS_INSUFFICIENT_RESOURCES;
479 }
480 wcscpy (rcName, fcb->PathName);
481 if (!vfatFCBIsRoot(fcb))
482 wcscat (rcName, L"\\");
483 wcscat (rcName, pRelativeFileName);
484 *pAbsoluteFilename = rcName;
485
486 return STATUS_SUCCESS;
487 }
488
489 NTSTATUS
490 VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
491 PWSTR FileName)
492 /*
493 * FUNCTION: Opens a file
494 */
495 {
496 PVFATFCB ParentFcb;
497 PVFATFCB Fcb;
498 NTSTATUS Status;
499 PWSTR AbsFileName = NULL;
500
501 DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
502
503 if (FileObject->RelatedFileObject)
504 {
505 DPRINT ("Converting relative filename to absolute filename\n");
506 Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject,
507 FileName,
508 &AbsFileName);
509 FileName = AbsFileName;
510 if (!NT_SUCCESS(Status))
511 {
512 return Status;
513 }
514 }
515
516 //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
517
518 DPRINT ("PathName to open: %S\n", FileName);
519
520 /* try first to find an existing FCB in memory */
521 DPRINT ("Checking for existing FCB in memory\n");
522 Fcb = vfatGrabFCBFromTable (DeviceExt, FileName);
523 if (Fcb == NULL)
524 {
525 DPRINT ("No existing FCB found, making a new one if file exists.\n");
526 Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileName);
527 if (ParentFcb != NULL)
528 {
529 vfatReleaseFCB (DeviceExt, ParentFcb);
530 }
531 if (!NT_SUCCESS (Status))
532 {
533 DPRINT ("Could not make a new FCB, status: %x\n", Status);
534
535 if (AbsFileName)
536 ExFreePool (AbsFileName);
537
538 return Status;
539 }
540 }
541 if (Fcb->Flags & FCB_DELETE_PENDING)
542 {
543 vfatReleaseFCB (DeviceExt, Fcb);
544 if (AbsFileName)
545 ExFreePool (AbsFileName);
546 return STATUS_DELETE_PENDING;
547 }
548 DPRINT ("Attaching FCB to fileObject\n");
549 Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
550
551 if (AbsFileName)
552 ExFreePool (AbsFileName);
553
554 return Status;
555 }
556
557 NTSTATUS
558 VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
559 /*
560 * FUNCTION: Create or open a file
561 */
562 {
563 PIO_STACK_LOCATION Stack;
564 PFILE_OBJECT FileObject;
565 NTSTATUS Status = STATUS_SUCCESS;
566 PDEVICE_EXTENSION DeviceExt;
567 ULONG RequestedDisposition, RequestedOptions;
568 PVFATCCB pCcb;
569 PVFATFCB pFcb;
570 PWCHAR c;
571 BOOLEAN PagingFileCreate = FALSE;
572
573 Stack = IoGetCurrentIrpStackLocation (Irp);
574 assert (Stack);
575 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
576 RequestedOptions =
577 Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
578 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
579 if ((RequestedOptions & FILE_DIRECTORY_FILE)
580 && RequestedDisposition == FILE_SUPERSEDE)
581 return STATUS_INVALID_PARAMETER;
582 FileObject = Stack->FileObject;
583 DeviceExt = DeviceObject->DeviceExtension;
584 assert (DeviceExt);
585
586 if (FileObject->FileName.Length == 0 && FileObject->RelatedFileObject == NULL)
587 {
588 /* This a open operation for the volume itself */
589 if (RequestedDisposition == FILE_CREATE ||
590 RequestedDisposition == FILE_OVERWRITE_IF ||
591 RequestedDisposition == FILE_SUPERSEDE)
592 {
593 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
594 return STATUS_ACCESS_DENIED;
595 }
596 if (RequestedOptions & FILE_DIRECTORY_FILE)
597 {
598 Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
599 return STATUS_NOT_A_DIRECTORY;
600 }
601 pFcb = DeviceExt->VolumeFcb;
602 pCcb = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
603 if (pCcb == NULL)
604 {
605 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
606 return STATUS_INSUFFICIENT_RESOURCES;
607 }
608 memset(pCcb, 0, sizeof(VFATCCB));
609 FileObject->Flags |= FO_FCB_IS_VALID;
610 FileObject->SectionObjectPointers = &pFcb->SectionObjectPointers;
611 FileObject->FsContext = (PVOID) &pFcb->RFCB;
612 FileObject->FsContext2 = pCcb;
613 pCcb->pFcb = pFcb;
614 pCcb->PtrFileObject = FileObject;
615 pFcb->pDevExt = DeviceExt;
616 pFcb->RefCount++;
617
618 Irp->IoStatus.Information = FILE_OPENED;
619 Irp->IoStatus.Status = STATUS_SUCCESS;
620 return STATUS_SUCCESS;
621 }
622
623 /*
624 * Check for illegal characters in the file name
625 */
626 c = FileObject->FileName.Buffer;
627 while (*c != 0)
628 {
629 if (*c == L'*' || *c == L'?' || (*c == L'\\' && c[1] == L'\\'))
630 {
631 Irp->IoStatus.Information = 0;
632 Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
633 return(STATUS_OBJECT_NAME_INVALID);
634 }
635 c++;
636 }
637
638 Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
639
640 /*
641 * If the directory containing the file to open doesn't exist then
642 * fail immediately
643 */
644 Irp->IoStatus.Information = 0;
645 if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
646 {
647 Irp->IoStatus.Status = Status;
648 return Status;
649 }
650 if (Status == STATUS_INVALID_PARAMETER)
651 {
652 Irp->IoStatus.Status = Status;
653 return Status;
654 }
655 if (Status == STATUS_DELETE_PENDING)
656 {
657 Irp->IoStatus.Status = Status;
658 return Status;
659 }
660 if (!NT_SUCCESS (Status))
661 {
662 /*
663 * If the file open failed then create the required file
664 */
665 if (RequestedDisposition == FILE_CREATE ||
666 RequestedDisposition == FILE_OPEN_IF ||
667 RequestedDisposition == FILE_OVERWRITE_IF ||
668 RequestedDisposition == FILE_SUPERSEDE)
669 {
670 CHECKPOINT;
671 Status =
672 addEntry (DeviceExt, FileObject, RequestedOptions,
673 (Stack->Parameters.
674 Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
675 if (NT_SUCCESS (Status))
676 {
677 if (PagingFileCreate)
678 {
679 DPRINT("Creating a new paging file.\n");
680 pCcb = FileObject->FsContext2;
681 pFcb = pCcb->pFcb;
682 pFcb->Flags |= FCB_IS_PAGE_FILE;
683 pFcb->FatChainSize = 0;
684 pFcb->FatChain = NULL;
685 }
686
687 Irp->IoStatus.Information = FILE_CREATED;
688 }
689 /* FIXME set size if AllocationSize requested */
690 /* FIXME set extended attributes? */
691 /* FIXME set share access */
692 /* IoSetShareAccess(DesiredAccess,ShareAccess,FileObject,
693 * ((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
694 */
695 }
696 }
697 else
698 {
699 /*
700 * Otherwise fail if the caller wanted to create a new file
701 */
702 if (RequestedDisposition == FILE_CREATE)
703 {
704 Irp->IoStatus.Information = FILE_EXISTS;
705 Status = STATUS_OBJECT_NAME_COLLISION;
706 }
707 pCcb = FileObject->FsContext2;
708 pFcb = pCcb->pFcb;
709 /*
710 * If requested then delete the file and create a new one with the
711 * same name
712 */
713 if (RequestedDisposition == FILE_SUPERSEDE)
714 {
715 ULONG Cluster, NextCluster;
716 /* FIXME set size to 0 and free clusters */
717 pFcb->entry.FileSize = 0;
718 if (DeviceExt->FatInfo.FatType == FAT32)
719 Cluster = pFcb->entry.FirstCluster
720 + pFcb->entry.FirstClusterHigh * 65536;
721 else
722 Cluster = pFcb->entry.FirstCluster;
723 pFcb->entry.FirstCluster = 0;
724 pFcb->entry.FirstClusterHigh = 0;
725 updEntry (DeviceExt, FileObject);
726 if ((ULONG)pFcb->RFCB.FileSize.QuadPart > 0)
727 {
728 pFcb->RFCB.AllocationSize.QuadPart = 0;
729 pFcb->RFCB.FileSize.QuadPart = 0;
730 pFcb->RFCB.ValidDataLength.QuadPart = 0;
731 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&pFcb->RFCB.AllocationSize);
732 }
733 while (Cluster != 0xffffffff && Cluster > 1)
734 {
735 Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
736 WriteCluster (DeviceExt, Cluster, 0);
737 Cluster = NextCluster;
738 }
739 }
740
741 /*
742 * If this create was for a paging file then make sure all the
743 * information needed to manipulate it is locked in memory.
744 */
745 if (PagingFileCreate)
746 {
747 ULONG CurrentCluster, NextCluster, i;
748 DPRINT("Open an existing paging file\n");
749 pFcb->Flags |= FCB_IS_PAGE_FILE;
750 pFcb->FatChainSize =
751 ((pFcb->entry.FileSize + DeviceExt->FatInfo.BytesPerCluster - 1) / DeviceExt->FatInfo.BytesPerCluster);
752 if (pFcb->FatChainSize)
753 {
754 pFcb->FatChain = ExAllocatePool(NonPagedPool,
755 pFcb->FatChainSize * sizeof(ULONG));
756 }
757
758 if (DeviceExt->FatInfo.FatType == FAT32)
759 {
760 CurrentCluster = pFcb->entry.FirstCluster +
761 pFcb->entry.FirstClusterHigh * 65536;
762 }
763 else
764 {
765 CurrentCluster = pFcb->entry.FirstCluster;
766 }
767
768 i = 0;
769 if (pFcb->FatChainSize)
770 {
771 while (CurrentCluster != 0xffffffff)
772 {
773 pFcb->FatChain[i] = CurrentCluster;
774 Status = GetNextCluster (DeviceExt, CurrentCluster, &NextCluster,
775 FALSE);
776 i++;
777 CurrentCluster = NextCluster;
778 }
779 }
780 }
781
782 /*
783 * Check the file has the requested attributes
784 */
785 if ((RequestedOptions & FILE_NON_DIRECTORY_FILE)
786 && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
787 {
788 Status = STATUS_FILE_IS_A_DIRECTORY;
789 }
790 if ((RequestedOptions & FILE_DIRECTORY_FILE)
791 && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
792 {
793 Status = STATUS_NOT_A_DIRECTORY;
794 }
795 /* FIXME : test share access */
796 /* FIXME : test write access if requested */
797 if (!NT_SUCCESS (Status))
798 VfatCloseFile (DeviceExt, FileObject);
799 else
800 Irp->IoStatus.Information = FILE_OPENED;
801 /* FIXME : make supersed or overwrite if requested */
802 }
803
804 Irp->IoStatus.Status = Status;
805
806 return Status;
807 }
808
809
810 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
811 /*
812 * FUNCTION: Create or open a file
813 */
814 {
815 NTSTATUS Status;
816
817 assert (IrpContext);
818
819 if (IrpContext->DeviceObject->Size == sizeof (DEVICE_OBJECT))
820 {
821 /* DeviceObject represents FileSystem instead of logical volume */
822 DPRINT ("FsdCreate called with file system\n");
823 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
824 Status = STATUS_SUCCESS;
825 goto ByeBye;
826 }
827
828 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
829 {
830 return VfatQueueRequest (IrpContext);
831 }
832
833 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
834 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
835 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
836
837 ByeBye:
838 IrpContext->Irp->IoStatus.Status = Status;
839 IoCompleteRequest (IrpContext->Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
840 VfatFreeIrpContext(IrpContext);
841 return Status;
842 }
843
844 /* EOF */