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
FatGetFileInfo(IN FAT_OFILE * OFile,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
FatGetVolumeInfo(IN FAT_VOLUME * Volume,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
FatGetVolumeLabelInfo(IN FAT_VOLUME * Volume,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
FatSetVolumeInfo(IN FAT_VOLUME * Volume,IN UINTN BufferSize,IN VOID * Buffer)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
FatSetVolumeLabelInfo(IN FAT_VOLUME * Volume,IN UINTN BufferSize,IN VOID * Buffer)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
FatSetFileInfo(IN FAT_VOLUME * Volume,IN FAT_IFILE * IFile,IN FAT_OFILE * OFile,IN UINTN BufferSize,IN VOID * Buffer)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
FatSetOrGetInfo(IN BOOLEAN IsSet,IN EFI_FILE_PROTOCOL * FHand,IN EFI_GUID * Type,IN OUT UINTN * BufferSize,IN OUT VOID * Buffer)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
FatGetInfo(IN EFI_FILE_PROTOCOL * FHand,IN EFI_GUID * Type,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
FatSetInfo(IN EFI_FILE_PROTOCOL * FHand,IN EFI_GUID * Type,IN UINTN BufferSize,IN VOID * Buffer)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