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