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