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