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