All:
[reactos.git] / reactos / drivers / fs / vfat / create.c
1 /* $Id: create.c,v 1.39 2002/03/18 22:37:12 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 /*
587 * Check for illegal characters in the file name
588 */
589 c = FileObject->FileName.Buffer;
590 while (*c != 0)
591 {
592 if (*c == L'*' || *c == L'?' || (*c == L'\\' && c[1] == L'\\'))
593 {
594 Irp->IoStatus.Information = 0;
595 Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
596 return(STATUS_OBJECT_NAME_INVALID);
597 }
598 c++;
599 }
600
601 Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
602
603 /*
604 * If the directory containing the file to open doesn't exist then
605 * fail immediately
606 */
607 Irp->IoStatus.Information = 0;
608 if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
609 {
610 Irp->IoStatus.Status = Status;
611 return Status;
612 }
613 if (Status == STATUS_INVALID_PARAMETER)
614 {
615 Irp->IoStatus.Status = Status;
616 return Status;
617 }
618 if (Status == STATUS_DELETE_PENDING)
619 {
620 Irp->IoStatus.Status = Status;
621 return Status;
622 }
623 if (!NT_SUCCESS (Status))
624 {
625 /*
626 * If the file open failed then create the required file
627 */
628 if (RequestedDisposition == FILE_CREATE ||
629 RequestedDisposition == FILE_OPEN_IF ||
630 RequestedDisposition == FILE_OVERWRITE_IF ||
631 RequestedDisposition == FILE_SUPERSEDE)
632 {
633 CHECKPOINT;
634 Status =
635 addEntry (DeviceExt, FileObject, RequestedOptions,
636 (Stack->Parameters.
637 Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
638 if (NT_SUCCESS (Status))
639 {
640 if (PagingFileCreate)
641 {
642 DPRINT("Creating a new paging file.\n");
643 pCcb = FileObject->FsContext2;
644 pFcb = pCcb->pFcb;
645 pFcb->Flags |= FCB_IS_PAGE_FILE;
646 pFcb->FatChainSize = 0;
647 pFcb->FatChain = NULL;
648 }
649
650 Irp->IoStatus.Information = FILE_CREATED;
651 }
652 /* FIXME set size if AllocationSize requested */
653 /* FIXME set extended attributes? */
654 /* FIXME set share access */
655 /* IoSetShareAccess(DesiredAccess,ShareAccess,FileObject,
656 * ((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
657 */
658 }
659 }
660 else
661 {
662 /*
663 * Otherwise fail if the caller wanted to create a new file
664 */
665 if (RequestedDisposition == FILE_CREATE)
666 {
667 Irp->IoStatus.Information = FILE_EXISTS;
668 Status = STATUS_OBJECT_NAME_COLLISION;
669 }
670 pCcb = FileObject->FsContext2;
671 pFcb = pCcb->pFcb;
672 /*
673 * If requested then delete the file and create a new one with the
674 * same name
675 */
676 if (RequestedDisposition == FILE_SUPERSEDE)
677 {
678 ULONG Cluster, NextCluster;
679 /* FIXME set size to 0 and free clusters */
680 pFcb->entry.FileSize = 0;
681 if (DeviceExt->FatInfo.FatType == FAT32)
682 Cluster = pFcb->entry.FirstCluster
683 + pFcb->entry.FirstClusterHigh * 65536;
684 else
685 Cluster = pFcb->entry.FirstCluster;
686 pFcb->entry.FirstCluster = 0;
687 pFcb->entry.FirstClusterHigh = 0;
688 updEntry (DeviceExt, FileObject);
689 if ((ULONG)pFcb->RFCB.FileSize.QuadPart > 0)
690 {
691 pFcb->RFCB.AllocationSize.QuadPart = 0;
692 pFcb->RFCB.FileSize.QuadPart = 0;
693 pFcb->RFCB.ValidDataLength.QuadPart = 0;
694 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&pFcb->RFCB.AllocationSize);
695 }
696 while (Cluster != 0xffffffff && Cluster > 1)
697 {
698 Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, FALSE);
699 WriteCluster (DeviceExt, Cluster, 0);
700 Cluster = NextCluster;
701 }
702 }
703
704 /*
705 * If this create was for a paging file then make sure all the
706 * information needed to manipulate it is locked in memory.
707 */
708 if (PagingFileCreate)
709 {
710 ULONG CurrentCluster, NextCluster, i;
711 DPRINT("Open an existing paging file\n");
712 pFcb->Flags |= FCB_IS_PAGE_FILE;
713 pFcb->FatChainSize =
714 ((pFcb->entry.FileSize + DeviceExt->FatInfo.BytesPerCluster - 1) / DeviceExt->FatInfo.BytesPerCluster);
715 if (pFcb->FatChainSize)
716 {
717 pFcb->FatChain = ExAllocatePool(NonPagedPool,
718 pFcb->FatChainSize * sizeof(ULONG));
719 }
720
721 if (DeviceExt->FatInfo.FatType == FAT32)
722 {
723 CurrentCluster = pFcb->entry.FirstCluster +
724 pFcb->entry.FirstClusterHigh * 65536;
725 }
726 else
727 {
728 CurrentCluster = pFcb->entry.FirstCluster;
729 }
730
731 i = 0;
732 if (pFcb->FatChainSize)
733 {
734 while (CurrentCluster != 0xffffffff)
735 {
736 pFcb->FatChain[i] = CurrentCluster;
737 Status = GetNextCluster (DeviceExt, CurrentCluster, &NextCluster,
738 FALSE);
739 i++;
740 CurrentCluster = NextCluster;
741 }
742 }
743 }
744
745 /*
746 * Check the file has the requested attributes
747 */
748 if ((RequestedOptions & FILE_NON_DIRECTORY_FILE)
749 && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
750 {
751 Status = STATUS_FILE_IS_A_DIRECTORY;
752 }
753 if ((RequestedOptions & FILE_DIRECTORY_FILE)
754 && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
755 {
756 Status = STATUS_NOT_A_DIRECTORY;
757 }
758 /* FIXME : test share access */
759 /* FIXME : test write access if requested */
760 if (!NT_SUCCESS (Status))
761 VfatCloseFile (DeviceExt, FileObject);
762 else
763 Irp->IoStatus.Information = FILE_OPENED;
764 /* FIXME : make supersed or overwrite if requested */
765 }
766
767 Irp->IoStatus.Status = Status;
768
769 return Status;
770 }
771
772
773 NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
774 /*
775 * FUNCTION: Create or open a file
776 */
777 {
778 NTSTATUS Status;
779
780 assert (IrpContext);
781
782 if (IrpContext->DeviceObject->Size == sizeof (DEVICE_OBJECT))
783 {
784 /* DeviceObject represents FileSystem instead of logical volume */
785 DPRINT ("FsdCreate called with file system\n");
786 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
787 Status = STATUS_SUCCESS;
788 goto ByeBye;
789 }
790
791 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
792 {
793 return VfatQueueRequest (IrpContext);
794 }
795
796 ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
797 Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
798 ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
799
800 ByeBye:
801 IrpContext->Irp->IoStatus.Status = Status;
802 IoCompleteRequest (IrpContext->Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
803 VfatFreeIrpContext(IrpContext);
804 return Status;
805 }
806
807 /* EOF */