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 /* If the file open failed then create the required file */ 732 if (!NT_SUCCESS (Status)) 733 { 734 if (RequestedDisposition == FILE_CREATE || 735 RequestedDisposition == FILE_OPEN_IF || 736 RequestedDisposition == FILE_OVERWRITE_IF || 737 RequestedDisposition == FILE_SUPERSEDE) 738 { 739 Attributes = Stack->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL; 740 if (!BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE)) 741 { 742 if (TrailingBackslash) 743 { 744 vfatReleaseFCB(DeviceExt, ParentFcb); 745 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 746 return STATUS_OBJECT_NAME_INVALID; 747 } 748 Attributes |= FILE_ATTRIBUTE_ARCHIVE; 749 } 750 vfatSplitPathName(&PathNameU, NULL, &FileNameU); 751 Status = VfatAddEntry(DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions, 752 (UCHAR)FlagOn(Attributes, FILE_ATTRIBUTE_VALID_FLAGS), NULL); 753 vfatReleaseFCB(DeviceExt, ParentFcb); 754 if (NT_SUCCESS(Status)) 755 { 756 Status = vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject); 757 if (!NT_SUCCESS(Status)) 758 { 759 vfatReleaseFCB(DeviceExt, pFcb); 760 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 761 return Status; 762 } 763 764 Irp->IoStatus.Information = FILE_CREATED; 765 VfatSetAllocationSizeInformation(FileObject, 766 pFcb, 767 DeviceExt, 768 &Irp->Overlay.AllocationSize); 769 VfatSetExtendedAttributes(FileObject, 770 Irp->AssociatedIrp.SystemBuffer, 771 Stack->Parameters.Create.EaLength); 772 773 if (PagingFileCreate) 774 { 775 pFcb->Flags |= FCB_IS_PAGE_FILE; 776 } 777 } 778 else 779 { 780 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 781 return Status; 782 } 783 } 784 else 785 { 786 vfatReleaseFCB(DeviceExt, ParentFcb); 787 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 788 return Status; 789 } 790 } 791 else 792 { 793 if (ParentFcb) 794 { 795 vfatReleaseFCB(DeviceExt, ParentFcb); 796 } 797 798 pFcb = FileObject->FsContext; 799 800 /* Otherwise fail if the caller wanted to create a new file */ 801 if (RequestedDisposition == FILE_CREATE) 802 { 803 VfatCloseFile(DeviceExt, FileObject); 804 if (TrailingBackslash && !vfatFCBIsDirectory(pFcb)) 805 { 806 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 807 return STATUS_OBJECT_NAME_INVALID; 808 } 809 Irp->IoStatus.Information = FILE_EXISTS; 810 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 811 return STATUS_OBJECT_NAME_COLLISION; 812 } 813 814 if (pFcb->OpenHandleCount != 0) 815 { 816 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, 817 Stack->Parameters.Create.ShareAccess, 818 FileObject, 819 &pFcb->FCBShareAccess, 820 FALSE); 821 if (!NT_SUCCESS(Status)) 822 { 823 VfatCloseFile(DeviceExt, FileObject); 824 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 825 return Status; 826 } 827 } 828 829 /* 830 * Check the file has the requested attributes 831 */ 832 if (BooleanFlagOn(RequestedOptions, FILE_NON_DIRECTORY_FILE) && 833 vfatFCBIsDirectory(pFcb)) 834 { 835 VfatCloseFile (DeviceExt, FileObject); 836 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 837 return STATUS_FILE_IS_A_DIRECTORY; 838 } 839 if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && 840 !vfatFCBIsDirectory(pFcb)) 841 { 842 VfatCloseFile (DeviceExt, FileObject); 843 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 844 return STATUS_NOT_A_DIRECTORY; 845 } 846 if (TrailingBackslash && !vfatFCBIsDirectory(pFcb)) 847 { 848 VfatCloseFile (DeviceExt, FileObject); 849 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 850 return STATUS_OBJECT_NAME_INVALID; 851 } 852 #ifndef USE_ROS_CC_AND_FS 853 if (!vfatFCBIsDirectory(pFcb)) 854 { 855 if (BooleanFlagOn(Stack->Parameters.Create.SecurityContext->DesiredAccess, FILE_WRITE_DATA) || 856 RequestedDisposition == FILE_OVERWRITE || 857 RequestedDisposition == FILE_OVERWRITE_IF || 858 (RequestedOptions & FILE_DELETE_ON_CLOSE)) 859 { 860 if (!MmFlushImageSection(&pFcb->SectionObjectPointers, MmFlushForWrite)) 861 { 862 DPRINT1("%wZ\n", &pFcb->PathNameU); 863 DPRINT1("%d %d %d\n", Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA, 864 RequestedDisposition == FILE_OVERWRITE, RequestedDisposition == FILE_OVERWRITE_IF); 865 VfatCloseFile (DeviceExt, FileObject); 866 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 867 return (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) ? STATUS_CANNOT_DELETE 868 : STATUS_SHARING_VIOLATION; 869 } 870 } 871 } 872 #endif 873 if (PagingFileCreate) 874 { 875 /* FIXME: 876 * Do more checking for page files. It is possible, 877 * that the file was opened and closed previously 878 * as a normal cached file. In this case, the cache 879 * manager has referenced the fileobject and the fcb 880 * is held in memory. Try to remove the fileobject 881 * from cache manager and use the fcb. 882 */ 883 if (pFcb->RefCount > 1) 884 { 885 if(!BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE)) 886 { 887 VfatCloseFile(DeviceExt, FileObject); 888 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 889 return STATUS_INVALID_PARAMETER; 890 } 891 } 892 else 893 { 894 pFcb->Flags |= FCB_IS_PAGE_FILE; 895 } 896 } 897 else 898 { 899 if (BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE)) 900 { 901 VfatCloseFile(DeviceExt, FileObject); 902 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 903 return STATUS_INVALID_PARAMETER; 904 } 905 } 906 907 if (RequestedDisposition == FILE_OVERWRITE || 908 RequestedDisposition == FILE_OVERWRITE_IF || 909 RequestedDisposition == FILE_SUPERSEDE) 910 { 911 if (!vfatFCBIsDirectory(pFcb)) 912 { 913 *pFcb->Attributes = Stack->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL; 914 *pFcb->Attributes |= FILE_ATTRIBUTE_ARCHIVE; 915 VfatUpdateEntry(pFcb, vfatVolumeIsFatX(DeviceExt)); 916 } 917 918 ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE); 919 Status = VfatSetAllocationSizeInformation(FileObject, 920 pFcb, 921 DeviceExt, 922 &Irp->Overlay.AllocationSize); 923 ExReleaseResourceLite(&(pFcb->MainResource)); 924 if (!NT_SUCCESS (Status)) 925 { 926 VfatCloseFile(DeviceExt, FileObject); 927 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 928 return Status; 929 } 930 } 931 932 if (RequestedDisposition == FILE_SUPERSEDE) 933 { 934 Irp->IoStatus.Information = FILE_SUPERSEDED; 935 } 936 else if (RequestedDisposition == FILE_OVERWRITE || 937 RequestedDisposition == FILE_OVERWRITE_IF) 938 { 939 Irp->IoStatus.Information = FILE_OVERWRITTEN; 940 } 941 else 942 { 943 Irp->IoStatus.Information = FILE_OPENED; 944 } 945 } 946 947 if (pFcb->OpenHandleCount == 0) 948 { 949 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, 950 Stack->Parameters.Create.ShareAccess, 951 FileObject, 952 &pFcb->FCBShareAccess); 953 } 954 else 955 { 956 IoUpdateShareAccess(FileObject, 957 &pFcb->FCBShareAccess); 958 } 959 960 pCcb = FileObject->FsContext2; 961 if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) 962 { 963 pCcb->Flags |= CCB_DELETE_ON_CLOSE; 964 } 965 966 if (Irp->IoStatus.Information == FILE_CREATED) 967 { 968 FsRtlNotifyFullReportChange(DeviceExt->NotifySync, 969 &(DeviceExt->NotifyList), 970 (PSTRING)&pFcb->PathNameU, 971 pFcb->PathNameU.Length - pFcb->LongNameU.Length, 972 NULL, 973 NULL, 974 (vfatFCBIsDirectory(pFcb) ? 975 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME), 976 FILE_ACTION_ADDED, 977 NULL); 978 } 979 980 pFcb->OpenHandleCount++; 981 DeviceExt->OpenHandleCount++; 982 983 /* FIXME : test write access if requested */ 984 985 /* FIXME: That is broken, we cannot reach this code path with failure */ 986 ASSERT(NT_SUCCESS(Status)); 987 if (NT_SUCCESS(Status)) 988 { 989 vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1); 990 } 991 else 992 { 993 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 994 } 995 996 return Status; 997 } 998 999 /* 1000 * FUNCTION: Create or open a file 1001 */ 1002 NTSTATUS 1003 VfatCreate( 1004 PVFAT_IRP_CONTEXT IrpContext) 1005 { 1006 NTSTATUS Status; 1007 1008 ASSERT(IrpContext); 1009 1010 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) 1011 { 1012 /* DeviceObject represents FileSystem instead of logical volume */ 1013 DPRINT ("FsdCreate called with file system\n"); 1014 IrpContext->Irp->IoStatus.Information = FILE_OPENED; 1015 IrpContext->PriorityBoost = IO_DISK_INCREMENT; 1016 1017 return STATUS_SUCCESS; 1018 } 1019 1020 if (!BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)) 1021 { 1022 return VfatMarkIrpContextForQueue(IrpContext); 1023 } 1024 1025 IrpContext->Irp->IoStatus.Information = 0; 1026 ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE); 1027 Status = VfatCreateFile(IrpContext->DeviceObject, IrpContext->Irp); 1028 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); 1029 1030 if (NT_SUCCESS(Status)) 1031 IrpContext->PriorityBoost = IO_DISK_INCREMENT; 1032 1033 return Status; 1034 } 1035 1036 /* EOF */ 1037