]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - StdLib/LibC/Uefi/SysCalls.c
StdLib: Fix IIO_Write() to return the number of bytes consumed, not characters output.
[mirror_edk2.git] / StdLib / LibC / Uefi / SysCalls.c
... / ...
CommitLineData
1/** @file\r
2 EFI versions of NetBSD system calls.\r
3\r
4 Copyright (c) 2016, Daryl McDaniel. All rights reserved.<BR>\r
5 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
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
17#include <Library/UefiBootServicesTableLib.h>\r
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
28#include <stdlib.h>\r
29#include <string.h>\r
30#include <wchar.h>\r
31#include <sys/poll.h>\r
32#include <sys/fcntl.h>\r
33#include <sys/stat.h>\r
34#include <sys/syslimits.h>\r
35#include <sys/filio.h>\r
36#include <Efi/SysEfi.h>\r
37#include <unistd.h>\r
38#include <kfile.h>\r
39#include <Device/Device.h>\r
40#include <Device/IIO.h>\r
41#include <MainData.h>\r
42#include <extern.h>\r
43\r
44/* EFI versions of BSD system calls used in stdio */\r
45\r
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
55BOOLEAN\r
56ValidateFD( int fd, int IsOpen)\r
57{\r
58 struct __filedes *filp;\r
59 BOOLEAN retval = FALSE;\r
60\r
61 if((fd >= 0) && (fd < OPEN_MAX)) {\r
62 filp = &gMD->fdarray[fd];\r
63 retval = TRUE;\r
64 if(IsOpen >= 0) {\r
65 retval = (BOOLEAN)((filp->f_iflags != 0) && // TRUE if OPEN\r
66 FILE_IS_USABLE(filp)); // and Usable (not Larval or Closing)\r
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
83int\r
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
94 if(Mfd[i].f_iflags == 0) {\r
95 Mfd[i].f_iflags = FIF_LARVAL; // Temporarily mark this fd as reserved\r
96 fd = i;\r
97 break;\r
98 }\r
99 }\r
100 return fd;\r
101}\r
102\r
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
119/** The isatty() function tests whether fd, an open file descriptor,\r
120 is associated with a terminal device.\r
121\r
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
127**/\r
128int\r
129isatty (int fd)\r
130{\r
131 int retval = 0;\r
132 struct __filedes *Fp;\r
133\r
134 if(ValidateFD( fd, VALID_OPEN)) {\r
135 Fp = &gMD->fdarray[fd];\r
136 retval = (Fp->f_iflags & _S_ITTY) ? 1 : 0;\r
137 }\r
138 else {\r
139 errno = EBADF;\r
140 }\r
141 return retval;\r
142}\r
143\r
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
151static BOOLEAN\r
152IsDupFd( int fd)\r
153{\r
154 void * DevData;\r
155 const struct fileops *FileOps;\r
156 int i;\r
157 BOOLEAN Ret = FALSE;\r
158\r
159 if(ValidateFD( fd, VALID_OPEN )) {\r
160 FileOps = gMD->fdarray[fd].f_ops;\r
161 DevData = gMD->fdarray[fd].devdata;\r
162 for(i=0; i < OPEN_MAX; ++i) {\r
163 if(i == fd) continue;\r
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
167 Ret = TRUE;\r
168 break;\r
169 }\r
170 }\r
171 }\r
172 }\r
173 return Ret;\r
174}\r
175\r
176/** Worker function to Close a file and set its fd to the specified state.\r
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
183 * EBADF fd is not a valid or open file descriptor.\r
184**/\r
185static int\r
186_closeX (int fd, int NewState)\r
187{\r
188 struct __filedes *Fp;\r
189 int retval = 0;\r
190\r
191 // Verify my pointers and get my FD.\r
192 if(ValidateFD( fd, VALID_OPEN )) {\r
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
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
203 }\r
204 else {\r
205 retval = Fp->f_ops->fo_close( Fp);\r
206 }\r
207 }\r
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
213 }\r
214 }\r
215 else {\r
216 // Bad FD\r
217 retval = -1;\r
218 errno = EBADF;\r
219 }\r
220 return retval;\r
221}\r
222\r
223/** The close() function deallocates the file descriptor indicated by fd.\r
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
227 associated with the file descriptor are removed (that is, unlocked).\r
228\r
229 @param[in] fd Descriptor for the File to close.\r
230\r
231 @retval 0 Successful completion.\r
232 @retval -1 An error occurred and errno is set to identify the error.\r
233**/\r
234int\r
235close (int fd)\r
236{\r
237 return _closeX(fd, 0);\r
238}\r
239\r
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
248**/\r
249int\r
250unlink (const char *path)\r
251{\r
252 struct __filedes *Fp;\r
253 int fd;\r
254 int retval = -1;\r
255\r
256 EFIerrno = RETURN_SUCCESS;\r
257\r
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
264 }\r
265 Fp->f_iflags = 0; // Close this FD\r
266 Fp->RefCount = 0; // No one using this FD\r
267 }\r
268 return retval;\r
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
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
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
384\r
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
392\r
393 case F_SETFD:\r
394 retval = MyFd->f_iflags;\r
395 break;\r
396 //case F_SETOWN:\r
397 // retval = MyFd->SocProc;\r
398 // MyFd->SocProc = va_arg(p3, int);\r
399 // break;\r
400 case F_GETFD:\r
401 retval = MyFd->f_iflags;\r
402 break;\r
403 case F_GETFL:\r
404 retval = MyFd->Oflags;\r
405 break;\r
406 //case F_GETOWN:\r
407 // retval = MyFd->SocProc;\r
408 // break;\r
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
428 @param[in] fildes Descriptor for the file to be examined.\r
429\r
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
440/** Make fildes2 refer to a duplicate of fildes.\r
441\r
442 The dup2() function provides an alternative interface to the\r
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
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
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
474 gMD->fdarray[fildes2].f_iflags = FIF_LARVAL; // Mark the file closed, but reserved\r
475 (void)memcpy(&gMD->fdarray[fildes2], // Duplicate fildes into fildes2\r
476 &gMD->fdarray[fildes], sizeof(struct __filedes));\r
477 gMD->fdarray[fildes2].MyFD = (UINT16)fildes2;\r
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
498 - If how is SEEK_SET, the offset is set to offset bytes.\r
499\r
500 - If how is SEEK_CUR, the offset is set to its current location\r
501 plus offset bytes.\r
502\r
503 - If how is SEEK_END, the offset is set to the size of the file\r
504 plus offset bytes.\r
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
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
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
524lseek (int fd, __off_t offset, int how)\r
525{\r
526 __off_t CurPos = -1;\r
527// RETURN_STATUS Status = RETURN_SUCCESS;\r
528 struct __filedes *filp;\r
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
533 if(ValidateFD( fd, VALID_OPEN)) {\r
534 filp = &gMD->fdarray[fd];\r
535 // Both of our parameters have been verified as valid\r
536 CurPos = filp->f_ops->fo_lseek( filp, offset, how);\r
537 if(CurPos >= 0) {\r
538 filp->f_offset = CurPos;\r
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
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
559 @retval 0 The directory was created successfully.\r
560 @retval -1 An error occurred and error codes are stored in errno and EFIerrno.\r
561**/\r
562int\r
563mkdir (const char *path, __mode_t perms)\r
564{\r
565 wchar_t *NewPath;\r
566 DeviceNode *Node;\r
567 char *GenI;\r
568 RETURN_STATUS Status;\r
569 int Instance = 0;\r
570 int retval = 0;\r
571\r
572 Status = ParsePath(path, &NewPath, &Node, &Instance, NULL);\r
573 if(Status == RETURN_SUCCESS) {\r
574 GenI = Node->InstanceList;\r
575 if(GenI == NULL) {\r
576 errno = EPERM;\r
577 retval = -1;\r
578 }\r
579 else {\r
580 //GenI += (Instance * Node->InstanceSize);\r
581 retval = ((GenericInstance *)GenI)->Abstraction.fo_mkdir( path, perms);\r
582 }\r
583 free(NewPath);\r
584 }\r
585 else {\r
586 retval = -1;\r
587 }\r
588 return retval;\r
589}\r
590\r
591/** Open a file.\r
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
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
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
618 The only valid flag combinations for ShellOpenFileByName() are:\r
619 - Read\r
620 - Read/Write\r
621 - Create/Read/Write\r
622\r
623 Values for mode specify the access permissions for newly created files.\r
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
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
641 <sys/stat.h>. Only used if a file is created\r
642 as a result of the open.\r
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
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
654**/\r
655int\r
656open(\r
657 const char *path,\r
658 int oflags,\r
659 int mode\r
660 )\r
661{\r
662 wchar_t *NewPath;\r
663 wchar_t *MPath;\r
664 DeviceNode *Node;\r
665 struct __filedes *filp;\r
666 struct termios *Termio;\r
667 int Instance = 0;\r
668 RETURN_STATUS Status;\r
669 UINT32 OpenMode;\r
670 int fd = -1;\r
671 int doresult;\r
672\r
673 Status = ParsePath(path, &NewPath, &Node, &Instance, &MPath);\r
674 if(Status == RETURN_SUCCESS) {\r
675 if ((Node == NULL) ||\r
676 (Node->InstanceList == NULL))\r
677 {\r
678 errno = EPERM;\r
679 }\r
680 else {\r
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
683\r
684 // Get an available fd\r
685 fd = FindFreeFD( VALID_CLOSED );\r
686\r
687 if( fd < 0 ) {\r
688 // All available FDs are in use\r
689 errno = EMFILE;\r
690 }\r
691 else {\r
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
696\r
697 doresult = Node->OpenFunc(Node, filp, Instance, NewPath, MPath);\r
698 if(doresult < 0) {\r
699 filp->f_iflags = 0; // Release this FD\r
700 fd = -1; // Indicate an error\r
701 }\r
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
718 }\r
719 ++filp->RefCount;\r
720 FILE_SET_MATURE(filp);\r
721 }\r
722 }\r
723 }\r
724 free(NewPath);\r
725 }\r
726 free(MPath); // We don't need this any more.\r
727\r
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
744 @param[in] pfd Address of an array of pollfd structures.\r
745\r
746 @param[in] nfds Number of elements in the array of pollfd structures.\r
747\r
748 @param[in] timeout Length of time in milliseconds to wait for the event\r
749\r
750 @return The number of file descriptors with detected events. Zero\r
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
813 return -1;\r
814 }\r
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
837 }\r
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
852 }\r
853 }\r
854 } while (( 0 == SelectedFDs )\r
855 && ( EFI_SUCCESS == Status ));\r
856\r
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
864 }\r
865 }\r
866 else {\r
867 SelectedFDs = -1;\r
868 errno = EAGAIN;\r
869 }\r
870\r
871 //\r
872 // Release the timer\r
873 //\r
874 if ( NULL != Timer ) {\r
875 gBS->CloseEvent ( Timer );\r
876 }\r
877\r
878 //\r
879 // Return the number of selected file system descriptors\r
880 //\r
881 return SelectedFDs;\r
882}\r
883\r
884\r
885/** The rename() function changes the name of a file.\r
886 The From argument points to the pathname of the file to be renamed. The To\r
887 argument points to the new pathname of the file.\r
888\r
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
894\r
895 If the From argument points to the pathname of a directory, the To\r
896 argument shall not point to the pathname of a file that is not a\r
897 directory. If the directory named by the To argument exists, it shall be\r
898 removed and From renamed to To.\r
899\r
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
903 directory, write access permission may be required for the directory named\r
904 by From, and, if it exists, the directory named by To.\r
905\r
906 If the rename() function fails for any reason other than [EIO], any file\r
907 named by To shall be unaffected.\r
908\r
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
919**/\r
920int\r
921rename(\r
922 const char *From,\r
923 const char *To\r
924 )\r
925{\r
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
933 Status = ParsePath(From, &FromPath, &FromNode, &Instance, NULL);\r
934 if(Status == RETURN_SUCCESS) {\r
935 GenI = FromNode->InstanceList;\r
936 if(GenI == NULL) {\r
937 errno = EPERM;\r
938 retval = -1;\r
939 }\r
940 else {\r
941 //GenI += (Instance * FromNode->InstanceSize);\r
942 retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( From, To);\r
943 }\r
944 free(FromPath);\r
945 }\r
946 return retval;\r
947}\r
948\r
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
955**/\r
956int\r
957rmdir(\r
958 const char *path\r
959 )\r
960{\r
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
970 filp->f_iflags = 0; // Close this FD\r
971 filp->RefCount = 0; // No one using this FD\r
972 }\r
973 return retval;\r
974}\r
975\r
976/** The fstat() function obtains information about an open file associated\r
977 with the file descriptor fd, and writes it to the area pointed to\r
978 by statbuf.\r
979\r
980 The statbuf argument is a pointer to a stat structure, as defined\r
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
995 - st_mode Populated with information from fd\r
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
1002 @param[in] fd File descriptor as returned from open().\r
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
1010fstat (int fd, struct stat *statbuf)\r
1011{\r
1012 int retval = -1;\r
1013 struct __filedes *filp;\r
1014\r
1015 if(ValidateFD( fd, VALID_OPEN)) {\r
1016 filp = &gMD->fdarray[fd];\r
1017 retval = filp->f_ops->fo_stat(filp, statbuf, NULL);\r
1018 }\r
1019 else {\r
1020 errno = EBADF;\r
1021 }\r
1022 return retval;\r
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
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
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
1038stat (const char *path, struct stat *statbuf)\r
1039{\r
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
1049 }\r
1050 return retval;\r
1051}\r
1052\r
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
1062int\r
1063lstat (const char *path, struct stat *statbuf)\r
1064{\r
1065 return stat(path, statbuf);\r
1066}\r
1067\r
1068/** Control a device.\r
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
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
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
1105 retval = filp->f_ops->fo_ioctl(filp, request, argp);\r
1106 }\r
1107 }\r
1108 else {\r
1109 errno = EBADF;\r
1110 }\r
1111 va_end(argp);\r
1112\r
1113 return retval;\r
1114}\r
1115\r
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
1157 number of bytes from the file at the file's current position and returns\r
1158 them in buf. If the read goes beyond the end of the file, the read\r
1159 length is truncated to the end of the file. The file's current position is\r
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
1163 the file's current position and returns the entry in buf. If buf\r
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
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
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
1186 struct __filedes *filp;\r
1187 cIIO *IIO;\r
1188 ssize_t BufSize;\r
1189\r
1190 BufSize = (ssize_t)nbyte;\r
1191 if(BufSize > 0) {\r
1192 if(ValidateFD( fildes, VALID_OPEN)) {\r
1193 filp = &gMD->fdarray[fildes];\r
1194\r
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
1207 }\r
1208 return BufSize;\r
1209}\r
1210\r
1211/** Write data to a file.\r
1212\r
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
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
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
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
1226\r
1227 Since the UEFI console device works on wide characters, the buffer is assumed\r
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
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
1246**/\r
1247ssize_t\r
1248write (int fd, const void *buf, size_t nbyte)\r
1249{\r
1250 struct __filedes *filp;\r
1251 cIIO *IIO;\r
1252 ssize_t BufSize;\r
1253\r
1254 BufSize = (ssize_t)nbyte;\r
1255\r
1256 if(ValidateFD( fd, VALID_OPEN)) {\r
1257 filp = &gMD->fdarray[fd];\r
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
1263 // (Terminal device or the slave side of a pseudo-tty)\r
1264 BufSize = IIO->Write(filp, buf, nbyte);\r
1265 }\r
1266 else {\r
1267 // Output to a regular file, socket, pipe, etc.\r
1268 BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);\r
1269 }\r
1270 }\r
1271 else {\r
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
1279 errno = EBADF;\r
1280 BufSize = -1;\r
1281 }\r
1282 return BufSize;\r
1283}\r
1284\r
1285/** Gets the current working directory.\r
1286\r
1287 The getcwd() function shall place an absolute pathname of the current\r
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
1291\r
1292 @param[in,out] buf The buffer to fill.\r
1293 @param[in] size The number of bytes in buffer.\r
1294\r
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
1303**/\r
1304char\r
1305*getcwd (char *buf, size_t size)\r
1306{\r
1307 CONST CHAR16 *Cwd;\r
1308\r
1309 if (size == 0 || buf == NULL) {\r
1310 errno = EINVAL;\r
1311 return NULL;\r
1312 }\r
1313\r
1314 Cwd = ShellGetCurrentDir(NULL);\r
1315 if (Cwd == NULL) {\r
1316 errno = ENOENT;\r
1317 return NULL;\r
1318 }\r
1319 if (size < ((StrLen (Cwd) + 1) * sizeof (CHAR8))) {\r
1320 errno = ERANGE;\r
1321 return (NULL);\r
1322 }\r
1323 return (UnicodeStrToAsciiStr(Cwd, buf));\r
1324}\r
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
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
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
1351 /* Old Shell does not support Set Current Dir. */\r
1352 if(gEfiShellProtocol != NULL) {\r
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
1365 errno = ENOENT;\r
1366 return -1;\r
1367 } else {\r
1368 return 0;\r
1369 }\r
1370 }\r
1371 }\r
1372 /* Add here for non-shell */\r
1373 errno = EPERM;\r
1374 return -1;\r
1375}\r
1376\r
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
1387pid_t tcgetpgrp (int x)\r
1388{\r
1389 return ((pid_t)(UINTN)(gImageHandle));\r
1390}\r
1391\r
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
1400pid_t getpgrp(void)\r
1401{\r
1402 return ((pid_t)(UINTN)(gImageHandle));\r
1403}\r
1404\r
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
1410int\r
1411EFIAPI\r
1412va_Utimes(\r
1413 const char *path,\r
1414 ...\r
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
1431}\r
1432\r
1433/** Set file access and modification times.\r
1434\r
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
1437\r
1438 @retval 0 File times successfully set.\r
1439 @retval -1 An error occured. Error type in errno.\r
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
1448}\r