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