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