rktio: wide-string handling for Windows

This commit is contained in:
Matthew Flatt 2017-06-12 20:31:06 -06:00
parent 4ffb01c6fa
commit 9bfaaf3ab3
5 changed files with 572 additions and 95 deletions

View File

@ -24,6 +24,7 @@ OBJS = rktio_fs.@LTO@ \
rktio_envvars.@LTO@ \
rktio_fs_change.@LTO@ \
rktio_error.@LTO@ \
rktio_wide.@LTO@ \
rktio_main.@LTO@
librktio.@LIBSFX@: $(OBJS)
@ -69,6 +70,9 @@ rktio_fs_change.@LTO@: $(srcdir)/rktio_fs_change.c $(RKTIO_HEADERS)
rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c
rktio_wide.@LTO@: $(srcdir)/rktio_wide.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_wide.@LTO@ -c $(srcdir)/rktio_wide.c
rktio_main.@LTO@: $(srcdir)/rktio_main.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_main.@LTO@ -c $(srcdir)/rktio_main.c

View File

@ -15,6 +15,10 @@
# include <poll.h>
#endif
/*========================================================================*/
/* fd struct */
/*========================================================================*/
struct rktio_fd_t {
int modes;
@ -31,16 +35,64 @@ struct rktio_fd_t {
HANDLE fd;
int sock; /* when `modes & RKTIO_OPEN_SOCKET` */
};
Win_FD_Input_Thread *th; /* input mode */
Win_FD_Output_Thread *oth; /* output mode */
struct Win_FD_Input_Thread *th; /* input mode */
struct Win_FD_Output_Thread *oth; /* output mode */
char *buffer;
#endif
};
/*************************************************************/
/* creating an fd */
/*************************************************************/
/*========================================================================*/
/* Windows I/O helper structs */
/*========================================================================*/
static void init_read_fd(rktio_fd_t *rfd)
#ifdef RKTIO_SYSTEM_WINDOWS
typedef struct Win_FD_Input_Thread {
/* This is malloced for use in a Win32 thread */
HANDLE fd;
volatile int avail, err, checking;
int *refcount;
HANDLE eof;
unsigned char *buffer;
HANDLE checking_sema, ready_sema, you_clean_up_sema;
HANDLE thread;
} Win_FD_Input_Thread;
typedef struct Win_FD_Output_Thread {
/* This is malloced for use in a Win32 thread */
HANDLE fd;
int nonblocking; /* non-zero => an NT pipe where non-blocking WriteFile
works. We still use a thread to detect when the
write has ben flushed, which in turn is needed to
know whether future writes will immediately succeed. */
volatile flushed, needflush; /* Used for non-blocking, only. The flushed
flag communicates from the flush-testing thread
to the main thread. For efficiency, we request
flush checking only when needed (instead of
after every write); needflush indicates that
a flush check is currently needed, but hasn't
been started. */
volatile int done, err_no;
volatile unsigned int buflen, bufstart, bufend; /* used for blocking, only */
unsigned char *buffer; /* used for blocking, only */
int *refcount;
HANDLE lock_sema, work_sema, ready_sema, you_clean_up_sema;
/* lock_sema protects the fields, work_sema starts the flush or
flush-checking thread to work, ready_sema indicates that a flush
finished, and you_clean_up_sema is essentially a reference
count */
HANDLE thread;
} Win_FD_Output_Thread;
# define RKTIO_FD_BUFFSIZE 4096
#endif
/*========================================================================*/
/* creating an fd */
/*========================================================================*/
static void init_read_fd(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_UNIX
# ifdef SOME_FDS_ARE_NOT_SELECTABLE
@ -60,17 +112,18 @@ static void init_read_fd(rktio_fd_t *rfd)
Win_FD_Input_Thread *th;
DWORD id;
HANDLE h;
OS_SEMAPHORE_TYPE sm;
HANDLE sm;
char *bfr;
th = malloc(sizeof(Win_FD_Input_Thread));
rfd->th = th;
/* Replace buffer with a malloced one: */
bfr = malloc(MZPORT_FD_BUFFSIZE);
fip->buffer = bfr;
bfr = malloc(RKTIO_FD_BUFFSIZE);
rfd->buffer = bfr;
th->buffer = bfr;
th->fd = (HANDLE)fd;
th->fd = rfd->fd;
th->avail = 0;
th->err = 0;
th->eof = NULL;
@ -123,7 +176,7 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
#endif
if (modes & RKTIO_OPEN_READ)
init_read_fd(rfd);
init_read_fd(rktio, rfd);
return rfd;
}
@ -192,9 +245,9 @@ rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd)
#endif
}
/*************************************************************/
/* closing */
/*************************************************************/
/*========================================================================*/
/* closing */
/*========================================================================*/
#ifdef RKTIO_SYSTEM_UNIX
void rktio_reliably_close(intptr_t s) {
@ -288,9 +341,9 @@ void rktio_forget(rktio_t *rktio, rktio_fd_t *rfd)
free(rfd);
}
/*************************************************************/
/* polling */
/*************************************************************/
/*========================================================================*/
/* polling */
/*========================================================================*/
#ifdef SOME_FDS_ARE_NOT_SELECTABLE
static int try_get_fd_char(int fd, int *ready)
@ -477,7 +530,7 @@ int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flush
} else
retval = (oth->err_no || (check_flushed
? !oth->buflen
: (oth->buflen < MZPORT_FD_BUFFSIZE)));
: (oth->buflen < RKTIO_FD_BUFFSIZE)));
if (!retval && !check_flushed)
WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */
ReleaseSemaphore(oth->lock_sema, 1, NULL);
@ -562,9 +615,9 @@ void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int
#endif
}
/*************************************************************/
/* reading */
/*************************************************************/
/*========================================================================*/
/* reading */
/*========================================================================*/
intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
{
@ -671,7 +724,7 @@ static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th)
if (GetFileType((HANDLE)th->fd) == FILE_TYPE_PIPE) {
/* Reading from a pipe will return early when data is available. */
toget = MZPORT_FD_BUFFSIZE;
toget = RKTIO_FD_BUFFSIZE;
} else {
/* Non-pipe: get one char at a time: */
toget = 1;
@ -735,9 +788,9 @@ static void WindowsFDICleanup(Win_FD_Input_Thread *th)
#endif
/*************************************************************/
/* writing */
/*************************************************************/
/*========================================================================*/
/* writing */
/*========================================================================*/
intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
{
@ -914,7 +967,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
HANDLE h;
DWORD id;
unsigned char *bfr;
OS_SEMAPHORE_TYPE sm;
HANDLE sm;
oth = malloc(sizeof(Win_FD_Output_Thread));
rfd->oth = oth;
@ -922,7 +975,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
oth->nonblocking = nonblocking;
if (!nonblocking) {
bfr = malloc(MZPORT_FD_BUFFSIZE);
bfr = malloc(RKTIO_FD_BUFFSIZE);
oth->buffer = bfr;
oth->flushed = 0;
oth->needflush = 0;
@ -975,7 +1028,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
if (oth->err_no) {
errsaved = oth->err_no;
ok = 0;
} else if (oth->buflen == MZPORT_FD_BUFFSIZE) {
} else if (oth->buflen == RKTIO_FD_BUFFSIZE) {
WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */
ok = 1;
} else {
@ -993,7 +1046,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
if (oth->bufstart <= oth->bufend) {
was_pre = 1;
topp = MZPORT_FD_BUFFSIZE;
topp = RKTIO_FD_BUFFSIZE;
} else {
was_pre = 0;
topp = oth->bufstart;
@ -1008,7 +1061,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
out_len = winwrote;
oth->bufend += winwrote;
if (oth->bufend == MZPORT_FD_BUFFSIZE)
if (oth->bufend == RKTIO_FD_BUFFSIZE)
oth->bufend = 0;
if (was_pre) {
@ -1046,3 +1099,56 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
}
#endif
}
/*========================================================================*/
/* refcounts for Windows fd threads */
/*========================================================================*/
#if defined(WINDOWS_FILE_HANDLES) || defined(MZ_USE_PLACES)
# define MZ_LOCK_REFCOUNTS
static mzrt_mutex *refcount_mutex;
#endif
static int *malloc_refcount(int val, int free_on_zero)
{
int *rc;
#ifdef MZ_LOCK_REFCOUNTS
if (!refcount_mutex)
mzrt_mutex_create(&refcount_mutex);
#endif
rc = (int *)malloc(2 * sizeof(int));
*rc = val;
rc[1] = free_on_zero;
return rc;
}
static int adj_refcount(int *refcount, int amt)
XFORM_SKIP_PROC
{
int rc;
if (!refcount)
return 0;
#ifdef MZ_LOCK_REFCOUNTS
mzrt_mutex_lock(refcount_mutex);
#endif
if (amt > 0) {
/* don't increment up from 0 */
if (*refcount)
*refcount += amt;
} else
*refcount += amt;
rc = *refcount;
#ifdef MZ_LOCK_REFCOUNTS
mzrt_mutex_unlock(refcount_mutex);
#endif
if (!rc && refcount[1])
free(refcount);
return rc;
}

View File

@ -13,6 +13,9 @@
#include <grp.h>
#include <dirent.h>
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
# include <shlobj.h>
#endif
#ifdef RKTIO_SYSTEM_UNIX
# define A_PATH_SEP '/'
@ -52,7 +55,7 @@ typedef struct group_member_cache_entry_t {
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
static int procs_initied = 0;
static int procs_inited = 0;
typedef BOOLEAN (WINAPI*CreateSymbolicLinkProc_t)(wchar_t *dest, wchar_t *src, DWORD flags);
static CreateSymbolicLinkProc_t CreateSymbolicLinkProc = NULL;
@ -60,6 +63,12 @@ typedef BOOL (WINAPI*DeviceIoControlProc_t)(HANDLE hDevice, DWORD dwIoControlCod
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped);
static DeviceIoControlProc_t DeviceIoControlProc;
typedef DWORD (WINAPI*GetFinalPathNameByHandle_t)(HANDLE hFile, wchar_t *lpszFilePath,
DWORD cchFilePath, DWORD dwFlags);
GetFinalPathNameByHandle_t GetFinalPathNameByHandleProc;
# define rktioFILE_NAME_NORMALIZED 0x0
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
@ -74,6 +83,7 @@ static void init_procs()
CreateSymbolicLinkProc = (CreateSymbolicLinkProc_t)GetProcAddress(hm, "CreateSymbolicLinkW");
DeviceIoControlProc = (DeviceIoControlProc_t)GetProcAddress(hm, "DeviceIoControl");
GetFinalPathNameByHandleProc = (GetFinalPathNameByHandle_t)GetProcAddress(hm, "GetFinalPathNameByHandleW");
FreeLibrary(hm);
}
@ -81,9 +91,9 @@ static void init_procs()
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
# define MZ_UNC_READ RKTIO_PERMISSION_READ
# define MZ_UNC_WRITE RKTIO_PERMISSION_WRITE
# define MZ_UNC_EXEC RKTIO_PERMISSION_EXEC
# define RKTIO_UNC_READ RKTIO_PERMISSION_READ
# define RKTIO_UNC_WRITE RKTIO_PERMISSION_WRITE
# define RKTIO_UNC_EXEC RKTIO_PERMISSION_EXEC
# define FIND_FIRST FindFirstFileW
# define FIND_NEXT FindNextFileW
@ -199,7 +209,7 @@ typedef struct mz_REPARSE_DATA_BUFFER {
#define mzFILE_FLAG_OPEN_REPARSE_POINT 0x200000
#define mzFSCTL_GET_REPARSE_POINT 0x900A8
static char *UNC_readlink(const char *fn)
static char *UNC_readlink(rktio_t *rktio, const char *fn)
{
HANDLE h;
DWORD got;
@ -307,7 +317,7 @@ static char *UNC_readlink(const char *fn)
}
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,
rktio_timestamp_t **date, rktio_size_t *filesize,
const char **resolved_path, int set_flags)
/* dirname must be absolute */
{
@ -390,7 +400,7 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
the path from the handle. */
HANDLE h;
wchar_t *dest = NULL;
DWORD len = 255;
DWORD len = 255, dest_len;
h = CreateFileW(WIDE_PATH_temp(copy), FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
@ -408,7 +418,7 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
if (dest) free(dest);
dest_len = len + 1;
dest = malloc(dest_len);
len = GetFinalPathNameByHandleW(h, dest, dest_len, FILE_NAME_NORMALIZED);
len = GetFinalPathNameByHandleProcW(h, dest, dest_len, rktioFILE_NAME_NORMALIZED);
} while (len > dest_len);
if (!len) {
@ -435,7 +445,7 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
if (set_flags != -1) {
DWORD attrs = GET_FF_ATTRIBS(fad);
if (!(set_flags & MZ_UNC_WRITE))
if (!(set_flags & RKTIO_UNC_WRITE))
attrs |= FF_A_RDONLY;
else if (attrs & FF_A_RDONLY)
attrs -= FF_A_RDONLY;
@ -452,7 +462,7 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
return 0;
}
if (flags)
*flags = MZ_UNC_READ | MZ_UNC_EXEC | ((GET_FF_ATTRIBS(fad) & FF_A_RDONLY) ? 0 : MZ_UNC_WRITE);
*flags = RKTIO_UNC_READ | RKTIO_UNC_EXEC | ((GET_FF_ATTRIBS(fad) & FF_A_RDONLY) ? 0 : RKTIO_UNC_WRITE);
if (date) {
rktio_timestamp_t *dt;
time_t mdt;
@ -736,11 +746,11 @@ rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, int follow_lin
}
#ifdef RKTIO_SYSTEM_WINDOWS
static int enable_write_permission(const char *fn)
static int enable_write_permission(rktio_t *rktio, const char *fn)
{
int flags;
return UNC_stat(rktio, fn, &flags, NULL, NULL, NULL, NULL, NULL, MZ_UNC_WRITE);
return UNC_stat(rktio, fn, &flags, NULL, NULL, NULL, NULL, NULL, RKTIO_UNC_WRITE);
}
#endif
@ -755,7 +765,7 @@ int rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail)
if ((errid == ERROR_ACCESS_DENIED) && enable_write_on_fail) {
/* Maybe it's just that the file has no write permission. Provide a more
Unix-like experience by attempting to change the file's permission. */
if (enable_write_permission(fn)) {
if (enable_write_permission(rktio, fn)) {
if (DeleteFileW(WIDE_PATH_temp(fn)))
return 1;
}
@ -830,9 +840,10 @@ int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok)
char *rktio_readlink(rktio_t *rktio, char *fullfilename)
{
#ifdef RKTIO_SYSTEM_WINDOWS
int is_link;
if (UNC_stat(rktio, fullfilename, NULL, NULL, &is_link, NULL, NULL, NULL, -1)
&& is_link) {
return UNC_readlink(fullfilename);
return UNC_readlink(rktio, fullfilename);
} else {
set_racket_error(RKTIO_ERROR_NOT_A_LINK);
return NULL;
@ -918,7 +929,7 @@ int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directo
tried_cwd = 1;
} else if ((errno == EACCES) && !tried_perm && enable_write_on_fail) {
/* Maybe the directory doesn't have write permission. */
(void)enable_write_permission(filename);
(void)enable_write_permission(rktio, filename);
tried_perm = 1;
}
# endif
@ -940,7 +951,7 @@ int rktio_make_link(rktio_t *rktio, char *src, char *dest, int dest_is_directory
if (CreateSymbolicLinkProc) {
int flags;
wchar_t *src_w = WIDE_PATH_COPY(src);
wchar_t *src_w = WIDE_PATH_copy(src);
if (dest_is_directory)
flags = 0x1; /* directory */
@ -1181,13 +1192,10 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
int flags;
if (UNC_stat(rktio, filename, &flags, NULL, NULL, NULL, NULL, NULL, -1)) {
if (as_bits)
if (all_bits)
return (flags | (flags << 3) | (flags << 6));
else {
return ((read ? MZ_UNC_READ : 0)
| (write ? MZ_UNC_WRITE : 0)
| (execute ? MZ_UNC_EXEC : 0));
}
else
return flags;
} else {
return -1;
}
@ -1219,12 +1227,12 @@ int rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int
# ifdef RKTIO_SYSTEM_WINDOWS
{
int len = strlen(filename);
int ALWAYS_SET_BITS = ((MZ_UNC_READ | MZ_UNC_EXEC)
| ((MZ_UNC_READ | MZ_UNC_EXEC) << 3)
| ((MZ_UNC_READ | MZ_UNC_EXEC) << 6));
int ALWAYS_SET_BITS = ((RKTIO_UNC_READ | RKTIO_UNC_EXEC)
| ((RKTIO_UNC_READ | RKTIO_UNC_EXEC) << 3)
| ((RKTIO_UNC_READ | RKTIO_UNC_EXEC) << 6));
if (((new_bits & ALWAYS_SET_BITS) != ALWAYS_SET_BITS)
|| ((new_bits & MZ_UNC_WRITE) != ((new_bits & (MZ_UNC_WRITE << 3)) >> 3))
|| ((new_bits & MZ_UNC_WRITE) != ((new_bits & (MZ_UNC_WRITE << 6)) >> 6))
|| ((new_bits & RKTIO_UNC_WRITE) != ((new_bits & (RKTIO_UNC_WRITE << 3)) >> 3))
|| ((new_bits & RKTIO_UNC_WRITE) != ((new_bits & (RKTIO_UNC_WRITE << 6)) >> 6))
|| (new_bits >= (1 << 9))) {
set_racket_error(RKTIO_ERROR_BAD_PERMISSION);
return 0;
@ -1244,7 +1252,10 @@ rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename)
rktio_size_t *sz = NULL;
#ifdef RKTIO_SYSTEM_WINDOWS
{
if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, &sz, NULL, -1)) {
rktio_size_t sz_v;
if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, &sz_v, NULL, -1)) {
sz = malloc(sizeof(rktio_size_t));
*sz = sz_v;
return sz;
}
return NULL;
@ -1283,9 +1294,10 @@ rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename)
/* directory list */
/*========================================================================*/
#ifdef USE_FINDFIRST
#ifdef RKTIO_SYSTEM_WINDOWS
struct rktio_directory_list_t {
int first_ready;
FF_HANDLE_TYPE hfile;
FF_TYPE info;
};
@ -1361,7 +1373,7 @@ rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filenam
}
dl = malloc(sizeof(rktio_directory_list_t));
memcpy(&dl->info, &info);
memcpy(&dl->info, &info, sizeof(info));
dl->hfile = hfile;
return dl;
@ -1377,7 +1389,7 @@ char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
&& !GET_FF_NAME(dl->info)[2]))) {
/* skip . and .. */
} else {
return NARROW_PATH_copy(info.cFileName);
return NARROW_PATH_copy(dl->info.cFileName);
}
}
@ -1600,7 +1612,7 @@ char **rktio_filesystem_root_list(rktio_t *rktio)
char drives[DRIVE_BUF_SIZE], *s;
intptr_t len, ds, ss_len, ss_count = 0;
UINT oldmode;
char **ss, *new_ss;
char **ss, **new_ss;
len = GetLogicalDriveStrings(DRIVE_BUF_SIZE, drives);
if (len <= DRIVE_BUF_SIZE)
@ -1618,7 +1630,7 @@ char **rktio_filesystem_root_list(rktio_t *rktio)
while (s[ds]) {
DWORD a, b, c, d;
/* GetDiskFreeSpace effectively checks whether we can read the disk: */
if (GetDiskFreeSpace(s XFORM_OK_PLUS ds, &a, &b, &c, &d)) {
if (GetDiskFreeSpace(s + ds, &a, &b, &c, &d)) {
if ((ss_count + 1) == ss_len) {
new_ss = malloc(sizeof(char*) * ss_len * 2);
mempcy(ss, new_ss, ss_count * sizeof(char*));
@ -1628,11 +1640,11 @@ char **rktio_filesystem_root_list(rktio_t *rktio)
ss[ss_count++] = strdup(s + ds);
}
ds += strlen(s XFORM_OK_PLUS ds) + 1;
ds += strlen(s + ds) + 1;
}
SetErrorMode(oldmode);
if (s != drived)
if (s != drives)
free(s);
ss[ss_count] = 0;
@ -1681,14 +1693,16 @@ char *rktio_expand_user_tilde(rktio_t *rktio, char *filename) {
user[u] = 0;
if (!user[0]) {
if (!(home = getenv("HOME"))) {
if (!(home = rktio_getenv(rktio, "HOME"))) {
char *ptr;
ptr = getenv("USER");
ptr = rktio_getenv(rktio, "USER");
if (!ptr)
ptr = getenv("LOGNAME");
ptr = rktio_getenv(rktio, "LOGNAME");
who = ptr ? getpwnam(ptr) : NULL;
if (ptr) free(ptr);
if (!who)
who = getpwuid(getuid());
@ -1696,8 +1710,8 @@ char *rktio_expand_user_tilde(rktio_t *rktio, char *filename) {
} else
who = getpwnam(user);
if (!home && who)
home = who->pw_dir;
if (!home && who && who->pw_dir)
home = strdup(who->pw_dir);
if (!home) {
set_racket_error(RKTIO_ERROR_UNKNOWN_USER);
@ -1716,6 +1730,8 @@ char *rktio_expand_user_tilde(rktio_t *rktio, char *filename) {
memcpy(naya + len + 1, filename + f + 1, flen);
naya[len + flen + 1] = 0;
free(home);
filename = naya;
return filename;
@ -1756,9 +1772,11 @@ char *rktio_system_path(rktio_t *rktio, int which)
if (which == RKTIO_PATH_TEMP_DIR) {
char *p;
if ((p = getenv("TMPDIR"))) {
if ((p = rktio_getenv(rktio, "TMPDIR"))) {
if (rktio_directory_exists(rktio, p))
return strdup(p);
return p;
else
free(p);
}
if (rktio_directory_exists(rktio, "/var/tmp"))
@ -1777,9 +1795,6 @@ char *rktio_system_path(rktio_t *rktio, int which)
/* Everything else is in ~: */
char *home_str, *ex_home, *alt_home, *home;
/* cast here avoids a clang warning: */
# define mz_STR_OFFSET(s, d) ((const char *)s XFORM_OK_PLUS d)
if ((which == RKTIO_PATH_PREF_DIR)
|| (which == RKTIO_PATH_PREF_FILE)
|| (which == RKTIO_PATH_ADDON_DIR)) {
@ -1802,9 +1817,9 @@ char *rktio_system_path(rktio_t *rktio, int which)
home_str = "~/";
}
alt_home = getenv("PLTUSERHOME");
alt_home = rktio_getenv(rktio, "PLTUSERHOME");
if (alt_home)
home = append_paths(alt_home, home_str + 2, 0, 0);
home = append_paths(alt_home, home_str + 2, 1, 0);
else {
home = rktio_expand_user_tilde(rktio, home_str);
@ -1846,22 +1861,25 @@ char *rktio_system_path(rktio_t *rktio, int which)
{
char *d, *p;
Scheme_Object *home;
char *home;
if (which == RKTIO_PATH_TEMP_DIR) {
if ((p = getenv("TMP")) || (p = getenv("TEMP"))) {
if (p && rktio_directory_exists(p))
return strdup(p);
if ((p = rktio_getenv(rktio, "TMP")) || (p = rktio_getenv(rktio, "TEMP"))) {
if (p) {
if (rktio_directory_exists(rktio, p))
return p;
free(p);
}
}
return rktio_current_drectory();
return rktio_get_current_directory(rktio);
}
home = NULL;
p = getenv("PLTUSERHOME");
p = rktio_getenv(rktio, "PLTUSERHOME");
if (p)
home = strdup(p);
home = p;
if (!home) {
/* Try to get Application Data directory: */
@ -1904,20 +1922,23 @@ char *rktio_system_path(rktio_t *rktio, int which)
if (!home) {
/* Back-up: try USERPROFILE environment variable */
d = getenv("USERPROFILE");
if (d && rktio_directory_exists(d))
return strdup(d);
d = rktio_getenv(rktio, "USERPROFILE");
if (d) {
if (rktio_directory_exists(rktio, d))
return d;
free(d);
}
}
if (!home) {
/* Last-ditch effort: try HOMEDRIVE+HOMEPATH */
d = getenv("HOMEDRIVE");
p = getenv("HOMEPATH");
d = rktio_getenv(rktio, "HOMEDRIVE");
p = rktio_getenv(rktio, "HOMEPATH");
if (d && p) {
home = append_paths(d, p);
home = append_paths(d, p, 1, 1);
if (rktio_directory_exists(home))
if (rktio_directory_exists(rktio, home))
return home;
else {
free(home);
@ -1931,7 +1952,7 @@ char *rktio_system_path(rktio_t *rktio, int which)
if (!GetModuleFileNameW(NULL, name, 1024)) {
/* Disaster. Use CWD. */
home = rktio_current_drectory();
home = rktio_get_current_directory(rktio);
if (!home)
return NULL;
} else {

View File

@ -23,7 +23,7 @@
# define USE_DYNAMIC_FDSET_SIZE
#endif
#if RKTIO_SYSTEM_WINDOWS
#ifdef RKTIO_SYSTEM_WINDOWS
# define USE_FAR_RKTIO_FDCALLS
#endif
#ifdef USE_DYNAMIC_FDSET_SIZE
@ -50,7 +50,7 @@ struct rktio_t {
#ifdef RKTIO_SYSTEM_WINDOWS
int windows_nt_or_later;
HANDLE break_semaphore;
int wsr_size = 0;
int wsr_size;
struct rktio_socket_t *wsr_array;
#endif
#ifdef USE_FAR_RKTIO_FDCALLS
@ -86,6 +86,11 @@ struct rktio_t {
#ifdef HAVE_INOTIFY_SYSCALL
struct rin_inotify_state_t *inotify_server;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
intptr_t wide_buffer_size;
wchar_t *wide_buffer;
#endif
};
/*========================================================================*/
@ -188,7 +193,7 @@ int rktio_process_init(rktio_t *rktio);
void rktio_process_deinit(rktio_t *rktio);
/*========================================================================*/
/* Misc */
/* Strings */
/*========================================================================*/
#ifdef RKTIO_SYSTEM_WINDOWS
@ -201,6 +206,23 @@ void rktio_process_deinit(rktio_t *rktio);
# define MSC_WIDE_PATH_temp(n) n
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
wchar_t *rktio_convert_to_wchar(rktio_t *rktio, const char *s, int do_copy);
char *rktio_convert_from_wchar(const wchar_t *ws, int free_given);
# define WIDE_PATH_temp(s) rktio_convert_to_wchar(rktio, s, 0)
# define WIDE_PATH_copy(s) rktio_convert_to_wchar(rktio, s, 1)
# define NARROW_PATH_copy(ws) rktio_convert_from_wchar(ws, 0)
# define NARROW_PATH_copy_then_free(ws) rktio_convert_from_wchar(ws, 1)
#endif
/*========================================================================*/
/* Misc */
/*========================================================================*/
void rktio_get_posix_error(rktio_t *rktio);
#define get_posix_error() rktio_get_posix_error(rktio)

View File

@ -0,0 +1,324 @@
#include "rktio.h"
#include "rktio_private.h"
/* For converting byte strings to and from "wide" strings on Windows. */
#ifdef RKTIO_SYSTEM_WINDOWS
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
/* A UTF-8 to UTF-16 conversion, but accepts an extended variant of
UTF-16 that accommodates unpaired surrogates, so that all 16-byte
sequences are accessible. */
static intptr_t utf8ish_to_utf16ish(const unsigned char *s, intptr_t end, unsigned short *us, int replacement)
{
intptr_t i, j, oki;
int state;
int init_doki;
int nextbits, v;
unsigned int sc;
int pending_surrogate = 0;
state = 0;
init_doki = 0;
nextbits = 0;
v = 0;
oki = 0;
j = 0;
i = 0;
while (i < end) {
sc = s[i];
if (sc < 0x80) {
if (state) {
/* In a sequence, but didn't continue */
state = 0;
nextbits = 0;
v = replacement;
i = oki;
j += init_doki;
} else {
v = sc;
}
} else if ((sc & 0xC0) == 0x80) {
/* Continues a sequence ... */
if (state) {
/* ... and we're in one ... */
if (!nextbits || (sc & nextbits)) {
/* and we have required bits. */
v = (v << 6) + (sc & 0x3F);
nextbits = 0;
--state;
if (state) {
i++;
continue;
}
/* We finished. One last check: */
if (v > 0x10FFFF) {
/* illegal code units */
v = replacement;
j += init_doki;
i = oki;
}
} else {
/* ... but we're missing required bits. */
state = 0;
nextbits = 0;
v = replacement;
j += init_doki;
i = oki;
}
} else {
/* ... but we're not in one */
v = replacement;
}
} else if (state) {
/* bad: already in a sequence */
state = 0;
v = replacement;
i = oki;
j += init_doki;
} else {
if ((sc & 0xE0) == 0xC0) {
if (sc & 0x1E) {
state = 1;
v = (sc & 0x1F);
i++;
continue;
}
/* else too small */
} else if ((sc & 0xF0) == 0xE0) {
state = 2;
v = (sc & 0xF);
if (!v)
nextbits = 0x20;
i++;
continue;
} else if ((sc & 0xF8) == 0xF0) {
v = (sc & 0x7);
if (v <= 4) {
state = 3;
if (!v)
nextbits = 0x30;
i++;
continue;
}
/* Else will be larger than 0x10FFFF, so fail */
}
/* Too small, or 0xFF or 0xFe, or start of a 5- or 6-byte sequence */
v = replacement;
}
/* If we get here, we're supposed to output v */
if (v > 0xFFFF) {
if (pending_surrogate) {
/* Accept previously written unpaired surrogate */
if (us)
us[j] = pending_surrogate;
j++;
pending_surrogate = 0;
}
if (us) {
v -= 0x10000;
us[j] = 0xD800 | ((v >> 10) & 0x3FF);
us[j+1] = 0xDC00 | (v & 0x3FF);
}
j++;
} else {
/* We allow a surrogate by itself, but don't allow a UTF-8ish a
0xDC00 after a UTF-8ish 0xD800, otherwise multiple encodings
can map to the same thing. */
if ((v >= 0xD800) && (v <= 0xDFFF)) {
if (pending_surrogate && ((v & 0xDC00) == 0xDC00)) {
/* This would look like a surrogate pair... */
/* We need to fill in 6 replacement substitutions,
one for each input byte. If we can't put all 6,
then don't use any input. */
int p;
if (us) {
for (p = 0; p < 5; p++) {
us[j+p] = replacement;
}
}
j += 5;
v = replacement;
pending_surrogate = 0;
} else {
if (pending_surrogate) {
if (us)
us[j] = pending_surrogate;
j++; /* Accept previousy written unpaired surrogate */
pending_surrogate = 0;
}
if ((v & 0xDC00) == 0xD800)
pending_surrogate = v;
else
pending_surrogate = 0;
}
} else {
if (pending_surrogate) {
if (us)
us[j] = pending_surrogate;
j++; /* Accept previousy written unpaired surrogate */
pending_surrogate = 0;
}
}
if (pending_surrogate)
--j; /* don't accept unpaired surrogate, yet */
else if (us)
us[j] = v;
}
j++;
i++;
oki = i;
init_doki = 0;
}
if (pending_surrogate) {
if (us)
us[j] = pending_surrogate;
j++;
}
if (state) {
for (i = oki; i < end; i++) {
if (us)
us[j] = replacement;
j++;
}
}
return j;
}
/* A UTF-16 to UTF-8 conversion, but unpaired surrogates map to an
extended variant of UTF-18, so all 16-byte sequences are
encodable. */
static intptr_t utf16ish_to_utf8ish(const unsigned short *us, intptr_t end, unsigned char *s)
{
intptr_t i, j;
unsigned int wc;
j = 0;
for (i = 0; i < end; i++) {
wc = us[i];
if ((wc & 0xF800) == 0xD800) {
/* Unparse surrogates. */
if ((wc & 0xFC00) != 0xD800) {
/* Count as one */
} else if ((i + 1 >= end)
|| (((us[i+1]) & 0xFC00) != 0xDC00)) {
/* Let the misplaced surrogate through */
} else {
i++;
wc = ((wc & 0x3FF) << 10) + ((us[i]) & 0x3FF);
wc += 0x10000;
}
}
if (!s) {
if (wc < 0x80) {
j += 1;
} else if (wc < 0x800) {
j += 2;
} else if (wc < 0x10000) {
j += 3;
} else if (wc < 0x200000) {
j += 4;
} else if (wc < 0x4000000) {
j += 5;
} else {
j += 6;
}
} else {
if (wc < 0x80) {
s[j++] = wc;
} else if (wc < 0x800) {
s[j++] = 0xC0 | ((wc & 0x7C0) >> 6);
s[j++] = 0x80 | (wc & 0x3F);
} else if (wc < 0x10000) {
s[j++] = 0xE0 | ((wc & 0xF000) >> 12);
s[j++] = 0x80 | ((wc & 0x0FC0) >> 6);
s[j++] = 0x80 | (wc & 0x3F);
} else if (wc < 0x200000) {
s[j++] = 0xF0 | ((wc & 0x1C0000) >> 18);
s[j++] = 0x80 | ((wc & 0x03F000) >> 12);
s[j++] = 0x80 | ((wc & 0x000FC0) >> 6);
s[j++] = 0x80 | (wc & 0x3F);
} else if (wc < 0x4000000) {
s[j++] = 0xF8 | ((wc & 0x3000000) >> 24);
s[j++] = 0x80 | ((wc & 0x0FC0000) >> 18);
s[j++] = 0x80 | ((wc & 0x003F000) >> 12);
s[j++] = 0x80 | ((wc & 0x0000FC0) >> 6);
s[j++] = 0x80 | (wc & 0x3F);
} else {
s[j++] = 0xFC | ((wc & 0x40000000) >> 30);
s[j++] = 0x80 | ((wc & 0x3F000000) >> 24);
s[j++] = 0x80 | ((wc & 0x00FC0000) >> 18);
s[j++] = 0x80 | ((wc & 0x0003F000) >> 12);
s[j++] = 0x80 | ((wc & 0x00000FC0) >> 6);
s[j++] = 0x80 | (wc & 0x3F);
}
}
}
return j;
}
#define RKTIO_MAX_IDEAL_BUFFER_SIZE 4096
wchar_t *rktio_convert_to_wchar(rktio_t *rktio, const char *s, int do_copy)
/* This function uses '\t' in place of invalid UTF-8 encoding
bytes, because '\t' is not a legal filename under Windows. */
{
intptr_t len, l;
wchar_t *ws;
l = strlen(s)+1; /* add nul terminator */
len = utf8ish_to_utf16ish((unsigned char *)s, l, NULL, '\t');
if (do_copy)
ws = malloc(sizeof(wchar_t) * len);
else if (len > rktio->wide_buffer_size) {
free(rktio->wide_buffer);
rktio->wide_buffer_size = len;
ws = malloc(sizeof(wchar_t) * len);
rktio->wide_buffer = ws;
} else if ((len < RKTIO_MAX_IDEAL_BUFFER_SIZE)
&& (rktio->wide_buffer_size > RKTIO_MAX_IDEAL_BUFFER_SIZE)) {
free(rktio->wide_buffer);
rktio->wide_buffer_size = RKTIO_MAX_IDEAL_BUFFER_SIZE;
ws = malloc(sizeof(wchar_t) * RKTIO_MAX_IDEAL_BUFFER_SIZE);
rktio->wide_buffer = ws;
}
(void)utf8ish_to_utf16ish((unsigned char *)s, l, (unsigned short*)ws, '\t');
return ws;
}
char *rktio_convert_from_wchar(const wchar_t *ws, int free_given)
{
intptr_t len, l;
char *s;
l = wc_slen(ws) + 1; /* add nul terminator */
len = utf16ish_to_utf8ish((unsigned short *)ws, l, NULL);
s = (char *)scheme_malloc_atomic(len);
len = utf16ish_to_utf8ish((unsigned short *)ws, l, s);
if (free_given)
free((void *)ws);
return s;
}
#endif