blob: 77508d8f9a6e42c77ec5080a520c2effebeeede2 [file] [edit]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "libc_shim.h"
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
// <dirent.h>
char *libc_shim_d_name_ptr(struct libc_shim_dirent *d) { return d->d_name; }
int libc_shim_closedir(libc_shim_DIR *d, int *err) {
errno = *err;
int r = closedir(d->_dir);
*err = errno;
free(d);
return r;
}
libc_shim_DIR *libc_shim_fdopendir(int fd, int *err) {
errno = *err;
DIR *d = fdopendir(fd);
*err = errno;
if (d == NULL) {
return NULL;
}
libc_shim_DIR *myd = malloc(sizeof(libc_shim_DIR));
myd->_dir = d;
return myd;
}
libc_shim_DIR *libc_shim_opendir(const char *path, int *err) {
errno = *err;
DIR *d = opendir(path);
*err = errno;
if (d == NULL) {
return NULL;
}
libc_shim_DIR *myd = malloc(sizeof(libc_shim_DIR));
myd->_dir = d;
return myd;
}
struct libc_shim_dirent *libc_shim_readdir(libc_shim_DIR *myd, int *err) {
errno = *err;
struct dirent *d = readdir(myd->_dir);
*err = errno;
if (d == NULL) {
return NULL;
}
myd->libc_shim_dirent.d_ino = d->d_ino;
myd->libc_shim_dirent.d_type = d->d_type;
assert(strlen(myd->libc_shim_dirent.d_name) <
sizeof(myd->libc_shim_dirent.d_name));
strncpy(myd->libc_shim_dirent.d_name, d->d_name,
sizeof(myd->libc_shim_dirent.d_name));
return &(myd->libc_shim_dirent);
}
// <sys/stat.h>
static void _fill(struct libc_shim_Stat *buf, struct stat *s) {
buf->st_dev = s->st_dev;
buf->st_ino = s->st_ino;
buf->st_mode = s->st_mode;
buf->st_nlink = s->st_nlink;
buf->std_uid = s->st_uid;
buf->st_size = s->st_size;
#ifdef __APPLE__
buf->st_atim.tv_sec = s->st_atimespec.tv_sec;
buf->st_atim.tv_nsec = s->st_atimespec.tv_nsec;
buf->st_ctim.tv_sec = s->st_ctimespec.tv_sec;
buf->st_ctim.tv_nsec = s->st_ctimespec.tv_nsec;
buf->st_mtim.tv_sec = s->st_mtimespec.tv_sec;
buf->st_mtim.tv_nsec = s->st_mtimespec.tv_nsec;
buf->st_btime.tv_sec = s->st_birthtimespec.tv_sec;
buf->st_btime.tv_nsec = s->st_birthtimespec.tv_nsec;
buf->st_flags = s->st_flags;
#elif __linux__
// https://man7.org/linux/man-pages/man3/stat.3type.html
buf->st_atim.tv_sec = s->st_atim.tv_sec;
buf->st_atim.tv_nsec = s->st_atim.tv_nsec;
buf->st_ctim.tv_sec = s->st_ctim.tv_sec;
buf->st_ctim.tv_nsec = s->st_ctim.tv_nsec;
buf->st_mtim.tv_sec = s->st_mtim.tv_sec;
buf->st_mtim.tv_nsec = s->st_mtim.tv_nsec;
#endif
}
int libc_shim_stat(const char *path, struct libc_shim_Stat *buf, int *err) {
struct stat s;
errno = *err;
int r = stat(path, &s);
*err = errno;
if (r != -1) {
_fill(buf, &s);
}
return r;
}
int libc_shim_lstat(const char *path, struct libc_shim_Stat *buf, int *err) {
struct stat s;
errno = *err;
int r = lstat(path, &s);
*err = errno;
if (r != -1) {
_fill(buf, &s);
}
return r;
}
int libc_shim_fstat(int fd, struct libc_shim_Stat *buf, int *err) {
struct stat s;
errno = *err;
int r = fstat(fd, &s);
*err = errno;
if (r != -1) {
_fill(buf, &s);
}
return r;
}
int libc_shim_fstatat(int fd, char *path, struct libc_shim_Stat *buf, int flag,
int *err) {
struct stat s;
errno = *err;
int r = fstatat(fd, path, &s, flag);
*err = errno;
if (r != -1) {
_fill(buf, &s);
}
return r;
}
// <pthread.h>
int libc_shim_pthread_cond_broadcast(libc_shim_pthread_cond_t *cond, int *err) {
errno = *err;
int r = pthread_cond_broadcast((pthread_cond_t *)cond->_pthread_cond_t);
*err = errno;
return r;
}
int libc_shim_pthread_cond_destroy(libc_shim_pthread_cond_t *cond, int *err) {
errno = *err;
int r = pthread_cond_destroy((pthread_cond_t *)cond->_pthread_cond_t);
*err = errno;
free(cond->_pthread_cond_t);
return r;
}
int libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond,
const libc_shim_pthread_condattr_t *attr,
int *err) {
pthread_cond_t *c = (pthread_cond_t *)calloc(1, sizeof(pthread_cond_t));
errno = *err;
int r = pthread_cond_init(
c,
(attr == NULL) ? NULL : (pthread_condattr_t *)attr->_pthread_condattr_t);
*err = errno;
if (r == 0) {
cond->_pthread_cond_t = c;
} else {
free(c);
}
return r;
}
int libc_shim_pthread_cond_signal(libc_shim_pthread_cond_t *cond, int *err) {
errno = *err;
int r = pthread_cond_signal((pthread_cond_t *)cond->_pthread_cond_t);
*err = errno;
return r;
}
int libc_shim_pthread_cond_timedwait(libc_shim_pthread_cond_t *cond,
libc_shim_pthread_mutex_t *mutex,
const struct libc_shim_timespec *abstime,
int *err) {
struct timespec s;
s.tv_nsec = abstime->tv_nsec;
s.tv_sec = abstime->tv_sec;
errno = *err;
int r =
pthread_cond_timedwait((pthread_cond_t *)cond->_pthread_cond_t,
(pthread_mutex_t *)mutex->_pthread_mutex_t, &s);
*err = errno;
return r;
}
int libc_shim_pthread_cond_wait(libc_shim_pthread_cond_t *cond,
libc_shim_pthread_mutex_t *mutex, int *err) {
errno = *err;
int r = pthread_cond_wait((pthread_cond_t *)cond->_pthread_cond_t,
(pthread_mutex_t *)mutex->_pthread_mutex_t);
*err = errno;
return r;
}
int libc_shim_pthread_create(libc_shim_pthread_t *restrict thread,
const libc_shim_pthread_attr_t *restrict attr,
void *(*start_routine)(void *), void *restrict arg,
int *err) {
pthread_t *t = (pthread_t *)calloc(1, sizeof(pthread_t));
errno = *err;
int r = pthread_create(t, (attr == NULL) ? NULL : attr->_pthread_attr_t,
start_routine, arg);
*err = errno;
if (r == 0) {
thread->_pthread_t = t;
} else {
free(t);
}
return r;
}
int libc_shim_pthread_detach(libc_shim_pthread_t thread, int *err) {
errno = *err;
int r = pthread_detach(*((pthread_t *)thread._pthread_t));
*err = errno;
free(thread._pthread_t);
return r;
}
int libc_shim_pthread_mutex_destroy(libc_shim_pthread_mutex_t *mutex,
int *err) {
errno = *err;
int r = pthread_mutex_destroy(mutex->_pthread_mutex_t);
*err = errno;
free(mutex->_pthread_mutex_t);
return r;
}
int libc_shim_pthread_mutex_init(
libc_shim_pthread_mutex_t *restrict mutex,
const libc_shim_pthread_mutexattr_t *restrict attr, int *err) {
pthread_mutex_t *m = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
errno = *err;
int r =
pthread_mutex_init(m, (attr == NULL) ? NULL : attr->_pthread_mutexattr_t);
*err = errno;
if (r == 0) {
mutex->_pthread_mutex_t = m;
} else {
free(m);
}
return r;
}
int libc_shim_pthread_mutex_lock(libc_shim_pthread_mutex_t *mutex, int *err) {
errno = *err;
int r = pthread_mutex_lock((pthread_mutex_t *)mutex->_pthread_mutex_t);
*err = errno;
return r;
}
int libc_shim_pthread_mutex_timedlock(
libc_shim_pthread_mutex_t *restrict mutex,
const struct libc_shim_timespec *restrict abs_timeout, int *err) {
#if defined(__linux__) || defined(__ANDROID__)
struct timespec s;
s.tv_nsec = abs_timeout->tv_nsec;
s.tv_sec = abs_timeout->tv_sec;
errno = *err;
int r =
pthread_mutex_timedlock((pthread_mutex_t *)mutex->_pthread_mutex_t, &s);
*err = errno;
return r;
#else
return ENOSYS;
#endif
}
int libc_shim_pthread_mutex_unlock(libc_shim_pthread_mutex_t *mutex, int *err) {
errno = *err;
int r = pthread_mutex_unlock((pthread_mutex_t *)mutex->_pthread_mutex_t);
*err = errno;
return r;
}