1 /** @file
2   Routines dealing with file open.
3 
4 Copyright (c) 2005 - 2014, 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 #include "Fat.h"
16 
17 /**
18 
19   Create an Open instance for the existing OFile.
20   The IFile of the newly opened file is passed out.
21 
22   @param  OFile                 - The file that serves as a starting reference point.
23   @param  PtrIFile              - The newly generated IFile instance.
24 
25   @retval EFI_OUT_OF_RESOURCES  - Can not allocate the memory for the IFile
26   @retval EFI_SUCCESS           - Create the new IFile for the OFile successfully
27 
28 **/
29 EFI_STATUS
FatAllocateIFile(IN FAT_OFILE * OFile,OUT FAT_IFILE ** PtrIFile)30 FatAllocateIFile (
31   IN FAT_OFILE    *OFile,
32   OUT FAT_IFILE   **PtrIFile
33   )
34 {
35   FAT_IFILE *IFile;
36 
37   ASSERT_VOLUME_LOCKED (OFile->Volume);
38 
39   //
40   // Allocate a new open instance
41   //
42   IFile = AllocateZeroPool (sizeof (FAT_IFILE));
43   if (IFile == NULL) {
44     return EFI_OUT_OF_RESOURCES;
45   }
46 
47   IFile->Signature = FAT_IFILE_SIGNATURE;
48 
49   CopyMem (&(IFile->Handle), &FatFileInterface, sizeof (EFI_FILE_PROTOCOL));
50 
51   //
52   // Report the correct revision number based on the DiskIo2 availability
53   //
54   if (OFile->Volume->DiskIo2 != NULL) {
55     IFile->Handle.Revision = EFI_FILE_PROTOCOL_REVISION2;
56   } else {
57     IFile->Handle.Revision = EFI_FILE_PROTOCOL_REVISION;
58   }
59 
60   IFile->OFile = OFile;
61   InsertTailList (&OFile->Opens, &IFile->Link);
62   InitializeListHead (&IFile->Tasks);
63 
64   *PtrIFile = IFile;
65   return EFI_SUCCESS;
66 }
67 
68 /**
69 
70   Open a file for a file name relative to an existing OFile.
71   The IFile of the newly opened file is passed out.
72 
73   @param  OFile                 - The file that serves as a starting reference point.
74   @param  NewIFile              - The newly generated IFile instance.
75   @param  FileName              - The file name relative to the OFile.
76   @param  OpenMode              - Open mode.
77   @param  Attributes            - Attributes to set if the file is created.
78 
79 
80   @retval EFI_SUCCESS           - Open the file successfully.
81   @retval EFI_INVALID_PARAMETER - The open mode is conflict with the attributes
82                           or the file name is not valid.
83   @retval EFI_NOT_FOUND         - Conficts between dir intention and attribute.
84   @retval EFI_WRITE_PROTECTED   - Can't open for write if the volume is read only.
85   @retval EFI_ACCESS_DENIED     - If the file's attribute is read only, and the
86                           open is for read-write fail it.
87   @retval EFI_OUT_OF_RESOURCES  - Can not allocate the memory.
88 
89 **/
90 EFI_STATUS
FatOFileOpen(IN FAT_OFILE * OFile,OUT FAT_IFILE ** NewIFile,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT8 Attributes)91 FatOFileOpen (
92   IN  FAT_OFILE            *OFile,
93   OUT FAT_IFILE            **NewIFile,
94   IN  CHAR16               *FileName,
95   IN  UINT64               OpenMode,
96   IN  UINT8                Attributes
97   )
98 {
99   FAT_VOLUME  *Volume;
100   EFI_STATUS  Status;
101   CHAR16      NewFileName[EFI_PATH_STRING_LENGTH];
102   FAT_DIRENT  *DirEnt;
103   UINT8       FileAttributes;
104   BOOLEAN     WriteMode;
105 
106   DirEnt = NULL;
107   Volume = OFile->Volume;
108   ASSERT_VOLUME_LOCKED (Volume);
109   WriteMode = (BOOLEAN) (OpenMode & EFI_FILE_MODE_WRITE);
110   if (Volume->ReadOnly && WriteMode) {
111     return EFI_WRITE_PROTECTED;
112   }
113   //
114   // Verify the source file handle isn't in an error state
115   //
116   Status = OFile->Error;
117   if (EFI_ERROR (Status)) {
118     return Status;
119   }
120   //
121   // Get new OFile for the file
122   //
123   Status = FatLocateOFile (&OFile, FileName, Attributes, NewFileName);
124   if (EFI_ERROR (Status)) {
125     return Status;
126   }
127 
128   if (*NewFileName != 0) {
129     //
130     // If there's a remaining part of the name, then we had
131     // better be creating the file in the directory
132     //
133     if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) {
134       return EFI_NOT_FOUND;
135     }
136 
137     Status = FatCreateDirEnt (OFile, NewFileName, Attributes, &DirEnt);
138     if (EFI_ERROR (Status)) {
139       return Status;
140     }
141 
142     ASSERT (DirEnt != NULL);
143     Status = FatOpenDirEnt (OFile, DirEnt);
144     if (EFI_ERROR (Status)) {
145       return Status;
146     }
147 
148     OFile = DirEnt->OFile;
149     if (OFile->ODir != NULL) {
150       //
151       // If we just created a directory, we need to create "." and ".."
152       //
153       Status = FatCreateDotDirEnts (OFile);
154       if (EFI_ERROR (Status)) {
155         return Status;
156       }
157     }
158   }
159   //
160   // If the file's attribute is read only, and the open is for
161   // read-write, then the access is denied.
162   //
163   FileAttributes = OFile->DirEnt->Entry.Attributes;
164   if ((FileAttributes & EFI_FILE_READ_ONLY) != 0 && (FileAttributes & FAT_ATTRIBUTE_DIRECTORY) == 0 && WriteMode) {
165     return EFI_ACCESS_DENIED;
166   }
167   //
168   // Create an open instance of the OFile
169   //
170   Status = FatAllocateIFile (OFile, NewIFile);
171   if (EFI_ERROR (Status)) {
172     return Status;
173   }
174 
175   (*NewIFile)->ReadOnly = (BOOLEAN)!WriteMode;
176 
177   DEBUG ((EFI_D_INFO, "FSOpen: Open '%S' %r\n", FileName, Status));
178   return FatOFileFlush (OFile);
179 }
180 
181 /**
182 
183   Implements OpenEx() of Simple File System Protocol.
184 
185   @param  FHand                 - File handle of the file serves as a starting reference point.
186   @param  NewHandle             - Handle of the file that is newly opened.
187   @param  FileName              - File name relative to FHand.
188   @param  OpenMode              - Open mode.
189   @param  Attributes            - Attributes to set if the file is created.
190   @param  Token                 - A pointer to the token associated with the transaction.:
191 
192   @retval EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.
193                           The OpenMode is not supported.
194                           The Attributes is not the valid attributes.
195   @retval EFI_OUT_OF_RESOURCES  - Can not allocate the memory for file string.
196   @retval EFI_SUCCESS           - Open the file successfully.
197   @return Others                - The status of open file.
198 
199 **/
200 EFI_STATUS
201 EFIAPI
FatOpenEx(IN EFI_FILE_PROTOCOL * FHand,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes,IN OUT EFI_FILE_IO_TOKEN * Token)202 FatOpenEx (
203   IN  EFI_FILE_PROTOCOL       *FHand,
204   OUT EFI_FILE_PROTOCOL       **NewHandle,
205   IN  CHAR16                  *FileName,
206   IN  UINT64                  OpenMode,
207   IN  UINT64                  Attributes,
208   IN OUT EFI_FILE_IO_TOKEN    *Token
209   )
210 {
211   FAT_IFILE   *IFile;
212   FAT_IFILE   *NewIFile;
213   FAT_OFILE   *OFile;
214   EFI_STATUS  Status;
215   FAT_TASK    *Task;
216 
217   //
218   // Perform some parameter checking
219   //
220   if (FileName == NULL) {
221     return EFI_INVALID_PARAMETER;
222   }
223   //
224   // Check for a valid mode
225   //
226   switch (OpenMode) {
227   case EFI_FILE_MODE_READ:
228   case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
229   case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
230     break;
231 
232   default:
233     return EFI_INVALID_PARAMETER;
234   }
235 
236   //
237   // Check for valid Attributes for file creation case.
238   //
239   if (((OpenMode & EFI_FILE_MODE_CREATE) != 0) && (Attributes & (EFI_FILE_READ_ONLY | (~EFI_FILE_VALID_ATTR))) != 0) {
240     return EFI_INVALID_PARAMETER;
241   }
242 
243   IFile = IFILE_FROM_FHAND (FHand);
244   OFile = IFile->OFile;
245   Task  = NULL;
246 
247   if (Token == NULL) {
248     FatWaitNonblockingTask (IFile);
249   } else {
250     //
251     // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.
252     // But if it calls, the below check can avoid crash.
253     //
254     if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {
255       return EFI_UNSUPPORTED;
256     }
257     Task = FatCreateTask (IFile, Token);
258     if (Task == NULL) {
259       return EFI_OUT_OF_RESOURCES;
260     }
261   }
262 
263   //
264   // Lock
265   //
266   FatAcquireLock ();
267 
268   //
269   // Open the file
270   //
271   Status = FatOFileOpen (OFile, &NewIFile, FileName, OpenMode, (UINT8) Attributes);
272 
273   //
274   // If the file was opened, return the handle to the caller
275   //
276   if (!EFI_ERROR (Status)) {
277     *NewHandle = &NewIFile->Handle;
278   }
279   //
280   // Unlock
281   //
282   Status = FatCleanupVolume (OFile->Volume, NULL, Status, Task);
283   FatReleaseLock ();
284 
285   if (Token != NULL) {
286     if (!EFI_ERROR (Status)) {
287       Status = FatQueueTask (IFile, Task);
288     } else {
289       FatDestroyTask (Task);
290     }
291   }
292 
293   return Status;
294 }
295 
296 /**
297 
298   Implements Open() of Simple File System Protocol.
299 
300 
301   @param   FHand                 - File handle of the file serves as a starting reference point.
302   @param   NewHandle             - Handle of the file that is newly opened.
303   @param   FileName              - File name relative to FHand.
304   @param   OpenMode              - Open mode.
305   @param   Attributes            - Attributes to set if the file is created.
306 
307   @retval EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.
308                           The OpenMode is not supported.
309                           The Attributes is not the valid attributes.
310   @retval EFI_OUT_OF_RESOURCES  - Can not allocate the memory for file string.
311   @retval EFI_SUCCESS           - Open the file successfully.
312   @return Others                - The status of open file.
313 
314 **/
315 EFI_STATUS
316 EFIAPI
FatOpen(IN EFI_FILE_PROTOCOL * FHand,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes)317 FatOpen (
318   IN  EFI_FILE_PROTOCOL   *FHand,
319   OUT EFI_FILE_PROTOCOL   **NewHandle,
320   IN  CHAR16              *FileName,
321   IN  UINT64              OpenMode,
322   IN  UINT64              Attributes
323   )
324 {
325   return FatOpenEx (FHand, NewHandle, FileName, OpenMode, Attributes, NULL);
326 }
327