[DRIVERS] Spelling fixes by Josh Soref. CORE-12286
[reactos.git] / reactos / drivers / filesystems / fastfat / create.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystems/fastfat/create.c
22 * PURPOSE: VFAT Filesystem
23 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
24 * Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "vfat.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* FUNCTIONS *****************************************************************/
35
36 VOID
37 vfat8Dot3ToString(
38 PFAT_DIR_ENTRY pEntry,
39 PUNICODE_STRING NameU)
40 {
41 OEM_STRING StringA;
42 USHORT Length;
43 CHAR cString[12];
44
45 RtlCopyMemory(cString, pEntry->ShortName, 11);
46 cString[11] = 0;
47 if (cString[0] == 0x05)
48 {
49 cString[0] = 0xe5;
50 }
51
52 StringA.Buffer = cString;
53 for (StringA.Length = 0;
54 StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' ';
55 StringA.Length++);
56 StringA.MaximumLength = StringA.Length;
57
58 RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
59
60 if (pEntry->lCase & VFAT_CASE_LOWER_BASE)
61 {
62 RtlDowncaseUnicodeString(NameU, NameU, FALSE);
63 }
64
65 if (cString[8] != ' ')
66 {
67 Length = NameU->Length;
68 NameU->Buffer += Length / sizeof(WCHAR);
69 if (!FAT_ENTRY_VOLUME(pEntry))
70 {
71 Length += sizeof(WCHAR);
72 NameU->Buffer[0] = L'.';
73 NameU->Buffer++;
74 }
75 NameU->Length = 0;
76 NameU->MaximumLength -= Length;
77
78 StringA.Buffer = &cString[8];
79 for (StringA.Length = 0;
80 StringA.Length < 3 && StringA.Buffer[StringA.Length] != ' ';
81 StringA.Length++);
82 StringA.MaximumLength = StringA.Length;
83 RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
84 if (pEntry->lCase & VFAT_CASE_LOWER_EXT)
85 {
86 RtlDowncaseUnicodeString(NameU, NameU, FALSE);
87 }
88 NameU->Buffer -= Length / sizeof(WCHAR);
89 NameU->Length += Length;
90 NameU->MaximumLength += Length;
91 }
92
93 NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
94 DPRINT("'%wZ'\n", NameU);
95 }
96
97 /*
98 * FUNCTION: Read the volume label
99 */
100 NTSTATUS
101 ReadVolumeLabel(
102 PDEVICE_EXTENSION DeviceExt,
103 PVPB Vpb)
104 {
105 PVOID Context = NULL;
106 ULONG DirIndex = 0;
107 PDIR_ENTRY Entry;
108 PVFATFCB pFcb;
109 LARGE_INTEGER FileOffset;
110 UNICODE_STRING NameU;
111 ULONG SizeDirEntry;
112 ULONG EntriesPerPage;
113 OEM_STRING StringO;
114 NTSTATUS Status = STATUS_SUCCESS;
115
116 NameU.Buffer = Vpb->VolumeLabel;
117 NameU.Length = 0;
118 NameU.MaximumLength = sizeof(Vpb->VolumeLabel);
119 *(Vpb->VolumeLabel) = 0;
120 Vpb->VolumeLabelLength = 0;
121
122 if (DeviceExt->Flags & VCB_IS_FATX)
123 {
124 SizeDirEntry = sizeof(FATX_DIR_ENTRY);
125 EntriesPerPage = FATX_ENTRIES_PER_PAGE;
126 }
127 else
128 {
129 SizeDirEntry = sizeof(FAT_DIR_ENTRY);
130 EntriesPerPage = FAT_ENTRIES_PER_PAGE;
131 }
132
133 ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
134 pFcb = vfatOpenRootFCB(DeviceExt);
135 ExReleaseResourceLite(&DeviceExt->DirResource);
136
137 FileOffset.QuadPart = 0;
138 _SEH2_TRY
139 {
140 CcMapData(pFcb->FileObject, &FileOffset, SizeDirEntry, MAP_WAIT, &Context, (PVOID*)&Entry);
141 }
142 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
143 {
144 Status = _SEH2_GetExceptionCode();
145 }
146 _SEH2_END;
147 if (NT_SUCCESS(Status))
148 {
149 while (TRUE)
150 {
151 if (ENTRY_VOLUME(DeviceExt, Entry))
152 {
153 /* copy volume label */
154 if (DeviceExt->Flags & VCB_IS_FATX)
155 {
156 StringO.Buffer = (PCHAR)Entry->FatX.Filename;
157 StringO.MaximumLength = StringO.Length = Entry->FatX.FilenameLength;
158 RtlOemStringToUnicodeString(&NameU, &StringO, FALSE);
159 }
160 else
161 {
162 vfat8Dot3ToString(&Entry->Fat, &NameU);
163 }
164 Vpb->VolumeLabelLength = NameU.Length;
165 break;
166 }
167 if (ENTRY_END(DeviceExt, Entry))
168 {
169 break;
170 }
171 DirIndex++;
172 Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
173 if ((DirIndex % EntriesPerPage) == 0)
174 {
175 CcUnpinData(Context);
176 FileOffset.u.LowPart += PAGE_SIZE;
177 _SEH2_TRY
178 {
179 CcMapData(pFcb->FileObject, &FileOffset, SizeDirEntry, MAP_WAIT, &Context, (PVOID*)&Entry);
180 }
181 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
182 {
183 Status = _SEH2_GetExceptionCode();
184 }
185 _SEH2_END;
186 if (!NT_SUCCESS(Status))
187 {
188 Context = NULL;
189 break;
190 }
191 }
192 }
193 if (Context)
194 {
195 CcUnpinData(Context);
196 }
197 }
198 ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
199 vfatReleaseFCB(DeviceExt, pFcb);
200 ExReleaseResourceLite(&DeviceExt->DirResource);
201
202 return STATUS_SUCCESS;
203 }
204
205 /*
206 * FUNCTION: Find a file
207 */
208 NTSTATUS
209 FindFile(
210 PDEVICE_EXTENSION DeviceExt,
211 PVFATFCB Parent,
212 PUNICODE_STRING FileToFindU,
213 PVFAT_DIRENTRY_CONTEXT DirContext,
214 BOOLEAN First)
215 {
216 PWCHAR PathNameBuffer;
217 USHORT PathNameBufferLength;
218 NTSTATUS Status;
219 PVOID Context = NULL;
220 PVOID Page;
221 PVFATFCB rcFcb;
222 BOOLEAN Found;
223 UNICODE_STRING PathNameU;
224 UNICODE_STRING FileToFindUpcase;
225 BOOLEAN WildCard;
226
227 DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
228 Parent, FileToFindU, DirContext->DirIndex);
229 DPRINT("FindFile: Path %wZ\n",&Parent->PathNameU);
230
231 PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR);
232 PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength + sizeof(WCHAR), TAG_VFAT);
233 if (!PathNameBuffer)
234 {
235 return STATUS_INSUFFICIENT_RESOURCES;
236 }
237
238 PathNameU.Buffer = PathNameBuffer;
239 PathNameU.Length = 0;
240 PathNameU.MaximumLength = PathNameBufferLength;
241
242 DirContext->LongNameU.Length = 0;
243 DirContext->ShortNameU.Length = 0;
244
245 WildCard = FsRtlDoesNameContainWildCards(FileToFindU);
246
247 if (WildCard == FALSE)
248 {
249 /* if there is no '*?' in the search name, than look first for an existing fcb */
250 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
251 if (!vfatFCBIsRoot(Parent))
252 {
253 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
254 PathNameU.Length += sizeof(WCHAR);
255 }
256 RtlAppendUnicodeStringToString(&PathNameU, FileToFindU);
257 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
258 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
259 if (rcFcb)
260 {
261 ULONG startIndex = rcFcb->startIndex;
262 if ((rcFcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Parent))
263 {
264 startIndex += 2;
265 }
266 if(startIndex >= DirContext->DirIndex)
267 {
268 RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU);
269 RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU);
270 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
271 DirContext->StartIndex = rcFcb->startIndex;
272 DirContext->DirIndex = rcFcb->dirIndex;
273 DPRINT("FindFile: new Name %wZ, DirIndex %u (%u)\n",
274 &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex);
275 Status = STATUS_SUCCESS;
276 }
277 else
278 {
279 DPRINT("FCB not found for %wZ\n", &PathNameU);
280 Status = STATUS_UNSUCCESSFUL;
281 }
282 vfatReleaseFCB(DeviceExt, rcFcb);
283 ExFreePool(PathNameBuffer);
284 return Status;
285 }
286 }
287
288 /* FsRtlIsNameInExpression need the searched string to be upcase,
289 * even if IgnoreCase is specified */
290 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE);
291 if (!NT_SUCCESS(Status))
292 {
293 ExFreePool(PathNameBuffer);
294 return Status;
295 }
296
297 while (TRUE)
298 {
299 Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
300 First = FALSE;
301 if (Status == STATUS_NO_MORE_ENTRIES)
302 {
303 break;
304 }
305 if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
306 {
307 DirContext->DirIndex++;
308 continue;
309 }
310 if (DirContext->LongNameU.Length == 0 ||
311 DirContext->ShortNameU.Length == 0)
312 {
313 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
314 if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
315 {
316 ASSERT(DirContext->LongNameU.Length != 0 &&
317 DirContext->ShortNameU.Length != 0);
318 }
319 DirContext->DirIndex++;
320 continue;
321 }
322 if (WildCard)
323 {
324 Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) ||
325 FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL);
326 }
327 else
328 {
329 Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
330 FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
331 }
332
333 if (Found)
334 {
335 if (WildCard)
336 {
337 RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
338 if (!vfatFCBIsRoot(Parent))
339 {
340 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
341 PathNameU.Length += sizeof(WCHAR);
342 }
343 RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU);
344 PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
345 rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
346 if (rcFcb != NULL)
347 {
348 RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
349 vfatReleaseFCB(DeviceExt, rcFcb);
350 }
351 }
352 DPRINT("%u\n", DirContext->LongNameU.Length);
353 DPRINT("FindFile: new Name %wZ, DirIndex %u\n",
354 &DirContext->LongNameU, DirContext->DirIndex);
355
356 if (Context)
357 {
358 CcUnpinData(Context);
359 }
360 RtlFreeUnicodeString(&FileToFindUpcase);
361 ExFreePool(PathNameBuffer);
362 return STATUS_SUCCESS;
363 }
364 DirContext->DirIndex++;
365 }
366
367 if (Context)
368 {
369 CcUnpinData(Context);
370 }
371
372 RtlFreeUnicodeString(&FileToFindUpcase);
373 ExFreePool(PathNameBuffer);
374 return Status;
375 }
376
377 /*
378 * FUNCTION: Opens a file
379 */
380 static
381 NTSTATUS
382 VfatOpenFile(
383 PDEVICE_EXTENSION DeviceExt,
384 PUNICODE_STRING PathNameU,
385 PFILE_OBJECT FileObject,
386 ULONG RequestedDisposition,
387 ULONG RequestedOptions,
388 PVFATFCB *ParentFcb)
389 {
390 PVFATFCB Fcb;
391 NTSTATUS Status;
392
393 DPRINT("VfatOpenFile(%p, '%wZ', %p, %p)\n", DeviceExt, PathNameU, FileObject, ParentFcb);
394
395 if (FileObject->RelatedFileObject)
396 {
397 DPRINT("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
398
399 *ParentFcb = FileObject->RelatedFileObject->FsContext;
400 }
401 else
402 {
403 *ParentFcb = NULL;
404 }
405
406 if (!DeviceExt->FatInfo.FixedMedia)
407 {
408 Status = VfatBlockDeviceIoControl(DeviceExt->StorageDevice,
409 IOCTL_DISK_CHECK_VERIFY,
410 NULL,
411 0,
412 NULL,
413 0,
414 FALSE);
415 if (!NT_SUCCESS(Status))
416 {
417 DPRINT("Status %lx\n", Status);
418 *ParentFcb = NULL;
419 return Status;
420 }
421 }
422
423 if (*ParentFcb)
424 {
425 vfatGrabFCB(DeviceExt, *ParentFcb);
426 }
427
428 /* try first to find an existing FCB in memory */
429 DPRINT("Checking for existing FCB in memory\n");
430
431 Status = vfatGetFCBForFile(DeviceExt, ParentFcb, &Fcb, PathNameU);
432 if (!NT_SUCCESS(Status))
433 {
434 DPRINT ("Could not make a new FCB, status: %x\n", Status);
435 return Status;
436 }
437
438 /* Fail, if we try to overwrite an existing directory */
439 if ((!(RequestedOptions & FILE_DIRECTORY_FILE) && (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)) &&
440 (RequestedDisposition == FILE_OVERWRITE ||
441 RequestedDisposition == FILE_OVERWRITE_IF ||
442 RequestedDisposition == FILE_SUPERSEDE))
443 {
444 vfatReleaseFCB(DeviceExt, Fcb);
445 return STATUS_OBJECT_NAME_COLLISION;
446 }
447
448 if (Fcb->Flags & FCB_DELETE_PENDING)
449 {
450 vfatReleaseFCB(DeviceExt, Fcb);
451 return STATUS_DELETE_PENDING;
452 }
453
454 /* Fail, if we try to overwrite a read-only file */
455 if ((*Fcb->Attributes & FILE_ATTRIBUTE_READONLY) &&
456 (RequestedDisposition == FILE_OVERWRITE ||
457 RequestedDisposition == FILE_OVERWRITE_IF))
458 {
459 vfatReleaseFCB(DeviceExt, Fcb);
460 return STATUS_ACCESS_DENIED;
461 }
462
463 if ((*Fcb->Attributes & FILE_ATTRIBUTE_READONLY) &&
464 (RequestedOptions & FILE_DELETE_ON_CLOSE))
465 {
466 vfatReleaseFCB(DeviceExt, Fcb);
467 return STATUS_CANNOT_DELETE;
468 }
469
470 if ((vfatFCBIsRoot(Fcb) ||
471 (Fcb->LongNameU.Length == sizeof(WCHAR) && Fcb->LongNameU.Buffer[0] == L'.') ||
472 (Fcb->LongNameU.Length == 2 * sizeof(WCHAR) && Fcb->LongNameU.Buffer[0] == L'.' && Fcb->LongNameU.Buffer[1] == L'.')) &&
473 (RequestedOptions & FILE_DELETE_ON_CLOSE))
474 {
475 // we cannot delete a '.', '..' or the root directory
476 vfatReleaseFCB(DeviceExt, Fcb);
477 return STATUS_CANNOT_DELETE;
478 }
479
480 DPRINT("Attaching FCB to fileObject\n");
481 Status = vfatAttachFCBToFileObject(DeviceExt, Fcb, FileObject);
482 if (!NT_SUCCESS(Status))
483 {
484 vfatReleaseFCB(DeviceExt, Fcb);
485 }
486 return Status;
487 }
488
489 /*
490 * FUNCTION: Create or open a file
491 */
492 static NTSTATUS
493 VfatCreateFile(
494 PDEVICE_OBJECT DeviceObject,
495 PIRP Irp)
496 {
497 PIO_STACK_LOCATION Stack;
498 PFILE_OBJECT FileObject;
499 NTSTATUS Status = STATUS_SUCCESS;
500 PDEVICE_EXTENSION DeviceExt;
501 ULONG RequestedDisposition, RequestedOptions;
502 PVFATFCB pFcb = NULL;
503 PVFATFCB ParentFcb = NULL;
504 PWCHAR c, last;
505 BOOLEAN PagingFileCreate;
506 BOOLEAN Dots;
507 BOOLEAN OpenTargetDir;
508 UNICODE_STRING FileNameU;
509 UNICODE_STRING PathNameU;
510 ULONG Attributes;
511
512 /* Unpack the various parameters. */
513 Stack = IoGetCurrentIrpStackLocation(Irp);
514 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
515 RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
516 PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
517 OpenTargetDir = (Stack->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE;
518
519 FileObject = Stack->FileObject;
520 DeviceExt = DeviceObject->DeviceExtension;
521
522 if (Stack->Parameters.Create.Options & FILE_OPEN_BY_FILE_ID)
523 {
524 return STATUS_NOT_IMPLEMENTED;
525 }
526
527 /* Check their validity. */
528 if (RequestedOptions & FILE_DIRECTORY_FILE &&
529 RequestedDisposition == FILE_SUPERSEDE)
530 {
531 return STATUS_INVALID_PARAMETER;
532 }
533
534 if (RequestedOptions & FILE_DIRECTORY_FILE &&
535 RequestedOptions & FILE_NON_DIRECTORY_FILE)
536 {
537 return STATUS_INVALID_PARAMETER;
538 }
539
540 /* Deny create if the volume is locked */
541 if (DeviceExt->Flags & VCB_VOLUME_LOCKED)
542 {
543 return STATUS_ACCESS_DENIED;
544 }
545
546 /* This a open operation for the volume itself */
547 if (FileObject->FileName.Length == 0 &&
548 (FileObject->RelatedFileObject == NULL ||
549 FileObject->RelatedFileObject->FsContext2 != NULL ||
550 FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb))
551 {
552 DPRINT("Volume opening\n");
553
554 if (RequestedDisposition != FILE_OPEN &&
555 RequestedDisposition != FILE_OPEN_IF)
556 {
557 return STATUS_ACCESS_DENIED;
558 }
559 #if 0
560 /* In spite of what is shown in WDK, it seems that Windows FAT driver doesn't perform that test */
561 if (RequestedOptions & FILE_DIRECTORY_FILE)
562 {
563 return STATUS_NOT_A_DIRECTORY;
564 }
565 #endif
566
567 if (OpenTargetDir)
568 {
569 return STATUS_INVALID_PARAMETER;
570 }
571
572 if (RequestedOptions & FILE_DELETE_ON_CLOSE)
573 {
574 return STATUS_CANNOT_DELETE;
575 }
576
577 pFcb = DeviceExt->VolumeFcb;
578
579 if (pFcb->OpenHandleCount == 0)
580 {
581 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
582 Stack->Parameters.Create.ShareAccess,
583 FileObject,
584 &pFcb->FCBShareAccess);
585 }
586 else
587 {
588 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
589 Stack->Parameters.Create.ShareAccess,
590 FileObject,
591 &pFcb->FCBShareAccess,
592 FALSE);
593 if (!NT_SUCCESS(Status))
594 {
595 return Status;
596 }
597 }
598
599 vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject);
600 DeviceExt->OpenHandleCount++;
601 pFcb->OpenHandleCount++;
602
603 Irp->IoStatus.Information = FILE_OPENED;
604 return STATUS_SUCCESS;
605 }
606
607 if (FileObject->RelatedFileObject != NULL &&
608 FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb)
609 {
610 ASSERT(FileObject->FileName.Length != 0);
611 return STATUS_OBJECT_PATH_NOT_FOUND;
612 }
613
614 /* Check for illegal characters and illegal dot sequences in the file name */
615 PathNameU = FileObject->FileName;
616 c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR);
617 last = c - 1;
618 Dots = TRUE;
619 while (c-- > PathNameU.Buffer)
620 {
621 if (*c == L'\\' || c == PathNameU.Buffer)
622 {
623 if (Dots && last > c)
624 {
625 return STATUS_OBJECT_NAME_INVALID;
626 }
627 last = c - 1;
628 Dots = TRUE;
629 }
630 else if (*c != L'.')
631 {
632 Dots = FALSE;
633 }
634
635 if (*c != '\\' && vfatIsLongIllegal(*c))
636 {
637 return STATUS_OBJECT_NAME_INVALID;
638 }
639 }
640
641 /* Check if we try to open target directory of root dir */
642 if (OpenTargetDir && FileObject->RelatedFileObject == NULL && PathNameU.Length == sizeof(WCHAR) &&
643 PathNameU.Buffer[0] == L'\\')
644 {
645 return STATUS_INVALID_PARAMETER;
646 }
647
648 if (FileObject->RelatedFileObject && PathNameU.Length >= sizeof(WCHAR) && PathNameU.Buffer[0] == L'\\')
649 {
650 return STATUS_OBJECT_NAME_INVALID;
651 }
652
653 if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\')
654 {
655 PathNameU.Length -= sizeof(WCHAR);
656 }
657
658 if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\')
659 {
660 return STATUS_OBJECT_NAME_INVALID;
661 }
662
663 /* Try opening the file. */
664 if (!OpenTargetDir)
665 {
666 Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, RequestedOptions, &ParentFcb);
667 }
668 else
669 {
670 PVFATFCB TargetFcb;
671 LONG idx, FileNameLen;
672
673 ParentFcb = (FileObject->RelatedFileObject != NULL) ? FileObject->RelatedFileObject->FsContext : NULL;
674 if (ParentFcb)
675 {
676 vfatGrabFCB(DeviceExt, ParentFcb);
677 }
678 Status = vfatGetFCBForFile(DeviceExt, &ParentFcb, &TargetFcb, &PathNameU);
679
680 if (NT_SUCCESS(Status))
681 {
682 vfatReleaseFCB(DeviceExt, TargetFcb);
683 Irp->IoStatus.Information = FILE_EXISTS;
684 }
685 else
686 {
687 Irp->IoStatus.Information = FILE_DOES_NOT_EXIST;
688 }
689
690 idx = FileObject->FileName.Length / sizeof(WCHAR) - 1;
691
692 /* Skip trailing \ - if any */
693 if (PathNameU.Buffer[idx] == L'\\')
694 {
695 --idx;
696 PathNameU.Length -= sizeof(WCHAR);
697 }
698
699 /* Get file name */
700 while (idx >= 0 && PathNameU.Buffer[idx] != L'\\')
701 {
702 --idx;
703 }
704
705 if (idx > 0 || PathNameU.Buffer[0] == L'\\')
706 {
707 /* We don't want to include / in the name */
708 FileNameLen = PathNameU.Length - ((idx + 1) * sizeof(WCHAR));
709
710 /* Update FO just to keep file name */
711 /* Skip first slash */
712 ++idx;
713 FileObject->FileName.Length = FileNameLen;
714 RtlMoveMemory(&PathNameU.Buffer[0], &PathNameU.Buffer[idx], FileObject->FileName.Length);
715 }
716 else
717 {
718 /* This is a relative open and we have only the filename, so open the parent directory
719 * It is in RelatedFileObject
720 */
721 ASSERT(FileObject->RelatedFileObject != NULL);
722
723 /* No need to modify the FO, it already has the name */
724 }
725
726 /* We're done with opening! */
727 if (ParentFcb != NULL)
728 {
729 Status = vfatAttachFCBToFileObject(DeviceExt, ParentFcb, FileObject);
730 }
731
732 if (NT_SUCCESS(Status))
733 {
734 pFcb = FileObject->FsContext;
735 ASSERT(pFcb == ParentFcb);
736
737 if (pFcb->OpenHandleCount == 0)
738 {
739 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
740 Stack->Parameters.Create.ShareAccess,
741 FileObject,
742 &pFcb->FCBShareAccess);
743 }
744 else
745 {
746 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
747 Stack->Parameters.Create.ShareAccess,
748 FileObject,
749 &pFcb->FCBShareAccess,
750 FALSE);
751 if (!NT_SUCCESS(Status))
752 {
753 VfatCloseFile(DeviceExt, FileObject);
754 return Status;
755 }
756 }
757
758 pFcb->OpenHandleCount++;
759 DeviceExt->OpenHandleCount++;
760 }
761 else if (ParentFcb != NULL)
762 {
763 vfatReleaseFCB(DeviceExt, ParentFcb);
764 }
765
766 return Status;
767 }
768
769 /*
770 * If the directory containing the file to open doesn't exist then
771 * fail immediately
772 */
773 if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
774 Status == STATUS_INVALID_PARAMETER ||
775 Status == STATUS_DELETE_PENDING ||
776 Status == STATUS_ACCESS_DENIED ||
777 Status == STATUS_OBJECT_NAME_COLLISION)
778 {
779 if (ParentFcb)
780 {
781 vfatReleaseFCB(DeviceExt, ParentFcb);
782 }
783 return Status;
784 }
785
786 if (!NT_SUCCESS(Status) && ParentFcb == NULL)
787 {
788 DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU, Status);
789 return Status;
790 }
791
792 /* If the file open failed then create the required file */
793 if (!NT_SUCCESS (Status))
794 {
795 if (RequestedDisposition == FILE_CREATE ||
796 RequestedDisposition == FILE_OPEN_IF ||
797 RequestedDisposition == FILE_OVERWRITE_IF ||
798 RequestedDisposition == FILE_SUPERSEDE)
799 {
800 Attributes = Stack->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL;
801 if (!(RequestedOptions & FILE_DIRECTORY_FILE))
802 Attributes |= FILE_ATTRIBUTE_ARCHIVE;
803 vfatSplitPathName(&PathNameU, NULL, &FileNameU);
804 Status = VfatAddEntry(DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
805 (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS), NULL);
806 vfatReleaseFCB(DeviceExt, ParentFcb);
807 if (NT_SUCCESS(Status))
808 {
809 Status = vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject);
810 if (!NT_SUCCESS(Status))
811 {
812 vfatReleaseFCB(DeviceExt, pFcb);
813 return Status;
814 }
815
816 Irp->IoStatus.Information = FILE_CREATED;
817 VfatSetAllocationSizeInformation(FileObject,
818 pFcb,
819 DeviceExt,
820 &Irp->Overlay.AllocationSize);
821 VfatSetExtendedAttributes(FileObject,
822 Irp->AssociatedIrp.SystemBuffer,
823 Stack->Parameters.Create.EaLength);
824
825 if (PagingFileCreate)
826 {
827 pFcb->Flags |= FCB_IS_PAGE_FILE;
828 }
829 }
830 else
831 {
832 return Status;
833 }
834 }
835 else
836 {
837 if (ParentFcb)
838 {
839 vfatReleaseFCB(DeviceExt, ParentFcb);
840 }
841 return Status;
842 }
843 }
844 else
845 {
846 if (ParentFcb)
847 {
848 vfatReleaseFCB(DeviceExt, ParentFcb);
849 }
850
851 /* Otherwise fail if the caller wanted to create a new file */
852 if (RequestedDisposition == FILE_CREATE)
853 {
854 Irp->IoStatus.Information = FILE_EXISTS;
855 VfatCloseFile(DeviceExt, FileObject);
856 return STATUS_OBJECT_NAME_COLLISION;
857 }
858
859 pFcb = FileObject->FsContext;
860
861 if (pFcb->OpenHandleCount != 0)
862 {
863 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
864 Stack->Parameters.Create.ShareAccess,
865 FileObject,
866 &pFcb->FCBShareAccess,
867 FALSE);
868 if (!NT_SUCCESS(Status))
869 {
870 VfatCloseFile(DeviceExt, FileObject);
871 return Status;
872 }
873 }
874
875 /*
876 * Check the file has the requested attributes
877 */
878 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
879 *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
880 {
881 VfatCloseFile (DeviceExt, FileObject);
882 return STATUS_FILE_IS_A_DIRECTORY;
883 }
884 if (RequestedOptions & FILE_DIRECTORY_FILE &&
885 !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
886 {
887 VfatCloseFile (DeviceExt, FileObject);
888 return STATUS_NOT_A_DIRECTORY;
889 }
890 #ifndef USE_ROS_CC_AND_FS
891 if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
892 {
893 if (Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA ||
894 RequestedDisposition == FILE_OVERWRITE ||
895 RequestedDisposition == FILE_OVERWRITE_IF ||
896 (RequestedOptions & FILE_DELETE_ON_CLOSE))
897 {
898 if (!MmFlushImageSection(&pFcb->SectionObjectPointers, MmFlushForWrite))
899 {
900 DPRINT1("%wZ\n", &pFcb->PathNameU);
901 DPRINT1("%d %d %d\n", Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA,
902 RequestedDisposition == FILE_OVERWRITE, RequestedDisposition == FILE_OVERWRITE_IF);
903 VfatCloseFile (DeviceExt, FileObject);
904 return (RequestedOptions & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE
905 : STATUS_SHARING_VIOLATION;
906 }
907 }
908 }
909 #endif
910 if (PagingFileCreate)
911 {
912 /* FIXME:
913 * Do more checking for page files. It is possible,
914 * that the file was opened and closed previously
915 * as a normal cached file. In this case, the cache
916 * manager has referenced the fileobject and the fcb
917 * is held in memory. Try to remove the fileobject
918 * from cache manager and use the fcb.
919 */
920 if (pFcb->RefCount > 1)
921 {
922 if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
923 {
924 VfatCloseFile(DeviceExt, FileObject);
925 return STATUS_INVALID_PARAMETER;
926 }
927 }
928 else
929 {
930 pFcb->Flags |= FCB_IS_PAGE_FILE;
931 }
932 }
933 else
934 {
935 if (pFcb->Flags & FCB_IS_PAGE_FILE)
936 {
937 VfatCloseFile(DeviceExt, FileObject);
938 return STATUS_INVALID_PARAMETER;
939 }
940 }
941
942 if (RequestedDisposition == FILE_OVERWRITE ||
943 RequestedDisposition == FILE_OVERWRITE_IF ||
944 RequestedDisposition == FILE_SUPERSEDE)
945 {
946 if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
947 {
948 *pFcb->Attributes = Stack->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL;
949 *pFcb->Attributes |= FILE_ATTRIBUTE_ARCHIVE;
950 VfatUpdateEntry(pFcb);
951 }
952
953 ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE);
954 Status = VfatSetAllocationSizeInformation(FileObject,
955 pFcb,
956 DeviceExt,
957 &Irp->Overlay.AllocationSize);
958 ExReleaseResourceLite(&(pFcb->MainResource));
959 if (!NT_SUCCESS (Status))
960 {
961 VfatCloseFile(DeviceExt, FileObject);
962 return Status;
963 }
964 }
965
966 if (RequestedDisposition == FILE_SUPERSEDE)
967 {
968 Irp->IoStatus.Information = FILE_SUPERSEDED;
969 }
970 else if (RequestedDisposition == FILE_OVERWRITE ||
971 RequestedDisposition == FILE_OVERWRITE_IF)
972 {
973 Irp->IoStatus.Information = FILE_OVERWRITTEN;
974 }
975 else
976 {
977 Irp->IoStatus.Information = FILE_OPENED;
978 }
979 }
980
981 if (pFcb->OpenHandleCount == 0)
982 {
983 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
984 Stack->Parameters.Create.ShareAccess,
985 FileObject,
986 &pFcb->FCBShareAccess);
987 }
988 else
989 {
990 IoUpdateShareAccess(FileObject,
991 &pFcb->FCBShareAccess);
992 }
993
994 if (Irp->IoStatus.Information == FILE_CREATED)
995 {
996 FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
997 &(DeviceExt->NotifyList),
998 (PSTRING)&pFcb->PathNameU,
999 pFcb->PathNameU.Length - pFcb->LongNameU.Length,
1000 NULL,
1001 NULL,
1002 ((*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
1003 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
1004 FILE_ACTION_ADDED,
1005 NULL);
1006 }
1007
1008 pFcb->OpenHandleCount++;
1009 DeviceExt->OpenHandleCount++;
1010
1011 /* FIXME : test write access if requested */
1012
1013 return Status;
1014 }
1015
1016 /*
1017 * FUNCTION: Create or open a file
1018 */
1019 NTSTATUS
1020 VfatCreate(
1021 PVFAT_IRP_CONTEXT IrpContext)
1022 {
1023 NTSTATUS Status;
1024
1025 ASSERT(IrpContext);
1026
1027 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
1028 {
1029 /* DeviceObject represents FileSystem instead of logical volume */
1030 DPRINT ("FsdCreate called with file system\n");
1031 IrpContext->Irp->IoStatus.Information = FILE_OPENED;
1032 IrpContext->PriorityBoost = IO_DISK_INCREMENT;
1033
1034 return STATUS_SUCCESS;
1035 }
1036
1037 if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
1038 {
1039 return VfatMarkIrpContextForQueue(IrpContext);
1040 }
1041
1042 IrpContext->Irp->IoStatus.Information = 0;
1043 ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE);
1044 Status = VfatCreateFile(IrpContext->DeviceObject, IrpContext->Irp);
1045 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
1046
1047 if (NT_SUCCESS(Status))
1048 IrpContext->PriorityBoost = IO_DISK_INCREMENT;
1049
1050 return Status;
1051 }
1052
1053 /* EOF */