rktio: switch file & directory operations to rktio
This commit is contained in:
parent
425fe36fa5
commit
6268cd7ce9
|
@ -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
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "schminc.h"
|
||||
#include "schmach.h"
|
||||
#include "schexpobs.h"
|
||||
#include "schrktio.h"
|
||||
#ifdef MZ_USE_FUTURES
|
||||
# include "future.h"
|
||||
#endif
|
||||
|
|
|
@ -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
|
@ -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,
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
/* The rktio library has no callbacks, so no GC. */
|
||||
#define RKTIO_EXTERN XFORM_NONGCING extern
|
||||
|
||||
#include "rktio.h"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
/*========================================================================*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user