1 /** @file
2   Internal file explorer helper functions for RamDiskDxe driver.
3 
4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this 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 #include "RamDiskImpl.h"
16 
17 
18 /**
19   Helper function called as part of the code needed to allocate the proper
20   sized buffer for various EFI interfaces.
21 
22   @param[in, out] Status     Current status.
23   @param[in, out] Buffer     Current allocated buffer, or NULL.
24   @param[in]      BufferSize Current buffer size needed.
25 
26   @retval  TRUE         If the buffer was reallocated and the caller should
27                         try the API again.
28   @retval  FALSE        The caller should not call this function again.
29 
30 **/
31 BOOLEAN
GrowBuffer(IN OUT EFI_STATUS * Status,IN OUT VOID ** Buffer,IN UINTN BufferSize)32 GrowBuffer (
33   IN OUT EFI_STATUS   *Status,
34   IN OUT VOID         **Buffer,
35   IN UINTN            BufferSize
36   )
37 {
38   BOOLEAN TryAgain;
39 
40   //
41   // If this is an initial request, buffer will be null with a new buffer size
42   //
43   if ((*Buffer == NULL) && (BufferSize != 0)) {
44     *Status = EFI_BUFFER_TOO_SMALL;
45   }
46   //
47   // If the status code is "buffer too small", resize the buffer
48   //
49   TryAgain = FALSE;
50   if (*Status == EFI_BUFFER_TOO_SMALL) {
51 
52     if (*Buffer != NULL) {
53       FreePool (*Buffer);
54     }
55 
56     *Buffer = AllocateZeroPool (BufferSize);
57 
58     if (*Buffer != NULL) {
59       TryAgain = TRUE;
60     } else {
61       *Status = EFI_OUT_OF_RESOURCES;
62     }
63   }
64   //
65   // If there's an error, free the buffer
66   //
67   if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) {
68     FreePool (*Buffer);
69     *Buffer = NULL;
70   }
71 
72   return TryAgain;
73 }
74 
75 
76 /**
77   This function gets the file information from an open file descriptor,
78   and stores it in a buffer allocated from pool.
79 
80   @param[in] FHand           File Handle.
81 
82   @return    A pointer to a buffer with file information or NULL is returned.
83 
84 **/
85 EFI_FILE_INFO *
FileInfo(IN EFI_FILE_HANDLE FHand)86 FileInfo (
87   IN EFI_FILE_HANDLE                        FHand
88   )
89 {
90   EFI_STATUS                           Status;
91   EFI_FILE_INFO                        *Buffer;
92   UINTN                                BufferSize;
93 
94   //
95   // Initialize for GrowBuffer loop
96   //
97   Buffer      = NULL;
98   BufferSize  = SIZE_OF_EFI_FILE_INFO + 200;
99 
100   //
101   // Call the real function
102   //
103   while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
104     Status = FHand->GetInfo (
105                       FHand,
106                       &gEfiFileInfoGuid,
107                       &BufferSize,
108                       Buffer
109                       );
110   }
111 
112   return Buffer;
113 }
114 
115 
116 /**
117   This function will open a file or directory referenced by DevicePath.
118 
119   This function opens a file with the open mode according to the file path. The
120   Attributes is valid only for EFI_FILE_MODE_CREATE.
121 
122   @param[in, out] FilePath   On input, the device path to the file.
123                              On output, the remaining device path.
124   @param[out]     FileHandle Pointer to the file handle.
125   @param[in]      OpenMode   The mode to open the file with.
126   @param[in]      Attributes The file's file attributes.
127 
128   @retval EFI_SUCCESS             The information was set.
129   @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.
130   @retval EFI_UNSUPPORTED         Could not open the file path.
131   @retval EFI_NOT_FOUND           The specified file could not be found on the
132                                   device or the file system could not be found
133                                   on the device.
134   @retval EFI_NO_MEDIA            The device has no medium.
135   @retval EFI_MEDIA_CHANGED       The device has a different medium in it or
136                                   the medium is no longer supported.
137   @retval EFI_DEVICE_ERROR        The device reported an error.
138   @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.
139   @retval EFI_WRITE_PROTECTED     The file or medium is write protected.
140   @retval EFI_ACCESS_DENIED       The file was opened read only.
141   @retval EFI_OUT_OF_RESOURCES    Not enough resources were available to open
142                                   the file.
143   @retval EFI_VOLUME_FULL         The volume is full.
144 **/
145 EFI_STATUS
146 EFIAPI
OpenFileByDevicePath(IN OUT EFI_DEVICE_PATH_PROTOCOL ** FilePath,OUT EFI_FILE_HANDLE * FileHandle,IN UINT64 OpenMode,IN UINT64 Attributes)147 OpenFileByDevicePath(
148   IN OUT EFI_DEVICE_PATH_PROTOCOL           **FilePath,
149   OUT EFI_FILE_HANDLE                       *FileHandle,
150   IN UINT64                                 OpenMode,
151   IN UINT64                                 Attributes
152   )
153 {
154   EFI_STATUS                           Status;
155   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL      *EfiSimpleFileSystemProtocol;
156   EFI_FILE_PROTOCOL                    *Handle1;
157   EFI_FILE_PROTOCOL                    *Handle2;
158   EFI_HANDLE                           DeviceHandle;
159 
160   if ((FilePath == NULL || FileHandle == NULL)) {
161     return EFI_INVALID_PARAMETER;
162   }
163 
164   Status = gBS->LocateDevicePath (
165                   &gEfiSimpleFileSystemProtocolGuid,
166                   FilePath,
167                   &DeviceHandle
168                   );
169   if (EFI_ERROR (Status)) {
170     return Status;
171   }
172 
173   Status = gBS->OpenProtocol(
174                   DeviceHandle,
175                   &gEfiSimpleFileSystemProtocolGuid,
176                   (VOID**)&EfiSimpleFileSystemProtocol,
177                   gImageHandle,
178                   NULL,
179                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
180                   );
181   if (EFI_ERROR (Status)) {
182     return Status;
183   }
184 
185   Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
186   if (EFI_ERROR (Status)) {
187     FileHandle = NULL;
188     return Status;
189   }
190 
191   //
192   // go down directories one node at a time.
193   //
194   while (!IsDevicePathEnd (*FilePath)) {
195     //
196     // For file system access each node should be a file path component
197     //
198     if (DevicePathType    (*FilePath) != MEDIA_DEVICE_PATH ||
199         DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
200        ) {
201       FileHandle = NULL;
202       return (EFI_INVALID_PARAMETER);
203     }
204     //
205     // Open this file path node
206     //
207     Handle2  = Handle1;
208     Handle1 = NULL;
209 
210     //
211     // Try to test opening an existing file
212     //
213     Status = Handle2->Open (
214                           Handle2,
215                           &Handle1,
216                           ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
217                           OpenMode &~EFI_FILE_MODE_CREATE,
218                           0
219                          );
220 
221     //
222     // see if the error was that it needs to be created
223     //
224     if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
225       Status = Handle2->Open (
226                             Handle2,
227                             &Handle1,
228                             ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
229                             OpenMode,
230                             Attributes
231                            );
232     }
233     //
234     // Close the last node
235     //
236     Handle2->Close (Handle2);
237 
238     if (EFI_ERROR(Status)) {
239       return (Status);
240     }
241 
242     //
243     // Get the next node
244     //
245     *FilePath = NextDevicePathNode (*FilePath);
246   }
247 
248   //
249   // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
250   //
251   *FileHandle = (VOID*)Handle1;
252   return EFI_SUCCESS;
253 }
254