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