ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

fcb.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.