Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfcb.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS FAT file system driver 00003 * LICENSE: GNU GPLv3 as published by the Free Software Foundation 00004 * FILE: drivers/filesystems/fastfat/fcb.c 00005 * PURPOSE: FCB manipulation routines. 00006 * PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org> 00007 */ 00008 00009 /* INCLUDES *****************************************************************/ 00010 00011 #define NDEBUG 00012 #include "fastfat.h" 00013 00014 #define TAG_FILENAME 'fBnF' 00015 00016 /* FUNCTIONS ****************************************************************/ 00017 00018 FSRTL_COMPARISON_RESULT 00019 NTAPI 00020 FatiCompareNames(PSTRING NameA, 00021 PSTRING NameB) 00022 { 00023 ULONG MinimumLen, i; 00024 00025 /* Calc the minimum length */ 00026 MinimumLen = NameA->Length < NameB->Length ? NameA->Length : 00027 NameB->Length; 00028 00029 /* Actually compare them */ 00030 i = (ULONG)RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinimumLen ); 00031 00032 if (i < MinimumLen) 00033 { 00034 /* Compare prefixes */ 00035 if (NameA->Buffer[i] < NameB->Buffer[i]) 00036 return LessThan; 00037 else 00038 return GreaterThan; 00039 } 00040 00041 /* Final comparison */ 00042 if (NameA->Length < NameB->Length) 00043 return LessThan; 00044 else if (NameA->Length > NameB->Length) 00045 return GreaterThan; 00046 else 00047 return EqualTo; 00048 } 00049 00050 PFCB 00051 NTAPI 00052 FatFindFcb(PFAT_IRP_CONTEXT IrpContext, 00053 PRTL_SPLAY_LINKS *RootNode, 00054 PSTRING AnsiName, 00055 PBOOLEAN IsDosName) 00056 { 00057 PFCB_NAME_LINK Node; 00058 FSRTL_COMPARISON_RESULT Comparison; 00059 PRTL_SPLAY_LINKS Links; 00060 00061 Links = *RootNode; 00062 00063 while (Links) 00064 { 00065 Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links); 00066 00067 /* Compare the prefix */ 00068 if (*(PUCHAR)Node->Name.Ansi.Buffer != *(PUCHAR)AnsiName->Buffer) 00069 { 00070 if (*(PUCHAR)Node->Name.Ansi.Buffer < *(PUCHAR)AnsiName->Buffer) 00071 Comparison = LessThan; 00072 else 00073 Comparison = GreaterThan; 00074 } 00075 else 00076 { 00077 /* Perform real comparison */ 00078 Comparison = FatiCompareNames(&Node->Name.Ansi, AnsiName); 00079 } 00080 00081 /* Do they match? */ 00082 if (Comparison == GreaterThan) 00083 { 00084 /* No, it's greater, go to the left child */ 00085 Links = RtlLeftChild(Links); 00086 } 00087 else if (Comparison == LessThan) 00088 { 00089 /* No, it's lesser, go to the right child */ 00090 Links = RtlRightChild(Links); 00091 } 00092 else 00093 { 00094 /* Exact match, balance the tree */ 00095 *RootNode = RtlSplay(Links); 00096 00097 /* Save type of the name, if needed */ 00098 if (IsDosName) 00099 *IsDosName = Node->IsDosName; 00100 00101 /* Return the found fcb */ 00102 return Node->Fcb; 00103 } 00104 } 00105 00106 /* Nothing found */ 00107 return NULL; 00108 } 00109 00110 PFCB 00111 NTAPI 00112 FatCreateFcb(IN PFAT_IRP_CONTEXT IrpContext, 00113 IN PVCB Vcb, 00114 IN PFCB ParentDcb, 00115 IN FF_FILE *FileHandle) 00116 { 00117 PFCB Fcb; 00118 00119 /* Allocate it and zero it */ 00120 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(FCB), TAG_FCB); 00121 RtlZeroMemory(Fcb, sizeof(FCB)); 00122 00123 /* Set node types */ 00124 Fcb->Header.NodeTypeCode = FAT_NTC_FCB; 00125 Fcb->Header.NodeByteSize = sizeof(FCB); 00126 Fcb->Condition = FcbGood; 00127 00128 /* Initialize resources */ 00129 Fcb->Header.Resource = &Fcb->Resource; 00130 ExInitializeResourceLite(Fcb->Header.Resource); 00131 00132 Fcb->Header.PagingIoResource = &Fcb->PagingIoResource; 00133 ExInitializeResourceLite(Fcb->Header.PagingIoResource); 00134 00135 /* Initialize mutexes */ 00136 Fcb->Header.FastMutex = &Fcb->HeaderMutex; 00137 ExInitializeFastMutex(&Fcb->HeaderMutex); 00138 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex); 00139 00140 /* Insert into parent's DCB list */ 00141 InsertTailList(&ParentDcb->Dcb.ParentDcbList, &Fcb->ParentDcbLinks); 00142 00143 /* Set backlinks */ 00144 Fcb->ParentFcb = ParentDcb; 00145 Fcb->Vcb = Vcb; 00146 00147 /* Set file handle and sizes */ 00148 Fcb->Header.FileSize.LowPart = FileHandle->Filesize; 00149 Fcb->Header.ValidDataLength.LowPart = FileHandle->Filesize; 00150 Fcb->FatHandle = FileHandle; 00151 00152 /* Initialize locks */ 00153 FsRtlInitializeFileLock(&Fcb->Fcb.Lock, NULL, NULL); 00154 FsRtlInitializeOplock(&Fcb->Fcb.Oplock); 00155 00156 /* Set names */ 00157 FatSetFcbNames(IrpContext, Fcb); 00158 00159 return Fcb; 00160 } 00161 00162 VOID 00163 NTAPI 00164 FatDeleteFcb(IN PFAT_IRP_CONTEXT IrpContext, 00165 IN PFCB Fcb) 00166 { 00167 DPRINT("FatDeleteFcb %p\n", Fcb); 00168 00169 if (Fcb->OpenCount != 0) 00170 { 00171 DPRINT1("Trying to delete FCB with OpenCount %d\n", Fcb->OpenCount); 00172 ASSERT(FALSE); 00173 } 00174 00175 if ((Fcb->Header.NodeTypeCode == FAT_NTC_DCB) || 00176 (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB)) 00177 { 00178 /* Make sure it's a valid deletion */ 00179 ASSERT(Fcb->Dcb.DirectoryFileOpenCount == 0); 00180 ASSERT(IsListEmpty(&Fcb->Dcb.ParentDcbList)); 00181 ASSERT(Fcb->Dcb.DirectoryFile == NULL); 00182 } 00183 else 00184 { 00185 /* Free locks */ 00186 FsRtlUninitializeFileLock(&Fcb->Fcb.Lock); 00187 FsRtlUninitializeOplock(&Fcb->Fcb.Oplock); 00188 } 00189 00190 /* Release any possible filter contexts */ 00191 FsRtlTeardownPerStreamContexts(&Fcb->Header); 00192 00193 /* Remove from parents queue */ 00194 if (Fcb->Header.NodeTypeCode != FAT_NTC_ROOT_DCB) 00195 { 00196 RemoveEntryList(&(Fcb->ParentDcbLinks)); 00197 } 00198 00199 /* Free FullFAT handle */ 00200 if (Fcb->FatHandle) FF_Close(Fcb->FatHandle); 00201 00202 /* Remove from the splay table */ 00203 if (FlagOn(Fcb->State, FCB_STATE_HAS_NAMES)) 00204 FatRemoveNames(IrpContext, Fcb); 00205 00206 /* Free file name buffers */ 00207 if (Fcb->Header.NodeTypeCode != FAT_NTC_ROOT_DCB) 00208 { 00209 if (Fcb->FullFileName.Buffer) 00210 ExFreePool(Fcb->FullFileName.Buffer); 00211 } 00212 00213 if (Fcb->ExactCaseLongName.Buffer) 00214 ExFreePool(Fcb->ExactCaseLongName.Buffer); 00215 00216 /* Free this FCB, finally */ 00217 ExFreePool(Fcb); 00218 } 00219 00220 PCCB 00221 NTAPI 00222 FatCreateCcb() 00223 { 00224 PCCB Ccb; 00225 00226 /* Allocate the CCB and zero it */ 00227 Ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), TAG_CCB); 00228 RtlZeroMemory(Ccb, sizeof(CCB)); 00229 00230 /* Set mandatory header */ 00231 Ccb->NodeTypeCode = FAT_NTC_FCB; 00232 Ccb->NodeByteSize = sizeof(CCB); 00233 00234 return Ccb; 00235 } 00236 00237 VOID 00238 NTAPI 00239 FatDeleteCcb(IN PFAT_IRP_CONTEXT IrpContext, 00240 IN PCCB Ccb) 00241 { 00242 // TODO: Deallocate CCB strings, if any 00243 00244 /* Free the CCB */ 00245 ExFreePool(Ccb); 00246 } 00247 00248 IO_STATUS_BLOCK 00249 NTAPI 00250 FatiOpenExistingFcb(IN PFAT_IRP_CONTEXT IrpContext, 00251 IN PFILE_OBJECT FileObject, 00252 IN PVCB Vcb, 00253 IN PFCB Fcb, 00254 IN PACCESS_MASK DesiredAccess, 00255 IN USHORT ShareAccess, 00256 IN ULONG AllocationSize, 00257 IN PFILE_FULL_EA_INFORMATION EaBuffer, 00258 IN ULONG EaLength, 00259 IN UCHAR FileAttributes, 00260 IN ULONG CreateDisposition, 00261 IN BOOLEAN NoEaKnowledge, 00262 IN BOOLEAN DeleteOnClose, 00263 IN BOOLEAN OpenedAsDos, 00264 OUT PBOOLEAN OplockPostIrp) 00265 { 00266 IO_STATUS_BLOCK Iosb = {{0}}; 00267 ACCESS_MASK AddedAccess = 0; 00268 BOOLEAN Hidden; 00269 BOOLEAN System; 00270 PCCB Ccb = NULL; 00271 NTSTATUS Status, StatusPrev; 00272 00273 /* Acquire exclusive FCB lock */ 00274 (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb); 00275 00276 *OplockPostIrp = FALSE; 00277 00278 /* Check if there is a batch oplock */ 00279 if (FsRtlCurrentBatchOplock(&Fcb->Fcb.Oplock)) 00280 { 00281 /* Return with a special information field */ 00282 Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY; 00283 00284 /* Check the oplock */ 00285 Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock, 00286 IrpContext->Irp, 00287 IrpContext, 00288 FatOplockComplete, 00289 FatPrePostIrp); 00290 00291 if (Iosb.Status != STATUS_SUCCESS && 00292 Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) 00293 { 00294 /* The Irp needs to be queued */ 00295 *OplockPostIrp = TRUE; 00296 00297 /* Release the FCB and return */ 00298 FatReleaseFcb(IrpContext, Fcb); 00299 return Iosb; 00300 } 00301 } 00302 00303 /* Validate parameters and modify access */ 00304 if (CreateDisposition == FILE_CREATE) 00305 { 00306 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 00307 00308 /* Release the FCB and return */ 00309 FatReleaseFcb(IrpContext, Fcb); 00310 return Iosb; 00311 } 00312 else if (CreateDisposition == FILE_SUPERSEDE) 00313 { 00314 SetFlag(AddedAccess, DELETE & ~(*DesiredAccess)); 00315 *DesiredAccess |= DELETE; 00316 } 00317 else if ((CreateDisposition == FILE_OVERWRITE) || 00318 (CreateDisposition == FILE_OVERWRITE_IF)) 00319 { 00320 SetFlag(AddedAccess, 00321 (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) 00322 & ~(*DesiredAccess) ); 00323 00324 *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; 00325 } 00326 00327 // TODO: Check desired access 00328 00329 // TODO: Check if this file is readonly and DeleteOnClose is set 00330 00331 /* Validate disposition information */ 00332 if ((CreateDisposition == FILE_SUPERSEDE) || 00333 (CreateDisposition == FILE_OVERWRITE) || 00334 (CreateDisposition == FILE_OVERWRITE_IF)) 00335 { 00336 // TODO: Get this attributes from the dirent 00337 Hidden = FALSE; 00338 System = FALSE; 00339 00340 if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || 00341 (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) 00342 { 00343 DPRINT1("Hidden/system attributes don't match\n"); 00344 00345 Iosb.Status = STATUS_ACCESS_DENIED; 00346 00347 /* Release the FCB and return */ 00348 FatReleaseFcb(IrpContext, Fcb); 00349 return Iosb; 00350 } 00351 00352 // TODO: Check for write protected volume 00353 } 00354 00355 /* Check share access */ 00356 Iosb.Status = IoCheckShareAccess(*DesiredAccess, 00357 ShareAccess, 00358 FileObject, 00359 &Fcb->ShareAccess, 00360 FALSE); 00361 if (!NT_SUCCESS(Iosb.Status)) 00362 { 00363 /* Release the FCB and return */ 00364 FatReleaseFcb(IrpContext, Fcb); 00365 return Iosb; 00366 } 00367 00368 /* Check the oplock status after checking for share access */ 00369 Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock, 00370 IrpContext->Irp, 00371 IrpContext, 00372 FatOplockComplete, 00373 FatPrePostIrp ); 00374 00375 if (Iosb.Status != STATUS_SUCCESS && 00376 Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) 00377 { 00378 /* The Irp needs to be queued */ 00379 *OplockPostIrp = TRUE; 00380 00381 /* Release the FCB and return */ 00382 FatReleaseFcb(IrpContext, Fcb); 00383 return Iosb; 00384 } 00385 00386 /* Set Fast I/O flag */ 00387 Fcb->Header.IsFastIoPossible = FALSE; //FatiIsFastIoPossible(Fcb); 00388 00389 /* Make sure image is not mapped */ 00390 if (DeleteOnClose || FlagOn(*DesiredAccess, FILE_WRITE_DATA)) 00391 { 00392 /* Try to flush the image section */ 00393 if (!MmFlushImageSection(&Fcb->SectionObjectPointers, MmFlushForWrite)) 00394 { 00395 /* Yes, image section exists, set correct status code */ 00396 if (DeleteOnClose) 00397 Iosb.Status = STATUS_CANNOT_DELETE; 00398 else 00399 Iosb.Status = STATUS_SHARING_VIOLATION; 00400 00401 /* Release the FCB and return */ 00402 FatReleaseFcb(IrpContext, Fcb); 00403 return Iosb; 00404 } 00405 } 00406 00407 /* Flush the cache if it's non-cached non-pagefile access */ 00408 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING) && 00409 Fcb->SectionObjectPointers.DataSectionObject && 00410 !FlagOn(Fcb->State, FCB_STATE_PAGEFILE)) 00411 { 00412 /* Set the flag that create is in progress */ 00413 SetFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS); 00414 00415 /* Flush the cache */ 00416 CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL); 00417 00418 /* Acquire and release Paging I/O resource before purging the cache section 00419 to let lazy writer finish */ 00420 ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE); 00421 ExReleaseResourceLite( Fcb->Header.PagingIoResource ); 00422 00423 /* Delete the cache section */ 00424 CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE); 00425 00426 /* Clear the flag */ 00427 ClearFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS); 00428 } 00429 00430 /* Check create disposition flags and branch accordingly */ 00431 if (CreateDisposition == FILE_OPEN || 00432 CreateDisposition == FILE_OPEN_IF) 00433 { 00434 DPRINT("Opening a file\n"); 00435 00436 /* Check if we need to bother with EA */ 00437 if (NoEaKnowledge && FALSE /* FatIsFat32(Vcb)*/) 00438 { 00439 UNIMPLEMENTED; 00440 } 00441 00442 /* Set up file object */ 00443 Ccb = FatCreateCcb(); 00444 FatSetFileObject(FileObject, 00445 UserFileOpen, 00446 Fcb, 00447 Ccb); 00448 00449 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; 00450 00451 /* The file is opened */ 00452 Iosb.Information = FILE_OPENED; 00453 goto SuccComplete; 00454 } 00455 else if ((CreateDisposition == FILE_SUPERSEDE) || 00456 (CreateDisposition == FILE_OVERWRITE) || 00457 (CreateDisposition == FILE_OVERWRITE_IF)) 00458 { 00459 /* Remember previous status */ 00460 StatusPrev = Iosb.Status; 00461 00462 // TODO: Check system security access 00463 00464 /* Perform overwrite operation */ 00465 Iosb = FatiOverwriteFile(IrpContext, 00466 FileObject, 00467 Fcb, 00468 AllocationSize, 00469 EaBuffer, 00470 EaLength, 00471 FileAttributes, 00472 CreateDisposition, 00473 NoEaKnowledge); 00474 00475 /* Restore previous status in case of success */ 00476 if (Iosb.Status == STATUS_SUCCESS) 00477 Iosb.Status = StatusPrev; 00478 00479 /* Fall down to completion */ 00480 } 00481 else 00482 { 00483 /* We can't get here */ 00484 KeBugCheckEx(FAT_FILE_SYSTEM, CreateDisposition, 0, 0, 0); 00485 } 00486 00487 00488 SuccComplete: 00489 /* If all is fine */ 00490 if (Iosb.Status != STATUS_PENDING && 00491 NT_SUCCESS(Iosb.Status)) 00492 { 00493 /* Update access if needed */ 00494 if (AddedAccess) 00495 { 00496 /* Remove added access flags from desired access */ 00497 ClearFlag(*DesiredAccess, AddedAccess); 00498 00499 /* Check share access */ 00500 Status = IoCheckShareAccess(*DesiredAccess, 00501 ShareAccess, 00502 FileObject, 00503 &Fcb->ShareAccess, 00504 TRUE); 00505 00506 /* Make sure it's success */ 00507 ASSERT(Status == STATUS_SUCCESS); 00508 } 00509 else 00510 { 00511 /* Update the share access */ 00512 IoUpdateShareAccess(FileObject, &Fcb->ShareAccess); 00513 } 00514 00515 /* Clear the delay close */ 00516 ClearFlag(Fcb->State, FCB_STATE_DELAY_CLOSE); 00517 00518 /* Increase counters */ 00519 Fcb->UncleanCount++; 00520 Fcb->OpenCount++; 00521 Vcb->OpenFileCount++; 00522 if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++; 00523 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) Fcb->NonCachedUncleanCount++; 00524 00525 // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB 00526 } 00527 00528 return Iosb; 00529 } 00530 00531 VOID 00532 NTAPI 00533 FatGetFcbUnicodeName(IN PFAT_IRP_CONTEXT IrpContext, 00534 IN PFCB Fcb, 00535 OUT PUNICODE_STRING LongName) 00536 { 00537 FF_DIRENT DirEnt; 00538 FF_ERROR Err; 00539 OEM_STRING ShortName; 00540 CHAR ShortNameBuf[13]; 00541 UCHAR EntryBuffer[32]; 00542 UCHAR NumLFNs; 00543 OEM_STRING LongNameOem; 00544 NTSTATUS Status; 00545 00546 /* Make sure this FCB has a FullFAT handle associated with it */ 00547 if (Fcb->FatHandle == NULL && 00548 FatNodeType(Fcb) == FAT_NTC_DCB) 00549 { 00550 /* Open the dir with FullFAT */ 00551 Fcb->FatHandle = FF_OpenW(Fcb->Vcb->Ioman, &Fcb->FullFileName, FF_MODE_DIR, NULL); 00552 if (!Fcb->FatHandle) 00553 { 00554 ASSERT(FALSE); 00555 } 00556 } 00557 00558 /* Get the dir entry */ 00559 Err = FF_GetEntry(Fcb->Vcb->Ioman, 00560 Fcb->FatHandle->DirEntry, 00561 Fcb->FatHandle->DirCluster, 00562 &DirEnt); 00563 00564 if (Err != FF_ERR_NONE) 00565 { 00566 DPRINT1("Error %d getting dirent of a file\n", Err); 00567 return; 00568 } 00569 00570 /* Read the dirent to fetch the raw short name */ 00571 FF_FetchEntry(Fcb->Vcb->Ioman, 00572 Fcb->FatHandle->DirCluster, 00573 Fcb->FatHandle->DirEntry, 00574 EntryBuffer); 00575 NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40); 00576 00577 /* Check if we only have a short name. 00578 Convert it to unicode and return if that's the case */ 00579 if (NumLFNs == 0) 00580 { 00581 /* Initialize short name string */ 00582 ShortName.Buffer = ShortNameBuf; 00583 ShortName.Length = 0; 00584 ShortName.MaximumLength = 12; 00585 00586 /* Convert raw short name to a proper string */ 00587 Fati8dot3ToString((PCHAR)EntryBuffer, FALSE, &ShortName); 00588 00589 /* Convert it to unicode */ 00590 Status = RtlOemStringToCountedUnicodeString(LongName, 00591 &ShortName, 00592 FALSE); 00593 00594 /* Ensure conversion was successful */ 00595 ASSERT(Status == STATUS_SUCCESS); 00596 00597 /* Exit */ 00598 return; 00599 } 00600 00601 /* Convert LFN from OEM to unicode and return */ 00602 LongNameOem.Buffer = DirEnt.FileName; 00603 LongNameOem.MaximumLength = FF_MAX_FILENAME; 00604 LongNameOem.Length = strlen(DirEnt.FileName); 00605 00606 /* Convert it to unicode */ 00607 Status = RtlOemStringToUnicodeString(LongName, &LongNameOem, FALSE); 00608 00609 /* Ensure conversion was successful */ 00610 ASSERT(Status == STATUS_SUCCESS); 00611 } 00612 00613 00614 VOID 00615 NTAPI 00616 FatSetFullNameInFcb(PFCB Fcb, 00617 PUNICODE_STRING Name) 00618 { 00619 PUNICODE_STRING ParentName; 00620 00621 /* Make sure this FCB's name wasn't already set */ 00622 ASSERT(Fcb->FullFileName.Buffer == NULL); 00623 00624 /* First of all, check exact case name */ 00625 if (Fcb->ExactCaseLongName.Buffer) 00626 { 00627 ASSERT(Fcb->ExactCaseLongName.Length != 0); 00628 00629 /* Use exact case name */ 00630 Name = &Fcb->ExactCaseLongName; 00631 } 00632 00633 /* Treat root dir different */ 00634 if (FatNodeType(Fcb->ParentFcb) == FAT_NTC_ROOT_DCB) 00635 { 00636 /* Set lengths */ 00637 Fcb->FullFileName.MaximumLength = sizeof(WCHAR) + Name->Length; 00638 Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength; 00639 00640 /* Allocate a buffer */ 00641 Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag(PagedPool, 00642 Fcb->FullFileName.Length, 00643 TAG_FILENAME); 00644 00645 /* Prefix with a backslash */ 00646 Fcb->FullFileName.Buffer[0] = L'\\'; 00647 00648 /* Copy the name here */ 00649 RtlCopyMemory(&Fcb->FullFileName.Buffer[1], 00650 &Name->Buffer[0], 00651 Name->Length ); 00652 } 00653 else 00654 { 00655 ParentName = &Fcb->ParentFcb->FullFileName; 00656 00657 /* Check if parent's name is set */ 00658 if (!ParentName->Buffer) 00659 return; 00660 00661 /* Set lengths */ 00662 Fcb->FullFileName.MaximumLength = 00663 ParentName->Length + sizeof(WCHAR) + Name->Length; 00664 Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength; 00665 00666 /* Allocate a buffer */ 00667 Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag(PagedPool, 00668 Fcb->FullFileName.Length, 00669 TAG_FILENAME ); 00670 00671 /* Copy parent's name here */ 00672 RtlCopyMemory(&Fcb->FullFileName.Buffer[0], 00673 &ParentName->Buffer[0], 00674 ParentName->Length ); 00675 00676 /* Add a backslash */ 00677 Fcb->FullFileName.Buffer[ParentName->Length / sizeof(WCHAR)] = L'\\'; 00678 00679 /* Copy given name here */ 00680 RtlCopyMemory(&Fcb->FullFileName.Buffer[(ParentName->Length / sizeof(WCHAR)) + 1], 00681 &Name->Buffer[0], 00682 Name->Length ); 00683 } 00684 } 00685 00686 VOID 00687 NTAPI 00688 FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext, 00689 IN PFCB Fcb) 00690 { 00691 UNICODE_STRING LongName; 00692 PFCB CurFcb = Fcb; 00693 PFCB StopFcb; 00694 PWCHAR TmpBuffer; 00695 ULONG PathLength = 0; 00696 00697 /* Do nothing if it's already set */ 00698 if (Fcb->FullFileName.Buffer) return; 00699 00700 /* Allocate a temporary buffer */ 00701 LongName.Length = 0; 00702 LongName.MaximumLength = FF_MAX_FILENAME * sizeof(WCHAR); 00703 LongName.Buffer = 00704 FsRtlAllocatePoolWithTag(PagedPool, 00705 FF_MAX_FILENAME * sizeof(WCHAR), 00706 TAG_FILENAME); 00707 00708 /* Go through all parents to calculate needed length */ 00709 while (CurFcb != Fcb->Vcb->RootDcb) 00710 { 00711 /* Does current FCB have FullFileName set? */ 00712 if (CurFcb != Fcb && 00713 CurFcb->FullFileName.Buffer) 00714 { 00715 /* Yes, just use it! */ 00716 PathLength += CurFcb->FullFileName.Length; 00717 00718 Fcb->FullFileName.Buffer = 00719 FsRtlAllocatePoolWithTag(PagedPool, 00720 PathLength, 00721 TAG_FILENAME); 00722 00723 RtlCopyMemory(Fcb->FullFileName.Buffer, 00724 CurFcb->FullFileName.Buffer, 00725 CurFcb->FullFileName.Length); 00726 00727 break; 00728 } 00729 00730 /* Sum up length of a current item */ 00731 PathLength += CurFcb->FileNameLength + sizeof(WCHAR); 00732 00733 /* Go to the parent */ 00734 CurFcb = CurFcb->ParentFcb; 00735 } 00736 00737 /* Allocate FullFileName if it wasn't already allocated above */ 00738 if (!Fcb->FullFileName.Buffer) 00739 { 00740 Fcb->FullFileName.Buffer = 00741 FsRtlAllocatePoolWithTag(PagedPool, 00742 PathLength, 00743 TAG_FILENAME); 00744 } 00745 00746 StopFcb = CurFcb; 00747 00748 CurFcb = Fcb; 00749 TmpBuffer = Fcb->FullFileName.Buffer + PathLength / sizeof(WCHAR); 00750 00751 /* Set lengths */ 00752 Fcb->FullFileName.Length = PathLength; 00753 Fcb->FullFileName.MaximumLength = PathLength; 00754 00755 while (CurFcb != StopFcb) 00756 { 00757 /* Get its unicode name */ 00758 FatGetFcbUnicodeName(IrpContext, 00759 CurFcb, 00760 &LongName); 00761 00762 /* Copy it */ 00763 TmpBuffer -= LongName.Length / sizeof(WCHAR); 00764 RtlCopyMemory(TmpBuffer, LongName.Buffer, LongName.Length); 00765 00766 /* Append with a backslash */ 00767 TmpBuffer -= 1; 00768 *TmpBuffer = L'\\'; 00769 00770 /* Go to the parent */ 00771 CurFcb = CurFcb->ParentFcb; 00772 } 00773 00774 /* Free the temp buffer */ 00775 ExFreePool(LongName.Buffer); 00776 } 00777 00778 00779 VOID 00780 NTAPI 00781 FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext, 00782 IN PFCB Fcb) 00783 { 00784 FF_DIRENT DirEnt; 00785 FF_ERROR Err; 00786 POEM_STRING ShortName; 00787 CHAR ShortNameRaw[13]; 00788 UCHAR EntryBuffer[32]; 00789 UCHAR NumLFNs; 00790 PUNICODE_STRING UnicodeName; 00791 OEM_STRING LongNameOem; 00792 NTSTATUS Status; 00793 00794 /* Get the dir entry */ 00795 Err = FF_GetEntry(Fcb->Vcb->Ioman, 00796 Fcb->FatHandle->DirEntry, 00797 Fcb->FatHandle->DirCluster, 00798 &DirEnt); 00799 00800 if (Err != FF_ERR_NONE) 00801 { 00802 DPRINT1("Error %d getting dirent of a file\n", Err); 00803 return; 00804 } 00805 00806 /* Read the dirent to fetch the raw short name */ 00807 FF_FetchEntry(Fcb->Vcb->Ioman, 00808 Fcb->FatHandle->DirCluster, 00809 Fcb->FatHandle->DirEntry, 00810 EntryBuffer); 00811 NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40); 00812 RtlCopyMemory(ShortNameRaw, EntryBuffer, 11); 00813 00814 /* Initialize short name string */ 00815 ShortName = &Fcb->ShortName.Name.Ansi; 00816 ShortName->Buffer = Fcb->ShortNameBuffer; 00817 ShortName->Length = 0; 00818 ShortName->MaximumLength = sizeof(Fcb->ShortNameBuffer); 00819 00820 /* Convert raw short name to a proper string */ 00821 Fati8dot3ToString(ShortNameRaw, FALSE, ShortName); 00822 00823 /* Add the short name link */ 00824 FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksAnsi, &Fcb->ShortName); 00825 Fcb->ShortName.Fcb = Fcb; 00826 00827 /* Get the long file name (if any) */ 00828 if (NumLFNs > 0) 00829 { 00830 /* Prepare the oem string */ 00831 LongNameOem.Buffer = DirEnt.FileName; 00832 LongNameOem.MaximumLength = FF_MAX_FILENAME; 00833 LongNameOem.Length = strlen(DirEnt.FileName); 00834 00835 /* Prepare the unicode string */ 00836 UnicodeName = &Fcb->LongName.Name.String; 00837 UnicodeName->Length = (LongNameOem.Length + 1) * sizeof(WCHAR); 00838 UnicodeName->MaximumLength = UnicodeName->Length; 00839 UnicodeName->Buffer = FsRtlAllocatePool(PagedPool, UnicodeName->Length); 00840 00841 /* Convert it to unicode */ 00842 Status = RtlOemStringToUnicodeString(UnicodeName, &LongNameOem, FALSE); 00843 if (!NT_SUCCESS(Status)) 00844 { 00845 ASSERT(FALSE); 00846 } 00847 00848 /* Set its length */ 00849 Fcb->FileNameLength = UnicodeName->Length; 00850 00851 /* Save case-preserved copy */ 00852 Fcb->ExactCaseLongName.Length = UnicodeName->Length; 00853 Fcb->ExactCaseLongName.MaximumLength = UnicodeName->Length; 00854 Fcb->ExactCaseLongName.Buffer = 00855 FsRtlAllocatePoolWithTag(PagedPool, UnicodeName->Length, TAG_FILENAME); 00856 00857 RtlCopyMemory(Fcb->ExactCaseLongName.Buffer, 00858 UnicodeName->Buffer, 00859 UnicodeName->Length); 00860 00861 /* Perform a trick which is done by MS's FASTFAT driver to monocase 00862 the filename */ 00863 RtlDowncaseUnicodeString(UnicodeName, UnicodeName, FALSE); 00864 RtlUpcaseUnicodeString(UnicodeName, UnicodeName, FALSE); 00865 00866 DPRINT("Converted long name: %wZ\n", UnicodeName); 00867 00868 /* Add the long unicode name link */ 00869 FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksUnicode, &Fcb->LongName); 00870 Fcb->LongName.Fcb = Fcb; 00871 00872 /* Indicate that this FCB has a unicode long name */ 00873 SetFlag(Fcb->State, FCB_STATE_HAS_UNICODE_NAME); 00874 } 00875 else 00876 { 00877 /* No LFN, set exact case name to 0 length */ 00878 Fcb->ExactCaseLongName.Length = 0; 00879 Fcb->ExactCaseLongName.MaximumLength = 0; 00880 00881 /* Set the length based on the short name */ 00882 Fcb->FileNameLength = RtlOemStringToCountedUnicodeSize(ShortName); 00883 } 00884 00885 /* Mark the fact that names were added to splay trees*/ 00886 SetFlag(Fcb->State, FCB_STATE_HAS_NAMES); 00887 } 00888 00889 VOID 00890 NTAPI 00891 Fati8dot3ToString(IN PCHAR FileName, 00892 IN BOOLEAN DownCase, 00893 OUT POEM_STRING OutString) 00894 { 00895 ULONG BaseLen, ExtLen; 00896 CHAR *cString = OutString->Buffer; 00897 ULONG i; 00898 00899 /* Calc base and ext lens */ 00900 for (BaseLen = 8; BaseLen > 0; BaseLen--) 00901 { 00902 if (FileName[BaseLen - 1] != ' ') break; 00903 } 00904 00905 for (ExtLen = 3; ExtLen > 0; ExtLen--) 00906 { 00907 if (FileName[8 + ExtLen - 1] != ' ') break; 00908 } 00909 00910 /* Process base name */ 00911 if (BaseLen) 00912 { 00913 RtlCopyMemory(cString, FileName, BaseLen); 00914 00915 /* Substitute the e5 thing */ 00916 if (cString[0] == 0x05) cString[0] = 0xe5; 00917 00918 /* Downcase if asked to */ 00919 if (DownCase) 00920 { 00921 /* Do it manually */ 00922 for (i = 0; i < BaseLen; i++) 00923 { 00924 if (cString[i] >= 'A' && 00925 cString[i] <= 'Z') 00926 { 00927 /* Lowercase it */ 00928 cString[i] += 'a' - 'A'; 00929 } 00930 00931 } 00932 } 00933 } 00934 00935 /* Process extension */ 00936 if (ExtLen) 00937 { 00938 /* Add the dot */ 00939 cString[BaseLen] = '.'; 00940 BaseLen++; 00941 00942 /* Copy the extension */ 00943 for (i = 0; i < ExtLen; i++) 00944 { 00945 cString[BaseLen + i] = FileName[8 + i]; 00946 } 00947 00948 /* Lowercase the extension if asked to */ 00949 if (DownCase) 00950 { 00951 /* Do it manually */ 00952 for (i = BaseLen; i < BaseLen + ExtLen; i++) 00953 { 00954 if (cString[i] >= 'A' && 00955 cString[i] <= 'Z') 00956 { 00957 /* Lowercase it */ 00958 cString[i] += 'a' - 'A'; 00959 } 00960 } 00961 } 00962 } 00963 00964 /* Set the length */ 00965 OutString->Length = BaseLen + ExtLen; 00966 00967 DPRINT("'%s', len %d\n", OutString->Buffer, OutString->Length); 00968 } 00969 00970 VOID 00971 NTAPI 00972 FatInsertName(IN PFAT_IRP_CONTEXT IrpContext, 00973 IN PRTL_SPLAY_LINKS *RootNode, 00974 IN PFCB_NAME_LINK Name) 00975 { 00976 PFCB_NAME_LINK NameLink; 00977 FSRTL_COMPARISON_RESULT Comparison; 00978 00979 /* Initialize the splay links */ 00980 RtlInitializeSplayLinks(&Name->Links); 00981 00982 /* Is this the first entry? */ 00983 if (*RootNode == NULL) 00984 { 00985 /* Yes, become root and return */ 00986 *RootNode = &Name->Links; 00987 return; 00988 } 00989 00990 /* Get the name link */ 00991 NameLink = CONTAINING_RECORD(*RootNode, FCB_NAME_LINK, Links); 00992 while (TRUE) 00993 { 00994 /* Compare the prefix */ 00995 if (*(PUCHAR)NameLink->Name.Ansi.Buffer != *(PUCHAR)&Name->Name.Ansi.Buffer) 00996 { 00997 if (*(PUCHAR)NameLink->Name.Ansi.Buffer < *(PUCHAR)&Name->Name.Ansi.Buffer) 00998 Comparison = LessThan; 00999 else 01000 Comparison = GreaterThan; 01001 } 01002 else 01003 { 01004 /* Perform real comparison */ 01005 Comparison = FatiCompareNames(&NameLink->Name.Ansi, &Name->Name.Ansi); 01006 } 01007 01008 /* Check the bad case first */ 01009 if (Comparison == EqualTo) 01010 { 01011 /* Must not happen */ 01012 ASSERT(FALSE); 01013 } 01014 01015 /* Check comparison result */ 01016 if (Comparison == GreaterThan) 01017 { 01018 /* Go to the left child */ 01019 if (!RtlLeftChild(&NameLink->Links)) 01020 { 01021 /* It's absent, insert here and break */ 01022 RtlInsertAsLeftChild(&NameLink->Links, &Name->Links); 01023 break; 01024 } 01025 else 01026 { 01027 /* It's present, go inside it */ 01028 NameLink = CONTAINING_RECORD(RtlLeftChild(&NameLink->Links), 01029 FCB_NAME_LINK, 01030 Links); 01031 } 01032 } 01033 else 01034 { 01035 /* Go to the right child */ 01036 if (!RtlRightChild(&NameLink->Links)) 01037 { 01038 /* It's absent, insert here and break */ 01039 RtlInsertAsRightChild(&NameLink->Links, &Name->Links); 01040 break; 01041 } 01042 else 01043 { 01044 /* It's present, go inside it */ 01045 NameLink = CONTAINING_RECORD(RtlRightChild(&NameLink->Links), 01046 FCB_NAME_LINK, 01047 Links); 01048 } 01049 } 01050 } 01051 } 01052 01053 VOID 01054 NTAPI 01055 FatRemoveNames(IN PFAT_IRP_CONTEXT IrpContext, 01056 IN PFCB Fcb) 01057 { 01058 PRTL_SPLAY_LINKS RootNew; 01059 PFCB Parent; 01060 01061 /* Reference the parent for simplicity */ 01062 Parent = Fcb->ParentFcb; 01063 01064 /* If this FCB hasn't been added to splay trees - just return */ 01065 if (!FlagOn( Fcb->State, FCB_STATE_HAS_NAMES )) 01066 return; 01067 01068 /* Delete the short name link */ 01069 RootNew = RtlDelete(&Fcb->ShortName.Links); 01070 01071 /* Set the new root */ 01072 Parent->Dcb.SplayLinksAnsi = RootNew; 01073 01074 /* Deal with a unicode name if it exists */ 01075 if (FlagOn( Fcb->State, FCB_STATE_HAS_UNICODE_NAME )) 01076 { 01077 /* Delete the long unicode name link */ 01078 RootNew = RtlDelete(&Fcb->LongName.Links); 01079 01080 /* Set the new root */ 01081 Parent->Dcb.SplayLinksUnicode = RootNew; 01082 01083 /* Free the long name string's buffer*/ 01084 RtlFreeUnicodeString(&Fcb->LongName.Name.String); 01085 01086 /* Clear the "has unicode name" flag */ 01087 ClearFlag(Fcb->State, FCB_STATE_HAS_UNICODE_NAME); 01088 } 01089 01090 /* This FCB has no names added to splay trees now */ 01091 ClearFlag(Fcb->State, FCB_STATE_HAS_NAMES); 01092 } 01093 01094 01095 /* EOF */ Generated on Sun May 27 2012 04:27:35 for ReactOS by
1.7.6.1
|