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