rktio: switch file & directory operations to rktio

This commit is contained in:
Matthew Flatt 2017-06-13 18:37:18 -06:00
parent 425fe36fa5
commit 6268cd7ce9
13 changed files with 690 additions and 2058 deletions

View File

@ -304,9 +304,11 @@ SCONFIG = $(srcdir)/../sconfig.h $(srcdir)/../uconfig.h ../mzconfig.h
COMMON_HEADERS = $(srcdir)/schpriv.h $(srcdir)/schexn.h $(SCONFIG) $(srcdir)/../include/scheme.h \
$(srcdir)/../include/schthread.h $(srcdir)/mzrt.h $(srcdir)/mzrt_cas.inc \
$(srcdir)/longdouble/longdouble.h $(srcdir)/../utils/schiptr.h \
$(srcdir)/longdouble/longdouble.h $(srcdir)/../utils/schiptr.h
RKTIO_HEADERS = $(srcdir)/schrktio.h \
$(srcdir)/../../rktio/rktio.h $(srcdir)/../../rktio/rktio_platform.h \
../../rktio/rktio_config.h
JIT_HEADERS = $(srcdir)/jit.h $(srcdir)/jitfpu.h $(srcdir)/stypes.h \
$(srcdir)/lightning/i386/core.h $(srcdir)/lightning/i386/core-common.h \
$(srcdir)/lightning/i386/asm.h $(srcdir)/lightning/i386/asm-common.h \
@ -324,7 +326,7 @@ JIT_HEADERS = $(srcdir)/jit.h $(srcdir)/jitfpu.h $(srcdir)/stypes.h \
$(srcdir)/lightning/arm/fp-vfp.h $(srcdir)/lightning/arm/fp-swf.h \
$(srcdir)/future.h $(srcdir)/jit_ts.c $(srcdir)/jit_ts_protos.h
salloc.@LTO@: $(COMMON_HEADERS) \
salloc.@LTO@: $(COMMON_HEADERS) $(RKTIOHEADERS) \
$(srcdir)/../gc/gc.h $(srcdir)/mzmark_salloc.inc
bignum.@LTO@: $(COMMON_HEADERS) \
$(srcdir)/stypes.h
@ -349,13 +351,13 @@ error.@LTO@: $(COMMON_HEADERS) \
$(srcdir)/stypes.h
eval.@LTO@: $(COMMON_HEADERS) \
$(srcdir)/stypes.h $(srcdir)/mzmark_eval.inc \
$(srcdir)/schmach.h $(srcdir)/mzstkchk.h $(srcdir)/schrunst.h \
$(srcdir)/future.h
file.@LTO@: $(COMMON_HEADERS) \
$(srcdir)/schmach.h $(srcdir)/mzstkchk.h $(srcdir)/schrunst.h \
$(srcdir)/future.h
file.@LTO@: $(COMMON_HEADERS) $(RKTIOHEADERS) \
$(srcdir)/stypes.h
fun.@LTO@: $(COMMON_HEADERS) \
fun.@LTO@: $(COMMON_HEADERS) $(RKTIOHEADERS) \
$(srcdir)/stypes.h $(srcdir)/mzmark_fun.inc $(srcdir)/schmap.inc \
$(srcdir)/future.h
$(srcdir)/future.h
future.@LTO@: $(COMMON_HEADERS) $(srcdir)/future.h $(SCONFIG) \
$(srcdir)/stypes.h $(srcdir)/mzmark_future.inc \
$(srcdir)/jit_ts_future_glue.c $(srcdir)/jit_ts_runtime_glue.c $(srcdir)/jit_ts_protos.h

View File

@ -31,6 +31,7 @@
#include "schminc.h"
#include "schmach.h"
#include "schexpobs.h"
#include "schrktio.h"
#ifdef MZ_USE_FUTURES
# include "future.h"
#endif

View File

@ -24,6 +24,7 @@
*/
#include "schpriv.h"
#include "schrktio.h"
#include <ctype.h>
#ifdef DOS_FILE_SYSTEM
# include <windows.h>
@ -281,6 +282,7 @@ Scheme_Config *scheme_init_error_escape_proc(Scheme_Config *config)
%- = skip int
%L = line number as intptr_t, -1 means no line
%R = get error numebr and string from rktio
%e = error number for strerror()
%E = error number for platform-specific error string
%Z = potential platform-specific error number; additional char*
@ -480,6 +482,44 @@ static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list
}
}
break;
case 'R':
{
intptr_t errid;
intptr_t errkind;
const char *es;
intptr_t elen;
errkind = rktio_get_last_error(scheme_rktio);
errid = rktio_get_last_error(scheme_rktio);
es = rktio_get_error_string(scheme_rktio, errkind, errid);
sprintf(buf, "; errno=%" PRIdPTR "", errid);
elen = strlen(es);
tlen = strlen(buf);
t = (const char *)scheme_malloc_atomic(tlen+elen+1);
memcpy((char *)t, es, elen);
memcpy((char *)t+elen, buf, tlen+1);
tlen += elen;
if (_errno_val) {
Scheme_Object *err_kind;
switch (errkind) {
case RKTIO_ERROR_KIND_WINDOWS:
err_kind = windows_symbol;
break;
case RKTIO_ERROR_KIND_POSIX:
err_kind = posix_symbol;
break;
case RKTIO_ERROR_KIND_GAI:
err_kind = gai_symbol;
break;
default:
err_kind = NULL;
}
if (err_kind) {
err_kind = scheme_make_pair(scheme_make_integer_value(errid), err_kind);
*_errno_val = err_kind;
}
}
}
break;
case 'e':
case 'm':
case 'E':
@ -668,6 +708,7 @@ static intptr_t sch_vsprintf(char *s, intptr_t maxlen, const char *msg, va_list
}
}
while (tlen && i < maxlen) {
s[i++] = *t;
t = t XFORM_OK_PLUS 1;
@ -705,6 +746,12 @@ static intptr_t scheme_sprintf(char *s, intptr_t maxlen, const char *msg, ...)
return len;
}
int scheme_last_error_is_racket(int errid)
{
return ((rktio_get_last_error_kind(scheme_rktio) == RKTIO_ERROR_KIND_RACKET)
&& (rktio_get_last_error(scheme_rktio) == errid));
}
#define ESCAPING_NONCM_PRIM(name, func, a1, a2, env) \
p = scheme_make_noncm_prim(func, name, a1, a2); \
SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_ALWAYS_ESCAPES); \

File diff suppressed because it is too large Load Diff

View File

@ -4067,6 +4067,8 @@ Scheme_Object *scheme_prune_bindings_table(Scheme_Object *bindings, Scheme_Objec
#define NOT_SUPPORTED_STR "unsupported on this platform"
int scheme_last_error_is_racket(int errid);
void scheme_read_err(Scheme_Object *port,
Scheme_Object *stxsrc,
intptr_t line, intptr_t column, intptr_t pos, intptr_t span,

View File

@ -1,2 +1,4 @@
/* The rktio library has no callbacks, so no GC. */
#define RKTIO_EXTERN XFORM_NONGCING extern
#include "rktio.h"

View File

@ -8,12 +8,59 @@ The library is meant to be
* always non-blocking;
* independent of global state (except on Windows, where internal
global state is managed appropriately with locks, and except for
Unix process handling without pthreads), so that it works with or
without threads; and
* independent of global state, so that it works with or without
threads; and
* easily callable though a FFI.
Many such libraries exist already. This one happens to have exactly
the things that a Racket implementation needs.
============================================================
Allocation conventions:
* Unless otherwise specified, returned data must be deallocated ---
using a type-specific deallocation function if provided or
rktio_free() otherwise. The rktio_free() function is the same as
free().
* There's no reference counting. If object A refers to object B, then
a client must keep object B alive as long as object A exists.
* String arguments are copied if they must be retained. Unless
otherwise specified, creating an object A with string S doesn't
require that S stay live as long as A exists. String results are
generally allocated and must be freed by the client.
Return type conventions:
* A return type `rktio_ok_t` (alias for `int`) means that 1 is
returned for succes and 0 for error. Use
rktio_get_last_error_kind() and rktio_get_last_error() for more
information about a 0 result.
* A return type `rktio_tri_t` (alias for `int`) means that 0 is
returned for an expected failuree, some `RKTIO_...` (alias for 1)
is returned for success, and `RKTIO_...ERROR` (alias for -2) is
returned for some error. Use rktio_get_last_error_kind() and
rktio_get_last_error() for more information about a
`RKTIO_...ERROR` result.
* For a pointer return type, unless otherwise specified, a NULL
result means an error. Use rktio_get_last_error_kind() and
rktio_get_last_error() for more information about the error.
* If a function returns `void`, you can rely on it to not change the
error reported by rktio_get_last_error_kind() and
rktio_get_last_error().
Thread conventions:
* A given `rktio_t` can be used from only one thread at a time.
Otherwise, as long as the initial call to rktio_init() returns
before a second call, there are no threading requirements.
Signals:
* SIGCHLD may be enabled, blocked, and/or handled.

View File

@ -8,7 +8,7 @@ static void do_check_valid(rktio_t *rktio, int ok, int where)
/* Beware that a reported error is nonsense if the failure
was an unexpected result insteda of an error result. */
if (!ok) {
printf("error at %d: %d@%d = %s\n",
printf(">> ERROR at %d: %d@%d = %s\n",
where,
rktio_get_last_error(rktio),
rktio_get_last_error_kind(rktio),
@ -21,7 +21,7 @@ static void do_check_valid(rktio_t *rktio, int ok, int where)
static void do_check_expected_error(rktio_t *rktio, int err, int where)
{
if (!err) {
printf("error expected at %d\n",
printf(">> ERROR expected at %d\n",
where);
}
}
@ -29,11 +29,11 @@ static void do_check_expected_error(rktio_t *rktio, int err, 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",
printf(">> ERROR expected at %d\n",
where);
} 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",
printf(">> WRONG ERROR at %d: %d@%d = %s\n",
where,
rktio_get_last_error(rktio),
rktio_get_last_error_kind(rktio),
@ -534,8 +534,8 @@ int main(int argc, char **argv)
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));
check_valid(perms & RKTIO_PERMISSION_READ);
check_valid(perms & RKTIO_PERMISSION_WRITE);
perms = rktio_get_file_or_directory_permissions(rktio, "test1", 1);
check_valid(perms != -1);
check_valid(perms & (RKTIO_PERMISSION_READ << 6));
@ -584,7 +584,7 @@ int main(int argc, char **argv)
/* Listing directory content */
ls = rktio_directory_list_start(rktio, pwd, 0);
ls = rktio_directory_list_start(rktio, pwd);
check_valid(ls);
saw_file = 0;
while (1) {

View File

@ -11,13 +11,23 @@
Almost every rktio_...() function takes it as the first argument. */
typedef struct rktio_t rktio_t;
/* Call rktio_init() before anything else. The first call to
rktio_init() must return before any additional calls (in other
threads), but there's no ordering requirement after that. */
RKTIO_EXTERN rktio_t *rktio_init(void);
/* Call rktio_destroy() as the last thing. Everything else must be
explicitly deallocated/closed/forgotten before calling
rktio_destroy(). */
RKTIO_EXTERN void rktio_destroy(rktio_t *);
/* Normally equivalent to free(), but ensures the same malloc()/free()
that rktio function use: */
RKTIO_EXTERN void rktio_free(void *p);
typedef int rktio_ok_t;
typedef int rktio_tri_t;
/*************************************************/
/* Reading and writing files */
@ -50,7 +60,7 @@ RKTIO_EXTERN int rktio_fd_is_terminal(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN int rktio_fd_modes(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_fd_t *rktio_open(rktio_t *rktio, char *src, int modes);
RKTIO_EXTERN int rktio_close(rktio_t *rktio, rktio_fd_t *fd);
RKTIO_EXTERN rktio_ok_t rktio_close(rktio_t *rktio, rktio_fd_t *fd);
RKTIO_EXTERN rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN void rktio_forget(rktio_t *rktio, rktio_fd_t *fd);
@ -58,21 +68,26 @@ RKTIO_EXTERN void rktio_forget(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)
#define RKTIO_POLL_READY 1
/* The read and write functions return the number of bytes read/write
in non-blocking mode, possibly 0. A read can produce `RKTIO_READ_EOF`
for end-of-file or `RKTIO_READ_ERROR` for an error. Similarly, write
can produce `RKTIO_WRITE_ERROR`. */
RKTIO_EXTERN intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
RKTIO_EXTERN intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
RKTIO_EXTERN int rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN int rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN int rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd);
#define RKTIO_POLL_ERROR (-2)
#define RKTIO_POLL_READY 1
RKTIO_EXTERN rktio_tri_t rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_tri_t rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd);
#define RKTIO_LOCK_ERROR (-2)
#define RKTIO_LOCK_ACQUIRED 1
RKTIO_EXTERN int rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl);
RKTIO_EXTERN int rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl);
RKTIO_EXTERN rktio_tri_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
/*************************************************/
/* Network */
@ -297,16 +312,31 @@ RKTIO_EXTERN int rktio_directory_exists(rktio_t *rktio, char *dirname);
RKTIO_EXTERN int rktio_link_exists(rktio_t *rktio, char *filename);
RKTIO_EXTERN int rktio_is_regular_file(rktio_t *rktio, char *filename);
RKTIO_EXTERN int rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail);
RKTIO_EXTERN int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok);
RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail);
/* Can report `RKTIO_ERROR_EXISTS`: */
RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok);
RKTIO_EXTERN char *rktio_get_current_directory(rktio_t *rktio);
RKTIO_EXTERN int rktio_set_current_directory(rktio_t *rktio, const char *path);
RKTIO_EXTERN int rktio_make_directory(rktio_t *rktio, char *filename);
RKTIO_EXTERN int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory, int enable_write_on_fail);
RKTIO_EXTERN rktio_ok_t rktio_set_current_directory(rktio_t *rktio, const char *path);
/* Can report `RKTIO_ERROR_EXISTS`: */
RKTIO_EXTERN rktio_ok_t rktio_make_directory(rktio_t *rktio, char *filename);
/* The `current_directory` argument is used on Windows to avoid being
in `filename` (instead) as a directory while trying to delete it.
The `enable_write_on_fail` argument also applied to Windows. */
RKTIO_EXTERN rktio_ok_t rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory,
int enable_write_on_fail);
/* Argument should not have a trailing separator. Can report
`RKTIO_ERROR_NOT_A_LINK`. */
RKTIO_EXTERN char *rktio_readlink(rktio_t *rktio, char *fullfilename);
RKTIO_EXTERN int rktio_make_link(rktio_t *rktio, char *src, char *dest, int dest_is_directory);
/* The `dest_is_directory` argument is used only
on Windows. Can report `RKTIO_ERROR_EXISTS`. */
RKTIO_EXTERN rktio_ok_t rktio_make_link(rktio_t *rktio, char *src, char *dest,
int dest_is_directory);
/*************************************************/
/* File attributes */
@ -317,14 +347,15 @@ typedef struct {
typedef intptr_t rktio_timestamp_t;
typedef struct {
uintptr_t a, b, c;
} rktio_identity_t;
RKTIO_EXTERN rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename);
RKTIO_EXTERN rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, char *file);
RKTIO_EXTERN int rktio_set_file_modify_seconds(rktio_t *rktio, char *file, rktio_timestamp_t secs);
RKTIO_EXTERN rktio_ok_t rktio_set_file_modify_seconds(rktio_t *rktio, char *file, rktio_timestamp_t secs);
typedef struct {
uintptr_t a, b, c;
int a_bits, b_bits, c_bits; /* size of each in bits */
} rktio_identity_t;
RKTIO_EXTERN rktio_identity_t *rktio_fd_identity(rktio_t *rktio, rktio_fd_t *fd);
RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, int follow_links);
@ -332,22 +363,41 @@ RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, i
/*************************************************/
/* Permissions */
/* Must match OS bits: */
/* Should match OS bits: */
#define RKTIO_PERMISSION_READ 0x4
#define RKTIO_PERMISSION_WRITE 0x2
#define RKTIO_PERMISSION_EXEC 0x1
#define RKTIO_PERMISSION_ERROR (-1)
/* Result is `RKTIO_PERMISSION_ERROR` for error, otherwise a combination of
bits. If not `all_bits`, then use constants above. */
RKTIO_EXTERN int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int all_bits);
RKTIO_EXTERN int rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int new_bits);
/* The `new_bits` format corresponds to `all_bits` for getting permissions.
Can report `RKTIO_ERROR_BAD_PERMISSION` for bits that make no sense. */
RKTIO_EXTERN rktio_ok_t 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_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive);
/* On Windows, the given `filename` must be normalized and not have
`.` or `..`: */
RKTIO_EXTERN rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename);
/* Returns an unallocated "" and deallocates `dl` when the iteration
is complete. A NULL result would mean an error without deallocating
`dl`, but that doesn't currently happen. */
RKTIO_EXTERN char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl);
/* Interrupt a directory list in progress, not needed after
rktio_directory_list_step() returns "": */
RKTIO_EXTERN void rktio_directory_list_stop(rktio_t *rktio, rktio_directory_list_t *dl);
/* Returns a NULL-terminated array. Free each string. Currently never
errors. */
RKTIO_EXTERN char **rktio_filesystem_root_list(rktio_t *rktio);
/*************************************************/
@ -355,9 +405,11 @@ RKTIO_EXTERN char **rktio_filesystem_root_list(rktio_t *rktio);
typedef struct rktio_file_copy_t rktio_file_copy_t;
/* Can report `RKTIO_ERROR_EXISTS`: */
RKTIO_EXTERN rktio_file_copy_t *rktio_copy_file_start(rktio_t *rktio, char *dest, char *src, int exists_ok);
RKTIO_EXTERN int rktio_copy_file_is_done(rktio_t *rktio, rktio_file_copy_t *fc);
RKTIO_EXTERN int rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc);
RKTIO_EXTERN rktio_ok_t rktio_copy_file_step(rktio_t *rktio, rktio_file_copy_t *fc);
RKTIO_EXTERN void rktio_copy_file_stop(rktio_t *rktio, rktio_file_copy_t *fc);
/*************************************************/
@ -377,6 +429,10 @@ enum {
};
RKTIO_EXTERN char *rktio_system_path(rktio_t *rktio, int which);
/* Path must start with tilde, otherwise `RKTIO_ERROR_NO_TILDE`.
Other possible errors are `RKTIO_ERROR_ILL_FORMED_USER` and
`RKTIO_ERROR_UNKNOWN_USER`. */
RKTIO_EXTERN char *rktio_expand_user_tilde(rktio_t *rktio, char *filename);
/*************************************************/
@ -423,7 +479,7 @@ enum {
/* Error IDs of kind RKTIO_ERROR_KIND_RACKET */
enum {
RKTIO_ERROR_UNSUPPORTED,
RKTIO_ERROR_UNSUPPORTED = 1,
RKTIO_ERROR_EXISTS,
RKTIO_ERROR_LINK_FAILED,
RKTIO_ERROR_NOT_A_LINK,
@ -455,7 +511,8 @@ RKTIO_EXTERN int rktio_get_last_error(rktio_t *rktio);
RKTIO_EXTERN int rktio_get_last_error_kind(rktio_t *rktio);
/* The returned strings for `rktio_...error_string()` should not be
deallocated. */
deallocated, but it only lasts reliably until the next call to
either of the functions. */
RKTIO_EXTERN const char *rktio_get_last_error_string(rktio_t *rktio);
RKTIO_EXTERN const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid);

View File

@ -6,6 +6,35 @@
#include <errno.h>
#include <string.h>
typedef struct err_str_t {
int id;
char *str;
} err_str_t;
err_str_t err_strs[] = {
{ RKTIO_ERROR_UNSUPPORTED, "unsupported" },
{ RKTIO_ERROR_EXISTS, "file or directory already exists"},
{ RKTIO_ERROR_LINK_FAILED, "link creation failed" },
{ RKTIO_ERROR_NOT_A_LINK, "not a link" },
{ RKTIO_ERROR_BAD_PERMISSION, "unsupported permission value" },
{ RKTIO_ERROR_IS_A_DIRECTORY, "path refers to a directory" },
{ RKTIO_ERROR_NOT_A_DIRECTORY, "path does not refer to a directory" },
{ RKTIO_ERROR_NO_TILDE, "path does not start with a tilde" },
{ RKTIO_ERROR_ILL_FORMED_USER, "ill-formed username in path" },
{ RKTIO_ERROR_UNKNOWN_USER, "unknown username in path" },
{ RKTIO_ERROR_INIT_FAILED, "initialization failed" },
{ RKTIO_ERROR_LTPS_NOT_FOUND, "not handle found" },
{ RKTIO_ERROR_LTPS_REMOVED, "handles successfully removed" },
{ RKTIO_ERROR_CONNECT_TRYING_NEXT, "connection failed, but can try again" },
{ RKTIO_ERROR_ACCEPT_NOT_READY, "no connection ready to accept" },
{ RKTIO_ERROR_HOST_AND_PORT_BOTH_UNSPECIFIED, "neither hostname nor port number specified" },
{ RKTIO_ERROR_INFO_TRY_AGAIN, "spurious empty UDP message; try again" },
{ RKTIO_ERROR_TRY_AGAIN, "no UDP message available" },
{ RKTIO_ERROR_TRY_AGAIN_WITH_IPV4, "listen failed, but try again with just IPv4 addresses" },
{ RKTIO_ERROR_TIME_OUT_OF_RANGE, "time value out-of-range for date conversion" },
{ 0, NULL }
};
void rktio_get_posix_error(rktio_t *rktio)
{
rktio->errid = errno;
@ -45,12 +74,50 @@ int rktio_get_last_error_kind(rktio_t *rktio)
const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid)
{
const char *s = NULL;
if (kind == RKTIO_ERROR_KIND_POSIX) {
if (kind == RKTIO_ERROR_KIND_RACKET) {
int i;
for (i = 0; err_strs[i].str; i++) {
if (err_strs[i].id == errid)
return err_strs[i].str;
}
} else if (kind == RKTIO_ERROR_KIND_POSIX) {
#ifndef NO_STRERROR_AVAILABLE
s = strerror(errid);
#endif
} else if (kind == RKTIO_ERROR_KIND_GAI)
s = rktio_gai_strerror(errid);
#ifdef RKTIO_SYSTEM_WINDOWS
else if (kind == RKTIO_ERROR_KIND_WINDOWS) {
wchar_t mbuf[256];
int len;
if ((type != 'e') && !es) {
if ((len = FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS),
NULL,
en, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
mbuf, 255, NULL))) {
if (len == 255)
mbuf[254] = 0;
else
mbuf[len] = 0;
es = NARROW_PATH_copy(mbuf);
/* Remove newlines: */
for (i = strlen(es) - 1; i > 0; i--) {
if (isspace(es[i]))
es[i] = 0;
else
break;
}
if (rktio->last_err_str)
free(rktio->last_err_str);
rktio->last_err_str = es;
return es;
}
}
}
#endif
if (s) return s;
return "???";
}
@ -61,3 +128,11 @@ const char *rktio_get_last_error_string(rktio_t *rktio)
rktio_get_last_error_kind(rktio),
rktio_get_last_error(rktio));
}
void rktio_error_clean(rktio_t *rktio)
{
#ifdef RKTIO_SYSTEM_WINDOWS
if (rktio->last_error_str)
free(rktio->last_err_str);
#endif
}

View File

@ -659,6 +659,7 @@ int rktio_set_current_directory(rktio_t *rktio, const char *path)
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;
uintptr_t devi_bits = 0, inoi_bits = 0, inoi2_bits = 0;
#ifdef FILES_HAVE_FDS
int errid = 0;
@ -684,6 +685,8 @@ static rktio_identity_t *get_identity(rktio_t *rktio, rktio_fd_t *fd, char *path
/* Warning: we assume that dev_t and ino_t fit in a pointer-sized integer. */
devi = (uintptr_t)buf.st_dev;
inoi = (uintptr_t)buf.st_ino;
devi_bits = sizeof(buf.st_dev) << 3;
inoi_bits = sizeof(buf.st_ino) << 3;
}
#endif
#ifdef WINDOWS_FILE_HANDLES
@ -721,6 +724,10 @@ static rktio_identity_t *get_identity(rktio_t *rktio, rktio_fd_t *fd, char *path
devi = info.dwVolumeSerialNumber;
inoi = info.nFileIndexLow;
inoi2 = info.nFileIndexHigh;
devi_bits = 32;
inoi_bits = 32;
inoi2_bits = 32;
#endif
{
@ -729,8 +736,11 @@ static rktio_identity_t *get_identity(rktio_t *rktio, rktio_fd_t *fd, char *path
id = malloc(sizeof(rktio_identity_t));
id->a = devi;
id->a_bits = devi_bits;
id->b = inoi;
id->b_bits = inoi_bits;
id->c = inoi2;
id->c_bits = inoi2_bits;
return id;
}
@ -837,6 +847,7 @@ int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok)
}
char *rktio_readlink(rktio_t *rktio, char *fullfilename)
/* fullfilename must not have a trailing separator */
{
#ifdef RKTIO_SYSTEM_WINDOWS
int is_link;
@ -855,7 +866,10 @@ char *rktio_readlink(rktio_t *rktio, char *fullfilename)
len = readlink(fullfilename, buffer, buf_len);
if (len == -1) {
if (errno != EINTR) {
get_posix_error();
if (errno == EINVAL)
set_racket_error(RKTIO_ERROR_NOT_A_LINK);
else
get_posix_error();
return NULL;
}
} else if (len == buf_len) {
@ -988,7 +1002,7 @@ rktio_timestamp_t *rktio_get_file_modify_seconds(rktio_t *rktio, char *file)
return NULL;
#else
struct MSC_IZE(stat) buf;
while (1) {
if (!MSC_W_IZE(stat)(MSC_WIDE_PATH_temp(file), &buf)){
rktio_timestamp_t *ts = malloc(sizeof(rktio_timestamp_t));
@ -1072,7 +1086,7 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
{
# ifdef NO_STAT_PROC
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
return -1;
return RKTIO_PERMISSION_ERROR;
# else
# ifdef RKTIO_SYSTEM_UNIX
/* General strategy for permissions (to deal with setuid)
@ -1097,7 +1111,7 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
if (ok && (errno != EACCES)) {
get_posix_error();
return -1;
return RKTIO_PERMISSION_ERROR;
} else {
do {
ok = access(filename, W_OK);
@ -1110,7 +1124,7 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
since the read test succeeded.) */
if (ok && (errno != EACCES) && (errno != EPERM) && (errno != EROFS)) {
get_posix_error();
return -1;
return RKTIO_PERMISSION_ERROR;
} else {
do {
ok = access(filename, X_OK);
@ -1122,11 +1136,11 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
not executable. */
if (ok && (errno != EACCES) && (errno != EPERM)) {
get_posix_error();
return -1;
return RKTIO_PERMISSION_ERROR;
} else {
return ((read ? S_IRUSR : 0)
| (write ? S_IWUSR : 0)
| (execute ? S_IXUSR : 0));
return ((read ? RKTIO_PERMISSION_READ : 0)
| (write ? RKTIO_PERMISSION_WRITE : 0)
| (execute ? RKTIO_PERMISSION_EXEC : 0));
}
}
}
@ -1143,7 +1157,7 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
if (cr) {
get_posix_error();
return -1;
return RKTIO_PERMISSION_ERROR;
} else {
if (all_bits) {
int bits = buf.st_mode;
@ -1178,9 +1192,9 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
execute = !!(buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH));
# endif
return ((read ? S_IRUSR : 0)
| (write ? S_IWUSR : 0)
| (execute ? S_IXUSR : 0));
return ((read ? RKTIO_PERMISSION_READ : 0)
| (write ? RKTIO_PERMISSION_WRITE : 0)
| (execute ? RKTIO_PERMISSION_EXEC : 0));
}
}
}
@ -1195,7 +1209,7 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
else
return flags;
} else {
return -1;
return RKTIO_PERMISSION_ERROR;
}
}
# endif
@ -1299,7 +1313,7 @@ struct rktio_directory_list_t {
FF_TYPE info;
};
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive)
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename)
/* path must be normalized */
{
char *pattern;
@ -1389,20 +1403,24 @@ char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
}
}
FIND_CLOSE(dl->hfile);
free(dl);
rktio_directory_list_stop(rktio, dl);
return "";
}
void rktio_directory_list_stop(rktio_t *rktio, rktio_directory_list_t *dl)
{
FIND_CLOSE(dl->hfile);
free(dl);
}
# elif !defined(NO_READDIR)
struct rktio_directory_list_t {
DIR *dir;
};
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive)
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename)
{
rktio_directory_list_t *dl;
DIR *dir;
@ -1445,15 +1463,20 @@ char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
return strndup(e->d_name, nlen);
}
closedir(dl->dir);
free(dl);
rktio_directory_list_stop(rktio, dl);
return "";
}
void rktio_directory_list_stop(rktio_t *rktio, rktio_directory_list_t *dl)
{
closedir(dl->dir);
free(dl);
}
#else
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename, int is_drive)
rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filename)
{
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
return NULL;
@ -1465,6 +1488,10 @@ char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
return NULL;
}
void rktio_directory_list_stop(rktio_t *rktio, rktio_directory_list_t *dl)
{
}
#endif
/*========================================================================*/

View File

@ -36,6 +36,7 @@ rktio_t *rktio_init(void)
void rktio_destroy(rktio_t *rktio)
{
rktio_error_clean(rktio);
rktio_process_deinit(rktio);
rktio_free_ghbn(rktio);
rktio_free_global_poll_set(rktio);

View File

@ -33,6 +33,9 @@
struct rktio_t {
intptr_t errid;
int errkind;
#ifdef RKTIO_SYSTEM_WINDOWS
char *last_err_str;
#endif
#ifdef RKTIO_SYSTEM_UNIX
struct group_member_cache_entry_t *group_member_cache;
@ -252,6 +255,8 @@ void rktio_set_windows_error(rktio_t *rktio, int errid);
# define set_windows_error(errid) rktio_set_windows_error(rktio, errid)
#endif
void rktio_error_clean(rktio_t *rktio);
#if defined(USE_FNDELAY_O_NONBLOCK)
# define RKTIO_NONBLOCKING FNDELAY
#else