- Implemented opendir, readdir, closedir, and related directory functions - Added fcntl system call support with proper flag handling - Integrated compiler-rt builtins for 128-bit integer operations - Updated build system to fetch and compile compiler-rt dependencies - Refactored ls command to use standard POSIX directory APIs - Added directory file descriptor management in kernel - Implemented getdents64master
parent
ee69e75f4f
commit
78d6d2b67b
34 changed files with 945 additions and 144 deletions
@ -0,0 +1,15 @@ |
||||
1a8f1058753f1ba890de984e48f0242a3a5c29a6a8f2ed9fd813f36985387e8d LICENSE.TXT |
||||
ec5175561075845b7b16a92ad5ecdfd42a284de2736dd07e4ca7011b75c37709 lib/builtins/int_endianness.h |
||||
a5735bf1bfacecd6cf5785ed19ae62a981ff2f0923c38caa99f4af47f2be57b5 lib/builtins/int_lib.h |
||||
198552b25faf8a75b077ea145591cd7f6762b7f2712321b18f5e38fee8cc2a1e lib/builtins/int_types.h |
||||
63d06198ab720a75c20bfd84be895c2746581b129168bae6201e7384bbb0473b lib/builtins/int_util.h |
||||
833906405d418f0f421d6155acc5abf79d9902ed37a44903d01c95ff55d3a010 lib/builtins/int_div_impl.inc |
||||
39afba4710d9b24c9c27cccdc8e18a18db10ce3616dc60cdcfa494f0a49a3a60 lib/builtins/ashlti3.c |
||||
a6da2dc32167fbf369bbb0d185daeaf1b23aa13fda72f832e2097926c9fb2d74 lib/builtins/ashrti3.c |
||||
89da91e31e33c3c62128c32ed1c740856a413c17ac1e7cd75702da37d1cf9fa4 lib/builtins/lshrti3.c |
||||
b8392be2b070cda2a01bc33c7912e06ab83ce9a1ec7995fe0acbe44540cf92ae lib/builtins/divti3.c |
||||
23b5f5af57a8a3ccdab785eec6e486bffef932cee87ff1152b3beedaa6296414 lib/builtins/modti3.c |
||||
b2e133764668e78119f7c76facbb11f0b4b7c0c6b279fb0b97a589da11d1d060 lib/builtins/multi3.c |
||||
c0b20f06f6e0e8a6b5423ca6674cf0c57219d07554f6f35c9ecc36bf28915355 lib/builtins/udivti3.c |
||||
2fb3eb297e006000935452cb34622b389c5ce39af6e1416b4a11398b78142251 lib/builtins/udivmodti4.c |
||||
3d88088419d87b486858a4bf54ff08209944ae526c77b8dc5e0c0b6b8001c1e9 lib/builtins/umodti3.c |
||||
@ -0,0 +1,34 @@ |
||||
#!/usr/bin/env sh |
||||
|
||||
set -eu |
||||
|
||||
project_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) |
||||
version=23.1.1 |
||||
tag="llvmorg-${version}" |
||||
target="${project_dir}/thirdparty/compiler-rt" |
||||
marker="${target}/.typephp-source-${version}" |
||||
manifest="${project_dir}/tools/compiler-rt-builtins-files.sha256" |
||||
base_url="https://raw.githubusercontent.com/llvm/llvm-project/${tag}/compiler-rt" |
||||
|
||||
if [ -f "${marker}" ] && [ -f "${target}/lib/builtins/udivti3.c" ]; then |
||||
exit 0 |
||||
fi |
||||
|
||||
temporary=$(mktemp -d "${TMPDIR:-/tmp}/typephp-os-compiler-rt.XXXXXX") |
||||
trap 'rm -rf "${temporary}"' EXIT HUP INT TERM |
||||
staging="${temporary}/installed" |
||||
|
||||
echo "Downloading compiler-rt builtins ${version}" |
||||
while read -r expected relative; do |
||||
[ -n "${relative}" ] || continue |
||||
destination="${staging}/${relative}" |
||||
mkdir -p "$(dirname -- "${destination}")" |
||||
curl -L --fail --retry 3 -o "${destination}" "${base_url}/${relative}" |
||||
printf '%s %s\n' "${expected}" "${destination}" | sha256sum -c - |
||||
done < "${manifest}" |
||||
|
||||
mkdir -p "${project_dir}/thirdparty" |
||||
rm -rf "${target}" |
||||
mv "${staging}" "${target}" |
||||
printf '%s\n' "${tag}" > "${marker}" |
||||
echo "Installed compiler-rt builtins ${version} in ${target}" |
||||
@ -0,0 +1,33 @@ |
||||
#!/usr/bin/env sh |
||||
|
||||
set -eu |
||||
|
||||
project_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) |
||||
version=7.0.0 |
||||
commit=7c2a178142625cc9852e59a1a090468c61a62d3b |
||||
archive_sha256=56d62366a6a15bc3fd8741bebcb311ca543553f7b734b1e780aeae33691bd621 |
||||
target="${project_dir}/thirdparty/mlibc" |
||||
marker="${target}/.typephp-source-${version}" |
||||
|
||||
if [ -f "${marker}" ] && [ -f "${target}/meson.build" ]; then |
||||
exit 0 |
||||
fi |
||||
|
||||
temporary=$(mktemp -d "${TMPDIR:-/tmp}/typephp-os-mlibc.XXXXXX") |
||||
trap 'rm -rf "${temporary}"' EXIT HUP INT TERM |
||||
archive="${temporary}/mlibc.tar.gz" |
||||
staging="${temporary}/installed" |
||||
|
||||
echo "Downloading mlibc v${version} (${commit})" |
||||
curl -L --fail --retry 3 -o "${archive}" \ |
||||
"https://github.com/managarm/mlibc/archive/refs/tags/v${version}.tar.gz" |
||||
printf '%s %s\n' "${archive_sha256}" "${archive}" | sha256sum -c - |
||||
mkdir -p "${staging}" |
||||
tar -xzf "${archive}" -C "${staging}" --strip-components=1 |
||||
test -f "${staging}/LICENSE" |
||||
|
||||
mkdir -p "${project_dir}/thirdparty" |
||||
rm -rf "${target}" |
||||
mv "${staging}" "${target}" |
||||
printf '%s\n' "${commit}" > "${marker}" |
||||
echo "Installed mlibc v${version} in ${target}" |
||||
@ -0,0 +1,39 @@ |
||||
#!/usr/bin/env sh |
||||
|
||||
set -eu |
||||
|
||||
project_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) |
||||
version=0.8.7 |
||||
archive_sha256=e328a1d59b94748b111e022bca6a9d2fc0481fb57d23c87d90f394b559d4f062 |
||||
target="${project_dir}/thirdparty/openlibm" |
||||
marker="${target}/.typephp-source-${version}" |
||||
manifest="${project_dir}/tools/openlibm-files.txt" |
||||
|
||||
if [ -f "${marker}" ] && [ -f "${target}/src/e_sqrt.c" ]; then |
||||
exit 0 |
||||
fi |
||||
|
||||
temporary=$(mktemp -d "${TMPDIR:-/tmp}/typephp-os-openlibm.XXXXXX") |
||||
trap 'rm -rf "${temporary}"' EXIT HUP INT TERM |
||||
archive="${temporary}/openlibm.tar.gz" |
||||
source_dir="${temporary}/openlibm-${version}" |
||||
staging="${temporary}/installed" |
||||
|
||||
echo "Downloading OpenLibm v${version}" |
||||
curl -L --fail --retry 3 \ |
||||
-o "${archive}" \ |
||||
"https://github.com/JuliaMath/openlibm/archive/refs/tags/v${version}.tar.gz" |
||||
echo "${archive_sha256} ${archive}" | sha256sum -c - |
||||
tar -xzf "${archive}" -C "${temporary}" |
||||
|
||||
while IFS= read -r relative; do |
||||
[ -n "${relative}" ] || continue |
||||
mkdir -p "${staging}/$(dirname -- "${relative}")" |
||||
cp "${source_dir}/${relative}" "${staging}/${relative}" |
||||
done < "${manifest}" |
||||
|
||||
mkdir -p "${project_dir}/thirdparty" |
||||
rm -rf "${target}" |
||||
mv "${staging}" "${target}" |
||||
printf '%s\n' "${archive_sha256}" > "${marker}" |
||||
echo "Installed OpenLibm v${version} in ${target}" |
||||
@ -0,0 +1,33 @@ |
||||
#!/usr/bin/env sh |
||||
|
||||
set -eu |
||||
|
||||
project_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) |
||||
version=0.8.14 |
||||
commit=b7ec52ac35e075caffca5d330995d44e8dbfc8c3 |
||||
archive_sha256=827e4cdfd69f5da973e00e2a59b30b3c9857fb7fae74c362fd0b4f96be7929b0 |
||||
target="${project_dir}/thirdparty/toybox" |
||||
marker="${target}/.typephp-source-${version}" |
||||
|
||||
if [ -f "${marker}" ] && [ -f "${target}/Makefile" ]; then |
||||
exit 0 |
||||
fi |
||||
|
||||
temporary=$(mktemp -d "${TMPDIR:-/tmp}/typephp-os-toybox.XXXXXX") |
||||
trap 'rm -rf "${temporary}"' EXIT HUP INT TERM |
||||
archive="${temporary}/toybox.tar.gz" |
||||
staging="${temporary}/installed" |
||||
|
||||
echo "Downloading Toybox ${version} (${commit})" |
||||
curl -L --fail --retry 3 -o "${archive}" \ |
||||
"https://landley.net/toybox/downloads/toybox-${version}.tar.gz" |
||||
printf '%s %s\n' "${archive_sha256}" "${archive}" | sha256sum -c - |
||||
mkdir -p "${staging}" |
||||
tar -xzf "${archive}" -C "${staging}" --strip-components=1 |
||||
test -f "${staging}/LICENSE" |
||||
|
||||
mkdir -p "${project_dir}/thirdparty" |
||||
rm -rf "${target}" |
||||
mv "${staging}" "${target}" |
||||
printf '%s\n' "${commit}" > "${marker}" |
||||
echo "Installed Toybox ${version} in ${target}" |
||||
@ -0,0 +1,14 @@ |
||||
[binaries] |
||||
c = 'gcc' |
||||
cpp = 'g++' |
||||
ar = 'ar' |
||||
strip = 'strip' |
||||
|
||||
[host_machine] |
||||
system = 'demo' |
||||
cpu_family = 'x86_64' |
||||
cpu = 'x86_64' |
||||
endian = 'little' |
||||
|
||||
[properties] |
||||
needs_exe_wrapper = true |
||||
@ -0,0 +1,26 @@ |
||||
#include <dirent.h> |
||||
#include <fcntl.h> |
||||
#include <stdint.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/mman.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/utsname.h> |
||||
#include <time.h> |
||||
#include <unistd.h> |
||||
|
||||
_Static_assert(sizeof(uintptr_t) == 8, "TypePHP-OS requires a 64-bit mlibc ABI"); |
||||
|
||||
static void typecheck(void) |
||||
{ |
||||
struct dirent entry; |
||||
struct stat status; |
||||
struct timespec timestamp; |
||||
struct utsname identity; |
||||
|
||||
(void) entry; |
||||
(void) status; |
||||
(void) timestamp; |
||||
(void) identity; |
||||
} |
||||
@ -0,0 +1,74 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
set -euo pipefail |
||||
|
||||
project_dir=$(cd -- "$(dirname -- "$0")/.." && pwd) |
||||
build_dir="${project_dir}/build/thirdparty-smoke" |
||||
meson_command=${MESON:-meson} |
||||
|
||||
if [[ ! -f "${project_dir}/build/libcompiler-rt-builtins.a" ]]; then |
||||
echo "compiler-rt archive is missing; run make compiler-rt-builtins first" >&2 |
||||
exit 1 |
||||
fi |
||||
for symbol in __udivti3 __udivmodti4 __divti3 __modti3 __multi3; do |
||||
if ! nm -g --defined-only "${project_dir}/build/libcompiler-rt-builtins.a" \ |
||||
| grep -qE "[[:space:]]${symbol}$"; then |
||||
echo "compiler-rt archive does not define ${symbol}" >&2 |
||||
exit 1 |
||||
fi |
||||
done |
||||
echo "compiler-rt builtins archive: OK" |
||||
|
||||
if ! command -v "${meson_command}" >/dev/null 2>&1; then |
||||
echo "Meson 1.3 or newer is required for the mlibc headers probe" >&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
mlibc_build="${build_dir}/mlibc-build" |
||||
mlibc_sysroot="${build_dir}/mlibc-sysroot" |
||||
rm -rf "${mlibc_build}" "${mlibc_sysroot}" |
||||
"${meson_command}" setup \ |
||||
"${mlibc_build}" "${project_dir}/thirdparty/mlibc" \ |
||||
--cross-file "${project_dir}/tools/mlibc-demo-cross.ini" \ |
||||
--prefix=/usr \ |
||||
-Dheaders_only=true \ |
||||
-Dposix_option=enabled \ |
||||
-Dlinux_option=disabled \ |
||||
-Dglibc_option=disabled \ |
||||
-Dbsd_option=disabled |
||||
DESTDIR="${mlibc_sysroot}" "${meson_command}" install -C "${mlibc_build}" |
||||
compiler_headers=$(gcc -print-file-name=include) |
||||
gcc -std=c11 -ffreestanding -fsyntax-only -nostdinc \ |
||||
-isystem "${mlibc_sysroot}/usr/include" \ |
||||
-isystem "${compiler_headers}" \ |
||||
"${project_dir}/tools/mlibc-headers-smoke.c" |
||||
echo "mlibc public-header ABI probe: OK" |
||||
|
||||
toybox_source="${project_dir}/thirdparty/toybox" |
||||
toybox_config="${build_dir}/toybox.config" |
||||
mkdir -p "${build_dir}" |
||||
KCONFIG_ALLCONFIG="${project_dir}/tools/toybox-miniconfig" \ |
||||
KCONFIG_CONFIG="${toybox_config}" \ |
||||
CFLAGS="-O2 -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0" \ |
||||
make -C "${toybox_source}" allnoconfig toybox |
||||
|
||||
test "$("${toybox_source}/toybox" | tr ' ' '\n' | sed '/^$/d' | sort | tr '\n' ' ')" \ |
||||
= "cat date echo pwd uname " |
||||
test "$("${toybox_source}/toybox" echo 'Toybox smoke: OK')" = "Toybox smoke: OK" |
||||
"${toybox_source}/toybox" date -u +%Y-%m-%d >/dev/null |
||||
"${toybox_source}/toybox" uname -s >/dev/null |
||||
|
||||
toybox_symbols="${build_dir}/toybox-undefined-symbols.txt" |
||||
nm -u "${toybox_source}/generated/unstripped/toybox" \ |
||||
| awk '{ print $NF }' | sed 's/@.*//' | sort -u > "${toybox_symbols}" |
||||
if grep -Eq '^(fork|vfork|execv|execve|execvp|posix_spawn)$' "${toybox_symbols}"; then |
||||
echo "the selected Toybox applets unexpectedly require process creation" >&2 |
||||
exit 1 |
||||
fi |
||||
echo "Toybox selected applets build: OK" |
||||
if grep -qx ioctl "${toybox_symbols}"; then |
||||
echo "Toybox install: deferred (the common runtime still references unsupported ioctl)" |
||||
else |
||||
echo "Toybox install: ABI audit no longer reports ioctl; reassess target linking" |
||||
fi |
||||
echo "Toybox ABI report: ${toybox_symbols}" |
||||
@ -0,0 +1,8 @@ |
||||
CONFIG_TOYBOX=y |
||||
CONFIG_TOYBOX_HELP=y |
||||
# CONFIG_TOYBOX_FORK is not set |
||||
CONFIG_CAT=y |
||||
CONFIG_DATE=y |
||||
CONFIG_ECHO=y |
||||
CONFIG_PWD=y |
||||
CONFIG_UNAME=y |
||||
@ -0,0 +1,44 @@ |
||||
#include <stddef.h> |
||||
#include <unistd.h> |
||||
|
||||
typedef unsigned __int128 uint128_t; |
||||
typedef __int128 int128_t; |
||||
|
||||
static int fail(void) |
||||
{ |
||||
static const char message[] = "compiler-rt builtins: failed\n"; |
||||
(void) write(STDERR_FILENO, message, sizeof(message) - 1); |
||||
return 1; |
||||
} |
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
volatile uint128_t unsigned_numerator = ((uint128_t) 1 << 100) + 123456789u; |
||||
volatile uint128_t unsigned_divisor = ((uint128_t) 1 << 37) + 19u; |
||||
volatile int128_t signed_numerator = -(((int128_t) 1 << 99) + 7654321); |
||||
volatile int128_t signed_divisor = ((int128_t) 1 << 35) + 11; |
||||
uint128_t quotient; |
||||
uint128_t remainder; |
||||
int128_t signed_quotient; |
||||
int128_t signed_remainder; |
||||
(void) argc; |
||||
(void) argv; |
||||
|
||||
quotient = unsigned_numerator / unsigned_divisor; |
||||
remainder = unsigned_numerator % unsigned_divisor; |
||||
if (quotient * unsigned_divisor + remainder != unsigned_numerator |
||||
|| remainder >= unsigned_divisor) { |
||||
return fail(); |
||||
} |
||||
|
||||
signed_quotient = signed_numerator / signed_divisor; |
||||
signed_remainder = signed_numerator % signed_divisor; |
||||
if (signed_quotient * signed_divisor + signed_remainder != signed_numerator |
||||
|| signed_remainder > 0) { |
||||
return fail(); |
||||
} |
||||
|
||||
(void) write(STDOUT_FILENO, "compiler-rt builtins: OK\n", |
||||
sizeof("compiler-rt builtins: OK\n") - 1); |
||||
return 0; |
||||
} |
||||
@ -0,0 +1,171 @@ |
||||
#include <dirent.h> |
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <stddef.h> |
||||
#include <stdint.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/syscall.h> |
||||
#include <unistd.h> |
||||
|
||||
/* glibc hides this GNU extension when php-nano requests POSIX.1-2008 only. */ |
||||
long syscall(long number, ...); |
||||
|
||||
#ifndef O_DIRECTORY |
||||
#define O_DIRECTORY 65536 |
||||
#endif |
||||
|
||||
#ifndef O_CLOEXEC |
||||
#define O_CLOEXEC 524288 |
||||
#endif |
||||
|
||||
enum { |
||||
TYPEPHP_DIRECTORY_STREAMS = 4, |
||||
TYPEPHP_DIRECTORY_BUFFER_SIZE = 1024, |
||||
}; |
||||
|
||||
typedef struct { |
||||
int used; |
||||
int fd; |
||||
size_t offset; |
||||
size_t length; |
||||
unsigned char buffer[TYPEPHP_DIRECTORY_BUFFER_SIZE]; |
||||
struct dirent entry; |
||||
} typephp_directory_stream; |
||||
|
||||
static typephp_directory_stream directory_streams[TYPEPHP_DIRECTORY_STREAMS]; |
||||
|
||||
static typephp_directory_stream *directory_state(DIR *directory) |
||||
{ |
||||
const uintptr_t address = (uintptr_t) directory; |
||||
const uintptr_t begin = (uintptr_t) directory_streams; |
||||
const uintptr_t end = (uintptr_t) (directory_streams |
||||
+ TYPEPHP_DIRECTORY_STREAMS); |
||||
typephp_directory_stream *state; |
||||
if (address < begin || address >= end |
||||
|| (address - begin) % sizeof(typephp_directory_stream) != 0) { |
||||
errno = EBADF; |
||||
return NULL; |
||||
} |
||||
state = (typephp_directory_stream *) directory; |
||||
if (!state->used) { |
||||
errno = EBADF; |
||||
return NULL; |
||||
} |
||||
return state; |
||||
} |
||||
|
||||
DIR *fdopendir(int fd) |
||||
{ |
||||
struct stat status; |
||||
size_t index; |
||||
if (fstat(fd, &status) != 0) { |
||||
return NULL; |
||||
} |
||||
if (!S_ISDIR(status.st_mode)) { |
||||
errno = ENOTDIR; |
||||
return NULL; |
||||
} |
||||
for (index = 0; index < TYPEPHP_DIRECTORY_STREAMS; ++index) { |
||||
typephp_directory_stream *state = &directory_streams[index]; |
||||
if (!state->used) { |
||||
state->used = 1; |
||||
state->fd = fd; |
||||
state->offset = 0; |
||||
state->length = 0; |
||||
return (DIR *) state; |
||||
} |
||||
} |
||||
errno = EMFILE; |
||||
return NULL; |
||||
} |
||||
|
||||
DIR *opendir(const char *path) |
||||
{ |
||||
int fd = open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC); |
||||
DIR *directory; |
||||
if (fd < 0) { |
||||
return NULL; |
||||
} |
||||
directory = fdopendir(fd); |
||||
if (directory == NULL) { |
||||
int saved_errno = errno; |
||||
(void) close(fd); |
||||
errno = saved_errno; |
||||
} |
||||
return directory; |
||||
} |
||||
|
||||
struct dirent *readdir(DIR *directory) |
||||
{ |
||||
typephp_directory_stream *state = directory_state(directory); |
||||
struct dirent *record; |
||||
size_t name_capacity; |
||||
size_t name_length = 0; |
||||
if (state == NULL) { |
||||
return NULL; |
||||
} |
||||
if (state->offset == state->length) { |
||||
long length = syscall(SYS_getdents64, state->fd, |
||||
state->buffer, sizeof(state->buffer)); |
||||
if (length <= 0) { |
||||
return NULL; |
||||
} |
||||
state->offset = 0; |
||||
state->length = (size_t) length; |
||||
} |
||||
record = (struct dirent *) (state->buffer + state->offset); |
||||
if (record->d_reclen < offsetof(struct dirent, d_name) + 1 |
||||
|| record->d_reclen > state->length - state->offset) { |
||||
errno = EIO; |
||||
return NULL; |
||||
} |
||||
name_capacity = record->d_reclen - offsetof(struct dirent, d_name); |
||||
while (name_length < name_capacity |
||||
&& record->d_name[name_length] != '\0') { |
||||
++name_length; |
||||
} |
||||
if (name_length == name_capacity |
||||
|| name_length >= sizeof(state->entry.d_name)) { |
||||
errno = EIO; |
||||
return NULL; |
||||
} |
||||
state->entry.d_ino = record->d_ino; |
||||
state->entry.d_off = record->d_off; |
||||
state->entry.d_reclen = record->d_reclen; |
||||
state->entry.d_type = record->d_type; |
||||
for (size_t index = 0; index <= name_length; ++index) { |
||||
state->entry.d_name[index] = record->d_name[index]; |
||||
} |
||||
state->offset += record->d_reclen; |
||||
return &state->entry; |
||||
} |
||||
|
||||
int closedir(DIR *directory) |
||||
{ |
||||
typephp_directory_stream *state = directory_state(directory); |
||||
int result; |
||||
if (state == NULL) { |
||||
return -1; |
||||
} |
||||
result = close(state->fd); |
||||
state->used = 0; |
||||
state->fd = -1; |
||||
state->offset = 0; |
||||
state->length = 0; |
||||
return result; |
||||
} |
||||
|
||||
void rewinddir(DIR *directory) |
||||
{ |
||||
typephp_directory_stream *state = directory_state(directory); |
||||
if (state != NULL && lseek(state->fd, 0, SEEK_SET) >= 0) { |
||||
state->offset = 0; |
||||
state->length = 0; |
||||
} |
||||
} |
||||
|
||||
int dirfd(DIR *directory) |
||||
{ |
||||
typephp_directory_stream *state = directory_state(directory); |
||||
return state == NULL ? -1 : state->fd; |
||||
} |
||||
@ -0,0 +1,18 @@ |
||||
#include <fcntl.h> |
||||
#include <stdarg.h> |
||||
#include <sys/syscall.h> |
||||
|
||||
/* glibc hides this GNU extension when php-nano requests POSIX.1-2008 only. */ |
||||
long syscall(long number, ...); |
||||
|
||||
int fcntl(int fd, int command, ...) |
||||
{ |
||||
long argument = 0; |
||||
if (command == F_SETFD || command == F_SETFL) { |
||||
va_list arguments; |
||||
va_start(arguments, command); |
||||
argument = va_arg(arguments, int); |
||||
va_end(arguments); |
||||
} |
||||
return (int) syscall(SYS_fcntl, fd, command, argument); |
||||
} |
||||
@ -0,0 +1,35 @@ |
||||
#ifndef TYPEPHP_OS_USER_DIRENT_H |
||||
#define TYPEPHP_OS_USER_DIRENT_H |
||||
|
||||
#include <sys/types.h> |
||||
|
||||
/* Linux x86-64 dirent64 layout. getdents64() returns variable-length records;
|
||||
* readdir() exposes the same prefix through this conventional fixed-size |
||||
* userspace view. */ |
||||
struct dirent { |
||||
ino_t d_ino; |
||||
off_t d_off; |
||||
unsigned short d_reclen; |
||||
unsigned char d_type; |
||||
char d_name[256]; |
||||
}; |
||||
|
||||
#define DT_UNKNOWN 0 |
||||
#define DT_FIFO 1 |
||||
#define DT_CHR 2 |
||||
#define DT_DIR 4 |
||||
#define DT_BLK 6 |
||||
#define DT_REG 8 |
||||
#define DT_LNK 10 |
||||
#define DT_SOCK 12 |
||||
|
||||
typedef struct __typephp_dir_stream DIR; |
||||
|
||||
DIR *opendir(const char *path); |
||||
DIR *fdopendir(int fd); |
||||
struct dirent *readdir(DIR *directory); |
||||
int closedir(DIR *directory); |
||||
void rewinddir(DIR *directory); |
||||
int dirfd(DIR *directory); |
||||
|
||||
#endif |
||||
@ -1,16 +1,27 @@ |
||||
#include <sys/syscall.h> |
||||
#include <dirent.h> |
||||
#include <stddef.h> |
||||
#include <unistd.h> |
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
char entries[512]; |
||||
const char *path = argc > 1 ? argv[1] : 0; |
||||
long length = syscall(SYS_typephp_listdir, path, entries, sizeof(entries)); |
||||
if (length < 0) { |
||||
const char *path = argc > 1 ? argv[1] : "."; |
||||
DIR *directory = opendir(path); |
||||
struct dirent *entry; |
||||
if (directory == NULL) { |
||||
(void) write(STDERR_FILENO, "ls: cannot read directory\n", |
||||
sizeof("ls: cannot read directory\n") - 1); |
||||
return 1; |
||||
} |
||||
(void) write(STDOUT_FILENO, entries, (size_t) length); |
||||
while ((entry = readdir(directory)) != NULL) { |
||||
size_t length = 0; |
||||
while (entry->d_name[length] != '\0') { |
||||
++length; |
||||
} |
||||
(void) write(STDOUT_FILENO, entry->d_name, length); |
||||
(void) write(STDOUT_FILENO, "\n", 1); |
||||
} |
||||
if (closedir(directory) != 0) { |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
Loading…
Reference in new issue