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