rktio: put "globals" in an rktio_t

Avoid thread-local state by threading a `rktio_t`
record through everything.
This commit is contained in:
Matthew Flatt 2017-06-09 13:55:57 -06:00
parent 68352ef86a
commit 09703b94f7
10 changed files with 842 additions and 276 deletions

View File

@ -9,13 +9,17 @@ RKTIO_HEADERS = $(srcdir)/rktio.h $(srcdir)/rktio_private.h rktio_config.h
OBJS = rktio_filesystem.o \
rktio_read_write.o \
rktio_poll_set.o \
rktio_error.o
rktio_error.o \
rktio_main.o
all: $(OBJS)
demo: $(OBJS) main.o
demo: $(OBJS) main.o demo_fifo
$(CC) -o demo $(CFLAGS) $(LDFLAGS) main.o $(OBJS)
demo_fifo:
mkfifo demo_fifo
rktio_filesystem.o: $(srcdir)/rktio_filesystem.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_filesystem.o -c $(srcdir)/rktio_filesystem.c
@ -28,5 +32,8 @@ rktio_poll_set.o: $(srcdir)/rktio_poll_set.c $(RKTIO_HEADERS)
rktio_error.o: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.o -c $(srcdir)/rktio_error.c
rktio_main.o: $(srcdir)/rktio_main.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_main.o -c $(srcdir)/rktio_main.c
main.o: $(srcdir)/main.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o main.o -c $(srcdir)/main.c

View File

@ -3,19 +3,20 @@
#include <stdlib.h>
#include <string.h>
static void do_check_valid(int ok, int where)
static void do_check_valid(rktio_t *rktio, int ok, int where)
{
if (!ok) {
printf("error at %d: %d@%d = %s\n",
where,
rktio_get_last_error(),
rktio_get_last_error_kind(),
rktio_get_error_string(rktio_get_last_error(),
rktio_get_last_error_kind()));
rktio_get_last_error(rktio),
rktio_get_last_error_kind(rktio),
rktio_get_error_string(rktio,
rktio_get_last_error_kind(rktio),
rktio_get_last_error(rktio)));
}
}
static void do_check_expected_error(int err, int where)
static void do_check_expected_error(rktio_t *rktio, int err, int where)
{
if (!err) {
printf("error expected at %d\n",
@ -23,121 +24,165 @@ static void do_check_expected_error(int err, int where)
}
}
static void do_check_expected_racket_error(int err, int what, int where)
static void do_check_expected_racket_error(rktio_t *rktio, int err, int what, int where)
{
if (!err) {
printf("error expected at %d\n",
where);
} else if ((what != rktio_get_last_error())
|| (RKTIO_ERROR_KIND_RACKET != rktio_get_last_error_kind())) {
} else if ((what != rktio_get_last_error(rktio))
|| (RKTIO_ERROR_KIND_RACKET != rktio_get_last_error_kind(rktio))) {
printf("wrong error at %d: %d@%d = %s\n",
where,
rktio_get_last_error(),
rktio_get_last_error_kind(),
rktio_get_error_string(rktio_get_last_error(),
rktio_get_last_error_kind()));
rktio_get_last_error(rktio),
rktio_get_last_error_kind(rktio),
rktio_get_error_string(rktio,
rktio_get_last_error_kind(rktio),
rktio_get_last_error(rktio)));
}
}
#define check_valid(e) do_check_valid(e, __LINE__)
#define check_expected_error(e) do_check_expected_error(e, __LINE__)
#define check_expected_racket_error(e, what) do_check_expected_racket_error(e, what, __LINE__)
#define check_valid(e) do_check_valid(rktio, e, __LINE__)
#define check_expected_error(e) do_check_expected_error(rktio, e, __LINE__)
#define check_expected_racket_error(e, what) do_check_expected_racket_error(rktio, e, what, __LINE__)
static void check_hello_content(char *fn)
static void check_hello_content(rktio_t *rktio, char *fn)
{
rktio_fd_t *fd;
intptr_t amt;
char buffer[256], *s;
fd = rktio_open(fn, RKTIO_OPEN_READ);
fd = rktio_open(rktio, fn, RKTIO_OPEN_READ);
check_valid(!!fd);
check_valid(rktio_poll_read_ready(fd) != RKTIO_POLL_ERROR);
amt = rktio_read(fd, buffer, sizeof(buffer));
check_valid(rktio_poll_read_ready(rktio, fd) != RKTIO_POLL_ERROR);
amt = rktio_read(rktio, fd, buffer, sizeof(buffer));
check_valid(amt == 5);
check_valid(!strncmp(buffer, "hello", 5));
check_valid(rktio_close(fd));
amt = rktio_read(rktio, fd, buffer, sizeof(buffer));
check_valid(amt == RKTIO_READ_EOF);
check_valid(rktio_close(rktio, fd));
}
int main()
{
rktio_t *rktio;
rktio_size_t *sz;
rktio_fd_t *fd;
intptr_t amt, i,saw_file;
char *s, *pwd;
rktio_fd_t *fd, *fd2;
intptr_t amt, i, saw_file;
int perms;
char buffer[256], *s, *pwd;
rktio_directory_list_t *ls;
rktio_file_copy_t *cp;
rktio_timestamp_t *ts1, *ts1a;
fd = rktio_open("test1", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST);
rktio = rktio_init();
/* Basic file I/O */
fd = rktio_open(rktio, "test1", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST);
check_valid(!!fd);
check_valid(rktio_poll_write_ready(fd) != RKTIO_POLL_ERROR);
amt = rktio_write(fd, "hello", 5);
check_valid(rktio_poll_write_ready(rktio, fd) != RKTIO_POLL_ERROR);
amt = rktio_write(rktio, fd, "hello", 5);
check_valid(amt == 5);
check_valid(rktio_close(fd));
check_valid(rktio_close(rktio, fd));
check_valid(rktio_file_exists("test1"));
check_valid(!rktio_directory_exists("test1"));
check_valid(rktio_is_regular_file("test1"));
check_valid(rktio_file_exists(rktio, "test1"));
check_valid(!rktio_directory_exists(rktio, "test1"));
check_valid(rktio_is_regular_file(rktio, "test1"));
s = rktio_get_current_directory();
s = rktio_get_current_directory(rktio);
check_valid(!!s);
check_valid(rktio_directory_exists(s));
check_valid(!rktio_file_exists(s));
check_valid(!rktio_is_regular_file(s));
check_expected_racket_error(!rktio_open(s, RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST),
check_valid(rktio_directory_exists(rktio, s));
check_valid(!rktio_file_exists(rktio, s));
check_valid(!rktio_is_regular_file(rktio, s));
check_expected_racket_error(!rktio_open(rktio, s, RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST),
RKTIO_ERROR_IS_A_DIRECTORY);
pwd = s;
sz = rktio_file_size("test1");
sz = rktio_file_size(rktio, "test1");
check_valid(!!sz);
check_valid(sz->lo == 5);
check_valid(sz->hi == 0);
free(sz);
fd = rktio_open("test2", RKTIO_OPEN_WRITE | RKTIO_OPEN_MUST_EXIST);
fd = rktio_open(rktio, "test2", RKTIO_OPEN_WRITE | RKTIO_OPEN_MUST_EXIST);
check_expected_error(!fd);
fd = rktio_open("test1", RKTIO_OPEN_WRITE);
fd = rktio_open(rktio, "test1", RKTIO_OPEN_WRITE);
check_expected_racket_error(!fd, RKTIO_ERROR_EXISTS);
check_hello_content("test1");
check_hello_content(rktio, "test1");
if (rktio_file_exists("test1a"))
check_valid(rktio_delete_file("test1a", 1));
if (rktio_file_exists("test1b"))
check_valid(rktio_delete_file("test1b", 1));
/* Copying, renaming, and deleting files */
cp = rktio_copy_file_start("test1a", "test1", 0);
if (rktio_file_exists(rktio, "test1a"))
check_valid(rktio_delete_file(rktio, "test1a", 1));
if (rktio_file_exists(rktio, "test1b"))
check_valid(rktio_delete_file(rktio, "test1b", 1));
ts1 = rktio_get_file_modify_seconds(rktio, "test1a");
check_expected_error(!ts1);
perms = rktio_get_file_or_directory_permissions(rktio, "test1a", 1);
check_expected_error(perms == -1);
check_expected_error(!rktio_set_file_or_directory_permissions(rktio, "test1a", 511));
ts1 = rktio_get_file_modify_seconds(rktio, "test1");
perms = rktio_get_file_or_directory_permissions(rktio, "test1", 0);
check_valid(perms != -1);
check_valid(perms & (RKTIO_PERMISSION_READ << 6));
check_valid(perms & (RKTIO_PERMISSION_WRITE << 6));
perms = rktio_get_file_or_directory_permissions(rktio, "test1", 1);
check_valid(perms != -1);
check_valid(perms & (RKTIO_PERMISSION_READ << 6));
check_valid(perms & (RKTIO_PERMISSION_WRITE << 6));
check_valid(rktio_set_file_or_directory_permissions(rktio, "test1", perms & (0x7 << 6)));
check_valid((perms & (0x7 << 6)) == rktio_get_file_or_directory_permissions(rktio, "test1", 1));
rktio_set_file_or_directory_permissions(rktio, "test1", perms);
cp = rktio_copy_file_start(rktio, "test1a", "test1", 0);
check_valid(!!cp);
while (!rktio_copy_file_is_done(cp)) {
check_valid(rktio_copy_file_step(cp));
while (!rktio_copy_file_is_done(rktio, cp)) {
check_valid(rktio_copy_file_step(rktio, cp));
}
rktio_copy_file_stop(cp);
check_hello_content("test1a");
rktio_copy_file_stop(rktio, cp);
check_hello_content(rktio, "test1a");
check_valid(rktio_file_exists("test1a"));
cp = rktio_copy_file_start("test1a", "test1", 0);
ts1a = rktio_get_file_modify_seconds(rktio, "test1a");
check_valid(*ts1a >= *ts1);
rktio_set_file_modify_seconds(rktio, "test1a", *ts1 - 10);
free(ts1a);
ts1a = rktio_get_file_modify_seconds(rktio, "test1a");
check_valid(*ts1a == (*ts1 - 10));
free(ts1);
free(ts1a);
check_valid(rktio_file_exists(rktio, "test1a"));
cp = rktio_copy_file_start(rktio, "test1a", "test1", 0);
check_expected_racket_error(!cp, RKTIO_ERROR_EXISTS);
cp = rktio_copy_file_start("test1a", "test1", 1);
cp = rktio_copy_file_start(rktio, "test1a", "test1", 1);
check_valid(!!cp);
rktio_copy_file_stop(cp);
rktio_copy_file_stop(rktio, cp);
check_valid(rktio_rename_file("test1b", "test1a", 0));
check_valid(rktio_file_exists("test1b"));
check_expected_racket_error(!rktio_rename_file("test1b", "test1", 0),
check_valid(rktio_rename_file(rktio, "test1b", "test1a", 0));
check_valid(rktio_file_exists(rktio, "test1b"));
check_expected_racket_error(!rktio_rename_file(rktio, "test1b", "test1", 0),
RKTIO_ERROR_EXISTS);
check_valid(rktio_file_exists("test1"));
check_valid(rktio_file_exists("test1b"));
check_valid(!rktio_file_exists("test1a"));
check_valid(rktio_file_exists(rktio, "test1"));
check_valid(rktio_file_exists(rktio, "test1b"));
check_valid(!rktio_file_exists(rktio, "test1a"));
check_valid(rktio_delete_file("test1b", 0));
check_valid(!rktio_file_exists("test1b"));
check_valid(rktio_delete_file(rktio, "test1b", 0));
check_valid(!rktio_file_exists(rktio, "test1b"));
ls = rktio_directory_list_start(pwd, 0);
/* Listing directory content */
ls = rktio_directory_list_start(rktio, pwd, 0);
check_valid(!!ls);
saw_file = 0;
while (1) {
s = rktio_directory_list_step(ls);
s = rktio_directory_list_step(rktio, ls);
check_valid(!!s);
if (!*s) break;
if (!strcmp(s, "test1"))
@ -145,6 +190,54 @@ int main()
check_valid(strcmp(s, "test1b"));
}
check_valid(saw_file);
/* Pipes and non-blocking operations */
fd = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_READ);
check_valid(!!fd);
check_valid(!rktio_poll_read_ready(rktio, fd));
fd2 = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST);
check_valid(!!fd2);
check_valid(!rktio_poll_read_ready(rktio, fd));
amt = rktio_write(rktio, fd2, "hello", 5);
check_valid(amt == 5);
check_valid(rktio_poll_read_ready(rktio, fd));
amt = rktio_read(rktio, fd, buffer, sizeof(buffer));
check_valid(amt == 5);
check_valid(!strncmp(buffer, "hello", 5));
check_valid(!rktio_poll_read_ready(rktio, fd));
check_valid(rktio_close(rktio, fd2));
amt = rktio_read(rktio, fd, buffer, sizeof(buffer));
check_valid(amt == RKTIO_READ_EOF);
check_valid(rktio_close(rktio, fd));
fd2 = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST);
check_valid(!!fd2);
/* should eventually block: */
for (i = 0; i < 100000; i++) {
amt = rktio_write(rktio, fd2, "hello", 5);
check_valid(amt != RKTIO_WRITE_ERROR);
if (!amt)
break;
}
check_valid(i < 100000);
fd = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_READ);
check_valid(!!fd);
/* should eventually block: */
for (i = 0; i < 100000; i++) {
amt = rktio_read(rktio, fd2, buffer, sizeof(buffer));
check_valid(amt != RKTIO_READ_ERROR);
check_valid(amt != RKTIO_READ_EOF);
if (!amt)
break;
}
check_valid(i < 100000);
check_valid(rktio_close(rktio, fd));
check_valid(rktio_close(rktio, fd2));
return 0;
}

View File

@ -3,6 +3,18 @@
#include "rktio_config.h"
/* A rktio_t value represents an instance of the Racket I/O system.
Every rktio_...() function takes it as the first argument, except
for rktio_init(), rktio_signal_received_at(), and rktio_free(). */
typedef struct rktio_t rktio_t;
rktio_t *rktio_init(void);
void rktio_destroy(rktio_t *);
/* Normally equivalent to free(), but ensures the same malloc()/free()
that rktio function use: */
void rktio_free(void *p);
/*************************************************/
/* Reading and writing files */
@ -16,23 +28,23 @@ typedef struct rktio_fd_t rktio_fd_t;
#define RKTIO_OPEN_MUST_EXIST (1<<5)
#define RKTIO_OPEN_CAN_EXIST (1<<6)
rktio_fd_t *rktio_system_fd(intptr_t system_fd, int modes);
intptr_t rktio_fd_system_fd(rktio_fd_t *rfd);
rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes);
intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd);
rktio_fd_t *rktio_open(char *src, int modes);
int rktio_close(rktio_fd_t *fd);
rktio_fd_t *rktio_open(rktio_t *rktio, char *src, int modes);
int rktio_close(rktio_t *rktio, rktio_fd_t *fd);
#define RKTIO_READ_EOF (-1)
#define RKTIO_READ_ERROR (-2)
#define RKTIO_WRITE_ERROR (-2)
#define RKTIO_POLL_ERROR (-2)
intptr_t rktio_read(rktio_fd_t *fd, char *buffer, intptr_t len);
intptr_t rktio_write(rktio_fd_t *fd, char *buffer, intptr_t len);
intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
int rktio_poll_read_ready(rktio_fd_t *rfd);
int rktio_poll_write_ready(rktio_fd_t *rfd);
int rktio_poll_write_flushed(rktio_fd_t *rfd);
int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd);
int rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd);
int rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd);
/*************************************************/
/* File-descriptor sets */
@ -42,26 +54,26 @@ typedef struct rktio_poll_set_t rktio_poll_set_t;
#define RKTIO_POLL_READ RKTIO_OPEN_READ
#define RKTIO_POLL_WRITE RKTIO_OPEN_WRITE
void rktio_poll_add(rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes);
void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes);
/*************************************************/
/* Files, directories, and links */
int rktio_file_exists(char *filename);
int rktio_directory_exists(char *dirname);
int rktio_link_exists(char *filename);
int rktio_is_regular_file(char *filename);
int rktio_file_exists(rktio_t *rktio, char *filename);
int rktio_directory_exists(rktio_t *rktio, char *dirname);
int rktio_link_exists(rktio_t *rktio, char *filename);
int rktio_is_regular_file(rktio_t *rktio, char *filename);
int rktio_delete_file(char *fn, int enable_write_on_fail);
int rktio_rename_file(char *dest, char *src, int exists_ok);
int rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail);
int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok);
char *rktio_get_current_directory();
int rktio_set_current_directory(char *expanded);
int rktio_make_directory(char *filename);
int rktio_delete_directory(char *filename, char *current_directory, int enable_write_on_fail);
char *rktio_get_current_directory(rktio_t *rktio);
int rktio_set_current_directory(rktio_t *rktio, char *expanded);
int rktio_make_directory(rktio_t *rktio, char *filename);
int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory, int enable_write_on_fail);
char *rktio_readlink(char *fullfilename);
int rktio_make_link(char *src, char *dest, int dest_is_directory);
char *rktio_readlink(rktio_t *rktio, char *fullfilename);
int rktio_make_link(rktio_t *rktio, char *src, char *dest, int dest_is_directory);
/*************************************************/
/* File attributes */
@ -76,43 +88,44 @@ typedef struct {
uintptr_t a, b, c;
} rktio_identity_t;
rktio_size_t *rktio_file_size(char *filename);
rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename);
rktio_timestamp_t *rktio_get_file_modify_seconds(char *file);
int rktio_set_file_modify_seconds(char *file, rktio_timestamp_t secs);
rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, char *file);
int rktio_set_file_modify_seconds(rktio_t *rktio, char *file, rktio_timestamp_t secs);
rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path);
rktio_identity_t *rktio_fd_identity(rktio_t *rktio, rktio_fd_t *fd);
rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, int follow_links);
/*************************************************/
/* Permissions */
/* Must match OS bits: */
#define RKTIO_PERMISSION_READ 0x1
#define RKTIO_PERMISSION_READ 0x4
#define RKTIO_PERMISSION_WRITE 0x2
#define RKTIO_PERMISSION_EXEC 0x4
#define RKTIO_PERMISSION_EXEC 0x1
int rktio_get_file_or_directory_permissions(char *filename, int all_bits);
int rktio_set_file_or_directory_permissions(char *filename, int new_bits);
int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits);
int rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int new_bits);
/*************************************************/
/* Directory listing */
typedef struct rktio_directory_list_t rktio_directory_list_t;
rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive);
char *rktio_directory_list_step(rktio_directory_list_t *dl);
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive);
char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl);
char **rktio_filesystem_root_list();
char **rktio_filesystem_root_list(rktio_t *rktio);
/*************************************************/
/* File copying */
typedef struct rktio_file_copy_t rktio_file_copy_t;
rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok);
int rktio_copy_file_is_done(rktio_file_copy_t *fc);
int rktio_copy_file_step(rktio_file_copy_t *fc);
void rktio_copy_file_stop(rktio_file_copy_t *fc);
rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src, int exists_ok);
int rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc);
int rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc);
void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc);
/*************************************************/
/* System paths */
@ -130,8 +143,17 @@ enum {
RKTIO_PATH_INIT_FILE
};
char *rktio_system_path(int which);
char *rktio_expand_user_tilde(char *filename);
char *rktio_system_path(rktio_t *rktio, int which);
char *rktio_expand_user_tilde(rktio_t *rktio, char *filename);
/*************************************************/
/* Sleep and signals */
typedef struct rktio_signal_handle_t rktio_signal_handle_t;
rktio_signal_handle_t *rktio_get_signal_handle(rktio_t *rktio);
void rktio_signal_received_at(rktio_signal_handle_t *h);
void rktio_signal_received(rktio_t *rktio);
/*************************************************/
/* Errors */
@ -155,13 +177,14 @@ enum {
RKTIO_ERROR_NOT_A_DIRECTORY,
RKTIO_ERROR_NO_TILDE,
RKTIO_ERROR_ILL_FORMED_USER,
RKTIO_ERROR_UNKNOWN_USER
RKTIO_ERROR_UNKNOWN_USER,
RKTIO_ERROR_INIT_FAILED
};
int rktio_get_last_error(void);
int rktio_get_last_error_kind(void);
int rktio_get_last_error(rktio_t *rktio);
int rktio_get_last_error_kind(rktio_t *rktio);
char *rktio_get_error_string(int kind, int errid);
char *rktio_get_error_string(rktio_t *rktio, int kind, int errid);
/*************************************************/

View File

@ -4,41 +4,43 @@
# include <windows.h>
#endif
#include <errno.h>
#include <string.h>
THREAD_LOCAL_DECL(static intptr_t errid);
THREAD_LOCAL_DECL(static int errkind);
void rktio_get_posix_error(void)
void rktio_get_posix_error(rktio_t *rktio)
{
errid = errno;
errkind = RKTIO_ERROR_KIND_POSIX;
rktio->errid = errno;
rktio->errkind = RKTIO_ERROR_KIND_POSIX;
}
void rktio_set_racket_error(int new_errid)
void rktio_set_racket_error(rktio_t *rktio, int new_errid)
{
errid = new_errid;
errkind = RKTIO_ERROR_KIND_RACKET;
rktio->errid = new_errid;
rktio->errkind = RKTIO_ERROR_KIND_RACKET;
}
#ifdef RKTIO_SYSTEM_WINDOWS
void rktio_get_windows_error(void)
void rktio_get_windows_error(rktio_t *rktio)
{
errid = GetLastError();
errkind = RKTIO_ERROR_KIND_WINDOWS;
rktio->errid = GetLastError();
rktio->errkind = RKTIO_ERROR_KIND_WINDOWS;
}
#endif
int rktio_get_last_error(void)
int rktio_get_last_error(rktio_t *rktio)
{
return errid;
return rktio->errid;
}
int rktio_get_last_error_kind(void)
int rktio_get_last_error_kind(rktio_t *rktio)
{
return errkind;
return rktio->errkind;
}
char *rktio_get_error_string(int kind, int errid)
char *rktio_get_error_string(rktio_t *rktio, int kind, int errid)
{
char *s = NULL;
if (kind == RKTIO_ERROR_KIND_POSIX)
s = strerror(errid);
if (s) return s;
return "???";
}

View File

@ -14,9 +14,6 @@
#include <uuid/uuid.h>
#include <dirent.h>
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
# include <windows.h>
#endif
#ifdef RKTIO_SYSTEM_UNIX
# define A_PATH_SEP '/'
@ -43,12 +40,11 @@ static gid_t egid;
#define GROUP_MEMBER_CACHE_STATE_UNUSED 0
#define GROUP_MEMBER_CACHE_STATE_IN 1
#define GROUP_MEMBER_CACHE_STATE_NOT_IN 2
typedef struct {
typedef struct group_member_cache_entry_t {
int state;
gid_t gid;
uid_t uid;
} group_member_cache_entry_t;
THREAD_LOCAL_DECL(static group_member_cache_entry_t *group_member_cache);
# define GROUP_CACHE_SIZE 10
#endif
@ -307,7 +303,7 @@ static char *UNC_readlink(const char *fn)
return buffer;
}
static int UNC_stat(const char *dirname, int *flags, int *isdir, int *islink,
static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir, int *islink,
rktio_timestamp_t **date, rktio_file_size_t *filesize,
const char **resolved_path, int set_flags)
/* dirname must be absolute */
@ -337,7 +333,7 @@ static int UNC_stat(const char *dirname, int *flags, int *isdir, int *islink,
copy = malloc(len+1);
memcpy(copy, dirname, len+1);
if (!rktio_windows_nt_or_later()
if (!rktio->windows_nt_or_later
|| ((len >= 4)
&& (copy[0] == '\\')
&& (copy[1] == '\\')
@ -478,7 +474,7 @@ static int UNC_stat(const char *dirname, int *flags, int *isdir, int *islink,
}
#endif
int rktio_file_exists(char *filename)
int rktio_file_exists(rktio_t *rktio, char *filename)
/* Windows: check for special filenames before calling */
{
# ifdef NO_STAT_PROC
@ -494,7 +490,7 @@ int rktio_file_exists(char *filename)
# ifdef RKTIO_SYSTEM_WINDOWS
{
int isdir;
return (UNC_stat(filename, NULL, &isdir, NULL, NULL, NULL, NULL, -1)
return (UNC_stat(rktio, filename, NULL, &isdir, NULL, NULL, NULL, NULL, -1)
&& !isdir);
}
# else
@ -510,7 +506,7 @@ int rktio_file_exists(char *filename)
# endif
}
int rktio_directory_exists(char *dirname)
int rktio_directory_exists(rktio_t *rktio, char *dirname)
{
# ifdef NO_STAT_PROC
return 0;
@ -518,7 +514,7 @@ int rktio_directory_exists(char *dirname)
# ifdef RKTIO_SYSTEM_WINDOWS
int isdir;
return (UNC_stat(dirname, NULL, &isdir, NULL, NULL, NULL, NULL, -1)
return (UNC_stat(rktio, dirname, NULL, &isdir, NULL, NULL, NULL, NULL, -1)
&& isdir);
# else
struct MSC_IZE(stat) buf;
@ -535,7 +531,7 @@ int rktio_directory_exists(char *dirname)
# endif
}
int rktio_is_regular_file(char *filename)
int rktio_is_regular_file(rktio_t *rktio, char *filename)
/* Windows: check for special filenames before calling */
{
# ifdef NO_STAT_PROC
@ -554,12 +550,12 @@ int rktio_is_regular_file(char *filename)
# endif
}
int rktio_link_exists(char *filename)
int rktio_link_exists(rktio_t *rktio, char *filename)
{
#ifdef RKTIO_SYSTEM_WINDOWS
{
int islink;
if (UNC_stat(filename, NULL, NULL, &islink, NULL, NULL, NULL, -1)
if (UNC_stat(rktio, filename, NULL, NULL, &islink, NULL, NULL, NULL, -1)
&& islink)
return 1;
else
@ -583,7 +579,7 @@ int rktio_link_exists(char *filename)
#endif
}
char *rktio_get_current_directory()
char *rktio_get_current_directory(rktio_t *rktio)
{
#ifdef RKTIO_SYSTEM_WINDOWS
int need_l, bl = 256;
@ -631,7 +627,7 @@ char *rktio_get_current_directory()
#endif
}
int rktio_set_current_directory(char *expanded)
int rktio_set_current_directory(rktio_t *rktio, char *expanded)
{
int err;
@ -646,8 +642,7 @@ int rktio_set_current_directory(char *expanded)
return !err;
}
rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path)
/* If path is supplied, then fd is 0 for stat, 1 for lstat */
static rktio_identity_t *get_identity(rktio_t *rktio, rktio_fd_t *fd, char *path, int follow_links)
{
uintptr_t devi = 0, inoi = 0, inoi2 = 0;
@ -656,11 +651,11 @@ rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path)
struct MSC_IZE(stat) buf;
while (1) {
if (!path && !MSC_IZE(fstat)(fd, &buf))
if (!path && !MSC_IZE(fstat)(rktio_fd_system_fd(rktio, fd), &buf))
break;
else if (path && !fd && !MSC_IZE(stat)(path, &buf))
else if (path && follow_links && !MSC_IZE(stat)(path, &buf))
break;
else if (path && fd && !MSC_IZE(lstat)(path, &buf))
else if (path && !follow_links && !MSC_IZE(lstat)(path, &buf))
break;
else if (errno != EINTR) {
errid = errno;
@ -679,7 +674,7 @@ rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path)
#endif
#ifdef WINDOWS_FILE_HANDLES
BY_HANDLE_FILE_INFORMATION info;
HANDLE fdh = (HANDLE)fd;
HANDLE fdh;
init_procs();
@ -698,7 +693,8 @@ rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path)
get_windows_error();
return NULL;
}
}
} else
fdh = (HANDLE)rktio_fd_system_fd(rktio, fd);
if (!GetFileInformationByHandle(fdh, &info)) {
get_windows_error();
@ -726,16 +722,26 @@ rktio_identity_t *rktio_get_fd_identity(intptr_t fd, char *path)
}
}
rktio_identity_t *rktio_fd_identity(rktio_t *rktio, rktio_fd_t *fd)
{
return get_identity(rktio, fd, NULL, 0);
}
rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, int follow_links)
{
return get_identity(rktio, NULL, path, follow_links);
}
#ifdef RKTIO_SYSTEM_WINDOWS
static int enable_write_permission(const char *fn)
{
int flags;
return UNC_stat(fn, &flags, NULL, NULL, NULL, NULL, NULL, MZ_UNC_WRITE);
return UNC_stat(rktio, fn, &flags, NULL, NULL, NULL, NULL, NULL, MZ_UNC_WRITE);
}
#endif
int rktio_delete_file(char *fn, int enable_write_on_fail)
int rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail)
{
int errid;
@ -767,7 +773,7 @@ int rktio_delete_file(char *fn, int enable_write_on_fail)
#endif
}
int rktio_rename_file(char *dest, char *src, int exists_ok)
int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok)
{
#ifdef RKTIO_SYSTEM_WINDOWS
int errid;
@ -798,7 +804,7 @@ int rktio_rename_file(char *dest, char *src, int exists_ok)
free(src_w);
return 0;
#else
if (!exists_ok && (rktio_file_exists(dest) || rktio_directory_exists(dest))) {
if (!exists_ok && (rktio_file_exists(rktio, dest) || rktio_directory_exists(rktio, dest))) {
/* We use a specialized error here, because it's not
a system error (e.g., setting `errval` to `EEXIST` would
be a lie). */
@ -818,10 +824,10 @@ int rktio_rename_file(char *dest, char *src, int exists_ok)
#endif
}
char *rktio_readlink(char *fullfilename)
char *rktio_readlink(rktio_t *rktio, char *fullfilename)
{
#ifdef RKTIO_SYSTEM_WINDOWS
if (UNC_stat(fullfilename, NULL, NULL, &is_link, NULL, NULL, NULL, -1)
if (UNC_stat(rktio, fullfilename, NULL, NULL, &is_link, NULL, NULL, NULL, -1)
&& is_link) {
return UNC_readlink(fullfilename);
} else {
@ -852,7 +858,7 @@ char *rktio_readlink(char *fullfilename)
#endif
}
int rktio_make_directory(char *filename)
int rktio_make_directory(rktio_t *rktio, char *filename)
{
#ifdef NO_MKDIR
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
@ -893,7 +899,7 @@ int rktio_make_directory(char *filename)
return 0;
}
int rktio_delete_directory(char *filename, char *current_directory, int enable_write_on_fail)
int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory, int enable_write_on_fail)
{
#ifdef RKTIO_SYSTEM_WINDOWS
int tried_cwd = 0, tried_perm = 0;
@ -922,7 +928,7 @@ int rktio_delete_directory(char *filename, char *current_directory, int enable_w
#endif
}
int rktio_make_link(char *src, char *dest, int dest_is_directory)
int rktio_make_link(rktio_t *rktio, char *src, char *dest, int dest_is_directory)
/* `src` is the file that is written, and `dest` is written to that
file */
{
@ -960,12 +966,12 @@ int rktio_make_link(char *src, char *dest, int dest_is_directory)
#endif
}
rktio_timestamp_t *rktio_get_file_modify_seconds(char *file)
rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, char *file)
{
#ifdef RKTIO_SYSTEM_WINDOWS
rktio_timestamp_t *secs;
if (UNC_stat(file, NULL, NULL, NULL, &secs, NULL, NULL, -1))
if (UNC_stat(rktio, file, NULL, NULL, NULL, &secs, NULL, NULL, -1))
return secs;
return NULL;
#else
@ -986,7 +992,7 @@ rktio_timestamp_t *rktio_get_file_modify_seconds(char *file)
#endif
}
int rktio_set_file_modify_seconds(char *file, rktio_timestamp_t secs)
int rktio_set_file_modify_seconds(rktio_t *rktio, char *file, rktio_timestamp_t secs)
{
while (1) {
struct MSC_IZE(utimbuf) ut;
@ -1003,20 +1009,20 @@ int rktio_set_file_modify_seconds(char *file, rktio_timestamp_t secs)
}
#if defined(RKTIO_SYSTEM_UNIX) && !defined(NO_UNIX_USERS)
static int user_in_group(uid_t uid, gid_t gid)
static int user_in_group(rktio_t *rktio, uid_t uid, gid_t gid)
{
struct group *g;
struct passwd *pw;
int i, in;
if (!group_member_cache)
group_member_cache = calloc(GROUP_CACHE_SIZE, sizeof(group_member_cache_entry_t));
if (!rktio->group_member_cache)
rktio->group_member_cache = calloc(GROUP_CACHE_SIZE, sizeof(group_member_cache_entry_t));
for (i = 0; i < GROUP_CACHE_SIZE; i++) {
if ((group_member_cache[i].state != GROUP_MEMBER_CACHE_STATE_UNUSED)
&& (group_member_cache[i].gid == gid)
&& (group_member_cache[i].uid == uid))
return (group_member_cache[i].state == GROUP_MEMBER_CACHE_STATE_IN);
if ((rktio->group_member_cache[i].state != GROUP_MEMBER_CACHE_STATE_UNUSED)
&& (rktio->group_member_cache[i].gid == gid)
&& (rktio->group_member_cache[i].uid == uid))
return (rktio->group_member_cache[i].state == GROUP_MEMBER_CACHE_STATE_IN);
}
pw = getpwuid(uid);
@ -1035,10 +1041,10 @@ static int user_in_group(uid_t uid, gid_t gid)
in = !!(g->gr_mem[i]);
for (i = 0; i < GROUP_CACHE_SIZE; i++) {
if (group_member_cache[i].state == GROUP_MEMBER_CACHE_STATE_UNUSED) {
group_member_cache[i].gid = gid;
group_member_cache[i].uid = uid;
group_member_cache[i].state = (in
if (rktio->group_member_cache[i].state == GROUP_MEMBER_CACHE_STATE_UNUSED) {
rktio->group_member_cache[i].gid = gid;
rktio->group_member_cache[i].uid = uid;
rktio->group_member_cache[i].state = (in
? GROUP_MEMBER_CACHE_STATE_IN
: GROUP_MEMBER_CACHE_STATE_NOT_IN);
break;
@ -1049,7 +1055,7 @@ static int user_in_group(uid_t uid, gid_t gid)
}
#endif
int rktio_get_file_or_directory_permissions(char *filename, int all_bits)
int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits)
/* -1 result indicates an error */
{
# ifdef NO_STAT_PROC
@ -1117,13 +1123,13 @@ int rktio_get_file_or_directory_permissions(char *filename, int all_bits)
{
/* Use stat, because setuid, or because or no user info available */
struct stat buf;
int ok, read, write, execute;
int cr, read, write, execute;
do {
ok = stat(filename, &buf);
} while ((ok == -1) && (errno == EINTR));
cr = stat(filename, &buf);
} while ((cr == -1) && (errno == EINTR));
if (ok) {
if (cr) {
get_posix_error();
return -1;
} else {
@ -1145,7 +1151,7 @@ int rktio_get_file_or_directory_permissions(char *filename, int all_bits)
read = !!(buf.st_mode & S_IRUSR);
write = !!(buf.st_mode & S_IWUSR);
execute = !!(buf.st_mode & S_IXUSR);
} else if ((egid == buf.st_gid) || user_in_group(euid, buf.st_gid)) {
} else if ((egid == buf.st_gid) || user_in_group(rktio, euid, buf.st_gid)) {
read = !!(buf.st_mode & S_IRGRP);
write = !!(buf.st_mode & S_IWGRP);
execute = !!(buf.st_mode & S_IXGRP);
@ -1171,7 +1177,7 @@ int rktio_get_file_or_directory_permissions(char *filename, int all_bits)
{
int flags;
if (UNC_stat(filename, &flags, NULL, NULL, NULL, NULL, NULL, -1)) {
if (UNC_stat(rktio, filename, &flags, NULL, NULL, NULL, NULL, NULL, -1)) {
if (as_bits)
return (flags | (flags << 3) | (flags << 6));
else {
@ -1187,7 +1193,7 @@ int rktio_get_file_or_directory_permissions(char *filename, int all_bits)
# endif
}
int rktio_set_file_or_directory_permissions(char *filename, int new_bits)
int rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int new_bits)
{
# ifdef NO_STAT_PROC
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
@ -1221,7 +1227,7 @@ int rktio_set_file_or_directory_permissions(char *filename, int new_bits)
return 0;
}
if (UNC_stat(filename, NULL, NULL, NULL, NULL, NULL, NULL, new_bits))
if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, NULL, NULL, new_bits))
return 1;
return 0;
@ -1230,12 +1236,12 @@ int rktio_set_file_or_directory_permissions(char *filename, int new_bits)
# endif
}
rktio_size_t *rktio_file_size(char *filename)
rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename)
{
rktio_size_t *sz = NULL;
#ifdef RKTIO_SYSTEM_WINDOWS
{
if (UNC_stat(filename, NULL, NULL, NULL, NULL, &sz, NULL, -1)) {
if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, &sz, NULL, -1)) {
return sz;
}
return NULL;
@ -1281,7 +1287,7 @@ struct rktio_directory_list_t {
FF_TYPE info;
};
rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive)
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive)
/* path must be normalized */
{
char *pattern;
@ -1340,7 +1346,7 @@ rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive)
if ((err_val == ERROR_DIRECTORY) && CreateSymbolicLinkProc) {
/* check for symbolic link */
const char *resolved;
if (UNC_stat(filename, NULL, NULL, NULL, NULL, NULL, &resolved, -1)) {
if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, NULL, &resolved, -1)) {
if (resolved) {
filename = (char *)resolved;
goto retry;
@ -1358,7 +1364,7 @@ rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive)
return dl;
}
char *rktio_directory_list_step(rktio_directory_list_t *dl)
char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
/* empty-strng result (don't deallocate) means done */
{
while (dl->first_ready || FIND_NEXT(dl->hfile, &dl->info)) {
@ -1385,7 +1391,7 @@ struct rktio_directory_list_t {
DIR *dir;
};
rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive)
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive)
{
rktio_directory_list_t *dl;
DIR *dir;
@ -1403,7 +1409,7 @@ rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive)
return dl;
}
char *rktio_directory_list_step(rktio_directory_list_t *dl)
char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
/* empty-strng result (don't deallocate) means done */
{
struct dirent *e;
@ -1437,13 +1443,13 @@ char *rktio_directory_list_step(rktio_directory_list_t *dl)
#else
rktio_directory_list_t *rktio_directory_list_start(char *filename, int is_drive)
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive)
{
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
return NULL;
}
char *rktio_directory_list_step(rktio_directory_list_t *dl)
char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
{
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
return NULL;
@ -1460,7 +1466,7 @@ struct rktio_file_copy_t {
rktio_fd_t *src_fd, *dest_fd;
};
rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok)
rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src, int exists_ok)
{
#ifdef RKTIO_SYSTEM_UNIX
{
@ -1469,12 +1475,12 @@ rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok)
struct stat buf;
rktio_fd_t *src_fd, *dest_fd;
src_fd = rktio_open(src, RKTIO_OPEN_READ);
src_fd = rktio_open(rktio, src, RKTIO_OPEN_READ);
if (!src_fd)
return NULL;
do {
ok = fstat(rktio_fd_system_fd(src_fd), &buf);
ok = fstat(rktio_fd_system_fd(rktio, src_fd), &buf);
} while ((ok == -1) && (errno == EINTR));
if (ok || S_ISDIR(buf.st_mode)) {
@ -1482,14 +1488,14 @@ rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok)
get_posix_error();
else
set_racket_error(RKTIO_ERROR_IS_A_DIRECTORY);
rktio_close(src_fd);
rktio_close(rktio, src_fd);
return NULL;
}
dest_fd = rktio_open(dest, (RKTIO_OPEN_WRITE
| (exists_ok ? RKTIO_OPEN_TRUNCATE : 0)));
dest_fd = rktio_open(rktio, dest, (RKTIO_OPEN_WRITE
| (exists_ok ? RKTIO_OPEN_TRUNCATE : 0)));
if (!dest_fd) {
rktio_close(src_fd);
rktio_close(rktio, src_fd);
return NULL;
}
@ -1532,12 +1538,12 @@ rktio_file_copy_t *rktio_copy_file_start(char *dest, char *src, int exists_ok)
#endif
}
int rktio_copy_file_is_done(rktio_file_copy_t *fc)
int rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc)
{
return fc->done;
}
int rktio_copy_file_step(rktio_file_copy_t *fc)
int rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc)
{
#ifdef RKTIO_SYSTEM_UNIX
char buffer[4096];
@ -1546,7 +1552,7 @@ int rktio_copy_file_step(rktio_file_copy_t *fc)
if (fc->done)
return 1;
len = rktio_read(fc->src_fd, buffer, sizeof(buffer));
len = rktio_read(rktio, fc->src_fd, buffer, sizeof(buffer));
if (len == RKTIO_READ_EOF) {
fc->done = 1;
return 1;
@ -1556,7 +1562,7 @@ int rktio_copy_file_step(rktio_file_copy_t *fc)
intptr_t done = 0, amt;
while (done < len) {
amt = rktio_write(fc->dest_fd, buffer + done, len - done);
amt = rktio_write(rktio, fc->dest_fd, buffer + done, len - done);
if (amt < 0)
return 0;
done += amt;
@ -1569,11 +1575,11 @@ int rktio_copy_file_step(rktio_file_copy_t *fc)
#endif
}
void rktio_copy_file_stop(rktio_file_copy_t *fc)
void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc)
{
#ifdef RKTIO_SYSTEM_UNIX
rktio_close(fc->src_fd);
rktio_close(fc->dest_fd);
rktio_close(rktio, fc->src_fd);
rktio_close(rktio, fc->dest_fd);
#endif
free(fc);
}
@ -1582,7 +1588,7 @@ void rktio_copy_file_stop(rktio_file_copy_t *fc)
/* filesystem root list */
/*************************************************************/
char **rktio_filesystem_root_list(void)
char **rktio_filesystem_root_list(rktio_t *rktio)
/* returns a NULL-terminated array of strings */
{
#ifdef RKTIO_SYSTEM_WINDOWS
@ -1645,7 +1651,7 @@ char **rktio_filesystem_root_list(void)
/* expand user tilde & system paths */
/*************************************************************/
char *rktio_expand_user_tilde(char *filename) {
char *rktio_expand_user_tilde(rktio_t *rktio, char *filename) {
#ifdef RKTIO_SYSTEM_WINDOWS
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
return NULL;
@ -1737,7 +1743,7 @@ static char *append_paths(char *a, char *b, int free_a, int free_b)
return s;
}
char *rktio_system_path(int which)
char *rktio_system_path(rktio_t *rktio, int which)
{
#ifdef RKTIO_SYSTEM_UNIX
if (which == RKTIO_PATH_SYS_DIR) {
@ -1748,20 +1754,20 @@ char *rktio_system_path(int which)
char *p;
if ((p = getenv("TMPDIR"))) {
if (rktio_directory_exists(p))
if (rktio_directory_exists(rktio, p))
return strdup(p);
}
if (rktio_directory_exists("/var/tmp"))
if (rktio_directory_exists(rktio, "/var/tmp"))
return strdup("/var/tmp");
if (rktio_directory_exists("/usr/tmp"))
if (rktio_directory_exists(rktio, "/usr/tmp"))
return strdup("/usr/tmp");
if (rktio_directory_exists("/tmp"))
if (rktio_directory_exists(rktio, "/tmp"))
return strdup("/tmp");
return rktio_get_current_directory();
return rktio_get_current_directory(rktio);
}
{
@ -1797,7 +1803,7 @@ char *rktio_system_path(int which)
if (alt_home)
home = append_paths(alt_home, home_str + 2, 0, 0);
else {
home = rktio_expand_user_tilde(home_str);
home = rktio_expand_user_tilde(rktio, home_str);
if (!home) {
/* Something went wrong with the user lookup. Just drop "~'. */

View File

@ -0,0 +1,33 @@
#include "rktio.h"
#include "rktio_private.h"
#include <stdlib.h>
#include <string.h>
rktio_t *rktio_init(void)
{
rktio_t *rktio;
rktio = malloc(sizeof(rktio_t));
memset(rktio, 0, sizeof(rktio_t));
rktio_alloc_global_poll_set(rktio);
if (!rktio_initialize_signal(rktio)) {
rktio_destroy(rktio);
return NULL;
}
return rktio;
}
void rktio_destroy(rktio_t *rktio)
{
free(rktio);
}
/* Useful on Windows to make sure everyone is using the same malloc()
and fre(): */
void rktio_free(void *p)
{
free(p);
}

View File

@ -3,6 +3,9 @@
#ifdef RKTIO_SYSTEM_UNIX
# include <sys/select.h>
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
# include <math.h>
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
# include <windows.h>
@ -13,13 +16,9 @@
special hooks for Windows "descriptors" like even queues and
semaphores, etc. */
void rktio_alloc_global_poll_set(rktio_t *rktio) {
#ifdef USE_FAR_RKTIO_FDCALLS
THREAD_LOCAL_DECL(rktio_poll_set_t *rktio_global_poll_set);
#endif
void rktio_alloc_global_poll_set() {
#ifdef USE_FAR_RKTIO_FDCALLS
rktio_global_poll_set = rktio_alloc_fdset_array(3);
rktio->rktio_global_poll_set = rktio_alloc_fdset_array(3);
#endif
}
@ -777,3 +776,362 @@ int rktio_get_fd_limit(rktio_poll_set_t *fds)
}
#endif
/************************************************************/
/* Sleeping as a generalized select() */
/************************************************************/
int rktio_initialize_signal(rktio_t *rktio)
{
#ifdef RKTIO_SYSTEM_UNIX
/* Set up a pipe for signaling external events: */
int fds[2];
if (!pipe(fds)) {
rktio->external_event_fd = fds[0];
rktio->put_external_event_fd = fds[1];
fcntl(rktio->external_event_fd, F_SETFL, RKTIO_NONBLOCKING);
fcntl(rktio->put_external_event_fd, F_SETFL, RKTIO_NONBLOCKING);
return 1;
} else {
set_racket_error(RKTIO_ERROR_INIT_FAILED);
return 0;
}
#endif
#ifdef WIN32_FD_HANDLES
break_semaphore = (void*)CreateSemaphore(NULL, 0, 1, NULL);
#endif
}
rktio_signal_handle_t *rktio_get_signal_handle(rktio_t *rktio)
{
#ifdef RKTIO_SYSTEM_UNIX
return (rktio_signal_handle_t *)&rktio->put_external_event_fd;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
return (rktio_signal_handle_t *)rktio->break_semaphore;
#endif
}
void rktio_signal_received(rktio_t *rktio)
{
rktio_signal_received_at(rktio_get_signal_handle(rktio));
}
void rktio_signal_received_at(rktio_signal_handle_t *h)
{
#ifdef RKTIO_SYSTEM_UNIX
int put_ext_event_fd = *(int *)h;
int saved_errno = errno;
if (put_ext_event_fd) {
int v;
do {
v = write(put_ext_event_fd, "!", 1);
} while ((v == -1) && (errno == EINTR));
}
errno = saved_errno;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
ReleaseSemaphore(*(HANDLE *)h, 1, NULL);
#endif
}
static void clear_signal(rktio_t *rktio)
{
#ifdef RKTIO_SYSTEM_UNIX
/* Clear external event flag */
if (rktio->external_event_fd) {
int rc;
char buf[10];
do {
rc = read(rktio->external_event_fd, buf, 10);
} while ((rc == -1) && errno == EINTR);
}
#endif
}
void rktio_wait_until_signal_received(rktio_t *rktio)
{
#ifdef RKTIO_SYSTEM_UNIX
int r;
# ifdef HAVE_POLL_SYSCALL
GC_CAN_IGNORE struct pollfd pfd[1];
pfd[0].fd = rktio->external_event_fd;
pfd[0].events = POLLIN;
do {
r = poll(pfd, 1, -1);
} while ((r == -1) && (errno == EINTR));
# else
DECL_FDSET(readfds, 1);
INIT_DECL_RD_FDSET(readfds);
RKTIO_FD_ZERO(readfds);
RKTIO_FD_SET(rktio->external_event_fd, readfds);
do {
r = select(rktio->external_event_fd + 1, RKTIO_FDS(readfds), NULL, NULL, NULL);
} while ((r == -1) && (errno == EINTR));
# endif
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
WaitForSingleObject(rktio->break_semaphore, INFINITE);
#endif
clear_signal(rktio);
}
/****************** Windows cleanup *****************/
#if RKTIO_SYSTEM_WINDOWS
static void clean_up_wait(intptr_t result, OS_SEMAPHORE_TYPE *array,
int *rps, int count)
{
if ((result >= (intptr_t)WAIT_OBJECT_0) && (result < (intptr_t)WAIT_OBJECT_0 + count)) {
result -= WAIT_OBJECT_0;
if (rps[result])
ReleaseSemaphore(array[result], 1, NULL);
}
/* Clear out break semaphore */
WaitForSingleObject((HANDLE)scheme_break_semaphore, 0);
}
static int made_progress;
static DWORD max_sleep_time;
void rkio_notify_sleep_progress(void)
{
made_progress = 1;
}
#else
void rkio_notify_sleep_progress(void)
{
}
#endif
/******************** Main sleep function *****************/
/* The simple select() stuff is buried in various kinds of complexity. */
/* FIXME: don't forget SIGCHILD_DOESNT_INTERRUPT_SELECT handling in Racket */
void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds)
{
if (!fds) {
/* Nothing to block on - just sleep for some amount of time. */
#ifdef RKTIO_SYSTEM_UNIX
# ifdef HAVE_POLL_SYSCALL
int timeout;
if (nsecs <= 0.0)
timeout = -1;
else {
timeout = (int)(nsecs * 1000.0);
if (timeout < 0)
timeout = 0;
}
if (external_event_fd) {
GC_CAN_IGNORE struct pollfd pfd[1];
pfd[0].fd = external_event_fd;
pfd[0].events = POLLIN;
poll(pfd, 1, timeout);
} else {
poll(NULL, 0, timeout);
}
# else
/* Sleep by selecting on the external event fd */
struct timeval time;
intptr_t secs = (intptr_t)nsecs;
intptr_t usecs = (intptr_t)(fmod(nsecs, 1.0) * 1000000);
if (nsecs && (nsecs > 100000))
secs = 100000;
if (usecs < 0)
usecs = 0;
if (usecs >= 1000000)
usecs = 999999;
time.tv_sec = secs;
time.tv_usec = usecs;
if (rktio->external_event_fd) {
DECL_FDSET(readfds, 1);
INIT_DECL_RD_FDSET(readfds);
RKTIO_FD_ZERO(readfds);
RKTIO_FD_SET(rktio->external_event_fd, readfds);
select(rktio->external_event_fd + 1, RKTIO_FDS(readfds), NULL, NULL, &time);
} else {
select(0, NULL, NULL, NULL, &time);
}
# endif
#else
# ifndef NO_SLEEP
# ifndef NO_USLEEP
usleep((unsigned)(nsecs * 1000));
# else
sleep(nsecs);
# endif
# endif
#endif
} else {
/* Something to block on.... */
#ifdef HAVE_POLL_SYSCALL
/******* poll() variant *******/
{
struct mz_fd_set_data_t *data = fds->data;
intptr_t count = data->count;
int timeout;
if (v <= 0.0)
timeout = -1;
else if (v > 100000)
timeout = 100000000;
else {
timeout = (int)(v * 1000.0);
if (timeout < 0)
timeout = 0;
}
if (external_event_fd) {
data->pfd[count].fd = external_event_fd;
data->pfd[count].events = POLLIN;
count++;
}
poll(data->pfd, count, timeout);
}
#elif !defined(RKTIO_SYSTEM_WINDOWS)
/******* select() variant *******/
{
int actual_limit;
fd_set *rd, *wr, *ex;
struct timeval time;
intptr_t secs = (intptr_t)nsecs;
intptr_t usecs = (intptr_t)(fmod(nsecs, 1.0) * 1000000);
if (nsecs && (nsecs > 100000))
secs = 100000;
if (usecs < 0)
usecs = 0;
if (usecs >= 1000000)
usecs = 999999;
time.tv_sec = secs;
time.tv_usec = usecs;
rd = RKTIO_FDS(fds);
wr = RKTIO_FDS(RKTIO_GET_FDSET(fds, 1));
ex = RKTIO_FDS(RKTIO_GET_FDSET(fds, 2));
actual_limit = rktio_get_fd_limit(fds);
/* Watch for external events, too: */
if (rktio->external_event_fd) {
FD_SET(rktio->external_event_fd, rd);
if (rktio->external_event_fd >= actual_limit)
actual_limit = rktio->external_event_fd + 1;
}
select(actual_limit, rd, wr, ex, nsecs ? &time : NULL);
}
#else
/******* Windows variant *******/
{
intptr_t result;
HANDLE *array, just_two_array[2], break_sema;
int count, rcount, *rps;
if (fds->no_sleep)
return;
scheme_collapse_win_fd(fds); /* merges */
rcount = fds->num_handles;
count = fds->combined_len;
array = fds->combined_wait_array;
rps = fds->repost_sema;
/* add break semaphore: */
if (!count)
array = just_two_array;
break_sema = (HANDLE)scheme_break_semaphore;
array[count++] = break_sema;
/* Extensions may handle events.
If the event queue is empty (as reported by GetQueueStatus),
everything's ok.
Otherwise, we have trouble sleeping until an event is ready. We
sometimes leave events on th queue because, say, an eventspace is
not ready. The problem is that MsgWait... only unblocks when a new
event appears. Since extensions may check the queue using a sequence of
PeekMessages, it's possible that an event is added during the
middle of the sequence, but doesn't get handled.
To avoid this problem, we don't actually sleep indefinitely if an event
is pending. Instead, we slep 10 ms, then 20 ms, etc. This exponential
backoff ensures that we eventually handle a pending event, but we don't
spin and eat CPU cycles. The back-off is reset whenever a thread makes
progress. */
if (SCHEME_INT_VAL(((win_extended_fd_set *)fds)->wait_event_mask)
&& GetQueueStatus(SCHEME_INT_VAL(((win_extended_fd_set *)fds)->wait_event_mask))) {
if (!made_progress) {
/* Ok, we've gone around at least once. */
if (max_sleep_time < 0x20000000)
max_sleep_time *= 2;
} else {
/* Starting back-off mode */
made_progress = 0;
max_sleep_time = 5;
}
} else {
/* Disable back-off mode */
made_progress = 1;
max_sleep_time = 0;
}
/* Wait for HANDLE-based input: */
{
DWORD msec;
if (nsecs) {
if (nsecs > 100000)
msec = 100000000;
else
msec = (DWORD)(nsecs * 1000);
if (max_sleep_time && (msec > max_sleep_time))
msec = max_sleep_time;
} else {
if (max_sleep_time)
msec = max_sleep_time;
else
msec = INFINITE;
}
result = MsgWaitForMultipleObjects(count, array, FALSE, msec,
SCHEME_INT_VAL(((win_extended_fd_set *)fds)->wait_event_mask));
}
clean_up_wait(result, array, rps, rcount);
scheme_collapse_win_fd(fds); /* cleans up */
return;
}
#endif
}
clear_signal(rktio);
}

View File

@ -1,33 +1,15 @@
#if ((defined(_MSC_VER) || defined(__MINGW32__)) \
#if ((defined(_MSC_VER) || defined(__MINGW32__)) \
&& (defined(__WIN32__) || defined(WIN32) || defined(_WIN32)))
# define RKTIO_SYSTEM_WINDOWS
# define MSC_IZE(n) _ ## n
# define MSC_W_IZE(n) _w ## n
# define MSC_WIDE_PATH_temp(n) WIDE_PATH_temp(n)
#else
# define RKTIO_SYSTEM_UNIX
# define MSC_IZE(n) n
# define MSC_W_IZE(n) MSC_IZE(n)
# define MSC_WIDE_PATH_temp(n) n
#endif
#define THREAD_LOCAL_DECL(decl) decl
void rktio_get_posix_error(void);
#define get_posix_error() rktio_get_posix_error()
void rktio_set_racket_error(int errid);
#define set_racket_error(e) rktio_set_racket_error(e)
#ifdef RKTIO_SYSTEM_WINDOWS
void rktio_get_windows_error(void);
# define get_windows_error() rktio_get_windows_error()
# include <windows.h>
#endif
/*******************************************************************/
typedef struct rktio_poll_set_t rktio_poll_set_t;
#if RKTIO_SYSTEM_WINDOWS
# define USE_FAR_RKTIO_FDCALLS
#endif
@ -38,19 +20,47 @@ typedef struct rktio_poll_set_t rktio_poll_set_t;
# define USE_FAR_RKTIO_FDCALLS
#endif
#ifdef USE_FAR_RKTIO_FDCALLS
/* A single fdset that can be reused for immediate actions: */
THREAD_LOCAL_DECL(extern rktio_poll_set_t *rktio_global_fd_set);
/************************************************************/
/* Globals, as gathered into `rktio_t` */
/************************************************************/
struct rktio_t {
intptr_t errid;
int errkind;
#ifdef RKTIO_SYSTEM_UNIX
struct group_member_cache_entry_t *group_member_cache;
int external_event_fd;
int put_external_event_fd;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
int windows_nt_or_later;
HANDLE break_semaphore;
#endif
#ifdef USE_FAR_RKTIO_FDCALLS
/* A single fdset that can be reused for immediate actions: */
struct rktio_poll_set_t *rktio_global_fd_set;
#endif
};
/************************************************************/
/* Poll sets */
/************************************************************/
typedef struct rktio_poll_set_t rktio_poll_set_t;
void rktio_alloc_global_poll_set(rktio_t *rktio);
int rktio_initialize_signal(rktio_t *rktio);
#ifdef USE_FAR_RKTIO_FDCALLS
# define DECL_FDSET(n, c) fd_set *n
# define INIT_DECL_FDSET(r, w, e) { \
r = RKTIO_GET_FDSET(rktio_global_poll_set, 0 ); \
w = RKTIO_GET_FDSET(rktio_global_poll_set, 1 ); \
e = RKTIO_GET_FDSET(rktio_global_poll_set, 2 ); \
r = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 0 ); \
w = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 1 ); \
e = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 2 ); \
}
# define INIT_DECL_RD_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 0 )
# define INIT_DECL_WR_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 1 )
# define INIT_DECL_ER_FDSET(r) r = RKTIO_GET_FDSET(rktio_global_poll_set, 2 )
# define INIT_DECL_RD_FDSET(r) r = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 0 )
# define INIT_DECL_WR_FDSET(r) r = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 1 )
# define INIT_DECL_ER_FDSET(r) r = RKTIO_GET_FDSET(rktio->rktio_global_poll_set, 2 )
# define RKTIO_GET_FDSET(p, n) rktio_get_fdset(p, n)
# define RKTIO_FD_ZERO(p) rktio_fdzero(p)
@ -58,6 +68,10 @@ THREAD_LOCAL_DECL(extern rktio_poll_set_t *rktio_global_fd_set);
# define RKTIO_FD_CLR(n, p) rktio_fdclr(p, n)
# define RKTIO_FD_ISSET(n, p) rktio_fdisset(p, n)
# if !defined(HAVE_POLL_SYSCALL) && !defined(RKTIO_SYSTEM_WINDOWS)
# define RKTIO_FDS(p) ((fd_set *)fds)
# endif
#else
#include <sys/select.h>
@ -82,3 +96,34 @@ struct rktio_poll_set_t { fd_set data; };
rktio_poll_set_t *rktio_merge_fd_sets(rktio_poll_set_t *fds, rktio_poll_set_t *src_fds);
void rktio_clean_fd_set(rktio_poll_set_t *fds);
int rktio_get_fd_limit(rktio_poll_set_t *fds);
/************************************************************/
/* Misc */
/************************************************************/
#ifdef RKTIO_SYSTEM_WINDOWS
# define MSC_IZE(n) _ ## n
# define MSC_W_IZE(n) _w ## n
# define MSC_WIDE_PATH_temp(n) WIDE_PATH_temp(n)
#else
# define MSC_IZE(n) n
# define MSC_W_IZE(n) MSC_IZE(n)
# define MSC_WIDE_PATH_temp(n) n
#endif
void rktio_get_posix_error(rktio_t *rktio);
#define get_posix_error() rktio_get_posix_error(rktio)
void rktio_set_racket_error(rktio_t *rktio, int errid);
#define set_racket_error(e) rktio_set_racket_error(rktio, e)
#ifdef RKTIO_SYSTEM_WINDOWS
void rktio_get_windows_error(rktio_t *rktio);
# define get_windows_error() rktio_get_windows_error(rktio)
#endif
#if defined(USE_FCNTL_O_NONBLOCK)
# define RKTIO_NONBLOCKING O_NONBLOCK
#else
# define RKTIO_NONBLOCKING FNDELAY
#endif

View File

@ -12,12 +12,6 @@
# include <windows.h>
#endif
#if defined(USE_FCNTL_O_NONBLOCK)
# define RKTIO_NONBLOCKING O_NONBLOCK
#else
# define RKTIO_NONBLOCKING FNDELAY
#endif
#ifndef RKTIO_BINARY
# define RKTIO_BINARY 0
#endif
@ -97,7 +91,7 @@ static void init_read_fd(rktio_fd_t *rfd)
#endif
}
rktio_fd_t *rktio_system_fd(intptr_t system_fd, int modes)
rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
{
rktio_fd_t *rfd;
@ -128,7 +122,7 @@ rktio_fd_t *rktio_system_fd(intptr_t system_fd, int modes)
return rfd;
}
intptr_t rktio_fd_system_fd(rktio_fd_t *rfd)
intptr_t rktio_fd_system_fd(rktio_t *rktio, rktio_fd_t *rfd)
{
return rfd->fd;
}
@ -137,7 +131,7 @@ intptr_t rktio_fd_system_fd(rktio_fd_t *rfd)
/* opening a file fd */
/*************************************************************/
static rktio_fd_t *open_read(char *filename)
static rktio_fd_t *open_read(rktio_t *rktio, char *filename)
{
#ifdef RKTIO_SYSTEM_UNIX
int fd;
@ -212,7 +206,7 @@ static rktio_fd_t *open_read(char *filename)
#endif
}
static rktio_fd_t *open_write(char *filename, int modes)
static rktio_fd_t *open_write(rktio_t *rktio, char *filename, int modes)
{
#ifdef RKTIO_SYSTEM_UNIX
int fd;
@ -369,19 +363,19 @@ static rktio_fd_t *open_write(char *filename, int modes)
#endif
}
rktio_fd_t *rktio_open(char *filename, int modes)
rktio_fd_t *rktio_open(rktio_t *rktio, char *filename, int modes)
{
if (modes & RKTIO_OPEN_WRITE)
return open_write(filename, modes);
return open_write(rktio, filename, modes);
else
return open_read(filename);
return open_read(rktio, filename);
}
/*************************************************************/
/* closing */
/*************************************************************/
int rktio_close(rktio_fd_t *rfd)
int rktio_close(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_UNIX
int cr;
@ -483,7 +477,7 @@ static int try_get_fd_char(int fd, int *ready)
}
#endif
int rktio_poll_read_ready(rktio_fd_t *rfd)
int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
{
if (rfd->regfile)
return 1;
@ -573,7 +567,7 @@ int rktio_poll_read_ready(rktio_fd_t *rfd)
#endif
}
int poll_write_ready_or_flushed(rktio_fd_t *rfd, int check_flushed)
int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flushed)
{
#ifdef RKTIO_SYSTEM_UNIX
if (check_flushed)
@ -645,17 +639,17 @@ int poll_write_ready_or_flushed(rktio_fd_t *rfd, int check_flushed)
#endif
}
int rktio_poll_write_ready(rktio_fd_t *rfd)
int rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd)
{
return poll_write_ready_or_flushed(rfd, 0);
return poll_write_ready_or_flushed(rktio, rfd, 0);
}
int rktio_poll_write_flushed(rktio_fd_t *rfd)
int rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd)
{
return poll_write_ready_or_flushed(rfd, 1);
return poll_write_ready_or_flushed(rktio, rfd, 1);
}
void rktio_poll_add(rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes)
void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes)
{
#ifdef RKTIO_SYSTEM_UNIX
rktio_poll_set_t *fds2;
@ -708,7 +702,7 @@ void rktio_poll_add(rktio_fd_t *rfd, rktio_poll_set_t *fds, int modes)
/* reading */
/*************************************************************/
intptr_t rktio_read(rktio_fd_t *rfd, char *buffer, intptr_t len)
intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
{
#ifdef RKTIO_SYSTEM_UNIX
intptr_t bc;
@ -875,10 +869,10 @@ static void WindowsFDICleanup(Win_FD_Input_Thread *th)
/* writing */
/*************************************************************/
intptr_t rktio_write(rktio_fd_t *rfd, char *buffer, intptr_t len)
intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
{
#ifdef RKTIO_SYSTEM_UNIX
int flags;
int flags, errsaved;
intptr_t amt;
flags = fcntl(rfd->fd, F_GETFL, 0);
@ -898,15 +892,20 @@ intptr_t rktio_write(rktio_fd_t *rfd, char *buffer, intptr_t len)
amt = amt >> 1;
} while ((len == -1) && (errno == EAGAIN) && (amt > 0));
if (len == -1)
if (len == -1) {
errsaved = errno;
get_posix_error();
}
if (!(flags & RKTIO_NONBLOCKING))
fcntl(rfd->fd, F_SETFL, flags);
if (len == -1)
return RKTIO_WRITE_ERROR;
else
if (len == -1) {
if (errsaved == EAGAIN)
return 0;
else
return RKTIO_WRITE_ERROR;
} else
return len;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS

View File