mirror of
https://gitlab.com/bztsrc/posix-uefi.git
synced 2024-12-28 06:55:08 +01:00
Added feof, stat, dirent, time, unlink, mkdir etc.
This commit is contained in:
parent
1bebb7ce51
commit
604ea36b6e
8 changed files with 651 additions and 126 deletions
251
README.md
251
README.md
|
@ -36,7 +36,7 @@ Distributing as Source
|
|||
|
||||
This is the preferred way, as it also provides a Makefile to set up your toolchain properly.
|
||||
|
||||
1. simply copy the `uefi` directory into your source tree (or set up a git submodule). A dozen files, about 96K in total.
|
||||
1. simply copy the `uefi` directory into your source tree (or set up a git submodule). A dozen files, about 128K in total.
|
||||
2. create an extremely simple **Makefile** like the one below
|
||||
3. compile your code for UEFI by running `make`
|
||||
|
||||
|
@ -83,6 +83,147 @@ USE_LLVM = 1
|
|||
include uefi/Makefile
|
||||
```
|
||||
|
||||
Notable Differences to POSIX libc
|
||||
---------------------------------
|
||||
|
||||
This library is nowhere near as complete as glibc or musl for example. It only provides the very basic libc functions
|
||||
for you, because simplicity was one of its main goals. It is the best to say this is just wrapper around the UEFI API,
|
||||
rather than a POSIX compatible libc.
|
||||
|
||||
All strings in the UEFI environment are stored with 16 bits wide characters. The library provides `wchar_t` type for that,
|
||||
so for example your main() is NOT like `main(int argc, char **argv)`, but `main(int argc, wchar_t **argv)` instead. All
|
||||
the other string related libc functions (like strlen() for example) use this wide character type too. For this reason, you
|
||||
must specify your string literals with `L""` and characters with `L''`. Functions that supposed to handle characters in int
|
||||
type (like `getchar`, `putchar`), do not truncate to unsigned char, rather to wchar_t. There's an additional `getchar_ifany`
|
||||
function, which does not block, but returns 0 when there's no key pressed.
|
||||
|
||||
File types in dirent are limited to directories and files only (DT_DIR, DT_REG), but for stat in addition to S_IFDIR and
|
||||
S_IFREG, S_IFIFO also returned (for console streams: stdin, stdout, stderr).
|
||||
|
||||
That's about it, everything else is the same.
|
||||
|
||||
List of Provided POSIX Functions
|
||||
--------------------------------
|
||||
|
||||
### dirent.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| opendir | as usual, but accepts wide char strings |
|
||||
| readdir | as usual |
|
||||
| rewinddir | as usual |
|
||||
| closedir | as usual |
|
||||
|
||||
Because UEFI has no concept of devices files nor of symlinks, only DT_DIR and DT_REG supported.
|
||||
|
||||
### stdlib.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| atoi | as usual, but accepts wide char strings and understands "0x" prefix |
|
||||
| atol | as usual, but accepts wide char strings and understands "0x" prefix |
|
||||
| strtol | as usual, but accepts wide char strings |
|
||||
| malloc | as usual |
|
||||
| calloc | as usual |
|
||||
| realloc | as usual (needs testing) |
|
||||
| free | as usual |
|
||||
| abort | as usual |
|
||||
| exit | as usual |
|
||||
| exit_bs | leave this entire UEFI bullshit behind (exit Boot Services) |
|
||||
| mbtowc | as usual (UTF-8 char to wchar_t) |
|
||||
| wctomb | as usual (wchar_t to UTF-8 char) |
|
||||
| mbstowcs | as usual (UTF-8 string to wchar_t string) |
|
||||
| wcstombs | as usual (wchar_t string to UTF-8 string) |
|
||||
| srand | as usual |
|
||||
| rand | as usual, uses EFI_RNG_PROTOCOL if possible |
|
||||
|
||||
### stdio.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| fopen | as usual, but accepts wide char strings, for mode L"r", L"w" and L"a" only |
|
||||
| fclose | as usual |
|
||||
| fflush | as usual |
|
||||
| fread | as usual, only real files accepted (no stdin) |
|
||||
| fwrite | as usual, only real files accepted (no stdout nor stderr) |
|
||||
| fseek | as usual, only real files accepted (no stdin, stdout, stderr) |
|
||||
| ftell | as usual, only real files accepted (no stdin, stdout, stderr) |
|
||||
| feof | as usual, only real files accepted (no stdin, stdout, stderr) |
|
||||
| fprintf | as usual, but accepts wide char strings, max BUFSIZ, files, stdout, stderr |
|
||||
| printf | as usual, but accepts wide char strings, max BUFSIZ, stdout only |
|
||||
| sprintf | as usual, but accepts wide char strings, max BUFSIZ |
|
||||
| vfprintf | as usual, but accepts wide char strings, max BUFSIZ, files, stdout, stderr |
|
||||
| vprintf | as usual, but accepts wide char strings, max BUFSIZ |
|
||||
| vsprintf | as usual, but accepts wide char strings, max BUFSIZ |
|
||||
| snprintf | as usual, but accepts wide char strings |
|
||||
| vsnprintf | as usual, but accepts wide char strings |
|
||||
| getchar | as usual, waits for a key, blocking, stdin only (no redirects) |
|
||||
| getchar_ifany | non-blocking, returns 0 if there was no key press, UNICODE otherwise |
|
||||
| putchar | as usual, stdout only (no redirects) |
|
||||
|
||||
File open modes: `r` read, `w` write, `a` append. Because of UEFI peculiarities, `wd` creates directory.
|
||||
|
||||
String formating is limited; only supports padding via number prefixes, `%d`, `%x`, `%X`, `%c`, `%s`, `%q` and
|
||||
`%p`. Because it operates on wchar_t, it also supports the non-standard `%C` (printing an UTF-8 character, needs
|
||||
char\*), `%S` (printing an UTF-8 string), `%Q` (printing an escaped UTF-8 string). These functions don't allocate
|
||||
memory, but in return the total length of the output string cannot be longer than BUFSIZ (8k if you haven't
|
||||
defined otherwise), except for the variants which have a maxlen argument. For convenience, `%D` requires
|
||||
`efi_physical_address_t` as argument, and it dumps memory, 16 bytes or one line at once. With the padding
|
||||
modifier you can dump more lines, for example `%5D` gives you 5 lines (80 dumped bytes).
|
||||
|
||||
### string.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| memcpy | as usual, works on bytes |
|
||||
| memmove | as usual, works on bytes |
|
||||
| memset | as usual, works on bytes |
|
||||
| memcmp | as usual, works on bytes |
|
||||
| memchr | as usual, works on bytes |
|
||||
| memrchr | as usual, works on bytes |
|
||||
| memmem | as usual, works on bytes |
|
||||
| memrmem | as usual, works on bytes |
|
||||
| strcpy | works on wide char strings |
|
||||
| strncpy | works on wide char strings |
|
||||
| strcat | works on wide char strings |
|
||||
| strncat | works on wide char strings |
|
||||
| strcmp | works on wide char strings |
|
||||
| strncmp | works on wide char strings |
|
||||
| strdup | works on wide char strings |
|
||||
| strchr | works on wide char strings |
|
||||
| strrchr | works on wide char strings |
|
||||
| strstr | works on wide char strings |
|
||||
| strtok | works on wide char strings |
|
||||
| strtok_r | works on wide char strings |
|
||||
| strlen | works on wide char strings |
|
||||
|
||||
### sys/stat.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| stat | as usual, but accepts wide char strings |
|
||||
| fstat | UEFI doesn't have fd, so it uses FILE\* |
|
||||
| mkdir | as usual, but accepts wide char strings, and mode unused |
|
||||
|
||||
Because UEFI has no concept of device major and minor number nor of inodes, struct stat's fields are limited.
|
||||
|
||||
### time.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| localtime | argument unused, always returns current time in struct tm |
|
||||
| mktime | as usual |
|
||||
| time | as usual |
|
||||
|
||||
### unistd.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| usleep | the usual |
|
||||
| sleep | the usual |
|
||||
| unlink | as usual, but accepts wide char strings |
|
||||
| rmdir | as usual, but accepts wide char strings |
|
||||
|
||||
Accessing UEFI Services
|
||||
-----------------------
|
||||
|
||||
|
@ -126,111 +267,3 @@ naming conflicts. POSIX-UEFI itself ships the very minimum set of typedefs and s
|
|||
#include <efi.h>
|
||||
#include <uefi.h> /* this will work as expected! Both POSIX-UEFI and EDK II / gnu-efi typedefs available */
|
||||
```
|
||||
|
||||
Notable Differences to POSIX libc
|
||||
---------------------------------
|
||||
|
||||
This library is nowhere near as complete as glibc or musl for example. It only provides the very basic libc functions
|
||||
for you, because simplicity was one of its main goals. It is the best to say this is just wrapper around the UEFI API,
|
||||
rather than a POSIX compatible libc.
|
||||
|
||||
All strings in the UEFI environment are stored with 16 bits wide characters. The library provides `wchar_t` type for that,
|
||||
so for example your main() is NOT like `main(int argc, char **argv)`, but `main(int argc, wchar_t **argv)` instead. All
|
||||
the other string related libc functions (like strlen() for example) use this wide character type too. Functions that supposed
|
||||
to handle characters in int type (like `getchar`, `putchar`), do not truncate to unsigned char, rather to wchar_t. For this
|
||||
reason, you must specify your string literals with `L""` and characters with `L''`. There's an additional `getchar_ifany`
|
||||
function, which does not block, but returns 0 when there's no key pressed.
|
||||
|
||||
That's about it, everything else is the same.
|
||||
|
||||
List of Provided POSIX Functions
|
||||
--------------------------------
|
||||
|
||||
### stdlib.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| atoi | as usual, but accepts wide char strings and understands "0x" prefix |
|
||||
| atol | as usual, but accepts wide char strings and understands "0x" prefix |
|
||||
| strtol | as usual, but accepts wide char strings |
|
||||
| malloc | as usual |
|
||||
| calloc | as usual |
|
||||
| realloc | as usual (needs testing) |
|
||||
| free | as usual |
|
||||
| abort | as usual |
|
||||
| exit | as usual |
|
||||
| exit_bs | leave this entire UEFI bullshit behind (exit Boot Services) |
|
||||
| mbtowc | as usual (UTF-8 char to wchar_t) |
|
||||
| wctomb | as usual (wchar_t to UTF-8 char) |
|
||||
| mbstowcs | as usual (UTF-8 string to wchar_t string) |
|
||||
| wcstombs | as usual (wchar_t string to UTF-8 string) |
|
||||
|
||||
### stdio.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| fopen | as usual, but accepts wide char strings, for mode L"r", L"w" and L"a" only |
|
||||
| fclose | as usual |
|
||||
| fflush | as usual |
|
||||
| fread | as usual, only real files accepted (no stdin) |
|
||||
| fwrite | as usual, only real files accepted (no stdout nor stderr) |
|
||||
| fseek | as usual, only real files accepted (no stdin, stdout, stderr) |
|
||||
| ftell | as usual, only real files accepted (no stdin, stdout, stderr) |
|
||||
| fprintf | as usual, but accepts wide char strings, max BUFSIZ, files, stdout, stderr |
|
||||
| printf | as usual, but accepts wide char strings, max BUFSIZ, stdout only |
|
||||
| sprintf | as usual, but accepts wide char strings, max BUFSIZ |
|
||||
| vfprintf | as usual, but accepts wide char strings, max BUFSIZ, files, stdout, stderr |
|
||||
| vprintf | as usual, but accepts wide char strings, max BUFSIZ |
|
||||
| vsprintf | as usual, but accepts wide char strings, max BUFSIZ |
|
||||
| snprintf | as usual, but accepts wide char strings |
|
||||
| vsnprintf | as usual, but accepts wide char strings |
|
||||
| getchar | as usual, waits for a key, blocking, stdin only (no redirects) |
|
||||
| getchar_ifany | non-blocking, returns 0 if there was no key press, UNICODE otherwise |
|
||||
| putchar | as usual, stdout only (no redirects) |
|
||||
|
||||
String formating is limited; only supports padding via number prefixes, `%d`, `%x`, `%X`, `%c`, `%s`, `%q` and
|
||||
`%p`. Because it operates on wchar_t, it also supports the non-standard `%C` (printing an UTF-8 character, needs
|
||||
char\*), `%S` (printing an UTF-8 string), `%Q` (printing an escaped UTF-8 string). These functions don't allocate
|
||||
memory, but in return the total length of the output string cannot be longer than BUFSIZ (8k if you haven't
|
||||
defined otherwise), except for the variants which have a maxlen argument. For convenience, `%D` requires
|
||||
`efi_physical_address_t` as argument, and it dumps memory, 16 bytes or one line at once. With the padding
|
||||
modifier you can dump more lines, for example `%5D`.
|
||||
|
||||
### string.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| memcpy | as usual, works on bytes |
|
||||
| memmove | as usual, works on bytes |
|
||||
| memset | as usual, works on bytes |
|
||||
| memcmp | as usual, works on bytes |
|
||||
| memchr | as usual, works on bytes |
|
||||
| memrchr | as usual, works on bytes |
|
||||
| memmem | as usual, works on bytes |
|
||||
| memrmem | as usual, works on bytes |
|
||||
| strcpy | works on wide char strings |
|
||||
| strncpy | works on wide char strings |
|
||||
| strcat | works on wide char strings |
|
||||
| strncat | works on wide char strings |
|
||||
| strcmp | works on wide char strings |
|
||||
| strncmp | works on wide char strings |
|
||||
| strdup | works on wide char strings |
|
||||
| strchr | works on wide char strings |
|
||||
| strrchr | works on wide char strings |
|
||||
| strstr | works on wide char strings |
|
||||
| strtok | works on wide char strings |
|
||||
| strtok_r | works on wide char strings |
|
||||
| strlen | works on wide char strings |
|
||||
|
||||
### time.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| localtime | argument unused, always returns current time in struct tm |
|
||||
|
||||
### unistd.h
|
||||
|
||||
| Function | Description |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| usleep | the usual |
|
||||
| sleep | the usual |
|
||||
|
|
72
uefi/dirent.c
Normal file
72
uefi/dirent.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* dirent.c
|
||||
*
|
||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the POSIX-UEFI package.
|
||||
* @brief Implementing functions which are defined in dirent.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <uefi.h>
|
||||
|
||||
extern void __stdio_seterrno(efi_status_t status);
|
||||
struct dirent __dirent;
|
||||
|
||||
DIR *opendir (const wchar_t *__name)
|
||||
{
|
||||
DIR *dp = (DIR*)fopen(__name, L"rd");
|
||||
rewinddir(dp);
|
||||
return dp;
|
||||
}
|
||||
|
||||
struct dirent *readdir (DIR *__dirp)
|
||||
{
|
||||
efi_status_t status;
|
||||
efi_file_info_t info;
|
||||
uintn_t bs;
|
||||
memset(&__dirent, 0, sizeof(struct dirent));
|
||||
status = __dirp->Read(__dirp, &bs, &info);
|
||||
if(EFI_ERROR(status) || !bs) {
|
||||
if(EFI_ERROR(status)) __stdio_seterrno(status);
|
||||
else errno = 0;
|
||||
return NULL;
|
||||
}
|
||||
__dirent.d_type = info.Attribute & EFI_FILE_DIRECTORY ? DT_DIR : DT_REG;
|
||||
__dirent.d_reclen = strlen(info.FileName);
|
||||
strcpy(__dirent.d_name, info.FileName);
|
||||
return &__dirent;
|
||||
}
|
||||
|
||||
void rewinddir (DIR *__dirp)
|
||||
{
|
||||
if(__dirp)
|
||||
__dirp->SetPosition(__dirp, 0);
|
||||
}
|
||||
|
||||
int closedir (DIR *__dirp)
|
||||
{
|
||||
return fclose((FILE*)__dirp);
|
||||
}
|
||||
|
||||
|
106
uefi/stat.c
Normal file
106
uefi/stat.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* stat.c
|
||||
*
|
||||
* Copyright (C) 2021 bzt (bztsrc@gitlab)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the POSIX-UEFI package.
|
||||
* @brief Implementing functions which are defined in sys/stat.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <uefi.h>
|
||||
|
||||
extern void __stdio_seterrno(efi_status_t status);
|
||||
extern time_t __mktime_efi(efi_time_t *t);
|
||||
|
||||
int fstat (FILE *__f, struct stat *__buf)
|
||||
{
|
||||
uint64_t off = 0;
|
||||
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
|
||||
efi_file_info_t info;
|
||||
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);
|
||||
efi_status_t status;
|
||||
|
||||
if(!__f || !__buf) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
memset(__buf, 0, sizeof(struct stat));
|
||||
if(__f == stdin) {
|
||||
__buf->st_mode = S_IREAD | S_IFIFO;
|
||||
return 0;
|
||||
}
|
||||
if(__f == stdout || __f == stderr) {
|
||||
__buf->st_mode = S_IWRITE | S_IFIFO;
|
||||
return 0;
|
||||
}
|
||||
status = __f->GetInfo(__f, &infGuid, &fsiz, &info);
|
||||
if(EFI_ERROR(status)) {
|
||||
__stdio_seterrno(status);
|
||||
return -1;
|
||||
}
|
||||
__buf->st_mode = S_IREAD |
|
||||
(info.Attribute & EFI_FILE_READ_ONLY ? 0 : S_IWRITE) |
|
||||
(info.Attribute & EFI_FILE_DIRECTORY ? S_IFDIR : S_IFREG);
|
||||
__buf->st_size = (off_t)info.FileSize;
|
||||
__buf->st_blocks = (blkcnt_t)info.PhysicalSize;
|
||||
__buf->st_atime = __mktime_efi(&info.LastAccessTime);
|
||||
__buf->st_mtime = __mktime_efi(&info.ModificationTime);
|
||||
__buf->st_ctime = __mktime_efi(&info.CreateTime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stat (const wchar_t *__file, struct stat *__buf)
|
||||
{
|
||||
int ret;
|
||||
FILE *f;
|
||||
|
||||
if(!__file || !*__file || !__buf) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
f = fopen(__file, L"*");
|
||||
if(!f) {
|
||||
memset(__buf, 0, sizeof(struct stat));
|
||||
return -1;
|
||||
}
|
||||
ret = fstat(f, __buf);
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern int mkdir (const wchar_t *__path, mode_t __mode)
|
||||
{
|
||||
FILE *f;
|
||||
(void)__mode;
|
||||
if(!__path || !*__path) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
f = fopen(__path, L"wd");
|
||||
if(!f) {
|
||||
return -1;
|
||||
}
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
132
uefi/stdio.c
132
uefi/stdio.c
|
@ -56,12 +56,72 @@ int fflush (FILE *__stream)
|
|||
return !EFI_ERROR(status);
|
||||
}
|
||||
|
||||
FILE *fopen (const wchar_t *__filename, const char *__modes)
|
||||
int __remove (const wchar_t *__filename, int isdir)
|
||||
{
|
||||
efi_status_t status;
|
||||
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
|
||||
efi_file_info_t info;
|
||||
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);
|
||||
FILE *f = fopen(__filename, L"r");
|
||||
if(f == stdin || f == stdout || f == stderr) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
if(isdir != -1) {
|
||||
status = f->GetInfo(f, &infGuid, &fsiz, &info);
|
||||
if(EFI_ERROR(status)) goto err;
|
||||
if(isdir == 0 && (info.Attribute & EFI_FILE_DIRECTORY)) {
|
||||
fclose(f); errno = EISDIR;
|
||||
return -1;
|
||||
}
|
||||
if(isdir == 1 && !(info.Attribute & EFI_FILE_DIRECTORY)) {
|
||||
fclose(f); errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
status = f->Delete(f);
|
||||
if(EFI_ERROR(status)) {
|
||||
err: __stdio_seterrno(status);
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
/* no need for fclose(f); */
|
||||
free(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remove (const wchar_t *__filename)
|
||||
{
|
||||
return __remove(__filename, -1);
|
||||
}
|
||||
|
||||
FILE *fopen (const wchar_t *__filename, const wchar_t *__modes)
|
||||
{
|
||||
FILE *ret;
|
||||
efi_status_t status;
|
||||
efi_guid_t sfsGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
||||
efi_simple_file_system_protocol_t *sfs = NULL;
|
||||
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
|
||||
efi_file_info_t info;
|
||||
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);
|
||||
|
||||
if(!__filename || !*__filename || !__modes || !*__modes) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
/* fake some device names. UEFI has no concept of device files */
|
||||
if(!strcmp(__filename, L"/dev/stdin")) {
|
||||
if(__modes[0] == L'w' || __modes[0] == L'a') { errno = EPERM; return NULL; }
|
||||
return stdin;
|
||||
}
|
||||
if(!strcmp(__filename, L"/dev/stdout")) {
|
||||
if(__modes[0] == L'r') { errno = EPERM; return NULL; }
|
||||
return stdout;
|
||||
}
|
||||
if(!strcmp(__filename, L"/dev/stderr")) {
|
||||
if(__modes[0] == L'r') { errno = EPERM; return NULL; }
|
||||
return stderr;
|
||||
}
|
||||
if(!__root_dir && LIP) {
|
||||
status = BS->HandleProtocol(LIP->DeviceHandle, &sfsGuid, (void **)&sfs);
|
||||
if(!EFI_ERROR(status))
|
||||
|
@ -75,11 +135,20 @@ FILE *fopen (const wchar_t *__filename, const char *__modes)
|
|||
ret = (FILE*)malloc(sizeof(FILE));
|
||||
if(!ret) return NULL;
|
||||
status = __root_dir->Open(__root_dir, &ret, (wchar_t*)__filename,
|
||||
__modes[0] == L'r' ? EFI_FILE_MODE_READ : (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE), 0);
|
||||
__modes[0] == L'w' ? (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE) : EFI_FILE_MODE_READ,
|
||||
__modes[1] == L'd' ? EFI_FILE_DIRECTORY : 0);
|
||||
if(EFI_ERROR(status)) {
|
||||
__stdio_seterrno(status);
|
||||
err: __stdio_seterrno(status);
|
||||
free(ret); ret = NULL;
|
||||
}
|
||||
status = ret->GetInfo(ret, &infGuid, &fsiz, &info);
|
||||
if(EFI_ERROR(status)) goto err;
|
||||
if(__modes[1] == L'd' && !(info.Attribute & EFI_FILE_DIRECTORY)) {
|
||||
free(ret); errno = ENOTDIR; return NULL;
|
||||
}
|
||||
if(__modes[1] != L'd' && (info.Attribute & EFI_FILE_DIRECTORY)) {
|
||||
free(ret); errno = EISDIR; return NULL;
|
||||
}
|
||||
if(__modes[0] == L'a') fseek(ret, 0, SEEK_END);
|
||||
return ret;
|
||||
}
|
||||
|
@ -87,15 +156,32 @@ FILE *fopen (const wchar_t *__filename, const char *__modes)
|
|||
size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream)
|
||||
{
|
||||
uintn_t bs = __size * __n;
|
||||
efi_status_t status = __stream->Read(__stream, &bs, __ptr);
|
||||
if(status == EFI_END_OF_FILE) bs = 0;
|
||||
efi_status_t status;
|
||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
||||
errno = ESPIPE;
|
||||
return 0;
|
||||
}
|
||||
status = __stream->Read(__stream, &bs, __ptr);
|
||||
if(EFI_ERROR(status)) {
|
||||
__stdio_seterrno(status);
|
||||
return 0;
|
||||
}
|
||||
return bs / __size;
|
||||
}
|
||||
|
||||
size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__stream)
|
||||
{
|
||||
uintn_t bs = __size * __n;
|
||||
efi_status_t status = __stream->Write(__stream, &bs, (void *)__ptr);
|
||||
efi_status_t status;
|
||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
||||
errno = ESPIPE;
|
||||
return 0;
|
||||
}
|
||||
status = __stream->Write(__stream, &bs, (void *)__ptr);
|
||||
if(EFI_ERROR(status)) {
|
||||
__stdio_seterrno(status);
|
||||
return 0;
|
||||
}
|
||||
return bs / __size;
|
||||
}
|
||||
|
||||
|
@ -106,6 +192,10 @@ int fseek (FILE *__stream, long int __off, int __whence)
|
|||
efi_guid_t infoGuid = EFI_FILE_INFO_GUID;
|
||||
efi_file_info_t *info;
|
||||
uintn_t infosiz = sizeof(efi_file_info_t) + 16;
|
||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
switch(__whence) {
|
||||
case SEEK_END:
|
||||
status = __stream->GetInfo(__stream, &infoGuid, &infosiz, info);
|
||||
|
@ -131,10 +221,38 @@ int fseek (FILE *__stream, long int __off, int __whence)
|
|||
long int ftell (FILE *__stream)
|
||||
{
|
||||
uint64_t off = 0;
|
||||
efi_status_t status = __stream->GetPosition(__stream, &off);
|
||||
efi_status_t status;
|
||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
status = __stream->GetPosition(__stream, &off);
|
||||
return EFI_ERROR(status) ? -1 : (long int)off;
|
||||
}
|
||||
|
||||
int feof (FILE *__stream)
|
||||
{
|
||||
uint64_t off = 0;
|
||||
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
|
||||
efi_file_info_t info;
|
||||
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t);
|
||||
efi_status_t status;
|
||||
int ret;
|
||||
if(__stream == stdin || __stream == stdout || __stream == stderr) {
|
||||
errno = ESPIPE;
|
||||
return 0;
|
||||
}
|
||||
status = __stream->GetPosition(__stream, &off);
|
||||
if(EFI_ERROR(status)) {
|
||||
err: __stdio_seterrno(status);
|
||||
return 1;
|
||||
}
|
||||
status = __stream->GetInfo(__stream, &infGuid, &fsiz, &info);
|
||||
if(EFI_ERROR(status)) goto err;
|
||||
__stream->SetPosition(__stream, off);
|
||||
return info.FileSize == off;
|
||||
}
|
||||
|
||||
int vsnprintf(wchar_t *dst, size_t maxlen, const wchar_t *fmt, __builtin_va_list args)
|
||||
{
|
||||
#define needsescape(a) (a==L'\"' || a==L'\\' || a==L'\a' || a==L'\b' || a==L'\033' || a=='\f' || \
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <uefi.h>
|
||||
|
||||
int errno = 0;
|
||||
static uint64_t __srand_seed = 6364136223846793005ULL;
|
||||
|
||||
int atoi(const wchar_t *s)
|
||||
{
|
||||
|
@ -228,3 +229,23 @@ size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n)
|
|||
};
|
||||
return __s - orig;
|
||||
}
|
||||
|
||||
void srand(unsigned int __seed)
|
||||
{
|
||||
__srand_seed = __seed - 1;
|
||||
}
|
||||
|
||||
int rand()
|
||||
{
|
||||
efi_guid_t rngGuid = EFI_RNG_PROTOCOL_GUID;
|
||||
efi_rng_protocol_t *rng = NULL;
|
||||
efi_status_t status;
|
||||
int ret = 0;
|
||||
|
||||
__srand_seed = 6364136223846793005ULL*__srand_seed + 1;
|
||||
status = BS->LocateProtocol(&rngGuid, NULL, (void**)&rng);
|
||||
if(!EFI_ERROR(status) && rng)
|
||||
rng->GetRNG(rng, NULL, (uintn_t)sizeof(int), (uint8_t*)&ret);
|
||||
ret ^= (int)(__srand_seed>>33);
|
||||
return ret;
|
||||
}
|
||||
|
|
108
uefi/time.c
108
uefi/time.c
|
@ -32,6 +32,67 @@
|
|||
|
||||
static struct tm __tm;
|
||||
|
||||
/* from musl */
|
||||
uint64_t __year_to_secs(uint64_t year, int *is_leap)
|
||||
{
|
||||
int y, cycles, centuries, leaps, rem;
|
||||
|
||||
if (year-2ULL <= 136) {
|
||||
y = year;
|
||||
leaps = (y-68)>>2;
|
||||
if (!((y-68)&3)) {
|
||||
leaps--;
|
||||
if (is_leap) *is_leap = 1;
|
||||
} else if (is_leap) *is_leap = 0;
|
||||
return 31536000*(y-70) + 86400*leaps;
|
||||
}
|
||||
|
||||
if (!is_leap) is_leap = &(int){0};
|
||||
cycles = (year-100) / 400;
|
||||
rem = (year-100) % 400;
|
||||
if (rem < 0) {
|
||||
cycles--;
|
||||
rem += 400;
|
||||
}
|
||||
if (!rem) {
|
||||
*is_leap = 1;
|
||||
centuries = 0;
|
||||
leaps = 0;
|
||||
} else {
|
||||
if (rem >= 200) {
|
||||
if (rem >= 300) centuries = 3, rem -= 300;
|
||||
else centuries = 2, rem -= 200;
|
||||
} else {
|
||||
if (rem >= 100) centuries = 1, rem -= 100;
|
||||
else centuries = 0;
|
||||
}
|
||||
if (!rem) {
|
||||
*is_leap = 0;
|
||||
leaps = 0;
|
||||
} else {
|
||||
leaps = rem / 4U;
|
||||
rem %= 4U;
|
||||
*is_leap = !rem;
|
||||
}
|
||||
}
|
||||
|
||||
leaps += 97*cycles + 24*centuries - *is_leap;
|
||||
|
||||
return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
|
||||
}
|
||||
|
||||
time_t __mktime_efi(efi_time_t *t)
|
||||
{
|
||||
__tm.tm_year = t->Year + 98;
|
||||
__tm.tm_mon = t->Month - 1;
|
||||
__tm.tm_mday = t->Day;
|
||||
__tm.tm_hour = t->Hour;
|
||||
__tm.tm_min = t->Minute;
|
||||
__tm.tm_sec = t->Second;
|
||||
__tm.tm_isdst = t->Daylight;
|
||||
return mktime(&__tm);
|
||||
}
|
||||
|
||||
/**
|
||||
* This isn't POSIX, no arguments. Just returns the current time in struct tm
|
||||
*/
|
||||
|
@ -40,12 +101,45 @@ struct tm *localtime (const time_t *__timer)
|
|||
efi_time_t t = {0};
|
||||
(void)__timer;
|
||||
ST->RuntimeServices->GetTime(&t, NULL);
|
||||
__tm.tm_year = t.Year + 98;
|
||||
__tm.tm_mon = t.Month - 1;
|
||||
__tm.tm_mday = t.Day;
|
||||
__tm.tm_hour = t.Hour;
|
||||
__tm.tm_min = t.Minute;
|
||||
__tm.tm_sec = t.Second;
|
||||
__tm.tm_isdst = t.Daylight;
|
||||
__mktime_efi(&t);
|
||||
return &__tm;
|
||||
}
|
||||
|
||||
time_t mktime(const struct tm *tm)
|
||||
{
|
||||
static const int secs_through_month[] = {
|
||||
0, 31*86400, 59*86400, 90*86400,
|
||||
120*86400, 151*86400, 181*86400, 212*86400,
|
||||
243*86400, 273*86400, 304*86400, 334*86400 };
|
||||
int is_leap;
|
||||
uint64_t year = tm->tm_year, t;
|
||||
int month = tm->tm_mon;
|
||||
if (month >= 12 || month < 0) {
|
||||
int adj = month / 12;
|
||||
month %= 12;
|
||||
if (month < 0) {
|
||||
adj--;
|
||||
month += 12;
|
||||
}
|
||||
year += adj;
|
||||
}
|
||||
t = __year_to_secs(year, &is_leap);
|
||||
t += secs_through_month[month];
|
||||
if (is_leap && month >= 2) t += 86400;
|
||||
t += 86400LL * (tm->tm_mday-1);
|
||||
t += 3600LL * tm->tm_hour;
|
||||
t += 60LL * tm->tm_min;
|
||||
t += tm->tm_sec;
|
||||
return (time_t)t;
|
||||
}
|
||||
|
||||
time_t time(time_t *__timer)
|
||||
{
|
||||
time_t ret;
|
||||
efi_time_t t = {0};
|
||||
ST->RuntimeServices->GetTime(&t, NULL);
|
||||
ret = __mktime_efi(&t);
|
||||
if(__timer) *__timer = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
75
uefi/uefi.h
75
uefi/uefi.h
|
@ -62,6 +62,9 @@ typedef uint16_t wchar_t;
|
|||
typedef uint64_t uintn_t;
|
||||
typedef uint64_t size_t;
|
||||
typedef uint64_t time_t;
|
||||
typedef uint64_t mode_t;
|
||||
typedef uint64_t off_t;
|
||||
typedef uint64_t blkcnt_t;
|
||||
typedef uint64_t efi_status_t;
|
||||
typedef uint64_t efi_tpl_t;
|
||||
typedef uint64_t efi_lba_t;
|
||||
|
@ -644,6 +647,7 @@ typedef struct {
|
|||
efi_query_variable_info_t QueryVariableInfo;
|
||||
} efi_runtime_services_t;
|
||||
extern efi_runtime_services_t *RT;
|
||||
#define gRT RT
|
||||
|
||||
/** Boot Services ***/
|
||||
typedef struct {
|
||||
|
@ -759,6 +763,7 @@ typedef struct {
|
|||
efi_calculate_crc32_t CalculateCrc32;
|
||||
} efi_boot_services_t;
|
||||
extern efi_boot_services_t *BS;
|
||||
#define gBS BS
|
||||
|
||||
/*** Loaded Image Protocol ***/
|
||||
#ifndef EFI_LOADED_IMAGE_PROTOCOL_GUID
|
||||
|
@ -814,6 +819,7 @@ typedef struct {
|
|||
efi_configuration_table_t *ConfigurationTable;
|
||||
} efi_system_table_t;
|
||||
extern efi_system_table_t *ST;
|
||||
#define gST ST
|
||||
|
||||
/*** Simple File System Protocol ***/
|
||||
#ifndef EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID
|
||||
|
@ -829,7 +835,7 @@ extern efi_system_table_t *ST;
|
|||
#define EFI_FILE_READ_ONLY 0x0000000000000001
|
||||
#define EFI_FILE_HIDDEN 0x0000000000000002
|
||||
#define EFI_FILE_SYSTEM 0x0000000000000004
|
||||
#define EFI_FILE_RESERVIED 0x0000000000000008
|
||||
#define EFI_FILE_RESERVED 0x0000000000000008
|
||||
#define EFI_FILE_DIRECTORY 0x0000000000000010
|
||||
#define EFI_FILE_ARCHIVE 0x0000000000000020
|
||||
#define EFI_FILE_VALID_ATTR 0x0000000000000037
|
||||
|
@ -842,6 +848,10 @@ extern efi_system_table_t *ST;
|
|||
#define EFI_FILE_INFO_GUID { 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} }
|
||||
#endif
|
||||
|
||||
#ifndef FILENAME_MAX
|
||||
#define FILENAME_MAX 262 /* from FAT spec */
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint64_t Size;
|
||||
uint64_t FileSize;
|
||||
|
@ -850,7 +860,7 @@ typedef struct {
|
|||
efi_time_t LastAccessTime;
|
||||
efi_time_t ModificationTime;
|
||||
uint64_t Attribute;
|
||||
wchar_t FileName[1];
|
||||
wchar_t FileName[FILENAME_MAX];
|
||||
} efi_file_info_t;
|
||||
|
||||
typedef struct efi_file_handle_s efi_file_handle_t;
|
||||
|
@ -918,6 +928,19 @@ typedef struct {
|
|||
efi_handle_t StdErr;
|
||||
} efi_shell_interface_protocol_t;
|
||||
|
||||
/*** Random Number Generator ***/
|
||||
#ifndef EFI_RNG_PROTOCOL_GUID
|
||||
#define EFI_RNG_PROTOCOL_GUID { 0x3152bca5, 0xeade, 0x433d, {0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44} }
|
||||
#endif
|
||||
|
||||
typedef efi_status_t (EFIAPI *efi_rng_get_info_t)(void *This, uintn_t *RNGAlgorithmListSize, efi_guid_t *RNGAlgorithmList);
|
||||
typedef efi_status_t (EFIAPI *efi_rng_get_rng_t)(void *This, efi_guid_t *RNGAlgorithm, uintn_t RNGValueLength, uint8_t *RNGValue);
|
||||
|
||||
typedef struct {
|
||||
efi_rng_get_info_t GetInfo;
|
||||
efi_rng_get_rng_t GetRNG;
|
||||
} efi_rng_protocol_t;
|
||||
|
||||
/*** Serial IO Protocol (not used, but could be useful to have) ***/
|
||||
#ifndef EFI_SERIAL_IO_PROTOCOL_GUID
|
||||
#define EFI_SERIAL_IO_PROTOCOL_GUID { 0xBB25CF6F, 0xF1D4, 0x11D2, {0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD} }
|
||||
|
@ -1114,6 +1137,22 @@ typedef struct {
|
|||
#define min(x,y) ((x)<(y)?(x):(y))
|
||||
#define max(x,y) ((x)>(y)?(x):(y))
|
||||
|
||||
/* dirent.h */
|
||||
#define IFTODT(mode) (((mode) & 0170000) >> 12)
|
||||
#define DTTOIF(dirtype) ((dirtype) << 12)
|
||||
#define DT_DIR 4
|
||||
#define DT_REG 8
|
||||
struct dirent {
|
||||
unsigned short int d_reclen;
|
||||
unsigned char d_type;
|
||||
wchar_t d_name[FILENAME_MAX];
|
||||
};
|
||||
typedef struct efi_file_handle_s DIR;
|
||||
extern DIR *opendir (const wchar_t *__name);
|
||||
extern struct dirent *readdir (DIR *__dirp);
|
||||
extern void rewinddir (DIR *__dirp);
|
||||
extern int closedir (DIR *__dirp);
|
||||
|
||||
/* errno.h */
|
||||
extern int errno;
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
|
@ -1152,6 +1191,7 @@ extern int errno;
|
|||
#define ERANGE 34 /* Math result not representable */
|
||||
|
||||
/* stdlib.h */
|
||||
#define RAND_MAX 2147483647
|
||||
typedef int (*__compar_fn_t) (const void *, const void *);
|
||||
extern int atoi (const wchar_t *__nptr);
|
||||
extern int64_t atol (const wchar_t *__nptr);
|
||||
|
@ -1171,6 +1211,8 @@ extern int mbtowc (wchar_t * __pwc, const char * __s, size_t __n);
|
|||
extern int wctomb (char *__s, wchar_t __wchar);
|
||||
extern size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n);
|
||||
extern size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n);
|
||||
extern void srand(unsigned int __seed);
|
||||
extern int rand(void);
|
||||
|
||||
/* stdio.h */
|
||||
#ifndef BUFSIZ
|
||||
|
@ -1185,7 +1227,8 @@ extern size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n);
|
|||
typedef struct efi_file_handle_s FILE;
|
||||
extern int fclose (FILE *__stream);
|
||||
extern int fflush (FILE *__stream);
|
||||
extern FILE *fopen (const wchar_t *__filename, const char *__modes);
|
||||
extern int remove (const wchar_t *__filename);
|
||||
extern FILE *fopen (const wchar_t *__filename, const wchar_t *__modes);
|
||||
extern size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream);
|
||||
extern size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__s);
|
||||
extern int fseek (FILE *__stream, long int __off, int __whence);
|
||||
|
@ -1236,6 +1279,29 @@ extern wchar_t *strtok (wchar_t *__s, const wchar_t *__delim);
|
|||
extern wchar_t *strtok_r (wchar_t *__s, const wchar_t *__delim, wchar_t **__save_ptr);
|
||||
extern size_t strlen (const wchar_t *__s);
|
||||
|
||||
/* sys/stat.h */
|
||||
#define S_IREAD 0400 /* Read by owner. */
|
||||
#define S_IWRITE 0200 /* Write by owner. */
|
||||
#define S_IFMT 0170000 /* These bits determine file type. */
|
||||
#define S_IFIFO 0010000 /* FIFO. */
|
||||
#define S_IFDIR 0040000 /* Directory. */
|
||||
#define S_IFREG 0100000 /* Regular file. */
|
||||
#define S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
|
||||
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
|
||||
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
|
||||
#define S_ISFIFO(mode) __S_ISTYPE((mode), __S_IFIFO)
|
||||
struct stat {
|
||||
mode_t st_mode;
|
||||
off_t st_size;
|
||||
blkcnt_t st_blocks;
|
||||
time_t st_atime;
|
||||
time_t st_mtime;
|
||||
time_t st_ctime;
|
||||
};
|
||||
extern int stat (const wchar_t *__file, struct stat *__buf);
|
||||
extern int fstat (FILE *__f, struct stat *__buf);
|
||||
extern int mkdir (const wchar_t *__path, mode_t __mode);
|
||||
|
||||
/* time.h */
|
||||
struct tm {
|
||||
int tm_sec; /* Seconds. [0-60] (1 leap second) */
|
||||
|
@ -1249,10 +1315,13 @@ struct tm {
|
|||
int tm_isdst; /* DST. [-1/0/1]*/
|
||||
};
|
||||
extern struct tm *localtime (const time_t *__timer);
|
||||
extern time_t mktime(const struct tm *__tm);
|
||||
extern time_t time(time_t *__timer);
|
||||
|
||||
/* unistd.h */
|
||||
extern unsigned int sleep (unsigned int __seconds);
|
||||
extern int usleep (unsigned long int __useconds);
|
||||
extern int unlink (const wchar_t *__filename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include <uefi.h>
|
||||
|
||||
int __remove(const wchar_t *__filename, int isdir);
|
||||
|
||||
int usleep (unsigned long int __useconds)
|
||||
{
|
||||
BS->Stall(__useconds);
|
||||
|
@ -41,3 +43,13 @@ unsigned int sleep (unsigned int __seconds)
|
|||
BS->Stall((unsigned long int)__seconds * 1000000UL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unlink (const wchar_t *__filename)
|
||||
{
|
||||
return __remove(__filename, 0);
|
||||
}
|
||||
|
||||
int rmdir (const wchar_t *__filename)
|
||||
{
|
||||
return __remove(__filename, 1);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue