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