Home | History | Annotate | Download | only in EnhancedFatDxe
      1 /** @file
      2   Routines dealing with setting/getting file/volume info
      3 
      4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed and made available
      6 under the terms and conditions of the BSD License which accompanies this
      7 distribution. The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 
     14 
     15 **/
     16 
     17 #include "Fat.h"
     18 
     19 /**
     20 
     21   Get the volume's info into Buffer.
     22 
     23   @param  Volume                - FAT file system volume.
     24   @param  BufferSize            - Size of Buffer.
     25   @param  Buffer                - Buffer containing volume info.
     26 
     27   @retval EFI_SUCCESS           - Get the volume info successfully.
     28   @retval EFI_BUFFER_TOO_SMALL  - The buffer is too small.
     29 
     30 **/
     31 EFI_STATUS
     32 FatGetVolumeInfo (
     33   IN FAT_VOLUME       *Volume,
     34   IN OUT UINTN        *BufferSize,
     35   OUT VOID            *Buffer
     36   );
     37 
     38 /**
     39 
     40   Set the volume's info.
     41 
     42   @param  Volume                - FAT file system volume.
     43   @param  BufferSize            - Size of Buffer.
     44   @param  Buffer                - Buffer containing the new volume info.
     45 
     46   @retval EFI_SUCCESS           - Set the volume info successfully.
     47   @retval EFI_BAD_BUFFER_SIZE   - The buffer size is error.
     48   @retval EFI_WRITE_PROTECTED   - The volume is read only.
     49   @return other                 - An error occurred when operation the disk.
     50 
     51 **/
     52 EFI_STATUS
     53 FatSetVolumeInfo (
     54   IN FAT_VOLUME       *Volume,
     55   IN UINTN            BufferSize,
     56   IN VOID            *Buffer
     57   );
     58 
     59 /**
     60 
     61   Set or Get the some types info of the file into Buffer.
     62 
     63   @param  IsSet      - TRUE:The access is set, else is get
     64   @param  FHand      - The handle of file
     65   @param  Type       - The type of the info
     66   @param  BufferSize - Size of Buffer
     67   @param  Buffer     - Buffer containing volume info
     68 
     69   @retval EFI_SUCCESS       - Get the info successfully
     70   @retval EFI_DEVICE_ERROR  - Can not find the OFile for the file
     71 
     72 **/
     73 EFI_STATUS
     74 FatSetOrGetInfo (
     75   IN BOOLEAN              IsSet,
     76   IN EFI_FILE_PROTOCOL    *FHand,
     77   IN EFI_GUID             *Type,
     78   IN OUT UINTN            *BufferSize,
     79   IN OUT VOID             *Buffer
     80   );
     81 
     82 /**
     83 
     84   Get the open file's info into Buffer.
     85 
     86   @param  OFile                 - The open file.
     87   @param  BufferSize            - Size of Buffer.
     88   @param  Buffer                - Buffer containing file info.
     89 
     90   @retval EFI_SUCCESS           - Get the file info successfully.
     91   @retval EFI_BUFFER_TOO_SMALL  - The buffer is too small.
     92 
     93 **/
     94 EFI_STATUS
     95 FatGetFileInfo (
     96   IN FAT_OFILE        *OFile,
     97   IN OUT UINTN        *BufferSize,
     98   OUT VOID            *Buffer
     99   )
    100 {
    101   return FatGetDirEntInfo (OFile->Volume, OFile->DirEnt, BufferSize, Buffer);
    102 }
    103 
    104 /**
    105 
    106   Get the volume's info into Buffer.
    107 
    108   @param  Volume                - FAT file system volume.
    109   @param  BufferSize            - Size of Buffer.
    110   @param  Buffer                - Buffer containing volume info.
    111 
    112   @retval EFI_SUCCESS           - Get the volume info successfully.
    113   @retval EFI_BUFFER_TOO_SMALL  - The buffer is too small.
    114 
    115 **/
    116 EFI_STATUS
    117 FatGetVolumeInfo (
    118   IN     FAT_VOLUME     *Volume,
    119   IN OUT UINTN          *BufferSize,
    120      OUT VOID           *Buffer
    121   )
    122 {
    123   UINTN                 Size;
    124   UINTN                 NameSize;
    125   UINTN                 ResultSize;
    126   CHAR16                Name[FAT_NAME_LEN + 1];
    127   EFI_STATUS            Status;
    128   EFI_FILE_SYSTEM_INFO  *Info;
    129   UINT8                 ClusterAlignment;
    130 
    131   Size              = SIZE_OF_EFI_FILE_SYSTEM_INFO;
    132   Status            = FatGetVolumeEntry (Volume, Name);
    133   NameSize          = StrSize (Name);
    134   ResultSize        = Size + NameSize;
    135   ClusterAlignment  = Volume->ClusterAlignment;
    136 
    137   //
    138   // If we don't have valid info, compute it now
    139   //
    140   FatComputeFreeInfo (Volume);
    141 
    142   Status = EFI_BUFFER_TOO_SMALL;
    143   if (*BufferSize >= ResultSize) {
    144     Status  = EFI_SUCCESS;
    145 
    146     Info    = Buffer;
    147     ZeroMem (Info, SIZE_OF_EFI_FILE_SYSTEM_INFO);
    148 
    149     Info->Size        = ResultSize;
    150     Info->ReadOnly    = Volume->ReadOnly;
    151     Info->BlockSize   = (UINT32) Volume->ClusterSize;
    152     Info->VolumeSize  = LShiftU64 (Volume->MaxCluster, ClusterAlignment);
    153     Info->FreeSpace   = LShiftU64 (
    154                           Volume->FatInfoSector.FreeInfo.ClusterCount,
    155                           ClusterAlignment
    156                           );
    157     CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);
    158   }
    159 
    160   *BufferSize = ResultSize;
    161   return Status;
    162 }
    163 
    164 /**
    165 
    166   Get the volume's label info into Buffer.
    167 
    168   @param  Volume                - FAT file system volume.
    169   @param  BufferSize            - Size of Buffer.
    170   @param  Buffer                - Buffer containing volume's label info.
    171 
    172   @retval EFI_SUCCESS           - Get the volume's label info successfully.
    173   @retval EFI_BUFFER_TOO_SMALL  - The buffer is too small.
    174 
    175 **/
    176 EFI_STATUS
    177 FatGetVolumeLabelInfo (
    178   IN FAT_VOLUME       *Volume,
    179   IN OUT UINTN        *BufferSize,
    180   OUT VOID            *Buffer
    181   )
    182 {
    183   UINTN                             Size;
    184   UINTN                             NameSize;
    185   UINTN                             ResultSize;
    186   CHAR16                            Name[FAT_NAME_LEN + 1];
    187   EFI_STATUS                        Status;
    188 
    189   Size        = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL;
    190   Status      = FatGetVolumeEntry (Volume, Name);
    191   NameSize    = StrSize (Name);
    192   ResultSize  = Size + NameSize;
    193 
    194   Status      = EFI_BUFFER_TOO_SMALL;
    195   if (*BufferSize >= ResultSize) {
    196     Status  = EFI_SUCCESS;
    197     CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);
    198   }
    199 
    200   *BufferSize = ResultSize;
    201   return Status;
    202 }
    203 
    204 /**
    205 
    206   Set the volume's info.
    207 
    208   @param  Volume                - FAT file system volume.
    209   @param  BufferSize            - Size of Buffer.
    210   @param  Buffer                - Buffer containing the new volume info.
    211 
    212   @retval EFI_SUCCESS           - Set the volume info successfully.
    213   @retval EFI_BAD_BUFFER_SIZE   - The buffer size is error.
    214   @retval EFI_WRITE_PROTECTED   - The volume is read only.
    215   @return other                 - An error occurred when operation the disk.
    216 
    217 **/
    218 EFI_STATUS
    219 FatSetVolumeInfo (
    220   IN FAT_VOLUME       *Volume,
    221   IN UINTN            BufferSize,
    222   IN VOID             *Buffer
    223   )
    224 {
    225   EFI_FILE_SYSTEM_INFO  *Info;
    226 
    227   Info = (EFI_FILE_SYSTEM_INFO *) Buffer;
    228 
    229   if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + 2 || Info->Size > BufferSize) {
    230     return EFI_BAD_BUFFER_SIZE;
    231   }
    232 
    233   return FatSetVolumeEntry (Volume, Info->VolumeLabel);
    234 }
    235 
    236 /**
    237 
    238   Set the volume's label info.
    239 
    240   @param  Volume                - FAT file system volume.
    241   @param  BufferSize            - Size of Buffer.
    242   @param  Buffer                - Buffer containing the new volume label info.
    243 
    244   @retval EFI_SUCCESS           - Set the volume label info successfully.
    245   @retval EFI_WRITE_PROTECTED   - The disk is write protected.
    246   @retval EFI_BAD_BUFFER_SIZE   - The buffer size is error.
    247   @return other                 - An error occurred when operation the disk.
    248 
    249 **/
    250 EFI_STATUS
    251 FatSetVolumeLabelInfo (
    252   IN FAT_VOLUME       *Volume,
    253   IN UINTN            BufferSize,
    254   IN VOID             *Buffer
    255   )
    256 {
    257   EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
    258 
    259   Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) Buffer;
    260 
    261   if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 2) {
    262     return EFI_BAD_BUFFER_SIZE;
    263   }
    264 
    265   return FatSetVolumeEntry (Volume, Info->VolumeLabel);
    266 }
    267 
    268 /**
    269 
    270   Set the file info.
    271 
    272   @param  Volume                - FAT file system volume.
    273   @param  IFile                 - The instance of the open file.
    274   @param  OFile                 - The open file.
    275   @param  BufferSize            - Size of Buffer.
    276   @param  Buffer                - Buffer containing the new file info.
    277 
    278   @retval EFI_SUCCESS           - Set the file info successfully.
    279   @retval EFI_ACCESS_DENIED     - It is the root directory
    280                           or the directory attribute bit can not change
    281                           or try to change a directory size
    282                           or something else.
    283   @retval EFI_UNSUPPORTED       - The new file size is larger than 4GB.
    284   @retval EFI_WRITE_PROTECTED   - The disk is write protected.
    285   @retval EFI_BAD_BUFFER_SIZE   - The buffer size is error.
    286   @retval EFI_INVALID_PARAMETER - The time info or attributes info is error.
    287   @retval EFI_OUT_OF_RESOURCES  - Can not allocate new memory.
    288   @retval EFI_VOLUME_CORRUPTED  - The volume is corrupted.
    289   @return other                 - An error occurred when operation the disk.
    290 
    291 **/
    292 EFI_STATUS
    293 FatSetFileInfo (
    294   IN FAT_VOLUME       *Volume,
    295   IN FAT_IFILE        *IFile,
    296   IN FAT_OFILE        *OFile,
    297   IN UINTN            BufferSize,
    298   IN VOID             *Buffer
    299   )
    300 {
    301   EFI_STATUS    Status;
    302   EFI_FILE_INFO *NewInfo;
    303   FAT_OFILE     *DotOFile;
    304   FAT_OFILE     *Parent;
    305   CHAR16        NewFileName[EFI_PATH_STRING_LENGTH];
    306   EFI_TIME      ZeroTime;
    307   FAT_DIRENT    *DirEnt;
    308   FAT_DIRENT    *TempDirEnt;
    309   UINT8         NewAttribute;
    310   BOOLEAN       ReadOnly;
    311 
    312   ZeroMem (&ZeroTime, sizeof (EFI_TIME));
    313   Parent  = OFile->Parent;
    314   DirEnt  = OFile->DirEnt;
    315   //
    316   // If this is the root directory, we can't make any updates
    317   //
    318   if (Parent == NULL) {
    319     return EFI_ACCESS_DENIED;
    320   }
    321   //
    322   // Make sure there's a valid input buffer
    323   //
    324   NewInfo = Buffer;
    325   if (BufferSize < SIZE_OF_EFI_FILE_INFO + 2 || NewInfo->Size > BufferSize) {
    326     return EFI_BAD_BUFFER_SIZE;
    327   }
    328 
    329   ReadOnly = (BOOLEAN)(IFile->ReadOnly || (DirEnt->Entry.Attributes & EFI_FILE_READ_ONLY));
    330   //
    331   // if a zero time is specified, then the original time is preserved
    332   //
    333   if (CompareMem (&ZeroTime, &NewInfo->CreateTime, sizeof (EFI_TIME)) != 0) {
    334     if (!FatIsValidTime (&NewInfo->CreateTime)) {
    335       return EFI_INVALID_PARAMETER;
    336     }
    337 
    338     if (!ReadOnly) {
    339       FatEfiTimeToFatTime (&NewInfo->CreateTime, &DirEnt->Entry.FileCreateTime);
    340     }
    341   }
    342 
    343   if (CompareMem (&ZeroTime, &NewInfo->ModificationTime, sizeof (EFI_TIME)) != 0) {
    344     if (!FatIsValidTime (&NewInfo->ModificationTime)) {
    345       return EFI_INVALID_PARAMETER;
    346     }
    347 
    348     if (!ReadOnly) {
    349       FatEfiTimeToFatTime (&NewInfo->ModificationTime, &DirEnt->Entry.FileModificationTime);
    350     }
    351 
    352     OFile->PreserveLastModification = TRUE;
    353   }
    354 
    355   if (NewInfo->Attribute & (~EFI_FILE_VALID_ATTR)) {
    356     return EFI_INVALID_PARAMETER;
    357   }
    358 
    359   NewAttribute = (UINT8) NewInfo->Attribute;
    360   //
    361   // Can not change the directory attribute bit
    362   //
    363   if ((NewAttribute ^ DirEnt->Entry.Attributes) & EFI_FILE_DIRECTORY) {
    364     return EFI_ACCESS_DENIED;
    365   }
    366   //
    367   // Set the current attributes even if the IFile->ReadOnly is TRUE
    368   //
    369   DirEnt->Entry.Attributes = (UINT8) ((DirEnt->Entry.Attributes &~EFI_FILE_VALID_ATTR) | NewAttribute);
    370   //
    371   // Open the filename and see if it refers to an existing file
    372   //
    373   Status = FatLocateOFile (&Parent, NewInfo->FileName, DirEnt->Entry.Attributes, NewFileName);
    374   if (EFI_ERROR (Status)) {
    375     return Status;
    376   }
    377 
    378   if (*NewFileName != 0) {
    379     //
    380     // File was not found.  We do not allow rename of the current directory if
    381     // there are open files below the current directory
    382     //
    383     if (!IsListEmpty (&OFile->ChildHead) || Parent == OFile) {
    384       return EFI_ACCESS_DENIED;
    385     }
    386 
    387     if (ReadOnly) {
    388       return EFI_ACCESS_DENIED;
    389     }
    390 
    391     Status = FatRemoveDirEnt (OFile->Parent, DirEnt);
    392     if (EFI_ERROR (Status)) {
    393       return Status;
    394     }
    395     //
    396     // Create new dirent
    397     //
    398     Status = FatCreateDirEnt (Parent, NewFileName, DirEnt->Entry.Attributes, &TempDirEnt);
    399     if (EFI_ERROR (Status)) {
    400       return Status;
    401     }
    402 
    403     FatCloneDirEnt (TempDirEnt, DirEnt);
    404     FatFreeDirEnt (DirEnt);
    405     DirEnt        = TempDirEnt;
    406     DirEnt->OFile = OFile;
    407     OFile->DirEnt = DirEnt;
    408     OFile->Parent = Parent;
    409     RemoveEntryList (&OFile->ChildLink);
    410     InsertHeadList (&Parent->ChildHead, &OFile->ChildLink);
    411     //
    412     // If this is a directory, synchronize its dot directory entry
    413     //
    414     if (OFile->ODir != NULL) {
    415       //
    416       // Syncronize its dot entry
    417       //
    418       FatResetODirCursor (OFile);
    419       ASSERT (OFile->Parent != NULL);
    420       for (DotOFile = OFile; DotOFile != OFile->Parent->Parent; DotOFile = DotOFile->Parent) {
    421         Status = FatGetNextDirEnt (OFile, &DirEnt);
    422         if (EFI_ERROR (Status) || DirEnt == NULL || !FatIsDotDirEnt (DirEnt)) {
    423           return EFI_VOLUME_CORRUPTED;
    424         }
    425 
    426         FatCloneDirEnt (DirEnt, DotOFile->DirEnt);
    427         Status = FatStoreDirEnt (OFile, DirEnt);
    428         if (EFI_ERROR (Status)) {
    429           return Status;
    430         }
    431       }
    432     }
    433     //
    434     // If the file is renamed, we should append the ARCHIVE attribute
    435     //
    436     OFile->Archive = TRUE;
    437   } else if (Parent != OFile) {
    438     //
    439     // filename is to a different filename that already exists
    440     //
    441     return EFI_ACCESS_DENIED;
    442   }
    443   //
    444   // If the file size has changed, apply it
    445   //
    446   if (NewInfo->FileSize != OFile->FileSize) {
    447     if (OFile->ODir != NULL || ReadOnly) {
    448       //
    449       // If this is a directory or the file is read only, we can't change the file size
    450       //
    451       return EFI_ACCESS_DENIED;
    452     }
    453 
    454     if (NewInfo->FileSize > OFile->FileSize) {
    455       Status = FatExpandOFile (OFile, NewInfo->FileSize);
    456     } else {
    457       Status = FatTruncateOFile (OFile, (UINTN) NewInfo->FileSize);
    458     }
    459 
    460     if (EFI_ERROR (Status)) {
    461       return Status;
    462     }
    463 
    464     FatUpdateDirEntClusterSizeInfo (OFile);
    465   }
    466 
    467   OFile->Dirty = TRUE;
    468   return FatOFileFlush (OFile);
    469 }
    470 
    471 /**
    472 
    473   Set or Get the some types info of the file into Buffer.
    474 
    475   @param  IsSet      - TRUE:The access is set, else is get
    476   @param  FHand      - The handle of file
    477   @param  Type       - The type of the info
    478   @param  BufferSize - Size of Buffer
    479   @param  Buffer     - Buffer containing volume info
    480 
    481   @retval EFI_SUCCESS       - Get the info successfully
    482   @retval EFI_DEVICE_ERROR  - Can not find the OFile for the file
    483 
    484 **/
    485 EFI_STATUS
    486 FatSetOrGetInfo (
    487   IN     BOOLEAN            IsSet,
    488   IN     EFI_FILE_PROTOCOL  *FHand,
    489   IN     EFI_GUID           *Type,
    490   IN OUT UINTN              *BufferSize,
    491   IN OUT VOID               *Buffer
    492   )
    493 {
    494   FAT_IFILE   *IFile;
    495   FAT_OFILE   *OFile;
    496   FAT_VOLUME  *Volume;
    497   EFI_STATUS  Status;
    498 
    499   IFile   = IFILE_FROM_FHAND (FHand);
    500   OFile   = IFile->OFile;
    501   Volume  = OFile->Volume;
    502 
    503   Status  = OFile->Error;
    504   if (Status == EFI_NOT_FOUND) {
    505     return EFI_DEVICE_ERROR;
    506   }
    507 
    508   FatWaitNonblockingTask (IFile);
    509 
    510   FatAcquireLock ();
    511 
    512   //
    513   // Verify the file handle isn't in an error state
    514   //
    515   if (!EFI_ERROR (Status)) {
    516     //
    517     // Get the proper information based on the request
    518     //
    519     Status = EFI_UNSUPPORTED;
    520     if (IsSet) {
    521       if (CompareGuid (Type, &gEfiFileInfoGuid)) {
    522         Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetFileInfo (Volume, IFile, OFile, *BufferSize, Buffer);
    523       }
    524 
    525       if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {
    526         Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeInfo (Volume, *BufferSize, Buffer);
    527       }
    528 
    529       if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
    530         Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeLabelInfo (Volume, *BufferSize, Buffer);
    531       }
    532     } else {
    533       if (CompareGuid (Type, &gEfiFileInfoGuid)) {
    534         Status = FatGetFileInfo (OFile, BufferSize, Buffer);
    535       }
    536 
    537       if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {
    538         Status = FatGetVolumeInfo (Volume, BufferSize, Buffer);
    539       }
    540 
    541       if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
    542         Status = FatGetVolumeLabelInfo (Volume, BufferSize, Buffer);
    543       }
    544     }
    545   }
    546 
    547   Status = FatCleanupVolume (Volume, NULL, Status, NULL);
    548 
    549   FatReleaseLock ();
    550   return Status;
    551 }
    552 
    553 /**
    554 
    555   Get the some types info of the file into Buffer.
    556 
    557   @param  FHand                 - The handle of file.
    558   @param  Type                  - The type of the info.
    559   @param  BufferSize            - Size of Buffer.
    560   @param  Buffer                - Buffer containing volume info.
    561 
    562   @retval EFI_SUCCESS           - Get the info successfully.
    563   @retval EFI_DEVICE_ERROR      - Can not find the OFile for the file.
    564 
    565 **/
    566 EFI_STATUS
    567 EFIAPI
    568 FatGetInfo (
    569   IN     EFI_FILE_PROTOCOL   *FHand,
    570   IN     EFI_GUID            *Type,
    571   IN OUT UINTN               *BufferSize,
    572      OUT VOID                *Buffer
    573   )
    574 {
    575   return FatSetOrGetInfo (FALSE, FHand, Type, BufferSize, Buffer);
    576 }
    577 
    578 /**
    579 
    580   Set the some types info of the file into Buffer.
    581 
    582   @param  FHand                 - The handle of file.
    583   @param  Type                  - The type of the info.
    584   @param  BufferSize            - Size of Buffer
    585   @param  Buffer                - Buffer containing volume info.
    586 
    587   @retval EFI_SUCCESS           - Set the info successfully.
    588   @retval EFI_DEVICE_ERROR      - Can not find the OFile for the file.
    589 
    590 **/
    591 EFI_STATUS
    592 EFIAPI
    593 FatSetInfo (
    594   IN EFI_FILE_PROTOCOL  *FHand,
    595   IN EFI_GUID           *Type,
    596   IN UINTN              BufferSize,
    597   IN VOID               *Buffer
    598   )
    599 {
    600   return FatSetOrGetInfo (TRUE, FHand, Type, &BufferSize, Buffer);
    601 }
    602