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