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_NAME); 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 ExFreePoolWithTag(PathNameBuffer, TAG_NAME); 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 ExFreePoolWithTag(PathNameBuffer, TAG_NAME); 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 ExFreePoolWithTag(PathNameBuffer, TAG_NAME); 255 return STATUS_SUCCESS; 256 } 257 DirContext->DirIndex++; 258 } 259 260 if (Context) 261 { 262 CcUnpinData(Context); 263 } 264 265 RtlFreeUnicodeString(&FileToFindUpcase); 266 ExFreePoolWithTag(PathNameBuffer, TAG_NAME); 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) || IsDotOrDotDot(&Fcb->LongNameU)) && 364 BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) 365 { 366 // we cannot delete a '.', '..' or the root directory 367 vfatReleaseFCB(DeviceExt, Fcb); 368 return STATUS_CANNOT_DELETE; 369 } 370 371 /* If that one was marked for closing, remove it */ 372 if (BooleanFlagOn(Fcb->Flags, FCB_DELAYED_CLOSE)) 373 { 374 BOOLEAN ConcurrentDeletion; 375 PVFAT_CLOSE_CONTEXT CloseContext; 376 377 /* Get the context */ 378 CloseContext = Fcb->CloseContext; 379 /* Is someone already taking over? */ 380 if (CloseContext != NULL) 381 { 382 ConcurrentDeletion = FALSE; 383 /* Lock list */ 384 ExAcquireFastMutex(&VfatGlobalData->CloseMutex); 385 /* Check whether it was already removed, if not, do it */ 386 if (!IsListEmpty(&CloseContext->CloseListEntry)) 387 { 388 RemoveEntryList(&CloseContext->CloseListEntry); 389 --VfatGlobalData->CloseCount; 390 ConcurrentDeletion = TRUE; 391 } 392 ExReleaseFastMutex(&VfatGlobalData->CloseMutex); 393 394 /* It's not delayed anymore! */ 395 ClearFlag(Fcb->Flags, FCB_DELAYED_CLOSE); 396 /* Release the extra reference (would have been removed by IRP_MJ_CLOSE) */ 397 vfatReleaseFCB(DeviceExt, Fcb); 398 Fcb->CloseContext = NULL; 399 /* If no concurrent deletion, free work item */ 400 if (!ConcurrentDeletion) 401 { 402 ExFreeToPagedLookasideList(&VfatGlobalData->CloseContextLookasideList, CloseContext); 403 } 404 } 405 406 DPRINT("Reusing delayed close FCB for %wZ\n", &Fcb->PathNameU); 407 } 408 409 DPRINT("Attaching FCB to fileObject\n"); 410 Status = vfatAttachFCBToFileObject(DeviceExt, Fcb, FileObject); 411 if (!NT_SUCCESS(Status)) 412 { 413 vfatReleaseFCB(DeviceExt, Fcb); 414 } 415 return Status; 416 } 417 418 /* 419 * FUNCTION: Create or open a file 420 */ 421 static NTSTATUS 422 VfatCreateFile( 423 PDEVICE_OBJECT DeviceObject, 424 PIRP Irp) 425 { 426 PIO_STACK_LOCATION Stack; 427 PFILE_OBJECT FileObject; 428 NTSTATUS Status = STATUS_SUCCESS; 429 PDEVICE_EXTENSION DeviceExt; 430 ULONG RequestedDisposition, RequestedOptions; 431 PVFATFCB pFcb = NULL; 432 PVFATFCB ParentFcb = NULL; 433 PVFATCCB pCcb = NULL; 434 PWCHAR c, last; 435 BOOLEAN PagingFileCreate; 436 BOOLEAN Dots; 437 BOOLEAN OpenTargetDir; 438 BOOLEAN TrailingBackslash; 439 UNICODE_STRING FileNameU; 440 UNICODE_STRING PathNameU; 441 ULONG Attributes; 442 443 /* Unpack the various parameters. */ 444 Stack = IoGetCurrentIrpStackLocation(Irp); 445 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff); 446 RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; 447 PagingFileCreate = BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE); 448 OpenTargetDir = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY); 449 450 FileObject = Stack->FileObject; 451 DeviceExt = DeviceObject->DeviceExtension; 452 453 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID)) 454 { 455 return STATUS_NOT_IMPLEMENTED; 456 } 457 458 /* Check their validity. */ 459 if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && 460 RequestedDisposition == FILE_SUPERSEDE) 461 { 462 return STATUS_INVALID_PARAMETER; 463 } 464 465 if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && 466 BooleanFlagOn(RequestedOptions, FILE_NON_DIRECTORY_FILE)) 467 { 468 return STATUS_INVALID_PARAMETER; 469 } 470 471 /* Deny create if the volume is locked */ 472 if (BooleanFlagOn(DeviceExt->Flags, VCB_VOLUME_LOCKED)) 473 { 474 return STATUS_ACCESS_DENIED; 475 } 476 477 /* This a open operation for the volume itself */ 478 if (FileObject->FileName.Length == 0 && 479 (FileObject->RelatedFileObject == NULL || 480 FileObject->RelatedFileObject->FsContext2 != NULL || 481 FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb)) 482 { 483 DPRINT("Volume opening\n"); 484 485 if (RequestedDisposition != FILE_OPEN && 486 RequestedDisposition != FILE_OPEN_IF) 487 { 488 return STATUS_ACCESS_DENIED; 489 } 490 491 if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && 492 (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 == NULL || FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb)) 493 { 494 return STATUS_NOT_A_DIRECTORY; 495 } 496 497 if (OpenTargetDir) 498 { 499 return STATUS_INVALID_PARAMETER; 500 } 501 502 if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) 503 { 504 return STATUS_CANNOT_DELETE; 505 } 506 507 vfatAddToStat(DeviceExt, Fat.CreateHits, 1); 508 509 pFcb = DeviceExt->VolumeFcb; 510 511 if (pFcb->OpenHandleCount == 0) 512 { 513 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, 514 Stack->Parameters.Create.ShareAccess, 515 FileObject, 516 &pFcb->FCBShareAccess); 517 } 518 else 519 { 520 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, 521 Stack->Parameters.Create.ShareAccess, 522 FileObject, 523 &pFcb->FCBShareAccess, 524 TRUE); 525 if (!NT_SUCCESS(Status)) 526 { 527 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 528 return Status; 529 } 530 } 531 532 vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject); 533 DeviceExt->OpenHandleCount++; 534 pFcb->OpenHandleCount++; 535 vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1); 536 537 Irp->IoStatus.Information = FILE_OPENED; 538 return STATUS_SUCCESS; 539 } 540 541 if (FileObject->RelatedFileObject != NULL && 542 FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb) 543 { 544 ASSERT(FileObject->FileName.Length != 0); 545 return STATUS_OBJECT_PATH_NOT_FOUND; 546 } 547 548 /* Check for illegal characters and illegal dot sequences in the file name */ 549 PathNameU = FileObject->FileName; 550 c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR); 551 last = c - 1; 552 553 Dots = TRUE; 554 while (c-- > PathNameU.Buffer) 555 { 556 if (*c == L'\\' || c == PathNameU.Buffer) 557 { 558 if (Dots && last > c) 559 { 560 return STATUS_OBJECT_NAME_INVALID; 561 } 562 if (*c == L'\\' && (c - 1) > PathNameU.Buffer && 563 *(c - 1) == L'\\') 564 { 565 return STATUS_OBJECT_NAME_INVALID; 566 } 567 568 last = c - 1; 569 Dots = TRUE; 570 } 571 else if (*c != L'.') 572 { 573 Dots = FALSE; 574 } 575 576 if (*c != '\\' && vfatIsLongIllegal(*c)) 577 { 578 return STATUS_OBJECT_NAME_INVALID; 579 } 580 } 581 582 /* Check if we try to open target directory of root dir */ 583 if (OpenTargetDir && FileObject->RelatedFileObject == NULL && PathNameU.Length == sizeof(WCHAR) && 584 PathNameU.Buffer[0] == L'\\') 585 { 586 return STATUS_INVALID_PARAMETER; 587 } 588 589 if (FileObject->RelatedFileObject && PathNameU.Length >= sizeof(WCHAR) && PathNameU.Buffer[0] == L'\\') 590 { 591 return STATUS_OBJECT_NAME_INVALID; 592 } 593 594 TrailingBackslash = FALSE; 595 if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\') 596 { 597 PathNameU.Length -= sizeof(WCHAR); 598 TrailingBackslash = TRUE; 599 } 600 601 if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\') 602 { 603 return STATUS_OBJECT_NAME_INVALID; 604 } 605 606 /* Try opening the file. */ 607 if (!OpenTargetDir) 608 { 609 vfatAddToStat(DeviceExt, Fat.CreateHits, 1); 610 611 Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, RequestedOptions, &ParentFcb); 612 } 613 else 614 { 615 PVFATFCB TargetFcb; 616 LONG idx, FileNameLen; 617 618 vfatAddToStat(DeviceExt, Fat.CreateHits, 1); 619 620 ParentFcb = (FileObject->RelatedFileObject != NULL) ? FileObject->RelatedFileObject->FsContext : NULL; 621 if (ParentFcb) 622 { 623 vfatGrabFCB(DeviceExt, ParentFcb); 624 } 625 626 Status = vfatGetFCBForFile(DeviceExt, &ParentFcb, &TargetFcb, &PathNameU); 627 if (NT_SUCCESS(Status)) 628 { 629 vfatReleaseFCB(DeviceExt, TargetFcb); 630 Irp->IoStatus.Information = FILE_EXISTS; 631 } 632 else 633 { 634 Irp->IoStatus.Information = FILE_DOES_NOT_EXIST; 635 } 636 637 idx = FileObject->FileName.Length / sizeof(WCHAR) - 1; 638 639 /* Skip trailing \ - if any */ 640 if (PathNameU.Buffer[idx] == L'\\') 641 { 642 --idx; 643 PathNameU.Length -= sizeof(WCHAR); 644 } 645 646 /* Get file name */ 647 while (idx >= 0 && PathNameU.Buffer[idx] != L'\\') 648 { 649 --idx; 650 } 651 652 if (idx > 0 || PathNameU.Buffer[0] == L'\\') 653 { 654 /* We don't want to include / in the name */ 655 FileNameLen = PathNameU.Length - ((idx + 1) * sizeof(WCHAR)); 656 657 /* Update FO just to keep file name */ 658 /* Skip first slash */ 659 ++idx; 660 FileObject->FileName.Length = FileNameLen; 661 RtlMoveMemory(&PathNameU.Buffer[0], &PathNameU.Buffer[idx], FileObject->FileName.Length); 662 #if 0 663 /* Terminate the string at the last backslash */ 664 PathNameU.Buffer[idx + 1] = UNICODE_NULL; 665 PathNameU.Length = (idx + 1) * sizeof(WCHAR); 666 PathNameU.MaximumLength = PathNameU.Length + sizeof(WCHAR); 667 668 /* Update the file object as well */ 669 FileObject->FileName.Length = PathNameU.Length; 670 FileObject->FileName.MaximumLength = PathNameU.MaximumLength; 671 #endif 672 } 673 else 674 { 675 /* This is a relative open and we have only the filename, so open the parent directory 676 * It is in RelatedFileObject 677 */ 678 ASSERT(FileObject->RelatedFileObject != NULL); 679 680 /* No need to modify the FO, it already has the name */ 681 } 682 683 /* We're done with opening! */ 684 if (ParentFcb != NULL) 685 { 686 Status = vfatAttachFCBToFileObject(DeviceExt, ParentFcb, FileObject); 687 } 688 689 if (NT_SUCCESS(Status)) 690 { 691 pFcb = FileObject->FsContext; 692 ASSERT(pFcb == ParentFcb); 693 694 if (pFcb->OpenHandleCount == 0) 695 { 696 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, 697 Stack->Parameters.Create.ShareAccess, 698 FileObject, 699 &pFcb->FCBShareAccess); 700 } 701 else 702 { 703 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, 704 Stack->Parameters.Create.ShareAccess, 705 FileObject, 706 &pFcb->FCBShareAccess, 707 FALSE); 708 if (!NT_SUCCESS(Status)) 709 { 710 VfatCloseFile(DeviceExt, FileObject); 711 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 712 return Status; 713 } 714 } 715 716 pCcb = FileObject->FsContext2; 717 if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) 718 { 719 pCcb->Flags |= CCB_DELETE_ON_CLOSE; 720 } 721 722 pFcb->OpenHandleCount++; 723 DeviceExt->OpenHandleCount++; 724 } 725 else if (ParentFcb != NULL) 726 { 727 vfatReleaseFCB(DeviceExt, ParentFcb); 728 } 729 730 if (NT_SUCCESS(Status)) 731 { 732 vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1); 733 } 734 else 735 { 736 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 737 } 738 739 return Status; 740 } 741 742 /* 743 * If the directory containing the file to open doesn't exist then 744 * fail immediately 745 */ 746 if (Status == STATUS_OBJECT_PATH_NOT_FOUND || 747 Status == STATUS_INVALID_PARAMETER || 748 Status == STATUS_DELETE_PENDING || 749 Status == STATUS_ACCESS_DENIED || 750 Status == STATUS_OBJECT_NAME_COLLISION) 751 { 752 if (ParentFcb) 753 { 754 vfatReleaseFCB(DeviceExt, ParentFcb); 755 } 756 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 757 return Status; 758 } 759 760 if (!NT_SUCCESS(Status) && ParentFcb == NULL) 761 { 762 DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU, Status); 763 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 764 return Status; 765 } 766 767 Attributes = (Stack->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_ARCHIVE | 768 FILE_ATTRIBUTE_SYSTEM | 769 FILE_ATTRIBUTE_HIDDEN | 770 FILE_ATTRIBUTE_DIRECTORY | 771 FILE_ATTRIBUTE_READONLY)); 772 773 /* If the file open failed then create the required file */ 774 if (!NT_SUCCESS (Status)) 775 { 776 if (RequestedDisposition == FILE_CREATE || 777 RequestedDisposition == FILE_OPEN_IF || 778 RequestedDisposition == FILE_OVERWRITE_IF || 779 RequestedDisposition == FILE_SUPERSEDE) 780 { 781 if (!BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE)) 782 { 783 if (TrailingBackslash) 784 { 785 vfatReleaseFCB(DeviceExt, ParentFcb); 786 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 787 return STATUS_OBJECT_NAME_INVALID; 788 } 789 Attributes |= FILE_ATTRIBUTE_ARCHIVE; 790 } 791 vfatSplitPathName(&PathNameU, NULL, &FileNameU); 792 793 if (IsDotOrDotDot(&FileNameU)) 794 { 795 vfatReleaseFCB(DeviceExt, ParentFcb); 796 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 797 return STATUS_OBJECT_NAME_INVALID; 798 } 799 Status = VfatAddEntry(DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions, 800 Attributes, NULL); 801 vfatReleaseFCB(DeviceExt, ParentFcb); 802 if (NT_SUCCESS(Status)) 803 { 804 Status = vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject); 805 if (!NT_SUCCESS(Status)) 806 { 807 vfatReleaseFCB(DeviceExt, pFcb); 808 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 809 return Status; 810 } 811 812 Irp->IoStatus.Information = FILE_CREATED; 813 VfatSetAllocationSizeInformation(FileObject, 814 pFcb, 815 DeviceExt, 816 &Irp->Overlay.AllocationSize); 817 VfatSetExtendedAttributes(FileObject, 818 Irp->AssociatedIrp.SystemBuffer, 819 Stack->Parameters.Create.EaLength); 820 821 if (PagingFileCreate) 822 { 823 pFcb->Flags |= FCB_IS_PAGE_FILE; 824 SetFlag(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE); 825 } 826 } 827 else 828 { 829 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 830 return Status; 831 } 832 } 833 else 834 { 835 vfatReleaseFCB(DeviceExt, ParentFcb); 836 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 837 return Status; 838 } 839 } 840 else 841 { 842 if (ParentFcb) 843 { 844 vfatReleaseFCB(DeviceExt, ParentFcb); 845 } 846 847 pFcb = FileObject->FsContext; 848 849 /* Otherwise fail if the caller wanted to create a new file */ 850 if (RequestedDisposition == FILE_CREATE) 851 { 852 VfatCloseFile(DeviceExt, FileObject); 853 if (TrailingBackslash && !vfatFCBIsDirectory(pFcb)) 854 { 855 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 856 return STATUS_OBJECT_NAME_INVALID; 857 } 858 Irp->IoStatus.Information = FILE_EXISTS; 859 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 860 return STATUS_OBJECT_NAME_COLLISION; 861 } 862 863 if (pFcb->OpenHandleCount != 0) 864 { 865 Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, 866 Stack->Parameters.Create.ShareAccess, 867 FileObject, 868 &pFcb->FCBShareAccess, 869 FALSE); 870 if (!NT_SUCCESS(Status)) 871 { 872 VfatCloseFile(DeviceExt, FileObject); 873 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 874 return Status; 875 } 876 } 877 878 /* 879 * Check the file has the requested attributes 880 */ 881 if (BooleanFlagOn(RequestedOptions, FILE_NON_DIRECTORY_FILE) && 882 vfatFCBIsDirectory(pFcb)) 883 { 884 VfatCloseFile (DeviceExt, FileObject); 885 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 886 return STATUS_FILE_IS_A_DIRECTORY; 887 } 888 if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && 889 !vfatFCBIsDirectory(pFcb)) 890 { 891 VfatCloseFile (DeviceExt, FileObject); 892 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 893 return STATUS_NOT_A_DIRECTORY; 894 } 895 if (TrailingBackslash && !vfatFCBIsDirectory(pFcb)) 896 { 897 VfatCloseFile (DeviceExt, FileObject); 898 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 899 return STATUS_OBJECT_NAME_INVALID; 900 } 901 #ifndef USE_ROS_CC_AND_FS 902 if (!vfatFCBIsDirectory(pFcb)) 903 { 904 if (BooleanFlagOn(Stack->Parameters.Create.SecurityContext->DesiredAccess, FILE_WRITE_DATA) || 905 RequestedDisposition == FILE_OVERWRITE || 906 RequestedDisposition == FILE_OVERWRITE_IF || 907 (RequestedOptions & FILE_DELETE_ON_CLOSE)) 908 { 909 if (!MmFlushImageSection(&pFcb->SectionObjectPointers, MmFlushForWrite)) 910 { 911 DPRINT1("%wZ\n", &pFcb->PathNameU); 912 DPRINT1("%d %d %d\n", Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA, 913 RequestedDisposition == FILE_OVERWRITE, RequestedDisposition == FILE_OVERWRITE_IF); 914 VfatCloseFile (DeviceExt, FileObject); 915 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 916 return (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) ? STATUS_CANNOT_DELETE 917 : STATUS_SHARING_VIOLATION; 918 } 919 } 920 } 921 #endif 922 if (PagingFileCreate) 923 { 924 /* FIXME: 925 * Do more checking for page files. It is possible, 926 * that the file was opened and closed previously 927 * as a normal cached file. In this case, the cache 928 * manager has referenced the fileobject and the fcb 929 * is held in memory. Try to remove the fileobject 930 * from cache manager and use the fcb. 931 */ 932 if (pFcb->RefCount > 1) 933 { 934 if(!BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE)) 935 { 936 VfatCloseFile(DeviceExt, FileObject); 937 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 938 return STATUS_INVALID_PARAMETER; 939 } 940 } 941 else 942 { 943 pFcb->Flags |= FCB_IS_PAGE_FILE; 944 SetFlag(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE); 945 } 946 } 947 else 948 { 949 if (BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE)) 950 { 951 VfatCloseFile(DeviceExt, FileObject); 952 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 953 return STATUS_INVALID_PARAMETER; 954 } 955 } 956 957 if (RequestedDisposition == FILE_OVERWRITE || 958 RequestedDisposition == FILE_OVERWRITE_IF || 959 RequestedDisposition == FILE_SUPERSEDE) 960 { 961 if ((BooleanFlagOn(*pFcb->Attributes, FILE_ATTRIBUTE_HIDDEN) && !BooleanFlagOn(Attributes, FILE_ATTRIBUTE_HIDDEN)) || 962 (BooleanFlagOn(*pFcb->Attributes, FILE_ATTRIBUTE_SYSTEM) && !BooleanFlagOn(Attributes, FILE_ATTRIBUTE_SYSTEM))) 963 { 964 VfatCloseFile(DeviceExt, FileObject); 965 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 966 return STATUS_ACCESS_DENIED; 967 } 968 969 if (!vfatFCBIsDirectory(pFcb)) 970 { 971 LARGE_INTEGER SystemTime; 972 973 if (RequestedDisposition == FILE_SUPERSEDE) 974 { 975 *pFcb->Attributes = Attributes; 976 } 977 else 978 { 979 *pFcb->Attributes |= Attributes; 980 } 981 *pFcb->Attributes |= FILE_ATTRIBUTE_ARCHIVE; 982 983 KeQuerySystemTime(&SystemTime); 984 if (vfatVolumeIsFatX(DeviceExt)) 985 { 986 FsdSystemTimeToDosDateTime(DeviceExt, 987 &SystemTime, &pFcb->entry.FatX.UpdateDate, 988 &pFcb->entry.FatX.UpdateTime); 989 } 990 else 991 { 992 FsdSystemTimeToDosDateTime(DeviceExt, 993 &SystemTime, &pFcb->entry.Fat.UpdateDate, 994 &pFcb->entry.Fat.UpdateTime); 995 } 996 997 VfatUpdateEntry(DeviceExt, pFcb); 998 } 999 1000 ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE); 1001 Status = VfatSetAllocationSizeInformation(FileObject, 1002 pFcb, 1003 DeviceExt, 1004 &Irp->Overlay.AllocationSize); 1005 ExReleaseResourceLite(&(pFcb->MainResource)); 1006 if (!NT_SUCCESS (Status)) 1007 { 1008 VfatCloseFile(DeviceExt, FileObject); 1009 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 1010 return Status; 1011 } 1012 } 1013 1014 if (RequestedDisposition == FILE_SUPERSEDE) 1015 { 1016 Irp->IoStatus.Information = FILE_SUPERSEDED; 1017 } 1018 else if (RequestedDisposition == FILE_OVERWRITE || 1019 RequestedDisposition == FILE_OVERWRITE_IF) 1020 { 1021 Irp->IoStatus.Information = FILE_OVERWRITTEN; 1022 } 1023 else 1024 { 1025 Irp->IoStatus.Information = FILE_OPENED; 1026 } 1027 } 1028 1029 if (pFcb->OpenHandleCount == 0) 1030 { 1031 IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, 1032 Stack->Parameters.Create.ShareAccess, 1033 FileObject, 1034 &pFcb->FCBShareAccess); 1035 } 1036 else 1037 { 1038 IoUpdateShareAccess(FileObject, 1039 &pFcb->FCBShareAccess); 1040 } 1041 1042 pCcb = FileObject->FsContext2; 1043 if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) 1044 { 1045 pCcb->Flags |= CCB_DELETE_ON_CLOSE; 1046 } 1047 1048 if (Irp->IoStatus.Information == FILE_CREATED) 1049 { 1050 vfatReportChange(DeviceExt, 1051 pFcb, 1052 (vfatFCBIsDirectory(pFcb) ? 1053 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME), 1054 FILE_ACTION_ADDED); 1055 } 1056 else if (Irp->IoStatus.Information == FILE_OVERWRITTEN || 1057 Irp->IoStatus.Information == FILE_SUPERSEDED) 1058 { 1059 vfatReportChange(DeviceExt, 1060 pFcb, 1061 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE, 1062 FILE_ACTION_MODIFIED); 1063 } 1064 1065 pFcb->OpenHandleCount++; 1066 DeviceExt->OpenHandleCount++; 1067 1068 /* FIXME : test write access if requested */ 1069 1070 /* FIXME: That is broken, we cannot reach this code path with failure */ 1071 ASSERT(NT_SUCCESS(Status)); 1072 if (NT_SUCCESS(Status)) 1073 { 1074 vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1); 1075 } 1076 else 1077 { 1078 vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); 1079 } 1080 1081 return Status; 1082 } 1083 1084 /* 1085 * FUNCTION: Create or open a file 1086 */ 1087 NTSTATUS 1088 VfatCreate( 1089 PVFAT_IRP_CONTEXT IrpContext) 1090 { 1091 NTSTATUS Status; 1092 1093 ASSERT(IrpContext); 1094 1095 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) 1096 { 1097 /* DeviceObject represents FileSystem instead of logical volume */ 1098 DPRINT ("FsdCreate called with file system\n"); 1099 IrpContext->Irp->IoStatus.Information = FILE_OPENED; 1100 IrpContext->PriorityBoost = IO_DISK_INCREMENT; 1101 1102 return STATUS_SUCCESS; 1103 } 1104 1105 IrpContext->Irp->IoStatus.Information = 0; 1106 ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE); 1107 Status = VfatCreateFile(IrpContext->DeviceObject, IrpContext->Irp); 1108 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); 1109 1110 if (NT_SUCCESS(Status)) 1111 IrpContext->PriorityBoost = IO_DISK_INCREMENT; 1112 1113 return Status; 1114 } 1115 1116 /* EOF */ 1117