]>
Commit | Line | Data |
---|---|---|
2aa62f2b | 1 | /** @file\r |
2 | EFI versions of NetBSD system calls.\r | |
3 | \r | |
a7a8363d | 4 | Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r |
2aa62f2b | 5 | This program and the accompanying materials are licensed and made available under\r |
6 | the terms and conditions of the BSD License that accompanies this distribution.\r | |
7 | The full text of the license may be found at\r | |
8 | http://opensource.org/licenses/bsd-license.\r | |
9 | \r | |
10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
12 | \r | |
13 | **/\r | |
14 | #include <Uefi.h>\r | |
15 | #include <Library/UefiLib.h>\r | |
53e1e5c6 | 16 | #include <Library/UefiBootServicesTableLib.h>\r |
2aa62f2b | 17 | #include <Library/BaseLib.h>\r |
18 | #include <Library/MemoryAllocationLib.h>\r | |
19 | #include <Library/ShellLib.h>\r | |
20 | \r | |
21 | #include <LibConfig.h>\r | |
22 | #include <sys/EfiCdefs.h>\r | |
23 | \r | |
24 | #include <sys/ansi.h>\r | |
25 | #include <errno.h>\r | |
26 | #include <stdarg.h>\r | |
53e1e5c6 | 27 | #include <stdlib.h>\r |
2aa62f2b | 28 | #include <string.h>\r |
29 | #include <wchar.h>\r | |
53e1e5c6 | 30 | #include <sys/poll.h>\r |
2aa62f2b | 31 | #include <sys/fcntl.h>\r |
32 | #include <sys/stat.h>\r | |
33 | #include <sys/syslimits.h>\r | |
0c1992fb | 34 | #include <sys/filio.h>\r |
53e1e5c6 | 35 | #include <Efi/SysEfi.h>\r |
0c1992fb | 36 | #include <unistd.h>\r |
53e1e5c6 | 37 | #include <kfile.h>\r |
38 | #include <Device/Device.h>\r | |
6c6c850a | 39 | #include <Device/IIO.h>\r |
2aa62f2b | 40 | #include <MainData.h>\r |
0c1992fb | 41 | #include <extern.h>\r |
2aa62f2b | 42 | \r |
43 | /* EFI versions of BSD system calls used in stdio */\r | |
44 | \r | |
2aa62f2b | 45 | /* Validate that fd refers to a valid file descriptor.\r |
46 | IsOpen is interpreted as follows:\r | |
47 | - Positive fd must be OPEN\r | |
48 | - Zero fd must be CLOSED\r | |
49 | - Negative fd may be OPEN or CLOSED\r | |
50 | \r | |
51 | @retval TRUE fd is VALID\r | |
52 | @retval FALSE fd is INVALID\r | |
53 | */\r | |
53e1e5c6 | 54 | BOOLEAN\r |
2aa62f2b | 55 | ValidateFD( int fd, int IsOpen)\r |
56 | {\r | |
53e1e5c6 | 57 | struct __filedes *filp;\r |
2aa62f2b | 58 | BOOLEAN retval = FALSE;\r |
59 | \r | |
60 | if((fd >= 0) && (fd < OPEN_MAX)) {\r | |
53e1e5c6 | 61 | filp = &gMD->fdarray[fd];\r |
2aa62f2b | 62 | retval = TRUE;\r |
63 | if(IsOpen >= 0) {\r | |
53e1e5c6 | 64 | retval = (BOOLEAN)((filp->f_iflags != 0) && // TRUE if OPEN\r |
65 | FILE_IS_USABLE(filp)); // and Usable (not Larval or Closing)\r | |
2aa62f2b | 66 | if(IsOpen == VALID_CLOSED) {\r |
67 | retval = (BOOLEAN)!retval; // We want TRUE if CLOSED\r | |
68 | }\r | |
69 | }\r | |
70 | }\r | |
71 | return retval;\r | |
72 | }\r | |
73 | \r | |
74 | /* Find and reserve a free File Descriptor.\r | |
75 | \r | |
76 | Returns the first free File Descriptor greater than or equal to the,\r | |
77 | already validated, fd specified by Minfd.\r | |
78 | \r | |
79 | @return Returns -1 if there are no free FDs. Otherwise returns the\r | |
80 | found fd.\r | |
81 | */\r | |
53e1e5c6 | 82 | int\r |
2aa62f2b | 83 | FindFreeFD( int MinFd )\r |
84 | {\r | |
85 | struct __filedes *Mfd;\r | |
86 | int i;\r | |
87 | int fd = -1;\r | |
88 | \r | |
89 | Mfd = gMD->fdarray;\r | |
90 | \r | |
91 | // Get an available fd\r | |
92 | for(i=MinFd; i < OPEN_MAX; ++i) {\r | |
53e1e5c6 | 93 | if(Mfd[i].f_iflags == 0) {\r |
94 | Mfd[i].f_iflags = FIF_LARVAL; // Temporarily mark this fd as reserved\r | |
2aa62f2b | 95 | fd = i;\r |
96 | break;\r | |
97 | }\r | |
98 | }\r | |
99 | return fd;\r | |
100 | }\r | |
101 | \r | |
53e1e5c6 | 102 | /* Mark that an open file is to be deleted when closed. */\r |
103 | int\r | |
104 | DeleteOnClose(int fd)\r | |
105 | {\r | |
106 | int retval = 0;\r | |
107 | \r | |
108 | if(ValidateFD( fd, VALID_OPEN)) {\r | |
109 | gMD->fdarray[fd].f_iflags |= FIF_DELCLOSE;\r | |
110 | }\r | |
111 | else {\r | |
112 | errno = EBADF;\r | |
113 | retval = -1;\r | |
114 | }\r | |
115 | return retval;\r | |
116 | }\r | |
117 | \r | |
6c6c850a | 118 | /** The isatty() function tests whether fd, an open file descriptor,\r |
2aa62f2b | 119 | is associated with a terminal device.\r |
120 | \r | |
6c6c850a | 121 | @param[in] fd File Descriptor for the file to be examined.\r |
122 | \r | |
123 | @retval 1 fd is associated with a terminal.\r | |
124 | @retval 0 fd is not associated with a terminal. errno is set to\r | |
125 | EBADF if fd is not a valid open FD.\r | |
2aa62f2b | 126 | **/\r |
127 | int\r | |
53e1e5c6 | 128 | isatty (int fd)\r |
2aa62f2b | 129 | {\r |
130 | int retval = 0;\r | |
53e1e5c6 | 131 | struct __filedes *Fp;\r |
2aa62f2b | 132 | \r |
53e1e5c6 | 133 | if(ValidateFD( fd, VALID_OPEN)) {\r |
134 | Fp = &gMD->fdarray[fd];\r | |
6c6c850a | 135 | retval = (Fp->f_iflags & _S_ITTY) ? 1 : 0;\r |
2aa62f2b | 136 | }\r |
137 | else {\r | |
138 | errno = EBADF;\r | |
139 | }\r | |
140 | return retval;\r | |
141 | }\r | |
142 | \r | |
0c1992fb | 143 | /** Determine if file descriptor fd is a duplicate of some other fd.\r |
144 | \r | |
145 | @param[in] fd The file descriptor to check.\r | |
146 | \r | |
147 | @retval TRUE fd is a duplicate of another fd.\r | |
148 | @retval FALSE fd is unique.\r | |
149 | **/\r | |
2aa62f2b | 150 | static BOOLEAN\r |
151 | IsDupFd( int fd)\r | |
152 | {\r | |
53e1e5c6 | 153 | void * DevData;\r |
154 | const struct fileops *FileOps;\r | |
2aa62f2b | 155 | int i;\r |
156 | BOOLEAN Ret = FALSE;\r | |
157 | \r | |
158 | if(ValidateFD( fd, VALID_OPEN )) {\r | |
53e1e5c6 | 159 | FileOps = gMD->fdarray[fd].f_ops;\r |
160 | DevData = gMD->fdarray[fd].devdata;\r | |
2aa62f2b | 161 | for(i=0; i < OPEN_MAX; ++i) {\r |
162 | if(i == fd) continue;\r | |
53e1e5c6 | 163 | if(ValidateFD( i, VALID_OPEN )) { // TRUE if fd is valid and OPEN\r |
164 | if((gMD->fdarray[i].f_ops == FileOps)\r | |
165 | &&(gMD->fdarray[i].devdata == DevData )) {\r | |
2aa62f2b | 166 | Ret = TRUE;\r |
167 | break;\r | |
168 | }\r | |
169 | }\r | |
170 | }\r | |
171 | }\r | |
172 | return Ret;\r | |
173 | }\r | |
174 | \r | |
6c6c850a | 175 | /** Worker function to Close a file and set its fd to the specified state.\r |
0c1992fb | 176 | \r |
177 | @param[in] fd The file descriptor to close.\r | |
178 | @param[in] NewState State to set the fd to after the file is closed.\r | |
179 | \r | |
180 | @retval 0 The operation completed successfully.\r | |
181 | @retval -1 The operation failed. Further information is in errno.\r | |
6c6c850a | 182 | * EBADF fd is not a valid or open file descriptor.\r |
0c1992fb | 183 | **/\r |
2aa62f2b | 184 | static int\r |
185 | _closeX (int fd, int NewState)\r | |
186 | {\r | |
53e1e5c6 | 187 | struct __filedes *Fp;\r |
2aa62f2b | 188 | int retval = 0;\r |
189 | \r | |
2aa62f2b | 190 | // Verify my pointers and get my FD.\r |
191 | if(ValidateFD( fd, VALID_OPEN )) {\r | |
53e1e5c6 | 192 | Fp = &gMD->fdarray[fd];\r |
193 | // Check if there are other users of this FileHandle\r | |
194 | if(Fp->RefCount == 1) { // There should be no other users\r | |
2aa62f2b | 195 | if(! IsDupFd(fd)) {\r |
196 | // Only do the close if no one else is using the FileHandle\r | |
48831246 | 197 | if(Fp->f_iflags & FIF_DELCLOSE) {\r |
198 | /* Handle files marked "Delete on Close". */\r | |
199 | if(Fp->f_ops->fo_delete != NULL) {\r | |
200 | retval = Fp->f_ops->fo_delete(Fp);\r | |
201 | }\r | |
2aa62f2b | 202 | }\r |
203 | else {\r | |
53e1e5c6 | 204 | retval = Fp->f_ops->fo_close( Fp);\r |
2aa62f2b | 205 | }\r |
206 | }\r | |
53e1e5c6 | 207 | Fp->f_iflags = NewState; // Close this FD or reserve it\r |
208 | Fp->RefCount = 0; // No one using this FD\r | |
209 | }\r | |
210 | else {\r | |
211 | --Fp->RefCount; /* One less user of this FD */\r | |
2aa62f2b | 212 | }\r |
213 | }\r | |
214 | else {\r | |
215 | // Bad FD\r | |
2aa62f2b | 216 | retval = -1;\r |
53e1e5c6 | 217 | errno = EBADF;\r |
2aa62f2b | 218 | }\r |
219 | return retval;\r | |
220 | }\r | |
221 | \r | |
0c1992fb | 222 | /** The close() function deallocates the file descriptor indicated by fd.\r |
2aa62f2b | 223 | To deallocate means to make the file descriptor available for return by\r |
224 | subsequent calls to open() or other functions that allocate file\r | |
225 | descriptors. All outstanding record locks owned by the process on the file\r | |
0c1992fb | 226 | associated with the file descriptor are removed (that is, unlocked).\r |
2aa62f2b | 227 | \r |
6c6c850a | 228 | @param[in] fd Descriptor for the File to close.\r |
229 | \r | |
0c1992fb | 230 | @retval 0 Successful completion.\r |
231 | @retval -1 An error occurred and errno is set to identify the error.\r | |
2aa62f2b | 232 | **/\r |
233 | int\r | |
234 | close (int fd)\r | |
235 | {\r | |
2aa62f2b | 236 | return _closeX(fd, 0);\r |
237 | }\r | |
238 | \r | |
6c6c850a | 239 | /** Delete the file specified by path.\r |
240 | \r | |
241 | @param[in] path The MBCS path of the file to delete.\r | |
242 | \r | |
243 | @retval -1 Unable to open the file specified by path.\r | |
244 | @retval -1 If (errno == EPERM), unlink is not permited for this file.\r | |
245 | @retval -1 Low-level delete filed. Reason is in errno.\r | |
246 | @retval 0 The file was successfully deleted.\r | |
53e1e5c6 | 247 | **/\r |
2aa62f2b | 248 | int\r |
53e1e5c6 | 249 | unlink (const char *path)\r |
2aa62f2b | 250 | {\r |
53e1e5c6 | 251 | struct __filedes *Fp;\r |
252 | int fd;\r | |
253 | int retval = -1;\r | |
2aa62f2b | 254 | \r |
255 | EFIerrno = RETURN_SUCCESS;\r | |
256 | \r | |
53e1e5c6 | 257 | fd = open(path, O_WRONLY, 0);\r |
258 | if(fd >= 0) {\r | |
259 | Fp = &gMD->fdarray[fd];\r | |
260 | \r | |
261 | if(Fp->f_ops->fo_delete != NULL) {\r | |
262 | retval = Fp->f_ops->fo_delete(Fp);\r | |
2aa62f2b | 263 | }\r |
53e1e5c6 | 264 | Fp->f_iflags = 0; // Close this FD\r |
265 | Fp->RefCount = 0; // No one using this FD\r | |
2aa62f2b | 266 | }\r |
53e1e5c6 | 267 | return retval;\r |
2aa62f2b | 268 | }\r |
269 | \r | |
270 | /** The fcntl() function shall perform the operations described below on open\r | |
271 | files. The fildes argument is a file descriptor.\r | |
272 | \r | |
273 | The available values for cmd are defined in <fcntl.h> and are as follows:\r | |
274 | - F_DUPFD - Return a new file descriptor which shall be the lowest\r | |
275 | numbered available (that is, not already open) file\r | |
276 | descriptor greater than or equal to the third argument, arg,\r | |
277 | taken as an integer of type int. The new file descriptor\r | |
278 | shall refer to the same open file description as the original\r | |
279 | file descriptor, and shall share any locks. The FD_CLOEXEC\r | |
280 | flag associated with the new file descriptor shall be cleared\r | |
281 | to keep the file open across calls to one of the exec functions.\r | |
282 | - F_GETFD - Get the file descriptor flags defined in <fcntl.h> that are\r | |
283 | associated with the file descriptor fildes. File descriptor\r | |
284 | flags are associated with a single file descriptor and do not\r | |
285 | affect other file descriptors that refer to the same file.\r | |
286 | - F_SETFD - Set the file descriptor flags defined in <fcntl.h>, that are\r | |
287 | associated with fildes, to the third argument, arg, taken\r | |
288 | as type int. If the FD_CLOEXEC flag in the third argument\r | |
289 | is 0, the file shall remain open across the exec\r | |
290 | functions; otherwise, the file shall be closed upon\r | |
291 | successful execution of one of the exec functions.\r | |
292 | - F_GETFL - Get the file status flags and file access modes, defined in\r | |
293 | <fcntl.h>, for the file description associated with fildes.\r | |
294 | The file access modes can be extracted from the return\r | |
295 | value using the mask O_ACCMODE, which is defined in\r | |
296 | <fcntl.h>. File status flags and file access modes are\r | |
297 | associated with the file description and do not affect\r | |
298 | other file descriptors that refer to the same file with\r | |
299 | different open file descriptions.\r | |
300 | - F_SETFL - Set the file status flags, defined in <fcntl.h>, for the file\r | |
301 | description associated with fildes from the corresponding\r | |
302 | bits in the third argument, arg, taken as type int. Bits\r | |
303 | corresponding to the file access mode and the file creation\r | |
304 | flags, as defined in <fcntl.h>, that are set in arg shall\r | |
305 | be ignored. If any bits in arg other than those mentioned\r | |
306 | here are changed by the application, the result is unspecified.\r | |
307 | - F_GETOWN - If fildes refers to a socket, get the process or process group\r | |
308 | ID specified to receive SIGURG signals when out-of-band\r | |
309 | data is available. Positive values indicate a process ID;\r | |
310 | negative values, other than -1, indicate a process group\r | |
311 | ID. If fildes does not refer to a socket, the results are\r | |
312 | unspecified.\r | |
313 | - F_SETOWN - If fildes refers to a socket, set the process or process\r | |
314 | group ID specified to receive SIGURG signals when\r | |
315 | out-of-band data is available, using the value of the third\r | |
316 | argument, arg, taken as type int. Positive values indicate\r | |
317 | a process ID; negative values, other than -1, indicate a\r | |
318 | process group ID. If fildes does not refer to a socket, the\r | |
319 | results are unspecified.\r | |
320 | \r | |
321 | The fcntl() function shall fail if:\r | |
322 | \r | |
323 | [EBADF] The fildes argument is not a valid open file descriptor.\r | |
324 | [EINVAL] The cmd argument is invalid, or the cmd argument is F_DUPFD\r | |
325 | and arg is negative or greater than or equal to {OPEN_MAX}.\r | |
326 | [EMFILE] The argument cmd is F_DUPFD and {OPEN_MAX} file descriptors\r | |
327 | are currently open in the calling process, or no file\r | |
328 | descriptors greater than or equal to arg are available.\r | |
329 | [EOVERFLOW] One of the values to be returned cannot be represented correctly.\r | |
330 | \r | |
6c6c850a | 331 | @param[in] fildes Descriptor for the file to be controlled.\r |
332 | @param[in] cmd Command to be acted upon.\r | |
333 | @param[in,out] ... Optional additional parameters as required by cmd.\r | |
334 | \r | |
2aa62f2b | 335 | @return Upon successful completion, the value returned shall depend on\r |
336 | cmd as follows:\r | |
337 | - F_DUPFD - A new file descriptor.\r | |
338 | - F_GETFD - Value of flags defined in <fcntl.h>. The return value\r | |
339 | shall not be negative.\r | |
340 | - F_SETFD - Value other than -1.\r | |
341 | - F_GETFL - Value of file status flags and access modes. The return\r | |
342 | value is not negative.\r | |
343 | - F_SETFL - Value other than -1.\r | |
344 | - F_GETOWN - Value of the socket owner process or process group;\r | |
345 | this will not be -1.\r | |
346 | - F_SETOWN - Value other than -1.\r | |
347 | Otherwise, -1 shall be returned and errno set to indicate the error.\r | |
348 | \r | |
349 | **/\r | |
350 | int\r | |
351 | fcntl (int fildes, int cmd, ...)\r | |
352 | {\r | |
353 | va_list p3;\r | |
354 | struct __filedes *MyFd;\r | |
355 | int retval = -1;\r | |
356 | int temp;\r | |
357 | \r | |
358 | //Print(L"%a( %d, %d, ...)\n", __func__, fildes, cmd);\r | |
359 | va_start(p3, cmd);\r | |
360 | \r | |
361 | if(ValidateFD( fildes, VALID_OPEN )) {\r | |
362 | MyFd = &gMD->fdarray[fildes];\r | |
363 | \r | |
364 | switch(cmd) {\r | |
365 | case F_DUPFD:\r | |
366 | temp = va_arg(p3, int);\r | |
367 | if(ValidateFD( temp, VALID_DONT_CARE )) {\r | |
368 | temp = FindFreeFD( temp );\r | |
369 | if(temp < 0) {\r | |
370 | errno = EMFILE;\r | |
371 | break;\r | |
372 | }\r | |
373 | /* temp is now a valid fd reserved for further use\r | |
374 | so copy fd into temp.\r | |
375 | */\r | |
376 | (void)memcpy(&gMD->fdarray[temp], MyFd, sizeof(struct __filedes));\r | |
377 | retval = temp;\r | |
378 | }\r | |
379 | else {\r | |
380 | errno = EINVAL;\r | |
381 | }\r | |
382 | break;\r | |
0c1992fb | 383 | \r |
2aa62f2b | 384 | case F_SETFL:\r |
385 | retval = MyFd->Oflags; // Get original value\r | |
386 | temp = va_arg(p3, int);\r | |
387 | temp &= O_SETMASK; // Only certain bits can be set\r | |
388 | temp |= retval & O_SETMASK;\r | |
389 | MyFd->Oflags = temp; // Set new value\r | |
390 | break;\r | |
0c1992fb | 391 | \r |
2aa62f2b | 392 | case F_SETFD:\r |
53e1e5c6 | 393 | retval = MyFd->f_iflags;\r |
2aa62f2b | 394 | break;\r |
53e1e5c6 | 395 | //case F_SETOWN:\r |
396 | // retval = MyFd->SocProc;\r | |
397 | // MyFd->SocProc = va_arg(p3, int);\r | |
398 | // break;\r | |
2aa62f2b | 399 | case F_GETFD:\r |
53e1e5c6 | 400 | retval = MyFd->f_iflags;\r |
2aa62f2b | 401 | break;\r |
402 | case F_GETFL:\r | |
2aa62f2b | 403 | retval = MyFd->Oflags;\r |
404 | break;\r | |
53e1e5c6 | 405 | //case F_GETOWN:\r |
406 | // retval = MyFd->SocProc;\r | |
407 | // break;\r | |
2aa62f2b | 408 | default:\r |
409 | errno = EINVAL;\r | |
410 | break;\r | |
411 | }\r | |
412 | }\r | |
413 | else {\r | |
414 | // Bad FD\r | |
415 | errno = EBADF;\r | |
416 | }\r | |
417 | va_end(p3);\r | |
418 | return retval;;\r | |
419 | }\r | |
420 | \r | |
421 | /** The dup() function provides an alternative interface to the\r | |
422 | service provided by fcntl() using the F_DUPFD command. The call:\r | |
423 | - fid = dup(fildes);\r | |
424 | shall be equivalent to:\r | |
425 | - fid = fcntl(fildes, F_DUPFD, 0);\r | |
426 | \r | |
6c6c850a | 427 | @param[in] fildes Descriptor for the file to be examined.\r |
428 | \r | |
2aa62f2b | 429 | @return Upon successful completion a non-negative integer, namely the\r |
430 | file descriptor, shall be returned; otherwise, -1 shall be\r | |
431 | returned and errno set to indicate the error.\r | |
432 | **/\r | |
433 | int\r | |
434 | dup (int fildes)\r | |
435 | {\r | |
436 | return fcntl(fildes, F_DUPFD, 0);\r | |
437 | }\r | |
438 | \r | |
6c6c850a | 439 | /** Make fildes2 refer to a duplicate of fildes.\r |
440 | \r | |
441 | The dup2() function provides an alternative interface to the\r | |
2aa62f2b | 442 | service provided by fcntl() using the F_DUPFD command. The call:\r |
443 | - fid = dup2(fildes, fildes2);\r | |
444 | shall be equivalent to:\r | |
445 | - close(fildes2);\r | |
446 | - fid = fcntl(fildes, F_DUPFD, fildes2);\r | |
447 | except for the following:\r | |
448 | - If fildes2 is less than 0 or greater than or equal to {OPEN_MAX},\r | |
449 | dup2() shall return -1 with errno set to [EBADF].\r | |
450 | - If fildes is a valid file descriptor and is equal to fildes2, dup2()\r | |
451 | shall return fildes2 without closing it.\r | |
452 | - If fildes is not a valid file descriptor, dup2() shall return -1 and\r | |
453 | shall not close fildes2.\r | |
454 | - The value returned shall be equal to the value of fildes2 upon\r | |
455 | successful completion, or -1 upon failure.\r | |
456 | \r | |
6c6c850a | 457 | @param[in] fildes File Descriptor to be duplicated.\r |
458 | @param[in] fildes2 File Descriptor to be made a duplicate of fildes.\r | |
459 | \r | |
2aa62f2b | 460 | @return Upon successful completion a non-negative integer, namely\r |
461 | fildes2, shall be returned; otherwise, -1 shall be\r | |
462 | returned and errno set to EBADF indicate the error.\r | |
463 | **/\r | |
464 | int\r | |
465 | dup2 (int fildes, int fildes2)\r | |
466 | {\r | |
467 | int retval = -1;\r | |
468 | \r | |
469 | if(ValidateFD( fildes, VALID_OPEN)) {\r | |
470 | retval = fildes2;\r | |
471 | if( fildes != fildes2) {\r | |
472 | if(ValidateFD( fildes2, VALID_DONT_CARE)) {\r | |
53e1e5c6 | 473 | gMD->fdarray[fildes2].f_iflags = FIF_LARVAL; // Mark the file closed, but reserved\r |
2aa62f2b | 474 | (void)memcpy(&gMD->fdarray[fildes2], // Duplicate fildes into fildes2\r |
475 | &gMD->fdarray[fildes], sizeof(struct __filedes));\r | |
53e1e5c6 | 476 | gMD->fdarray[fildes2].MyFD = (UINT16)fildes2;\r |
2aa62f2b | 477 | }\r |
478 | else {\r | |
479 | errno = EBADF;\r | |
480 | retval = -1;\r | |
481 | }\r | |
482 | }\r | |
483 | }\r | |
484 | else {\r | |
485 | errno = EBADF;\r | |
486 | }\r | |
487 | return retval;\r | |
488 | }\r | |
489 | \r | |
490 | /** Reposition a file's read/write offset.\r | |
491 | \r | |
492 | The lseek() function repositions the offset of the file descriptor fildes\r | |
493 | to the argument offset according to the directive how. The argument\r | |
494 | fildes must be an open file descriptor. lseek() repositions the file\r | |
495 | pointer fildes as follows:\r | |
496 | \r | |
6c6c850a | 497 | - If how is SEEK_SET, the offset is set to offset bytes.\r |
2aa62f2b | 498 | \r |
6c6c850a | 499 | - If how is SEEK_CUR, the offset is set to its current location\r |
500 | plus offset bytes.\r | |
2aa62f2b | 501 | \r |
6c6c850a | 502 | - If how is SEEK_END, the offset is set to the size of the file\r |
503 | plus offset bytes.\r | |
2aa62f2b | 504 | \r |
505 | The lseek() function allows the file offset to be set beyond the end of\r | |
506 | the existing end-of-file of the file. If data is later written at this\r | |
507 | point, subsequent reads of the data in the gap return bytes of zeros\r | |
508 | (until data is actually written into the gap).\r | |
509 | \r | |
510 | Some devices are incapable of seeking. The value of the pointer associ-\r | |
511 | ated with such a device is undefined.\r | |
512 | \r | |
6c6c850a | 513 | @param[in] fd Descriptor for the File to be affected.\r |
514 | @param[in] offset Value to adjust the file position by.\r | |
515 | @param[in] how How the file position is to be adjusted.\r | |
516 | \r | |
2aa62f2b | 517 | @return Upon successful completion, lseek() returns the resulting offset\r |
518 | location as measured in bytes from the beginning of the file.\r | |
519 | Otherwise, a value of -1 is returned and errno is set to\r | |
520 | indicate the error.\r | |
521 | **/\r | |
522 | __off_t\r | |
53e1e5c6 | 523 | lseek (int fd, __off_t offset, int how)\r |
2aa62f2b | 524 | {\r |
525 | __off_t CurPos = -1;\r | |
53e1e5c6 | 526 | // RETURN_STATUS Status = RETURN_SUCCESS;\r |
527 | struct __filedes *filp;\r | |
2aa62f2b | 528 | \r |
529 | EFIerrno = RETURN_SUCCESS; // In case of error without an EFI call\r | |
530 | \r | |
531 | if( how == SEEK_SET || how == SEEK_CUR || how == SEEK_END) {\r | |
53e1e5c6 | 532 | if(ValidateFD( fd, VALID_OPEN)) {\r |
533 | filp = &gMD->fdarray[fd];\r | |
2aa62f2b | 534 | // Both of our parameters have been verified as valid\r |
53e1e5c6 | 535 | CurPos = filp->f_ops->fo_lseek( filp, offset, how);\r |
536 | if(CurPos >= 0) {\r | |
537 | filp->f_offset = CurPos;\r | |
2aa62f2b | 538 | }\r |
539 | }\r | |
540 | else {\r | |
541 | errno = EBADF; // Bad File Descriptor\r | |
542 | }\r | |
543 | }\r | |
544 | else {\r | |
545 | errno = EINVAL; // Invalid how argument\r | |
546 | }\r | |
547 | return CurPos;\r | |
548 | }\r | |
549 | \r | |
550 | /** The directory path is created with the access permissions specified by\r | |
551 | perms.\r | |
552 | \r | |
553 | The directory is closed after it is created.\r | |
554 | \r | |
6c6c850a | 555 | @param[in] path The path to a directory to create.\r |
556 | @param[in] perms Permissions as defined in <sys/stat.h>\r | |
557 | \r | |
2aa62f2b | 558 | @retval 0 The directory was created successfully.\r |
53e1e5c6 | 559 | @retval -1 An error occurred and error codes are stored in errno and EFIerrno.\r |
2aa62f2b | 560 | **/\r |
561 | int\r | |
562 | mkdir (const char *path, __mode_t perms)\r | |
563 | {\r | |
53e1e5c6 | 564 | wchar_t *NewPath;\r |
565 | DeviceNode *Node;\r | |
566 | char *GenI;\r | |
0c1992fb | 567 | RETURN_STATUS Status;\r |
53e1e5c6 | 568 | int Instance = 0;\r |
569 | int retval = 0;\r | |
2aa62f2b | 570 | \r |
d7ce7006 | 571 | Status = ParsePath(path, &NewPath, &Node, &Instance, NULL);\r |
2aa62f2b | 572 | if(Status == RETURN_SUCCESS) {\r |
53e1e5c6 | 573 | GenI = Node->InstanceList;\r |
574 | if(GenI == NULL) {\r | |
575 | errno = EPERM;\r | |
576 | retval = -1;\r | |
2aa62f2b | 577 | }\r |
53e1e5c6 | 578 | else {\r |
d7ce7006 | 579 | //GenI += (Instance * Node->InstanceSize);\r |
53e1e5c6 | 580 | retval = ((GenericInstance *)GenI)->Abstraction.fo_mkdir( path, perms);\r |
581 | }\r | |
582 | free(NewPath);\r | |
2aa62f2b | 583 | }\r |
53e1e5c6 | 584 | else {\r |
585 | retval = -1;\r | |
2aa62f2b | 586 | }\r |
53e1e5c6 | 587 | return retval;\r |
2aa62f2b | 588 | }\r |
589 | \r | |
590 | /** Open a file.\r | |
a7a8363d | 591 | The open() function establishes the connection between a file and a file\r |
592 | descriptor. It creates an open file description that refers to a file\r | |
593 | and a file descriptor that refers to that open file description. The file\r | |
594 | descriptor is used by other I/O functions to refer to that file.\r | |
595 | \r | |
596 | The open() function returns a file descriptor for the named file that is\r | |
597 | the lowest file descriptor not currently open for that process. The open\r | |
598 | file description is new, and therefore the file descriptor shall not\r | |
599 | share it with any other process in the system.\r | |
600 | \r | |
601 | The file offset used to mark the current position within the file is set\r | |
602 | to the beginning of the file.\r | |
2aa62f2b | 603 | \r |
604 | The EFI ShellOpenFileByName() function is used to perform the low-level\r | |
605 | file open operation. The primary task of open() is to translate from the\r | |
606 | flags used in the <stdio.h> environment to those used by the EFI function.\r | |
607 | \r | |
a7a8363d | 608 | The file status flags and file access modes of the open file description\r |
609 | are set according to the value of oflags.\r | |
610 | \r | |
611 | Values for oflags are constructed by a bitwise-inclusive OR of flags from\r | |
612 | the following list, defined in <fcntl.h>. Applications shall specify\r | |
613 | exactly one of { O_RDONLY, O_RDWR, O_WRONLY } in the value of oflags.\r | |
614 | Any combination of { O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, O_EXCL } may\r | |
615 | also be specified in oflags.\r | |
616 | \r | |
2aa62f2b | 617 | The only valid flag combinations for ShellOpenFileByName() are:\r |
618 | - Read\r | |
619 | - Read/Write\r | |
620 | - Create/Read/Write\r | |
621 | \r | |
a7a8363d | 622 | Values for mode specify the access permissions for newly created files.\r |
2aa62f2b | 623 | The mode value is saved in the FD to indicate permissions for further operations.\r |
624 | \r | |
625 | O_RDONLY -- flags = EFI_FILE_MODE_READ -- this is always done\r | |
626 | O_WRONLY -- flags |= EFI_FILE_MODE_WRITE\r | |
627 | O_RDWR -- flags |= EFI_FILE_MODE_WRITE -- READ is already set\r | |
628 | \r | |
629 | O_NONBLOCK -- ignored\r | |
630 | O_APPEND -- Seek to EOF before every write\r | |
631 | O_CREAT -- flags |= EFI_FILE_MODE_CREATE\r | |
632 | O_TRUNC -- delete first then create new\r | |
633 | O_EXCL -- if O_CREAT is also set, open will fail if the file already exists.\r | |
a7a8363d | 634 | \r |
635 | @param[in] Path The path argument points to a pathname naming the\r | |
636 | object to be opened.\r | |
637 | @param[in] oflags File status flags and file access modes of the\r | |
638 | open file description.\r | |
639 | @param[in] mode File access permission bits as defined in\r | |
6c6c850a | 640 | <sys/stat.h>. Only used if a file is created\r |
641 | as a result of the open.\r | |
a7a8363d | 642 | \r |
643 | @return Upon successful completion, open() opens the file and returns\r | |
644 | a non-negative integer representing the lowest numbered\r | |
645 | unused file descriptor. Otherwise, open returns -1 and sets\r | |
646 | errno to indicate the error. If a negative value is\r | |
647 | returned, no files are created or modified.\r | |
6c6c850a | 648 | - EMFILE - No file descriptors available -- Max number already open.\r |
649 | - EINVAL - Bad value specified for oflags or mode.\r | |
650 | - ENOMEM - Failure allocating memory for internal buffers.\r | |
651 | - EEXIST - File exists and open attempted with (O_EXCL | O_CREAT) set.\r | |
652 | - EIO - UEFI failure. Check value in EFIerrno.\r | |
2aa62f2b | 653 | **/\r |
654 | int\r | |
d7ce7006 | 655 | open(\r |
656 | const char *path,\r | |
657 | int oflags,\r | |
658 | int mode\r | |
659 | )\r | |
2aa62f2b | 660 | {\r |
53e1e5c6 | 661 | wchar_t *NewPath;\r |
d7ce7006 | 662 | wchar_t *MPath;\r |
53e1e5c6 | 663 | DeviceNode *Node;\r |
53e1e5c6 | 664 | struct __filedes *filp;\r |
6c6c850a | 665 | struct termios *Termio;\r |
53e1e5c6 | 666 | int Instance = 0;\r |
2aa62f2b | 667 | RETURN_STATUS Status;\r |
6c6c850a | 668 | UINT32 OpenMode;\r |
2aa62f2b | 669 | int fd = -1;\r |
53e1e5c6 | 670 | int doresult;\r |
2aa62f2b | 671 | \r |
d7ce7006 | 672 | Status = ParsePath(path, &NewPath, &Node, &Instance, &MPath);\r |
53e1e5c6 | 673 | if(Status == RETURN_SUCCESS) {\r |
d7ce7006 | 674 | if((Node == NULL) ||\r |
6c6c850a | 675 | (Node->InstanceList == NULL))\r |
676 | {\r | |
53e1e5c6 | 677 | errno = EPERM;\r |
6c6c850a | 678 | }\r |
53e1e5c6 | 679 | else {\r |
2aa62f2b | 680 | // Could add a test to see if the file name begins with a period.\r |
681 | // If it does, then add the HIDDEN flag to Attributes.\r | |
682 | \r | |
683 | // Get an available fd\r | |
53e1e5c6 | 684 | fd = FindFreeFD( VALID_CLOSED );\r |
2aa62f2b | 685 | \r |
686 | if( fd < 0 ) {\r | |
687 | // All available FDs are in use\r | |
688 | errno = EMFILE;\r | |
2aa62f2b | 689 | }\r |
d7ce7006 | 690 | else {\r |
53e1e5c6 | 691 | filp = &gMD->fdarray[fd];\r |
692 | // Save the flags and mode in the File Descriptor\r | |
693 | filp->Oflags = oflags;\r | |
694 | filp->Omode = mode;\r | |
695 | \r | |
d7ce7006 | 696 | doresult = Node->OpenFunc(Node, filp, Instance, NewPath, MPath);\r |
53e1e5c6 | 697 | if(doresult < 0) {\r |
698 | filp->f_iflags = 0; // Release this FD\r | |
699 | fd = -1; // Indicate an error\r | |
700 | }\r | |
701 | else {\r | |
6c6c850a | 702 | // Build our final f_iflags value\r |
53e1e5c6 | 703 | OpenMode = ( mode & S_ACC_READ ) ? S_ACC_READ : 0;\r |
704 | OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0;\r | |
2aa62f2b | 705 | \r |
6c6c850a | 706 | filp->f_iflags |= OpenMode;\r |
707 | \r | |
708 | if((oflags & O_TTY_INIT) && (filp->f_iflags & _S_ITTY) && (filp->devdata != NULL)) {\r | |
709 | // Initialize the device's termios flags to a "sane" value\r | |
710 | Termio = &((cIIO *)filp->devdata)->Termio;\r | |
9f4b48a1 | 711 | Termio->c_iflag = ICRNL | IGNSPEC;\r |
6c6c850a | 712 | Termio->c_oflag = OPOST | ONLCR | OXTABS | ONOEOT | ONOCR | ONLRET | OCTRL;\r |
713 | Termio->c_lflag = ECHO | ECHOE | ECHONL | ICANON;\r | |
714 | Termio->c_cc[VERASE] = 0x08; // ^H Backspace\r | |
715 | Termio->c_cc[VKILL] = 0x15; // ^U\r | |
716 | Termio->c_cc[VINTR] = 0x03; // ^C Interrupt character\r | |
717 | }\r | |
53e1e5c6 | 718 | ++filp->RefCount;\r |
719 | FILE_SET_MATURE(filp);\r | |
720 | }\r | |
2aa62f2b | 721 | }\r |
d7ce7006 | 722 | }\r |
53e1e5c6 | 723 | free(NewPath);\r |
2aa62f2b | 724 | }\r |
d7ce7006 | 725 | free(MPath); // We don't need this any more.\r |
6c6c850a | 726 | \r |
53e1e5c6 | 727 | // return the fd of our now open file\r |
728 | return fd;\r | |
729 | }\r | |
730 | \r | |
731 | \r | |
732 | /**\r | |
733 | Poll a list of file descriptors.\r | |
734 | \r | |
735 | The ::poll routine waits for up to timeout milliseconds for an event\r | |
736 | to occur on one or more of the file descriptors listed. The event\r | |
737 | types of interested are specified for each file descriptor in the events\r | |
738 | field. The actual event detected is returned in the revents field of\r | |
739 | the array. The\r | |
740 | <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">POSIX</a>\r | |
741 | documentation is available online.\r | |
742 | \r | |
6c6c850a | 743 | @param[in] pfd Address of an array of pollfd structures.\r |
53e1e5c6 | 744 | \r |
6c6c850a | 745 | @param[in] nfds Number of elements in the array of pollfd structures.\r |
53e1e5c6 | 746 | \r |
6c6c850a | 747 | @param[in] timeout Length of time in milliseconds to wait for the event\r |
53e1e5c6 | 748 | \r |
7dc13291 | 749 | @return The number of file descriptors with detected events. Zero\r |
53e1e5c6 | 750 | indicates that the call timed out and -1 indicates an error.\r |
751 | \r | |
752 | **/\r | |
753 | int\r | |
754 | poll (\r | |
755 | struct pollfd * pfd,\r | |
756 | nfds_t nfds,\r | |
757 | int timeout\r | |
758 | )\r | |
759 | {\r | |
760 | struct __filedes * pDescriptor;\r | |
761 | struct pollfd * pEnd;\r | |
762 | struct pollfd * pPollFD;\r | |
763 | int SelectedFDs;\r | |
764 | EFI_STATUS Status;\r | |
765 | EFI_EVENT Timer;\r | |
766 | UINT64 TimerTicks;\r | |
767 | \r | |
768 | //\r | |
769 | // Create the timer for the timeout\r | |
770 | //\r | |
771 | Timer = NULL;\r | |
772 | Status = EFI_SUCCESS;\r | |
773 | if ( INFTIM != timeout ) {\r | |
774 | Status = gBS->CreateEvent ( EVT_TIMER,\r | |
775 | TPL_NOTIFY,\r | |
776 | NULL,\r | |
777 | NULL,\r | |
778 | &Timer );\r | |
779 | if ( !EFI_ERROR ( Status )) {\r | |
780 | //\r | |
781 | // Start the timeout timer\r | |
782 | //\r | |
783 | TimerTicks = timeout;\r | |
784 | TimerTicks *= 1000 * 10;\r | |
785 | Status = gBS->SetTimer ( Timer,\r | |
786 | TimerRelative,\r | |
787 | TimerTicks );\r | |
788 | }\r | |
789 | else {\r | |
790 | SelectedFDs = -1;\r | |
791 | errno = ENOMEM;\r | |
792 | }\r | |
793 | }\r | |
794 | if ( !EFI_ERROR ( Status )) {\r | |
795 | //\r | |
796 | // Poll until an event is detected or the timer fires\r | |
797 | //\r | |
798 | SelectedFDs = 0;\r | |
799 | errno = 0;\r | |
800 | do {\r | |
801 | //\r | |
802 | // Poll the list of file descriptors\r | |
803 | //\r | |
804 | pPollFD = pfd;\r | |
805 | pEnd = &pPollFD [ nfds ];\r | |
806 | while ( pEnd > pPollFD ) {\r | |
807 | //\r | |
808 | // Validate the file descriptor\r | |
809 | //\r | |
810 | if ( !ValidateFD ( pPollFD->fd, VALID_OPEN )) {\r | |
811 | errno = EINVAL;\r | |
2aa62f2b | 812 | return -1;\r |
813 | }\r | |
53e1e5c6 | 814 | \r |
815 | //\r | |
816 | // Poll the device or file\r | |
817 | //\r | |
818 | pDescriptor = &gMD->fdarray [ pPollFD->fd ];\r | |
819 | pPollFD->revents = pDescriptor->f_ops->fo_poll ( pDescriptor,\r | |
820 | pPollFD->events );\r | |
821 | \r | |
822 | //\r | |
823 | // Determine if this file descriptor detected an event\r | |
824 | //\r | |
825 | if ( 0 != pPollFD->revents ) {\r | |
826 | //\r | |
827 | // Select this descriptor\r | |
828 | //\r | |
829 | SelectedFDs += 1;\r | |
830 | }\r | |
831 | \r | |
832 | //\r | |
833 | // Set the next file descriptor\r | |
834 | //\r | |
835 | pPollFD += 1;\r | |
2aa62f2b | 836 | }\r |
53e1e5c6 | 837 | \r |
838 | //\r | |
839 | // Check for timeout\r | |
840 | //\r | |
841 | if ( NULL != Timer ) {\r | |
842 | Status = gBS->CheckEvent ( Timer );\r | |
843 | if ( EFI_SUCCESS == Status ) {\r | |
844 | //\r | |
845 | // Timeout\r | |
846 | //\r | |
847 | break;\r | |
848 | }\r | |
849 | else if ( EFI_NOT_READY == Status ) {\r | |
850 | Status = EFI_SUCCESS;\r | |
2aa62f2b | 851 | }\r |
2aa62f2b | 852 | }\r |
53e1e5c6 | 853 | } while (( 0 == SelectedFDs )\r |
854 | && ( EFI_SUCCESS == Status ));\r | |
d7ce7006 | 855 | \r |
53e1e5c6 | 856 | //\r |
857 | // Stop the timer\r | |
858 | //\r | |
859 | if ( NULL != Timer ) {\r | |
860 | gBS->SetTimer ( Timer,\r | |
861 | TimerCancel,\r | |
862 | 0 );\r | |
2aa62f2b | 863 | }\r |
2aa62f2b | 864 | }\r |
865 | else {\r | |
53e1e5c6 | 866 | SelectedFDs = -1;\r |
867 | errno = EAGAIN;\r | |
2aa62f2b | 868 | }\r |
869 | \r | |
53e1e5c6 | 870 | //\r |
871 | // Release the timer\r | |
872 | //\r | |
873 | if ( NULL != Timer ) {\r | |
874 | gBS->CloseEvent ( Timer );\r | |
875 | }\r | |
2aa62f2b | 876 | \r |
53e1e5c6 | 877 | //\r |
878 | // Return the number of selected file system descriptors\r | |
879 | //\r | |
880 | return SelectedFDs;\r | |
881 | }\r | |
2aa62f2b | 882 | \r |
2aa62f2b | 883 | \r |
2aa62f2b | 884 | /** The rename() function changes the name of a file.\r |
6c6c850a | 885 | The From argument points to the pathname of the file to be renamed. The To\r |
2aa62f2b | 886 | argument points to the new pathname of the file.\r |
887 | \r | |
6c6c850a | 888 | If the From argument points to the pathname of a file that is not a\r |
889 | directory, the To argument shall not point to the pathname of a\r | |
890 | directory. If the file named by the To argument exists, it shall be\r | |
891 | removed and From renamed to To. Write access permission is required for\r | |
892 | both the directory containing old and the directory containing To.\r | |
2aa62f2b | 893 | \r |
6c6c850a | 894 | If the From argument points to the pathname of a directory, the To\r |
2aa62f2b | 895 | argument shall not point to the pathname of a file that is not a\r |
6c6c850a | 896 | directory. If the directory named by the To argument exists, it shall be\r |
897 | removed and From renamed to To.\r | |
2aa62f2b | 898 | \r |
6c6c850a | 899 | The To pathname shall not contain a path prefix that names From. Write\r |
900 | access permission is required for the directory containing From and the\r | |
901 | directory containing To. If the From argument points to the pathname of a\r | |
2aa62f2b | 902 | directory, write access permission may be required for the directory named\r |
6c6c850a | 903 | by From, and, if it exists, the directory named by To.\r |
2aa62f2b | 904 | \r |
905 | If the rename() function fails for any reason other than [EIO], any file\r | |
6c6c850a | 906 | named by To shall be unaffected.\r |
2aa62f2b | 907 | \r |
6c6c850a | 908 | @param[in] From Path to the file to be renamed.\r |
909 | @param[in] To The new name of From.\r | |
910 | \r | |
911 | @retval 0 Successful completion.\r | |
912 | @retval -1 An error has occured and errno has been set to further specify the error.\r | |
913 | Neither the file named by From nor the file named by To are\r | |
914 | changed or created.\r | |
915 | - ENXIO: Path specified is not supported by any loaded driver.\r | |
916 | - ENOMEM: Insufficient memory to calloc a MapName buffer.\r | |
917 | - EINVAL: The path parameter is not valid.\r | |
2aa62f2b | 918 | **/\r |
919 | int\r | |
53e1e5c6 | 920 | rename(\r |
6c6c850a | 921 | const char *From,\r |
922 | const char *To\r | |
53e1e5c6 | 923 | )\r |
2aa62f2b | 924 | {\r |
53e1e5c6 | 925 | wchar_t *FromPath;\r |
926 | DeviceNode *FromNode;\r | |
927 | char *GenI;\r | |
928 | int Instance = 0;\r | |
929 | RETURN_STATUS Status;\r | |
930 | int retval = -1;\r | |
931 | \r | |
6c6c850a | 932 | Status = ParsePath(From, &FromPath, &FromNode, &Instance, NULL);\r |
2aa62f2b | 933 | if(Status == RETURN_SUCCESS) {\r |
53e1e5c6 | 934 | GenI = FromNode->InstanceList;\r |
935 | if(GenI == NULL) {\r | |
936 | errno = EPERM;\r | |
937 | retval = -1;\r | |
2aa62f2b | 938 | }\r |
939 | else {\r | |
d7ce7006 | 940 | //GenI += (Instance * FromNode->InstanceSize);\r |
6c6c850a | 941 | retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( From, To);\r |
2aa62f2b | 942 | }\r |
53e1e5c6 | 943 | free(FromPath);\r |
2aa62f2b | 944 | }\r |
53e1e5c6 | 945 | return retval;\r |
2aa62f2b | 946 | }\r |
947 | \r | |
6c6c850a | 948 | /** Delete a specified directory.\r |
949 | \r | |
950 | @param[in] path Path to the directory to delete.\r | |
951 | \r | |
952 | @retval -1 The directory couldn't be opened (doesn't exist).\r | |
953 | @retval -1 The directory wasn't empty or an IO error occured.\r | |
53e1e5c6 | 954 | **/\r |
955 | int\r | |
53e1e5c6 | 956 | rmdir(\r |
957 | const char *path\r | |
958 | )\r | |
2aa62f2b | 959 | {\r |
53e1e5c6 | 960 | struct __filedes *filp;\r |
961 | int fd;\r | |
962 | int retval = -1;\r | |
963 | \r | |
964 | fd = open(path, O_RDWR, 0);\r | |
965 | if(fd >= 0) {\r | |
966 | filp = &gMD->fdarray[fd];\r | |
967 | \r | |
968 | retval = filp->f_ops->fo_rmdir(filp);\r | |
0c1992fb | 969 | filp->f_iflags = 0; // Close this FD\r |
970 | filp->RefCount = 0; // No one using this FD\r | |
48831246 | 971 | }\r |
53e1e5c6 | 972 | return retval;\r |
2aa62f2b | 973 | }\r |
974 | \r | |
975 | /** The fstat() function obtains information about an open file associated\r | |
6c6c850a | 976 | with the file descriptor fd, and writes it to the area pointed to\r |
977 | by statbuf.\r | |
2aa62f2b | 978 | \r |
6c6c850a | 979 | The statbuf argument is a pointer to a stat structure, as defined\r |
2aa62f2b | 980 | in <sys/stat.h>, into which information is placed concerning the file.\r |
981 | \r | |
982 | The structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atime,\r | |
983 | st_ctime, and st_mtime shall have meaningful values. The value of the\r | |
984 | member st_nlink shall be set to the number of links to the file.\r | |
985 | \r | |
986 | The fstat() function shall update any time-related fields before writing\r | |
987 | into the stat structure.\r | |
988 | \r | |
989 | The fstat() function is implemented using the ShellGetFileInfo()\r | |
990 | function.\r | |
991 | \r | |
992 | The stat structure members which don't have direct analogs to EFI file\r | |
993 | information are filled in as follows:\r | |
6c6c850a | 994 | - st_mode Populated with information from fd\r |
2aa62f2b | 995 | - st_ino Set to zero. (inode)\r |
996 | - st_dev Set to zero.\r | |
997 | - st_uid Set to zero.\r | |
998 | - st_gid Set to zero.\r | |
999 | - st_nlink Set to one.\r | |
1000 | \r | |
53e1e5c6 | 1001 | @param[in] fd File descriptor as returned from open().\r |
2aa62f2b | 1002 | @param[out] statbuf Buffer in which the file status is put.\r |
1003 | \r | |
1004 | @retval 0 Successful Completion.\r | |
1005 | @retval -1 An error has occurred and errno has been set to\r | |
1006 | identify the error.\r | |
1007 | **/\r | |
1008 | int\r | |
53e1e5c6 | 1009 | fstat (int fd, struct stat *statbuf)\r |
2aa62f2b | 1010 | {\r |
53e1e5c6 | 1011 | int retval = -1;\r |
1012 | struct __filedes *filp;\r | |
2aa62f2b | 1013 | \r |
53e1e5c6 | 1014 | if(ValidateFD( fd, VALID_OPEN)) {\r |
1015 | filp = &gMD->fdarray[fd];\r | |
1016 | retval = filp->f_ops->fo_stat(filp, statbuf, NULL);\r | |
2aa62f2b | 1017 | }\r |
1018 | else {\r | |
53e1e5c6 | 1019 | errno = EBADF;\r |
2aa62f2b | 1020 | }\r |
53e1e5c6 | 1021 | return retval;\r |
2aa62f2b | 1022 | }\r |
1023 | \r | |
1024 | /** Obtains information about the file pointed to by path.\r | |
1025 | \r | |
1026 | Opens the file pointed to by path, calls _EFI_FileInfo with the file's handle,\r | |
1027 | then closes the file.\r | |
1028 | \r | |
6c6c850a | 1029 | @param[in] path Path to the file to obtain information about.\r |
1030 | @param[out] statbuf Buffer in which the file status is put.\r | |
1031 | \r | |
2aa62f2b | 1032 | @retval 0 Successful Completion.\r |
1033 | @retval -1 An error has occurred and errno has been set to\r | |
1034 | identify the error.\r | |
1035 | **/\r | |
1036 | int\r | |
41b152c5 | 1037 | stat (const char *path, struct stat *statbuf)\r |
2aa62f2b | 1038 | {\r |
53e1e5c6 | 1039 | int fd;\r |
1040 | int retval = -1;\r | |
1041 | struct __filedes *filp;\r | |
1042 | \r | |
1043 | fd = open(path, O_RDONLY, 0);\r | |
1044 | if(fd >= 0) {\r | |
1045 | filp = &gMD->fdarray[fd];\r | |
1046 | retval = filp->f_ops->fo_stat( filp, statbuf, NULL);\r | |
1047 | close(fd);\r | |
2aa62f2b | 1048 | }\r |
53e1e5c6 | 1049 | return retval;\r |
2aa62f2b | 1050 | }\r |
1051 | \r | |
6c6c850a | 1052 | /** Same as stat since EFI doesn't have symbolic links.\r |
1053 | \r | |
1054 | @param[in] path Path to the file to obtain information about.\r | |
1055 | @param[out] statbuf Buffer in which the file status is put.\r | |
1056 | \r | |
1057 | @retval 0 Successful Completion.\r | |
1058 | @retval -1 An error has occurred and errno has been set to\r | |
1059 | identify the error.\r | |
1060 | **/\r | |
2aa62f2b | 1061 | int\r |
1062 | lstat (const char *path, struct stat *statbuf)\r | |
1063 | {\r | |
1064 | return stat(path, statbuf);\r | |
1065 | }\r | |
1066 | \r | |
53e1e5c6 | 1067 | /** Control a device.\r |
6c6c850a | 1068 | \r |
1069 | @param[in] fd Descriptor for the file to be acted upon.\r | |
1070 | @param[in] request Specifies the operation to perform.\r | |
1071 | @param[in,out] ... Zero or more parameters as required for request.\r | |
1072 | \r | |
1073 | @retval >=0 The operation completed successfully.\r | |
1074 | @retval -1 An error occured. More information is in errno.\r | |
53e1e5c6 | 1075 | **/\r |
1076 | int\r | |
1077 | ioctl(\r | |
1078 | int fd,\r | |
1079 | unsigned long request,\r | |
1080 | ...\r | |
1081 | )\r | |
1082 | {\r | |
1083 | int retval = -1;\r | |
1084 | struct __filedes *filp;\r | |
1085 | va_list argp;\r | |
1086 | \r | |
1087 | va_start(argp, request);\r | |
1088 | \r | |
1089 | if(ValidateFD( fd, VALID_OPEN)) {\r | |
1090 | filp = &gMD->fdarray[fd];\r | |
0c1992fb | 1091 | \r |
1092 | if(request == FIODLEX) {\r | |
1093 | /* set Delete-on-Close */\r | |
1094 | filp->f_iflags |= FIF_DELCLOSE;\r | |
1095 | retval = 0;\r | |
1096 | }\r | |
1097 | else if(request == FIONDLEX) {\r | |
1098 | /* clear Delete-on-Close */\r | |
1099 | filp->f_iflags &= ~FIF_DELCLOSE;\r | |
1100 | retval = 0;\r | |
1101 | }\r | |
1102 | else {\r | |
1103 | /* All other requests. */\r | |
48831246 | 1104 | retval = filp->f_ops->fo_ioctl(filp, request, argp);\r |
1105 | }\r | |
0c1992fb | 1106 | }\r |
53e1e5c6 | 1107 | else {\r |
1108 | errno = EBADF;\r | |
1109 | }\r | |
1110 | va_end(argp);\r | |
1111 | \r | |
1112 | return retval;\r | |
1113 | }\r | |
1114 | \r | |
2aa62f2b | 1115 | /** Read from a file.\r |
1116 | \r | |
1117 | The read() function shall attempt to read nbyte bytes from the file\r | |
1118 | associated with the open file descriptor, fildes, into the buffer pointed\r | |
1119 | to by buf.\r | |
1120 | \r | |
1121 | Before any action described below is taken, and if nbyte is zero, the\r | |
1122 | read() function may detect and return errors as described below. In the\r | |
1123 | absence of errors, or if error detection is not performed, the read()\r | |
1124 | function shall return zero and have no other results.\r | |
1125 | \r | |
1126 | On files that support seeking (for example, a regular file), the read()\r | |
1127 | shall start at a position in the file given by the file offset associated\r | |
1128 | with fildes. The file offset shall be incremented by the number of bytes\r | |
1129 | actually read.\r | |
1130 | \r | |
1131 | Files that do not support seeking - for example, terminals - always read\r | |
1132 | from the current position. The value of a file offset associated with\r | |
1133 | such a file is undefined.\r | |
1134 | \r | |
1135 | No data transfer shall occur past the current end-of-file. If the\r | |
1136 | starting position is at or after the end-of-file, 0 shall be returned.\r | |
1137 | \r | |
1138 | The read() function reads data previously written to a file. If any\r | |
1139 | portion of a regular file prior to the end-of-file has not been written,\r | |
1140 | read() shall return bytes with value 0. For example, lseek() allows the\r | |
1141 | file offset to be set beyond the end of existing data in the file. If data\r | |
1142 | is later written at this point, subsequent reads in the gap between the\r | |
1143 | previous end of data and the newly written data shall return bytes with\r | |
1144 | value 0 until data is written into the gap.\r | |
1145 | \r | |
1146 | Upon successful completion, where nbyte is greater than 0, read() shall\r | |
1147 | mark for update the st_atime field of the file, and shall return the\r | |
1148 | number of bytes read. This number shall never be greater than nbyte. The\r | |
1149 | value returned may be less than nbyte if the number of bytes left in the\r | |
1150 | file is less than nbyte, if the read() request was interrupted by a\r | |
1151 | signal, or if the file is a pipe or FIFO or special file and has fewer\r | |
1152 | than nbyte bytes immediately available for reading. For example, a read()\r | |
1153 | from a file associated with a terminal may return one typed line of data.\r | |
1154 | \r | |
1155 | If fildes does not refer to a directory, the function reads the requested\r | |
d7ce7006 | 1156 | number of bytes from the file at the file's current position and returns\r |
2aa62f2b | 1157 | them in buf. If the read goes beyond the end of the file, the read\r |
d7ce7006 | 1158 | length is truncated to the end of the file. The file's current position is\r |
2aa62f2b | 1159 | increased by the number of bytes returned.\r |
1160 | \r | |
1161 | If fildes refers to a directory, the function reads the directory entry at\r | |
d7ce7006 | 1162 | the file's current position and returns the entry in buf. If buf\r |
2aa62f2b | 1163 | is not large enough to hold the current directory entry, then\r |
1164 | errno is set to EBUFSIZE, EFIerrno is set to EFI_BUFFER_TOO_SMALL, and the\r | |
1165 | current file position is not updated. The size of the buffer needed to read\r | |
1166 | the entry will be returned as a negative number. On success, the current\r | |
1167 | position is updated to the next directory entry. If there are no more\r | |
1168 | directory entries, the read returns a zero-length buffer.\r | |
1169 | EFI_FILE_INFO is the structure returned as the directory entry.\r | |
1170 | \r | |
6c6c850a | 1171 | @param[in] fildes Descriptor of the file to be read.\r |
1172 | @param[out] buf Pointer to location in which to store the read data.\r | |
1173 | @param[in] nbyte Maximum number of bytes to be read.\r | |
1174 | \r | |
2aa62f2b | 1175 | @return Upon successful completion, read() returns a non-negative integer\r |
1176 | indicating the number of bytes actually read. Otherwise, the\r | |
1177 | functions return a negative value and sets errno to indicate the\r | |
1178 | error. If errno is EBUFSIZE, the absolute value of the\r | |
1179 | return value indicates the size of the buffer needed to read\r | |
1180 | the directory entry.\r | |
1181 | **/\r | |
1182 | ssize_t\r | |
1183 | read (int fildes, void *buf, size_t nbyte)\r | |
1184 | {\r | |
53e1e5c6 | 1185 | struct __filedes *filp;\r |
6c6c850a | 1186 | cIIO *IIO;\r |
2aa62f2b | 1187 | ssize_t BufSize;\r |
2aa62f2b | 1188 | \r |
1189 | BufSize = (ssize_t)nbyte;\r | |
6c6c850a | 1190 | if(BufSize > 0) {\r |
1191 | if(ValidateFD( fildes, VALID_OPEN)) {\r | |
1192 | filp = &gMD->fdarray[fildes];\r | |
53e1e5c6 | 1193 | \r |
6c6c850a | 1194 | IIO = filp->devdata;\r |
1195 | if(isatty(fildes) && (IIO != NULL)) {\r | |
1196 | BufSize = IIO->Read(filp, nbyte, buf);\r | |
1197 | }\r | |
1198 | else {\r | |
1199 | BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf);\r | |
1200 | }\r | |
1201 | }\r | |
1202 | else {\r | |
1203 | errno = EBADF;\r | |
1204 | BufSize = -1;\r | |
1205 | }\r | |
2aa62f2b | 1206 | }\r |
1207 | return BufSize;\r | |
1208 | }\r | |
1209 | \r | |
2aa62f2b | 1210 | /** Write data to a file.\r |
1211 | \r | |
6c6c850a | 1212 | This function writes the specified number of bytes to the file at the current\r |
1213 | file position. The current file position is advanced the actual number of bytes\r | |
1214 | written, which is returned in BufferSize. Partial writes only occur when there\r | |
1215 | has been a data error during the write attempt (such as "volume space full").\r | |
1216 | The file is automatically grown to hold the data if required. Direct writes to\r | |
1217 | opened directories are not supported.\r | |
1218 | \r | |
1219 | If fildes refers to a terminal device, isatty() returns TRUE, a partial write\r | |
1220 | will occur if a NULL or EOF character is encountered before n characters have\r | |
1221 | been written. Characters inserted due to line-end translations will not be\r | |
1222 | counted. Unconvertable characters are translated into the UEFI character\r | |
1223 | BLOCKELEMENT_LIGHT_SHADE.\r | |
1224 | \r | |
1225 | Since the UEFI console device works on wide characters, the buffer is assumed\r | |
1226 | to contain a single-byte character stream which is then translated to wide\r | |
1227 | characters using the mbtowc() functions. The resulting wide character stream\r | |
1228 | is what is actually sent to the UEFI console.\r | |
1229 | \r | |
1230 | @param[in] fd Descriptor of file to be written to.\r | |
1231 | @param[in] buf Pointer to data to write to the file.\r | |
1232 | @param[in] nbyte Number of bytes to be written to the file.\r | |
1233 | \r | |
1234 | @retval >=0 Number of bytes actually written to the file.\r | |
1235 | @retval <0 An error occurred. More data is provided by errno.\r | |
2aa62f2b | 1236 | **/\r |
1237 | ssize_t\r | |
53e1e5c6 | 1238 | write (int fd, const void *buf, size_t nbyte)\r |
2aa62f2b | 1239 | {\r |
53e1e5c6 | 1240 | struct __filedes *filp;\r |
6c6c850a | 1241 | cIIO *IIO;\r |
2aa62f2b | 1242 | ssize_t BufSize;\r |
53e1e5c6 | 1243 | \r |
1244 | BufSize = (ssize_t)nbyte;\r | |
2aa62f2b | 1245 | \r |
53e1e5c6 | 1246 | if(ValidateFD( fd, VALID_OPEN)) {\r |
1247 | filp = &gMD->fdarray[fd];\r | |
6c6c850a | 1248 | if ((filp->Oflags & O_ACCMODE) != 0) {\r |
1249 | // File is open for writing\r | |
1250 | IIO = filp->devdata;\r | |
1251 | if(isatty(fd) && (IIO != NULL)) {\r | |
1252 | // Output to an Interactive I/O device\r | |
1253 | BufSize = IIO->Write(filp, buf, nbyte);\r | |
1254 | }\r | |
1255 | else {\r | |
1256 | // Output to a file, socket, pipe, etc.\r | |
1257 | BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);\r | |
1258 | }\r | |
2aa62f2b | 1259 | }\r |
1260 | else {\r | |
6c6c850a | 1261 | // File is NOT open for writing\r |
1262 | errno = EINVAL;\r | |
1263 | BufSize = -1;\r | |
1264 | }\r | |
1265 | }\r | |
1266 | else {\r | |
1267 | // fd is not for a valid open file\r | |
53e1e5c6 | 1268 | errno = EBADF;\r |
6c6c850a | 1269 | BufSize = -1;\r |
1270 | }\r | |
53e1e5c6 | 1271 | return BufSize;\r |
1272 | }\r | |
1273 | \r | |
1274 | /** Gets the current working directory.\r | |
1275 | \r | |
7dc13291 | 1276 | The getcwd() function shall place an absolute pathname of the current\r |
0c1992fb | 1277 | working directory in the array pointed to by buf, and return buf.The\r |
1278 | size argument is the size in bytes of the character array pointed to\r | |
1279 | by the buf argument.\r | |
7dc13291 | 1280 | \r |
53e1e5c6 | 1281 | @param[in,out] buf The buffer to fill.\r |
1282 | @param[in] size The number of bytes in buffer.\r | |
1283 | \r | |
0c1992fb | 1284 | @retval NULL The function failed. The value in errno provides\r |
1285 | further information about the cause of the failure.\r | |
1286 | Values for errno are:\r | |
1287 | - EINVAL: buf is NULL or size is zero.\r | |
1288 | - ENOENT: directory does not exist.\r | |
1289 | - ERANGE: buf size is too small to hold CWD\r | |
1290 | \r | |
1291 | @retval buf The function completed successfully.\r | |
53e1e5c6 | 1292 | **/\r |
7dc13291 | 1293 | char\r |
1294 | *getcwd (char *buf, size_t size)\r | |
53e1e5c6 | 1295 | {\r |
1296 | CONST CHAR16 *Cwd;\r | |
1297 | \r | |
1298 | if (size == 0 || buf == NULL) {\r | |
1299 | errno = EINVAL;\r | |
1300 | return NULL;\r | |
2aa62f2b | 1301 | }\r |
53e1e5c6 | 1302 | \r |
1303 | Cwd = ShellGetCurrentDir(NULL);\r | |
1304 | if (Cwd == NULL) {\r | |
0c1992fb | 1305 | errno = ENOENT;\r |
53e1e5c6 | 1306 | return NULL;\r |
2aa62f2b | 1307 | }\r |
53e1e5c6 | 1308 | if (size < ((StrLen (Cwd) + 1) * sizeof (CHAR8))) {\r |
1309 | errno = ERANGE;\r | |
1310 | return (NULL);\r | |
2aa62f2b | 1311 | }\r |
53e1e5c6 | 1312 | return (UnicodeStrToAsciiStr(Cwd, buf));\r |
2aa62f2b | 1313 | }\r |
d7ce7006 | 1314 | \r |
1315 | /** Change the current working directory.\r | |
1316 | \r | |
1317 | The chdir() function shall cause the directory named by the pathname\r | |
1318 | pointed to by the path argument to become the current working directory;\r | |
1319 | that is, the starting point for path searches for pathnames not beginning\r | |
1320 | with '/'.\r | |
1321 | \r | |
1322 | @param[in] path The new path to set.\r | |
1323 | \r | |
0c1992fb | 1324 | @retval 0 Operation completed successfully.\r |
1325 | @retval -1 Function failed. The value in errno provides more\r | |
1326 | information on the cause of failure:\r | |
1327 | - EPERM: Operation not supported with this Shell version.\r | |
1328 | - ENOMEM: Unable to allocate memory.\r | |
1329 | - ENOENT: Target directory does not exist.\r | |
1330 | \r | |
1331 | @todo Add non-NEW-shell CWD changing.\r | |
d7ce7006 | 1332 | **/\r |
1333 | int\r | |
1334 | chdir (const char *path)\r | |
1335 | {\r | |
1336 | CONST CHAR16 *Cwd;\r | |
1337 | EFI_STATUS Status;\r | |
1338 | CHAR16 *UnicodePath;\r | |
1339 | \r | |
0c1992fb | 1340 | /* Old Shell does not support Set Current Dir. */\r |
1341 | if(gEfiShellProtocol != NULL) {\r | |
48831246 | 1342 | Cwd = ShellGetCurrentDir(NULL);\r |
1343 | if (Cwd != NULL) {\r | |
1344 | /* We have shell support */\r | |
1345 | UnicodePath = AllocatePool(((AsciiStrLen (path) + 1) * sizeof (CHAR16)));\r | |
1346 | if (UnicodePath == NULL) {\r | |
1347 | errno = ENOMEM;\r | |
1348 | return -1;\r | |
1349 | }\r | |
1350 | AsciiStrToUnicodeStr(path, UnicodePath);\r | |
1351 | Status = gEfiShellProtocol->SetCurDir(NULL, UnicodePath);\r | |
1352 | FreePool(UnicodePath);\r | |
1353 | if (EFI_ERROR(Status)) {\r | |
0c1992fb | 1354 | errno = ENOENT;\r |
48831246 | 1355 | return -1;\r |
1356 | } else {\r | |
1357 | return 0;\r | |
1358 | }\r | |
d7ce7006 | 1359 | }\r |
1360 | }\r | |
d7ce7006 | 1361 | /* Add here for non-shell */\r |
0c1992fb | 1362 | errno = EPERM;\r |
d7ce7006 | 1363 | return -1;\r |
1364 | }\r | |
1365 | \r | |
6c6c850a | 1366 | /** Get the foreground process group ID associated with a terminal.\r |
1367 | \r | |
1368 | Just returns the Image Handle for the requestor since UEFI does not have\r | |
1369 | a concept of processes or groups.\r | |
1370 | \r | |
1371 | @param[in] x Ignored.\r | |
1372 | \r | |
1373 | @return Returns the Image Handle of the application or driver which\r | |
1374 | called this function.\r | |
1375 | **/\r | |
d7ce7006 | 1376 | pid_t tcgetpgrp (int x)\r |
1377 | {\r | |
1378 | return ((pid_t)(UINTN)(gImageHandle));\r | |
1379 | }\r | |
1380 | \r | |
6c6c850a | 1381 | /** Get the process group ID of the calling process.\r |
1382 | \r | |
1383 | Just returns the Image Handle for the requestor since UEFI does not have\r | |
1384 | a concept of processes or groups.\r | |
1385 | \r | |
1386 | @return Returns the Image Handle of the application or driver which\r | |
1387 | called this function.\r | |
1388 | **/\r | |
d7ce7006 | 1389 | pid_t getpgrp(void)\r |
1390 | {\r | |
1391 | return ((pid_t)(UINTN)(gImageHandle));\r | |
1392 | }\r | |
1393 | \r | |
48831246 | 1394 | /* Internal worker function for utimes.\r |
1395 | This works around an error produced by GCC when the va_* macros\r | |
1396 | are used within a function with a fixed number of arguments.\r | |
1397 | */\r | |
1398 | static\r | |
0c1992fb | 1399 | int\r |
48831246 | 1400 | EFIAPI\r |
1401 | va_Utimes(\r | |
1402 | const char *path,\r | |
1403 | ...\r | |
0c1992fb | 1404 | )\r |
1405 | {\r | |
1406 | struct __filedes *filp;\r | |
1407 | va_list ap;\r | |
1408 | int fd;\r | |
1409 | int retval = -1;\r | |
1410 | \r | |
1411 | va_start(ap, path);\r | |
1412 | fd = open(path, O_RDWR, 0);\r | |
1413 | if(fd >= 0) {\r | |
1414 | filp = &gMD->fdarray[fd];\r | |
1415 | retval = filp->f_ops->fo_ioctl( filp, FIOSETIME, ap);\r | |
1416 | close(fd);\r | |
1417 | }\r | |
1418 | va_end(ap);\r | |
1419 | return retval;\r | |
48831246 | 1420 | }\r |
1421 | \r | |
1422 | /** Set file access and modification times.\r | |
0c1992fb | 1423 | \r |
6c6c850a | 1424 | @param[in] path Path to the file to be modified.\r |
1425 | @param[in] times Pointer to an array of two timeval structures\r | |
48831246 | 1426 | \r |
6c6c850a | 1427 | @retval 0 File times successfully set.\r |
1428 | @retval -1 An error occured. Error type in errno.\r | |
48831246 | 1429 | **/\r |
1430 | int\r | |
1431 | utimes(\r | |
1432 | const char *path,\r | |
1433 | const struct timeval *times\r | |
1434 | )\r | |
1435 | {\r | |
1436 | return va_Utimes(path, times);\r | |
0c1992fb | 1437 | }\r |