aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/drivers')
-rw-r--r--erts/emulator/drivers/common/efile_drv.c65
-rw-r--r--erts/emulator/drivers/common/erl_efile.h3
-rw-r--r--erts/emulator/drivers/common/gzio.c74
-rw-r--r--erts/emulator/drivers/common/gzio.h16
-rw-r--r--erts/emulator/drivers/common/gzio_zutil.h9
-rw-r--r--erts/emulator/drivers/common/inet_drv.c793
-rw-r--r--erts/emulator/drivers/common/zlib_drv.c3
-rw-r--r--erts/emulator/drivers/ose/ose_efile.c1124
-rw-r--r--erts/emulator/drivers/ose/ose_signal_drv.c896
-rw-r--r--erts/emulator/drivers/ose/ttsl_drv.c68
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c17
-rw-r--r--erts/emulator/drivers/win32/win_efile.c777
12 files changed, 3583 insertions, 262 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 8de578d8b7..b62e9a0306 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -99,7 +99,16 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+
+#ifndef __OSE__
+#include <ctype.h>
+#include <sys/types.h>
#include <stdlib.h>
+#else
+#include "ctype.h"
+#include "sys/types.h"
+#include "stdlib.h"
+#endif
/* Need (NON)BLOCKING macros for sendfile */
#ifndef WANT_NONBLOCKING
@@ -111,11 +120,9 @@
#include "erl_driver.h"
#include "erl_efile.h"
#include "erl_threads.h"
-#include "zlib.h"
#include "gzio.h"
#include "dtrace-wrapper.h"
-#include <ctype.h>
-#include <sys/types.h>
+
void erl_exit(int n, char *fmt, ...);
@@ -168,7 +175,7 @@ dt_private *get_dt_private(int);
#ifdef USE_THREADS
-#define IF_THRDS if (sys_info.async_threads > 0)
+#define THRDS_AVAILABLE (sys_info.async_threads > 0)
#ifdef HARDDEBUG /* HARDDEBUG in io.c is expected too */
#define TRACE_DRIVER fprintf(stderr, "Efile: ")
#else
@@ -178,24 +185,26 @@ dt_private *get_dt_private(int);
#define MUTEX_LOCK(m) do { IF_THRDS { TRACE_DRIVER; driver_pdl_lock(m); } } while (0)
#define MUTEX_UNLOCK(m) do { IF_THRDS { TRACE_DRIVER; driver_pdl_unlock(m); } } while (0)
#else
-#define IF_THRDS if (0)
+#define THRDS_AVAILABLE (0)
#define MUTEX_INIT(m, p)
#define MUTEX_LOCK(m)
#define MUTEX_UNLOCK(m)
#endif
+#define IF_THRDS if (THRDS_AVAILABLE)
+#define SENDFILE_FLGS_USE_THREADS (1 << 0)
/**
* On DARWIN sendfile can deadlock with close if called in
* different threads. So until Apple fixes so that sendfile
* is not buggy we disable usage of the async pool for
* DARWIN. The testcase t_sendfile_crashduring reproduces
- * this error when using +A 10.
+ * this error when using +A 10 and enabling SENDFILE_FLGS_USE_THREADS.
*/
#if defined(__APPLE__) && defined(__MACH__)
-#define USE_THRDS_FOR_SENDFILE 0
+#define USE_THRDS_FOR_SENDFILE(DATA) 0
#else
-#define USE_THRDS_FOR_SENDFILE (sys_info.async_threads > 0)
+#define USE_THRDS_FOR_SENDFILE(DATA) (DATA->flags & SENDFILE_FLGS_USE_THREADS)
#endif /* defined(__APPLE__) && defined(__MACH__) */
@@ -301,7 +310,7 @@ static void file_stop_select(ErlDrvEvent event, void* _);
enum e_timer {timer_idle, timer_again, timer_write};
#ifdef HAVE_SENDFILE
enum e_sendfile {sending, not_sending};
-static void free_sendfile(void *data);
+#define SENDFILE_USE_THREADS (1 << 0)
#endif /* HAVE_SENDFILE */
struct t_data;
@@ -764,6 +773,9 @@ file_init(void)
: 0);
driver_system_info(&sys_info, sizeof(ErlDrvSysInfo));
+ /* run initiation of efile_driver if needed */
+ efile_init();
+
#ifdef USE_VM_PROBES
erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex");
pthread_key_create(&dt_driver_key, NULL);
@@ -818,7 +830,7 @@ file_start(ErlDrvPort port, char* command)
static void do_close(int flags, SWord fd) {
if (flags & EFILE_COMPRESSED) {
- erts_gzclose((gzFile)(fd));
+ erts_gzclose((ErtsGzFile)(fd));
} else {
efile_closefile((int) fd);
}
@@ -910,6 +922,7 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num,
driver_output2(desc->port, response, t-response, NULL, 0);
}
+#ifdef HAVE_SENDFILE
static void reply_string_error(file_descriptor *desc, char* str) {
char response[256]; /* Response buffer. */
char* s;
@@ -920,6 +933,7 @@ static void reply_string_error(file_descriptor *desc, char* str) {
*t = tolower(*s);
driver_output2(desc->port, response, t-response, NULL, 0);
}
+#endif
static int reply_error(file_descriptor *desc,
Efile_error *errInfo) /* The error codes. */
@@ -1136,7 +1150,7 @@ static void invoke_read(void *data)
}
read_size = size;
if (d->flags & EFILE_COMPRESSED) {
- read_size = erts_gzread((gzFile)d->fd,
+ read_size = erts_gzread((ErtsGzFile)d->fd,
d->c.read.binp->orig_bytes + d->c.read.bin_offset,
size);
status = (read_size != (size_t) -1);
@@ -1209,7 +1223,7 @@ static void invoke_read_line(void *data)
size = need - d->c.read_line.read_size;
}
if (d->flags & EFILE_COMPRESSED) {
- read_size = erts_gzread((gzFile)d->fd,
+ read_size = erts_gzread((ErtsGzFile)d->fd,
d->c.read_line.binp->orig_bytes +
d->c.read_line.read_offset + d->c.read_line.read_size,
size);
@@ -1250,7 +1264,7 @@ static void invoke_read_line(void *data)
d->c.read_line.read_size -= too_much;
ASSERT(d->c.read_line.read_size >= 0);
if (d->flags & EFILE_COMPRESSED) {
- Sint64 location = erts_gzseek((gzFile)d->fd,
+ Sint64 location = erts_gzseek((ErtsGzFile)d->fd,
-((Sint64) too_much), EFILE_SEEK_CUR);
if (location == -1) {
d->result_ok = 0;
@@ -1535,7 +1549,7 @@ static void invoke_writev(void *data) {
*/
errno = EINVAL;
if (! (status =
- erts_gzwrite((gzFile)d->fd,
+ erts_gzwrite((ErtsGzFile)d->fd,
iov[i].iov_base,
iov[i].iov_len)) == iov[i].iov_len) {
d->errInfo.posix_errno =
@@ -1797,7 +1811,7 @@ static void invoke_lseek(void *data)
d->errInfo.posix_errno = EINVAL;
status = 0;
} else {
- d->c.lseek.location = erts_gzseek((gzFile)d->fd,
+ d->c.lseek.location = erts_gzseek((ErtsGzFile)d->fd,
offset, d->c.lseek.origin);
if (d->c.lseek.location == -1) {
d->errInfo.posix_errno = errno;
@@ -1885,7 +1899,7 @@ static void invoke_open(void *data)
if (status || (d->errInfo.posix_errno != EISDIR)) {
mode = (d->flags & EFILE_MODE_READ) ? "rb" : "wb";
d->fd = (SWord) erts_gzopen(d->b, mode);
- if ((gzFile)d->fd) {
+ if ((ErtsGzFile)d->fd) {
status = 1;
} else {
if (errno == 0) {
@@ -1933,7 +1947,7 @@ static void invoke_sendfile(void *data)
d->c.sendfile.written += nbytes;
- if (result == 1 || (result == 0 && USE_THRDS_FOR_SENDFILE)) {
+ if (result == 1 || (result == 0 && USE_THRDS_FOR_SENDFILE(d))) {
d->result_ok = 0;
} else if (result == 0 && (d->errInfo.posix_errno == EAGAIN
|| d->errInfo.posix_errno == EINTR)) {
@@ -1950,7 +1964,7 @@ static void invoke_sendfile(void *data)
static void free_sendfile(void *data) {
struct t_data *d = (struct t_data *)data;
- if (USE_THRDS_FOR_SENDFILE) {
+ if (USE_THRDS_FOR_SENDFILE(d)) {
SET_NONBLOCKING(d->c.sendfile.out_fd);
} else {
MUTEX_LOCK(d->c.sendfile.q_mtx);
@@ -4123,8 +4137,16 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
goto done;
}
- if (hd_len != 0 || tl_len != 0 || flags != 0) {
- /* We do not allow header, trailers and/or flags right now */
+ if (hd_len != 0 || tl_len != 0) {
+ /* We do not allow header, trailers */
+ reply_posix_error(desc, EINVAL);
+ goto done;
+ }
+
+
+ if (flags & SENDFILE_FLGS_USE_THREADS && !THRDS_AVAILABLE) {
+ /* We do not allow use_threads flag on a system where
+ no threads are available. */
reply_posix_error(desc, EINVAL);
goto done;
}
@@ -4134,6 +4156,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->command = command;
d->invoke = invoke_sendfile;
d->free = free_sendfile;
+ d->flags = flags;
d->level = 2;
d->c.sendfile.out_fd = (int) out_fd;
@@ -4153,7 +4176,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->c.sendfile.nbytes = nbytes;
- if (USE_THRDS_FOR_SENDFILE) {
+ if (USE_THRDS_FOR_SENDFILE(d)) {
SET_BLOCKING(d->c.sendfile.out_fd);
} else {
/**
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index 5387f75efc..5a8e3bc5db 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -34,6 +34,7 @@
#define EFILE_COMPRESSED 8
#define EFILE_MODE_EXCL 16
#define EFILE_NO_TRUNCATE 32 /* Special for reopening on VxWorks */
+#define EFILE_MODE_SYNC 64
/*
* Seek modes for efile_seek().
@@ -126,7 +127,7 @@ struct t_sendfile_hdtl {
/*
* Functions.
*/
-
+int efile_init(void);
int efile_mkdir(Efile_error* errInfo, char* name);
int efile_rmdir(Efile_error* errInfo, char* name);
int efile_delete_file(Efile_error* errInfo, char* name);
diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c
index e085c262b0..1ef1602ec9 100644
--- a/erts/emulator/drivers/common/gzio.c
+++ b/erts/emulator/drivers/common/gzio.c
@@ -20,6 +20,7 @@
#endif
#include <ctype.h>
#include "erl_driver.h"
+#include "erl_efile.h"
#include "sys.h"
#ifdef __WIN32__
@@ -73,15 +74,15 @@ typedef struct gz_stream {
int transparent; /* 1 if input file is not a .gz file */
char mode; /* 'w' or 'r' */
int position; /* Position (for seek) */
- int (*destroy)OF((struct gz_stream*)); /* Function to destroy
+ int (*destroy)(struct gz_stream*); /* Function to destroy
* this structure. */
} gz_stream;
-local gzFile gz_open OF((const char *path, const char *mode));
-local int get_byte OF((gz_stream *s));
-local void check_header OF((gz_stream *s));
-local int destroy OF((gz_stream *s));
-local uLong getLong OF((gz_stream *s));
+local ErtsGzFile gz_open (const char *path, const char *mode);
+local int get_byte (gz_stream *s);
+local void check_header (gz_stream *s);
+local int destroy (gz_stream *s);
+local uLong getLong (gz_stream *s);
#ifdef UNIX
/*
@@ -144,7 +145,7 @@ local uLong getLong OF((gz_stream *s));
can be checked to distinguish the two cases (if errno is zero, the
zlib error is Z_MEM_ERROR).
*/
-local gzFile gz_open (path, mode)
+local ErtsGzFile gz_open (path, mode)
const char *path;
const char *mode;
{
@@ -179,7 +180,7 @@ local gzFile gz_open (path, mode)
s->path = (char*)ALLOC(FILENAME_BYTELEN(path)+FILENAME_CHARSIZE);
if (s->path == NULL) {
- return s->destroy(s), (gzFile)Z_NULL;
+ return s->destroy(s), (ErtsGzFile)Z_NULL;
}
FILENAME_COPY(s->path, path); /* do this early for debugging */
@@ -197,7 +198,7 @@ local gzFile gz_open (path, mode)
} while (*p++ && m < fmode + sizeof(fmode) - 1);
*m = '\0';
if (s->mode == '\0')
- return s->destroy(s), (gzFile)Z_NULL;
+ return s->destroy(s), (ErtsGzFile)Z_NULL;
if (s->mode == 'w') {
err = deflateInit2(&(s->stream), level,
@@ -207,7 +208,7 @@ local gzFile gz_open (path, mode)
s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
if (err != Z_OK || s->outbuf == Z_NULL) {
- return s->destroy(s), (gzFile)Z_NULL;
+ return s->destroy(s), (ErtsGzFile)Z_NULL;
}
} else {
/*
@@ -221,7 +222,7 @@ local gzFile gz_open (path, mode)
s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
if (err != Z_OK || s->inbuf == Z_NULL) {
- return s->destroy(s), (gzFile)Z_NULL;
+ return s->destroy(s), (ErtsGzFile)Z_NULL;
}
}
s->stream.avail_out = Z_BUFSIZE;
@@ -229,17 +230,17 @@ local gzFile gz_open (path, mode)
errno = 0;
#if defined(FILENAMES_16BIT)
{
- char wfmode[160];
- int i=0,j;
- for(j=0;fmode[j] != '\0';++j) {
- wfmode[i++]=fmode[j];
- wfmode[i++]='\0';
+ FILE* efile_wfopen(const WCHAR* name, const WCHAR* mode);
+ WCHAR wfmode[80];
+ int i = 0;
+ int j;
+ for(j = 0; fmode[j] != '\0'; ++j) {
+ wfmode[i++] = (WCHAR) fmode[j];
}
- wfmode[i++] = '\0';
- wfmode[i++] = '\0';
- s->file = F_OPEN(path, wfmode);
+ wfmode[i++] = L'\0';
+ s->file = efile_wfopen((WCHAR *)path, wfmode);
if (s->file == NULL) {
- return s->destroy(s), (gzFile)Z_NULL;
+ return s->destroy(s), (ErtsGzFile)Z_NULL;
}
}
#elif defined(UNIX)
@@ -249,18 +250,18 @@ local gzFile gz_open (path, mode)
s->file = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
}
if (s->file == -1) {
- return s->destroy(s), (gzFile)Z_NULL;
+ return s->destroy(s), (ErtsGzFile)Z_NULL;
}
#else
- s->file = F_OPEN(path, fmode);
+ s->file = fopen(path, fmode);
if (s->file == NULL) {
- return s->destroy(s), (gzFile)Z_NULL;
+ return s->destroy(s), (ErtsGzFile)Z_NULL;
}
#endif
if (s->mode == 'r') {
check_header(s); /* skip the .gz header */
}
- return (gzFile)s;
+ return (ErtsGzFile)s;
}
/* ===========================================================================
@@ -296,7 +297,7 @@ local int gz_rewind (gz_stream *s)
/* ===========================================================================
Opens a gzip (.gz) file for reading or writing.
*/
-gzFile erts_gzopen (path, mode)
+ErtsGzFile erts_gzopen (path, mode)
const char *path;
const char *mode;
{
@@ -447,7 +448,7 @@ local int destroy (s)
gzread returns the number of bytes actually read (0 for end of file).
*/
int
-erts_gzread(gzFile file, voidp buf, unsigned len)
+erts_gzread(ErtsGzFile file, voidp buf, unsigned len)
{
gz_stream *s = (gz_stream*)file;
Bytef *start = buf; /* starting point for crc computation */
@@ -557,7 +558,7 @@ erts_gzread(gzFile file, voidp buf, unsigned len)
gzwrite returns the number of bytes actually written (0 in case of error).
*/
int
-erts_gzwrite(gzFile file, voidp buf, unsigned len)
+erts_gzwrite(ErtsGzFile file, voidp buf, unsigned len)
{
gz_stream *s = (gz_stream*)file;
@@ -593,11 +594,20 @@ erts_gzwrite(gzFile file, voidp buf, unsigned len)
*/
int
-erts_gzseek(gzFile file, int offset, int whence)
+erts_gzseek(ErtsGzFile file, int offset, int whence)
{
int pos;
gz_stream* s = (gz_stream *) file;
+ switch (whence) {
+ case EFILE_SEEK_SET: whence = SEEK_SET; break;
+ case EFILE_SEEK_CUR: whence = SEEK_CUR; break;
+ case EFILE_SEEK_END: whence = SEEK_END; break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
if (s == NULL) {
errno = EINVAL;
return -1;
@@ -655,7 +665,7 @@ erts_gzseek(gzFile file, int offset, int whence)
degrade compression.
*/
int
-erts_gzflush(gzFile file, int flush)
+erts_gzflush(ErtsGzFile file, int flush)
{
uInt len;
int done = 0;
@@ -714,7 +724,7 @@ local uLong getLong (s)
and deallocates all the (de)compression state.
*/
int
-erts_gzclose(gzFile file)
+erts_gzclose(ErtsGzFile file)
{
int err;
gz_stream *s = (gz_stream*)file;
@@ -723,9 +733,9 @@ erts_gzclose(gzFile file)
if (s->mode == 'w') {
err = erts_gzflush (file, Z_FINISH);
- if (err != Z_OK) return s->destroy(file);
+ if (err != Z_OK) return s->destroy(s);
}
- return s->destroy(file);
+ return s->destroy(s);
}
diff --git a/erts/emulator/drivers/common/gzio.h b/erts/emulator/drivers/common/gzio.h
index 3f1e546140..ea50d922ec 100644
--- a/erts/emulator/drivers/common/gzio.h
+++ b/erts/emulator/drivers/common/gzio.h
@@ -17,11 +17,15 @@
* %CopyrightEnd%
*/
-gzFile erts_gzopen (const char *path, const char *mode);
-int erts_gzread(gzFile file, voidp buf, unsigned len);
-int erts_gzwrite(gzFile file, voidp buf, unsigned len);
-int erts_gzseek(gzFile, int, int);
-int erts_gzflush(gzFile file, int flush);
-int erts_gzclose(gzFile file);
+#include "zlib.h"
+
+typedef struct erts_gzFile* ErtsGzFile;
+
+ErtsGzFile erts_gzopen (const char *path, const char *mode);
+int erts_gzread(ErtsGzFile file, voidp buf, unsigned len);
+int erts_gzwrite(ErtsGzFile file, voidp buf, unsigned len);
+int erts_gzseek(ErtsGzFile, int, int);
+int erts_gzflush(ErtsGzFile file, int flush);
+int erts_gzclose(ErtsGzFile file);
ErlDrvBinary* erts_gzinflate_buffer(char*, uLong);
ErlDrvBinary* erts_gzdeflate_buffer(char*, uLong);
diff --git a/erts/emulator/drivers/common/gzio_zutil.h b/erts/emulator/drivers/common/gzio_zutil.h
index 00eccc80fc..854205cc2c 100644
--- a/erts/emulator/drivers/common/gzio_zutil.h
+++ b/erts/emulator/drivers/common/gzio_zutil.h
@@ -23,12 +23,6 @@
* that may change or not exist at all.
*/
-#ifndef HAVE_LIBZ
-/* Use our "real" copy of zutil.h if we don't use shared zlib */
-#include "zutil.h"
-
-#else /* HAVE_LIBZ: Shared zlib is used */
-
#define local static
#define DEF_MEM_LEVEL 8
#define zmemcpy sys_memcpy
@@ -77,6 +71,3 @@
# define OS_CODE 0x03 /* assume Unix */
#endif
-
-#endif /* HAVE_LIBZ */
-
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 45fac69303..09bada457d 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -86,6 +86,17 @@
#endif
typedef unsigned long long llu_t;
+#ifndef INT16_MIN
+#define INT16_MIN (-32768)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+
+#ifdef __OSE__
+#include "inet.h"
+#endif
+
#ifdef __WIN32__
#define STRNCASECMP strncasecmp
@@ -189,6 +200,7 @@ typedef unsigned long long llu_t;
#define HAVE_MULTICAST_SUPPORT
+#define HAVE_UDP
#define ERRNO_BLOCK WSAEWOULDBLOCK
@@ -282,7 +294,135 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD);
static unsigned long zero_value = 0;
static unsigned long one_value = 1;
-#else /* #ifdef __WIN32__ */
+#elif defined (__OSE__)
+
+/*
+ * Some notes about how inet (currently only tcp) works on OSE.
+ * The driver uses OSE signals to communicate with the one_inet
+ * process. Because of the difference in how signals and file descriptors
+ * work the whole select/deselect mechanic is very different.
+ * In ose when a sock_select is done a function is called. That function
+ * notes the changes that the driver want to do, but does not act on it.
+ * later when the function returns the new desired state is compared
+ * to the previous state and the apprioriate actions are taken. The action
+ * is usually to either request more data from the stack or stop requesting
+ * data.
+ *
+ * One thing to note is that the driver never does select/deselect. It always
+ * listens for the signals. Flow of data is regulated by sending or not sending
+ * signals to the ose inet process.
+ *
+ * The interesting functions to look at are:
+ * * inet_driver_select : called when sock_select is called
+ * * tcp_inet_ose_dispatch_signal : checks state changes and sends new signals
+ * * tcp_inet_drv_output_ose : ready output callback, reads signals and calls
+ * dispatch_signal
+ * * tcp_inet_drv_input_ose : ready input callback.
+ */
+
+#include "efs.h"
+#include "sys/socket.h"
+#include "sys/uio.h"
+#include "sfk/sys/sfk_uio.h"
+#include "netinet/in.h"
+#include "netinet/tcp.h"
+#include "netdb.h"
+#include "ose_spi/socket.sig"
+
+
+static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz);
+
+#define INVALID_SOCKET -1
+#define INVALID_EVENT -1
+#define SOCKET_ERROR -1
+
+#define SOCKET int
+#define HANDLE int
+#define FD_READ ERL_DRV_READ
+#define FD_WRITE ERL_DRV_WRITE
+#define FD_CLOSE 0
+#define FD_CONNECT (1<<4)
+#define FD_ACCEPT (1<<5)
+#define SOCK_FD_ERROR (1<<6)
+
+#define sock_connect(s, addr, len) connect((s), (addr), (len))
+#define sock_listen(s, b) listen((s), (b))
+#define sock_bind(s, addr, len) bind((s), (addr), (len))
+#define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l))
+#define sock_setopt(s,t,n,v,l) setsockopt((s),(t),(n),(v),(l))
+#define sock_name(s, addr, len) getsockname((s), (addr), (len))
+#define sock_peer(s, addr, len) getpeername((s), (addr), (len))
+#define sock_ntohs(x) ntohs((x))
+#define sock_ntohl(x) ntohl((x))
+#define sock_htons(x) htons((x))
+#define sock_htonl(x) htonl((x))
+
+#define sock_accept(s, addr, len) accept((s), (addr), (len))
+#define sock_send(s,buf,len,flag) inet_send((s),(buf),(len),(flag))
+#define sock_sendto(s,buf,blen,flag,addr,alen) \
+ sendto((s),(buf),(blen),(flag),(addr),(alen))
+#define sock_sendv(s, vec, size, np, flag) \
+ (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np))))
+#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag))
+
+#define sock_open(af, type, proto) socket((af), (type), (proto))
+#define sock_close(s) close((s))
+#define sock_dup(s) dup((s))
+#define sock_shutdown(s, how) shutdown((s), (how))
+
+#define sock_hostname(buf, len) gethostname((buf), (len))
+#define sock_getservbyname(name,proto) getservbyname((name), (proto))
+#define sock_getservbyport(port,proto) getservbyport((port), (proto))
+
+#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag))
+#define sock_recvfrom(s,buf,blen,flag,addr,alen) \
+ recvfrom((s),(buf),(blen),(flag),(addr),(alen))
+#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag))
+
+#define sock_errno() errno
+#define sock_create_event(d) ((d)->s) /* return file descriptor */
+#define sock_close_event(e) /* do nothing */
+
+#ifndef WANT_NONBLOCKING
+#define WANT_NONBLOCKING
+#endif
+#include "sys.h"
+
+typedef unsigned long u_long;
+#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0)
+#define IN_CLASSA_NET 0xff000000
+#define IN_CLASSA_NSHIFT 24
+#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
+#define IN_CLASSA_MAX 128
+
+#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000)
+#define IN_CLASSB_NET 0xffff0000
+#define IN_CLASSB_NSHIFT 16
+#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
+#define IN_CLASSB_MAX 65536
+
+#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000)
+#define IN_CLASSC_NET 0xffffff00
+#define IN_CLASSC_NSHIFT 8
+#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
+
+#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000)
+#define IN_MULTICAST(a) IN_CLASSD(a)
+
+#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000)
+#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000)
+
+#define sock_select(d, flags, onoff) do { \
+ ASSERT(!(d)->is_ignored); \
+ (d)->event_mask = (onoff) ? \
+ ((d)->event_mask | (flags)) : \
+ ((d)->event_mask & ~(flags)); \
+ DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX, s=%d\r\n", \
+ __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask, (d)->s)); \
+ inet_driver_select((d), (flags), (onoff)); \
+ } while(0)
+
+#else /* !__OSE__ && !__WIN32__ */
#include <sys/time.h>
#ifdef NETDB_H_NEEDS_IN_H
@@ -323,6 +463,8 @@ static unsigned long one_value = 1;
#include <setns.h>
#endif
+#define HAVE_UDP
+
/* SCTP support -- currently for UNIX platforms only: */
#undef HAVE_SCTP
#if defined(HAVE_SCTP_H)
@@ -545,13 +687,13 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
(d)->event_mask = (onoff) ? \
((d)->event_mask | (flags)) : \
((d)->event_mask & ~(flags)); \
- DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \
- (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \
+ DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \
+ __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \
inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \
} while(0)
-#endif /* #ifdef __WIN32__ #else */
+#endif /* !__WIN32__ && !__OSE__ */
#ifdef HAVE_SOCKLEN_T
# define SOCKLEN_T socklen_t
@@ -612,6 +754,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_PASSIVE 0 /* false */
#define INET_ACTIVE 1 /* true */
#define INET_ONCE 2 /* true; active once then passive */
+#define INET_MULTI 3 /* true; active N then passive */
/* INET_REQ_GETSTATUS enumeration */
#define INET_F_OPEN 0x0001
@@ -846,9 +989,10 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_IFNAMSIZ 16
/* INET Ignore states */
-#define INET_IGNORE_NONE 0
-#define INET_IGNORE_READ 1
-#define INET_IGNORE_WRITE 1 << 1
+#define INET_IGNORE_NONE 0
+#define INET_IGNORE_READ (1 << 0)
+#define INET_IGNORE_WRITE (1 << 1)
+#define INET_IGNORE_PASSIVE (1 << 2)
/* Max length of Erlang Term Buffer (for outputting structured terms): */
#ifdef HAVE_SCTP
@@ -958,6 +1102,7 @@ typedef struct {
inet_async_op op_queue[INET_MAX_ASYNC]; /* call queue */
int active; /* 0 = passive, 1 = active, 2 = active once */
+ Sint16 active_count; /* counter for {active,N} */
int stype; /* socket type:
SOCK_STREAM/SOCK_DGRAM/SOCK_SEQPACKET */
int sprotocol; /* socket protocol:
@@ -1001,6 +1146,13 @@ typedef struct {
char *netns; /* Socket network namespace name
as full file path */
#endif
+#ifdef __OSE__
+ int select_state; /* state to keep track of whether we
+ should trigger another read/write
+ request at end of ready_input/output */
+ ErlDrvEvent events[6];
+#endif
+
} inet_descriptor;
@@ -1016,8 +1168,10 @@ static void tcp_inet_stop(ErlDrvData);
static void tcp_inet_command(ErlDrvData, char*, ErlDrvSizeT);
static void tcp_inet_commandv(ErlDrvData, ErlIOVec*);
static void tcp_inet_flush(ErlDrvData drv_data);
+#ifndef __OSE__
static void tcp_inet_drv_input(ErlDrvData, ErlDrvEvent);
static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event);
+#endif
static ErlDrvData tcp_inet_start(ErlDrvPort, char* command);
static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int,
char*, ErlDrvSizeT, char**, ErlDrvSizeT);
@@ -1029,7 +1183,72 @@ static void tcp_inet_event(ErlDrvData, ErlDrvEvent);
static void find_dynamic_functions(void);
#endif
-static struct erl_drv_entry tcp_inet_driver_entry =
+#ifdef __OSE__
+/* The structure of the signal used for requesting asynchronous
+ * notification from the stack. Under normal circumstances the network stack
+ * shouldn't overwrite the value set in the fd field by the sender
+ * of the request */
+struct OseAsyncSig {
+ struct FmEvent event;
+ int fd;
+};
+
+union SIGNAL {
+ SIGSELECT signo;
+ struct OseAsyncSig async;
+};
+
+static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize);
+static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev);
+static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event);
+static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event);
+static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig);
+
+#ifdef INET_DRV_DEBUG
+
+static char *read_req = "SO_EVENT_READ_REQUEST";
+static char *read_rep = "SO_EVENT_READ_REPLY";
+static char *write_req = "SO_EVENT_WRITE_REQUEST";
+static char *write_rep = "SO_EVENT_WRITE_REPLY";
+static char *eof_req = "SO_EVENT_EOF_REQUEST";
+static char *eof_rep = "SO_EVENT_EOF_REPLY";
+static char *accept_req = "SO_EVENT_ACCEPT_REQUEST";
+static char *accept_rep = "SO_EVENT_ACCEPT_REPLY";
+static char *connect_req = "SO_EVENT_CONNECT_REQUEST";
+static char *connect_rep = "SO_EVENT_CONNECT_REPLY";
+static char *error_req = "SO_EVENT_ERROR_REQUEST";
+static char *error_rep = "SO_EVENT_ERROR_REPLY";
+static char signo_tmp[32];
+
+static char *signo_to_string(SIGSELECT signo) {
+ switch (signo) {
+ case SO_EVENT_READ_REQUEST: { return read_req; }
+ case SO_EVENT_READ_REPLY: { return read_rep; }
+ case SO_EVENT_WRITE_REQUEST: { return write_req; }
+ case SO_EVENT_WRITE_REPLY: { return write_rep; }
+ case SO_EVENT_EOF_REQUEST: { return eof_req; }
+ case SO_EVENT_EOF_REPLY: { return eof_rep; }
+ case SO_EVENT_ACCEPT_REQUEST: { return accept_req; }
+ case SO_EVENT_ACCEPT_REPLY: { return accept_rep; }
+ case SO_EVENT_CONNECT_REQUEST: { return connect_req; }
+ case SO_EVENT_CONNECT_REPLY: { return connect_rep; }
+ case SO_EVENT_ERROR_REQUEST: { return error_req; }
+ case SO_EVENT_ERROR_REPLY: { return error_rep; }
+ }
+
+ snprintf(signo_tmp,32,"0x%x",signo);
+
+ return signo_tmp;
+}
+
+#endif
+
+#endif /* __OSE__ */
+
+
+static struct erl_drv_entry tcp_inet_driver_entry =
{
tcp_inet_init, /* inet_init will add this driver !! */
tcp_inet_start,
@@ -1038,6 +1257,9 @@ static struct erl_drv_entry tcp_inet_driver_entry =
#ifdef __WIN32__
tcp_inet_event,
NULL,
+#elif defined(__OSE__)
+ tcp_inet_drv_input_ose, /*ready_input*/
+ tcp_inet_drv_output_ose, /*ready_output*/
#else
tcp_inet_drv_input,
tcp_inet_drv_output,
@@ -1045,9 +1267,17 @@ static struct erl_drv_entry tcp_inet_driver_entry =
"tcp_inet",
NULL,
NULL,
+#ifdef __OSE__
+ tcp_inet_ctl_ose,
+#else
tcp_inet_ctl,
+#endif
tcp_inet_timeout,
+#ifdef __OSE__
+ tcp_inet_commandv_ose,
+#else
tcp_inet_commandv,
+#endif
NULL,
tcp_inet_flush,
NULL,
@@ -1063,6 +1293,7 @@ static struct erl_drv_entry tcp_inet_driver_entry =
+#ifdef HAVE_UDP
static int packet_inet_init(void);
static void packet_inet_stop(ErlDrvData);
static void packet_inet_command(ErlDrvData, char*, ErlDrvSizeT);
@@ -1112,6 +1343,7 @@ static struct erl_drv_entry udp_inet_driver_entry =
NULL,
inet_stop_select
};
+#endif
#ifdef HAVE_SCTP
static struct erl_drv_entry sctp_inet_driver_entry =
@@ -1175,6 +1407,7 @@ static int tcp_deliver(tcp_descriptor* desc, int len);
static int tcp_inet_output(tcp_descriptor* desc, HANDLE event);
static int tcp_inet_input(tcp_descriptor* desc, HANDLE event);
+#ifdef HAVE_UDP
typedef struct {
inet_descriptor inet; /* common data structure (DON'T MOVE) */
int read_packets; /* Number of packets to read per invocation */
@@ -1186,29 +1419,54 @@ typedef struct {
static int packet_inet_input(udp_descriptor* udesc, HANDLE event);
static int packet_inet_output(udp_descriptor* udesc, HANDLE event);
+#endif
/* convert descriptor poiner to inet_descriptor pointer */
#define INETP(d) (&(d)->inet)
+#ifdef __OSE__
+static void inet_driver_select(inet_descriptor* desc,
+ int flags, int onoff);
+static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc,
+ int prev_select_state,
+ union SIGNAL *sig);
+#endif
+
static int async_ref = 0; /* async reference id generator */
#define NEW_ASYNC_ID() ((async_ref++) & 0xffff)
+/* check for transition from active to passive */
+#define INET_CHECK_ACTIVE_TO_PASSIVE(inet) \
+ do { \
+ if ((inet)->active == INET_ONCE) \
+ (inet)->active = INET_PASSIVE; \
+ else if ((inet)->active == INET_MULTI && --((inet)->active_count) == 0) { \
+ (inet)->active = INET_PASSIVE; \
+ packet_passive_message(inet); \
+ } \
+ } while (0)
static ErlDrvTermData am_ok;
static ErlDrvTermData am_tcp;
-static ErlDrvTermData am_udp;
static ErlDrvTermData am_error;
+static ErlDrvTermData am_einval;
static ErlDrvTermData am_inet_async;
static ErlDrvTermData am_inet_reply;
static ErlDrvTermData am_timeout;
static ErlDrvTermData am_closed;
+static ErlDrvTermData am_tcp_passive;
static ErlDrvTermData am_tcp_closed;
static ErlDrvTermData am_tcp_error;
-static ErlDrvTermData am_udp_error;
static ErlDrvTermData am_empty_out_q;
static ErlDrvTermData am_ssl_tls;
+#ifdef HAVE_UDP
+static ErlDrvTermData am_udp;
+static ErlDrvTermData am_udp_passive;
+static ErlDrvTermData am_udp_error;
+#endif
#ifdef HAVE_SCTP
static ErlDrvTermData am_sctp;
+static ErlDrvTermData am_sctp_passive;
static ErlDrvTermData am_sctp_error;
static ErlDrvTermData am_true;
static ErlDrvTermData am_false;
@@ -1218,6 +1476,7 @@ static ErlDrvTermData am_list;
static ErlDrvTermData am_binary;
static ErlDrvTermData am_active;
static ErlDrvTermData am_once;
+static ErlDrvTermData am_multi;
static ErlDrvTermData am_buffer;
static ErlDrvTermData am_linger;
static ErlDrvTermData am_recbuf;
@@ -1412,6 +1671,7 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){
# define SCTP_ANC_BUFF_SIZE INET_DEF_BUFFER/2 /* XXX: not very good... */
#endif
+#ifdef HAVE_UDP
static int load_ip_port(ErlDrvTermData* spec, int i, char* buf)
{
spec[i++] = ERL_DRV_INT;
@@ -1446,6 +1706,7 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf)
}
return i;
}
+#endif
#ifdef HAVE_SCTP
@@ -1466,8 +1727,8 @@ static int load_ip_and_port
unsigned int alen = len;
char abuf [len];
int res = inet_get_address(abuf, (inet_address*) addr, &alen);
- ASSERT(res==0);
- res = 0;
+ ASSERT(res==0); (void)res;
+
/* Now "abuf" contains: Family(1b), Port(2b), IP(4|16b) */
/* NB: the following functions are safe to use, as they create tuples
@@ -1612,10 +1873,12 @@ static void release_buffer(ErlDrvBinary* buf)
}
}
+#ifdef HAVE_UDP
static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, ErlDrvSizeT newsz)
{
return driver_realloc_binary(buf, newsz);
}
+#endif
/* use a TRICK, access the refc field to see if any one else has
* a ref to this buffer then call driver_free_binary else
@@ -3276,6 +3539,7 @@ static int tcp_error_message(tcp_descriptor* desc, int err)
return erl_drv_output_term(desc->inet.dport, spec, i);
}
+#ifdef HAVE_UDP
/*
** active mode message:
** {udp, S, IP, Port, [H1,...Hsz | Data]} or
@@ -3366,8 +3630,42 @@ static int packet_binary_message
ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN);
return erl_drv_output_term(desc->dport, spec, i);
}
+#endif
/*
+** active mode message: send active-to-passive transition message
+** {tcp_passive, S} or
+** {udp_passive, S} or
+** {sctp_passive, S}
+*/
+ static int packet_passive_message(inet_descriptor* desc)
+ {
+ ErlDrvTermData spec[6];
+ int i = 0;
+
+ DEBUGF(("packet_passive_message(%ld):\r\n", (long)desc->port));
+
+#if !defined(HAVE_UDP) && !defined(HAVE_SCTP)
+ i = LOAD_ATOM(spec, i, am_tcp_passive);
+#else
+ if (desc->sprotocol == IPPROTO_TCP)
+ i = LOAD_ATOM(spec, i, am_tcp_passive);
+ else {
+#ifdef HAVE_SCTP
+ i = LOAD_ATOM(spec, i, IS_SCTP(desc) ? am_sctp_passive : am_udp_passive);
+#else
+ i = LOAD_ATOM(spec, i, am_udp_passive);
+#endif
+ }
+#endif
+ i = LOAD_PORT(spec, i, desc->dport);
+ i = LOAD_TUPLE(spec, i, 2);
+ ASSERT(i <= 6);
+ return erl_drv_output_term(desc->dport, spec, i);
+ }
+
+#ifdef HAVE_UDP
+/*
** send active message {udp_error|sctp_error, S, Error}
*/
static int packet_error_message(udp_descriptor* udesc, int err)
@@ -3393,7 +3691,7 @@ static int packet_error_message(udp_descriptor* udesc, int err)
ASSERT(i == sizeof(spec)/sizeof(*spec));
return erl_drv_output_term(desc->dport, spec, i);
}
-
+#endif
/*
** active=TRUE:
@@ -3409,7 +3707,7 @@ static int tcp_reply_data(tcp_descriptor* desc, char* buf, int len)
int code;
const char* body = buf;
int bodylen = len;
-
+
packet_get_body(desc->inet.htype, &body, &bodylen);
if (desc->inet.deliver == INET_DELIVER_PORT) {
@@ -3427,8 +3725,7 @@ static int tcp_reply_data(tcp_descriptor* desc, char* buf, int len)
if (code < 0)
return code;
- if (desc->inet.active == INET_ONCE)
- desc->inet.active = INET_PASSIVE;
+ INET_CHECK_ACTIVE_TO_PASSIVE(INETP(desc));
return code;
}
@@ -3455,12 +3752,11 @@ tcp_reply_binary_data(tcp_descriptor* desc, ErlDrvBinary* bin, int offs, int len
}
if (code < 0)
return code;
- if (desc->inet.active == INET_ONCE)
- desc->inet.active = INET_PASSIVE;
+ INET_CHECK_ACTIVE_TO_PASSIVE(INETP(desc));
return code;
}
-
+#ifdef HAVE_UDP
static int
packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz,
ErlDrvBinary * bin, int offs, int len,
@@ -3479,11 +3775,11 @@ packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz,
code = packet_binary_message(desc, bin, offs, len, extra);
if (code < 0)
return code;
- if (desc->active == INET_ONCE)
- desc->active = INET_PASSIVE;
+ INET_CHECK_ACTIVE_TO_PASSIVE(desc);
return code;
}
}
+#endif
/* ----------------------------------------------------------------------------
@@ -3525,6 +3821,7 @@ sock_init(void) /* May be called multiple times. */
#ifdef HAVE_SCTP
static void inet_init_sctp(void) {
INIT_ATOM(sctp);
+ INIT_ATOM(sctp_passive);
INIT_ATOM(sctp_error);
INIT_ATOM(true);
INIT_ATOM(false);
@@ -3534,6 +3831,7 @@ static void inet_init_sctp(void) {
INIT_ATOM(binary);
INIT_ATOM(active);
INIT_ATOM(once);
+ INIT_ATOM(multi);
INIT_ATOM(buffer);
INIT_ATOM(linger);
INIT_ATOM(recbuf);
@@ -3657,15 +3955,22 @@ static int inet_init()
INIT_ATOM(ok);
INIT_ATOM(tcp);
+#ifdef HAVE_UDP
INIT_ATOM(udp);
+#endif
INIT_ATOM(error);
+ INIT_ATOM(einval);
INIT_ATOM(inet_async);
INIT_ATOM(inet_reply);
INIT_ATOM(timeout);
INIT_ATOM(closed);
+ INIT_ATOM(tcp_passive);
INIT_ATOM(tcp_closed);
INIT_ATOM(tcp_error);
+#ifdef HAVE_UDP
+ INIT_ATOM(udp_passive);
INIT_ATOM(udp_error);
+#endif
INIT_ATOM(empty_out_q);
INIT_ATOM(ssl_tls);
@@ -3684,7 +3989,10 @@ static int inet_init()
/* add TCP, UDP and SCTP drivers */
add_driver_entry(&tcp_inet_driver_entry);
+#ifdef HAVE_UDP
add_driver_entry(&udp_inet_driver_entry);
+#endif
+
#ifdef HAVE_SCTP
/* Check the size of SCTP AssocID -- currently both this driver and the
Erlang part require 32 bit: */
@@ -4013,6 +4321,16 @@ static void desc_close(inet_descriptor* desc)
desc->forced_events = 0;
desc->send_would_block = 0;
#endif
+#ifdef __OSE__
+ if (desc->events[0]) {
+ driver_select(desc->port,desc->events[0],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[1],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[2],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[3],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[4],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ driver_select(desc->port,desc->events[5],FD_READ|FD_WRITE|ERL_DRV_USE,0);
+ }
+#else
/*
* We should close the fd here, but the other driver might still
* be selecting on it.
@@ -4022,6 +4340,7 @@ static void desc_close(inet_descriptor* desc)
ERL_DRV_USE, 0);
else
inet_stop_select((ErlDrvEvent)(long)desc->event,NULL);
+#endif
desc->event = INVALID_EVENT; /* closed by stop_select callback */
desc->s = INVALID_SOCKET;
desc->event_mask = 0;
@@ -4063,6 +4382,64 @@ static int erl_inet_close(inet_descriptor* desc)
return 0;
}
+#ifdef __OSE__
+static void inet_select_init(inet_descriptor* desc)
+{
+ desc->events[0] =
+ erl_drv_ose_event_alloc(SO_EVENT_READ_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[0],
+ ERL_DRV_READ|ERL_DRV_USE, 1);
+
+ desc->events[1] =
+ erl_drv_ose_event_alloc(SO_EVENT_EOF_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[1],
+ ERL_DRV_READ|ERL_DRV_USE, 1);
+
+ desc->events[2] =
+ erl_drv_ose_event_alloc(SO_EVENT_ACCEPT_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[2],
+ ERL_DRV_READ|ERL_DRV_USE, 1);
+
+ /* trigger tcp_inet_input */
+ desc->events[3] =
+ erl_drv_ose_event_alloc(SO_EVENT_WRITE_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[3],
+ ERL_DRV_WRITE|ERL_DRV_USE, 1);
+
+ desc->events[4] =
+ erl_drv_ose_event_alloc(SO_EVENT_CONNECT_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[4],
+ ERL_DRV_WRITE|ERL_DRV_USE, 1);
+
+ desc->events[5] =
+ erl_drv_ose_event_alloc(SO_EVENT_ERROR_REPLY,
+ desc->s,
+ inet_resolve_signal,
+ NULL);
+ driver_select(desc->port, desc->events[5],
+ ERL_DRV_WRITE|ERL_DRV_USE, 1);
+
+ /* Issue a select on error event before any other select to be sure we are
+ prepared to receive error notifications from the stack, even in the
+ situations when select isn't issued */
+ sock_select(desc, SOCK_FD_ERROR, 1);
+}
+#endif
static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
char** rbuf, ErlDrvSizeT rsize)
@@ -4146,6 +4523,10 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
#ifdef __WIN32__
driver_select(desc->port, desc->event, ERL_DRV_READ, 1);
#endif
+#ifdef __OSE__
+ inet_select_init(desc);
+#endif
+
desc->state = INET_STATE_OPEN;
desc->stype = type;
desc->sfamily = domain;
@@ -4165,7 +4546,14 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
return ctl_error(sock_errno(), rbuf, rsize);
if (name.sa.sa_family != domain)
return ctl_error(EINVAL, rbuf, rsize);
+#ifdef __OSE__
+ /* for fdopen duplicating the sd will allow to uniquely identify
+ the signal from OSE with erlang port */
+ desc->s = sock_dup(s);
+#else
desc->s = s;
+#endif
+
if ((desc->event = sock_create_event(desc)) == INVALID_EVENT)
return ctl_error(sock_errno(), rbuf, rsize);
SET_NONBLOCKING(desc->s);
@@ -4175,8 +4563,15 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
desc->state = INET_STATE_BOUND; /* assume bound */
if (type == SOCK_STREAM) { /* check if connected */
sz = sizeof(name);
- if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz)))
+ if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) {
desc->state = INET_STATE_CONNECTED;
+#ifdef __OSE__
+ /* since we are dealing with different descriptors (i.e. inet and
+ socket) the select part should be initialized with the right
+ values */
+ inet_select_init(desc);
+#endif
+ }
}
desc->prebound = 1; /* used to prevent a real close since
@@ -4202,8 +4597,7 @@ struct addr_if {
#ifndef SIOCGIFNETMASK
-static struct in_addr net_mask(in)
-struct in_addr in;
+static struct in_addr net_mask(struct in_addr in)
{
register u_long i = sock_ntohl(in.s_addr);
@@ -5652,8 +6046,25 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
case INET_LOPT_ACTIVE:
DEBUGF(("inet_set_opts(%ld): s=%d, ACTIVE=%d\r\n",
- (long)desc->port, desc->s,ival));
+ (long)desc->port, desc->s, ival));
desc->active = ival;
+ if (desc->active == INET_MULTI) {
+ long ac = desc->active_count;
+ Sint16 nval = get_int16(ptr);
+ ptr += 2;
+ len -= 2;
+ ac += nval;
+ if (ac > INT16_MAX || ac < INT16_MIN)
+ return -1;
+ desc->active_count += nval;
+ if (desc->active_count < 0)
+ desc->active_count = 0;
+ if (desc->active_count == 0) {
+ desc->active = INET_PASSIVE;
+ packet_passive_message(desc);
+ }
+ } else
+ desc->active_count = 0;
if ((desc->stype == SOCK_STREAM) && (desc->active != INET_PASSIVE) &&
(desc->state == INET_STATE_CLOSED)) {
tcp_closed_message((tcp_descriptor *) desc);
@@ -5749,6 +6160,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
}
continue;
+#ifdef HAVE_UDP
case INET_LOPT_UDP_READ_PACKETS:
if (desc->stype == SOCK_DGRAM) {
udp_descriptor* udesc = (udp_descriptor*) desc;
@@ -5756,6 +6168,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
udesc->read_packets = ival;
}
continue;
+#endif
#ifdef HAVE_SETNS
case INET_LOPT_NETNS:
@@ -5964,7 +6377,8 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
/* XXX fprintf(stderr,"desc->htype == %d, old_htype == %d,
desc->active == %d, old_active == %d\r\n",(int)desc->htype,
(int) old_htype, (int) desc->active, (int) old_active );*/
- return 1+(desc->htype == old_htype && desc->active == INET_ONCE);
+ return 1+(desc->htype == old_htype &&
+ (desc->active == INET_ONCE || desc->active == INET_MULTI));
}
return 0;
}
@@ -6097,6 +6511,21 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
case INET_LOPT_ACTIVE:
desc->active = get_int32(curr); curr += 4;
+ if (desc->active == INET_MULTI) {
+ long ac = desc->active_count;
+ Sint16 nval = get_int16(curr); curr += 2;
+ ac += nval;
+ if (ac > INT16_MAX || ac < INT16_MIN)
+ return -1;
+ desc->active_count += nval;
+ if (desc->active_count < 0)
+ desc->active_count = 0;
+ if (desc->active_count == 0) {
+ desc->active = INET_PASSIVE;
+ packet_passive_message(desc);
+ }
+ } else
+ desc->active_count = 0;
res = 0;
continue;
@@ -6619,6 +7048,11 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
case INET_LOPT_ACTIVE:
*ptr++ = opt;
put_int32(desc->active, ptr);
+ if (desc->active == INET_MULTI) {
+ PLACE_FOR(2,ptr);
+ put_int16(desc->active_count, ptr);
+ ptr += 2;
+ }
continue;
case INET_LOPT_PACKET:
*ptr++ = opt;
@@ -6701,6 +7135,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
}
continue;
+#ifdef HAVE_UDP
case INET_LOPT_UDP_READ_PACKETS:
if (desc->stype == SOCK_DGRAM) {
*ptr++ = opt;
@@ -6710,6 +7145,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
TRUNCATE_TO(0,ptr);
}
continue;
+#endif
#ifdef HAVE_SETNS
case INET_LOPT_NETNS:
@@ -6991,7 +7427,10 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
}
case INET_LOPT_ACTIVE:
{
- PLACE_FOR(spec, i, 2*LOAD_ATOM_CNT + LOAD_TUPLE_CNT);
+ if (desc->active == INET_MULTI)
+ PLACE_FOR(spec, i, LOAD_ATOM_CNT + LOAD_INT_CNT + LOAD_TUPLE_CNT);
+ else
+ PLACE_FOR(spec, i, 2*LOAD_ATOM_CNT + LOAD_TUPLE_CNT);
i = LOAD_ATOM (spec, i, am_active);
switch (desc->active)
{
@@ -7004,6 +7443,9 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
case INET_ONCE :
{ i = LOAD_ATOM (spec, i, am_once); break; }
+ case INET_MULTI :
+ { i = LOAD_INT(spec, i, desc->active_count); break; }
+
default: ASSERT (0);
}
i = LOAD_TUPLE (spec, i, 2);
@@ -7800,6 +8242,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
socket */
desc->deliver = INET_DELIVER_TERM; /* standard term format */
desc->active = INET_PASSIVE; /* start passive */
+ desc->active_count = 0;
desc->oph = NULL;
desc->opt = NULL;
@@ -7833,6 +8276,15 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
#ifdef HAVE_SETNS
desc->netns = NULL;
#endif
+#ifdef __OSE__
+ desc->select_state = 0;
+ desc->events[0] = NULL;
+ desc->events[1] = NULL;
+ desc->events[2] = NULL;
+ desc->events[3] = NULL;
+ desc->events[4] = NULL;
+ desc->events[5] = NULL;
+#endif
return (ErlDrvData)desc;
}
@@ -8208,11 +8660,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (*buf == 1 && !desc->is_ignored) {
sock_select(desc, (FD_READ|FD_WRITE|FD_CLOSE|ERL_DRV_USE_NO_CALLBACK), 0);
- desc->is_ignored = INET_IGNORE_READ;
+ if (desc->active)
+ desc->is_ignored = INET_IGNORE_READ;
+ else
+ desc->is_ignored = INET_IGNORE_PASSIVE;
} else if (*buf == 0 && desc->is_ignored) {
- int flags = (FD_READ|FD_CLOSE|((desc->is_ignored & INET_IGNORE_WRITE)?FD_WRITE:0));
+ int flags = FD_CLOSE;
+ if (desc->is_ignored & INET_IGNORE_READ)
+ flags |= FD_READ;
+ if (desc->is_ignored & INET_IGNORE_WRITE)
+ flags |= FD_WRITE;
desc->is_ignored = INET_IGNORE_NONE;
- sock_select(desc, flags, 1);
+ if (flags != FD_CLOSE)
+ sock_select(desc, flags, 1);
} else
return ctl_error(EINVAL, rbuf, rsize);
@@ -8545,6 +9005,11 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
copy_desc->inet.port = port;
copy_desc->inet.dport = driver_mk_port(port);
+
+#ifdef __OSE__
+ inet_select_init(&copy_desc->inet);
+#endif
+
*err = 0;
return copy_desc;
}
@@ -8606,8 +9071,22 @@ static void tcp_inet_stop(ErlDrvData e)
inet_stop(INETP(desc));
}
+#ifdef __OSE__
-
+static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize) {
+
+ tcp_descriptor* desc = (tcp_descriptor*)e;
+ int prev_select_state = INETP(desc)->select_state;
+
+ ErlDrvSSizeT res = tcp_inet_ctl(e,cmd,buf,len,rbuf,rsize);
+
+ tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL);
+
+ return res;
+}
+#endif
/* TCP requests from Erlang */
static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
@@ -8823,7 +9302,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
ErlDrvTermData caller = driver_caller(desc->inet.port);
tcp_descriptor* accept_desc;
int err;
-
+
if ((accept_desc = tcp_inet_copy(desc,s,caller,&err)) == NULL) {
sock_close(s);
return ctl_error(err, rbuf, rsize);
@@ -8857,7 +9336,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
char tbuf[2];
int n;
- DEBUGF(("tcp_inet_ctl(%ld): RECV\r\n", (long)desc->inet.port));
+ DEBUGF(("tcp_inet_ctl(%ld): RECV (s=%d)\r\n",
+ (long)desc->inet.port, desc->inet.s));
/* INPUT: Timeout(4), Length(4) */
if (!IS_CONNECTED(INETP(desc))) {
if (desc->tcp_add_flags & TCP_ADDF_DELAYED_CLOSE_RECV) {
@@ -8889,6 +9369,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
driver_set_timer(desc->inet.port, timeout);
if (!INETP(desc)->is_ignored)
sock_select(INETP(desc),(FD_READ|FD_CLOSE),1);
+ else
+ INETP(desc)->is_ignored |= INET_IGNORE_READ;
}
}
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
@@ -9027,6 +9509,16 @@ static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len)
DEBUGF(("tcp_inet_command(%ld) }\r\n", (long)desc->inet.port));
}
+#ifdef __OSE__
+
+static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev) {
+ int prev_select_state = INETP((tcp_descriptor*)e)->select_state;
+ tcp_inet_commandv(e, ev);
+ tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL);
+}
+
+#endif
+
static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev)
{
@@ -9090,6 +9582,22 @@ static void inet_stop_select(ErlDrvEvent event, void* _)
{
#ifdef __WIN32__
WSACloseEvent((HANDLE)event);
+#elif defined(__OSE__)
+ ErlDrvOseEventId id;
+ union SIGNAL *sig;
+ erl_drv_ose_event_fetch(event, NULL, &id,NULL);
+ DEBUGF(("inet_stop_select(?#?) {s=%d\n",id));
+ sock_close((int)id);
+ /* On socket close all the signals waiting to be processed as part of the
+ select should be deallocated */
+ while((sig = erl_drv_ose_get_signal(event))) {
+ DEBUGF(("inet_stop_select(?#?): Freeing signal %s\n",
+ signo_to_string(sig->signo)));
+ free_buf(&sig);
+ }
+ erl_drv_ose_event_free(event);
+ DEBUGF(("inet_stop_select(?#?) }\n"));
+
#else
sock_close((SOCKET)(long)event);
#endif
@@ -9209,12 +9717,13 @@ static int tcp_remain(tcp_descriptor* desc, int* len)
int n = desc->i_ptr - ptr; /* number of bytes read */
int tlen;
- DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d\r\n",
- (long)desc->inet.port, desc->inet.s, n, nfill, nsz));
-
tlen = packet_get_length(desc->inet.htype, ptr, n,
desc->inet.psize, desc->i_bufsz,
&desc->http_state);
+
+ DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n",
+ (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen));
+
if (tlen > 0) {
if (tlen <= n) { /* got a packet */
*len = tlen;
@@ -9622,7 +10131,146 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event)
return;
}
-#endif /* WIN32 */
+#elif defined(__OSE__) /* !__WIN32__ */
+/* The specific resolve signal function. It will return the socket descriptor
+ for which the select was issued */
+static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig) {
+ DEBUGF(("%s(?#?): s=%d got signal %s, status = %d, extra = %d, sender = 0x%x\n",
+ __FUNCTION__,sig->async.fd,signo_to_string(sig->signo),
+ sig->async.event.status,
+ sig->async.event.extra,sender(&sig)));
+ if (sig->signo == SO_EVENT_READ_REPLY ||
+ sig->signo == SO_EVENT_ACCEPT_REPLY ||
+ sig->signo == SO_EVENT_EOF_REPLY ||
+ sig->signo == SO_EVENT_WRITE_REPLY ||
+ sig->signo == SO_EVENT_ERROR_REPLY ||
+ sig->signo == SO_EVENT_CONNECT_REPLY ) {
+ return sig->async.fd;
+ }
+
+ return -1;
+}
+
+static void inet_driver_select(inet_descriptor* desc,
+ int flags, int onoff) {
+ ASSERT(!desc->is_ignored);
+
+ if(onoff) {
+ desc->select_state |= flags;
+ } else {
+ desc->select_state &= ~flags;
+ }
+}
+
+static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz)
+{
+ size_t data_len = 0;
+ size_t sent = 0;
+ ssize_t n;
+ int i;
+
+ for(i = 0; i < iovcnt; i++)
+ {
+ data_len = iov[i].iov_len;
+tryagain:
+ n = sock_send(fd, iov[i].iov_base, data_len, 0);
+ if (IS_SOCKET_ERROR(n)) {
+ /* If buffer length is greater than the amount stack is able to
+ * send out then try to send at least max_sz (this comes with
+ * SO_EVENT_WRITE_REPLY signal*/
+ if ((errno == EMSGSIZE) && (max_sz > 0) && (data_len > max_sz)) {
+ data_len = max_sz;
+ goto tryagain;
+ }
+ break;
+ }
+ sent += n;
+ }
+ return sent;
+}
+
+#define OSE_EVENT_REQ(TCP_DESC,EVENT) do { \
+ union SIGNAL *sig = alloc(sizeof(struct OseAsyncSig), EVENT); \
+ sig->async.fd = INETP(TCP_DESC)->s; \
+ ose_request_event(INETP(TCP_DESC)->s, &sig, 1); \
+ DEBUGF(("%s(%ld): s=%d sent %s\r\n",__FUNCTION__, \
+ INETP(TCP_DESC)->port,INETP(TCP_DESC)->s,signo_to_string(EVENT))); \
+ } while(0)
+
+static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc,
+ int prev_select_state,
+ union SIGNAL *sig) {
+ if (sig) {
+ DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d resend\r\n",
+ (long)INETP(desc)->port,INETP(desc)->s));
+ /* We are reacting to a signal, which means that if
+ the select_state for that signal is still activated
+ we should send a new signal */
+ switch (sig->signo) {
+ case SO_EVENT_READ_REPLY: {
+ if (INETP(desc)->select_state & FD_READ)
+ OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST);
+ break;
+ }
+ case SO_EVENT_WRITE_REPLY: {
+ if (INETP(desc)->select_state & FD_WRITE)
+ OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST);
+ break;
+ }
+ case SO_EVENT_CONNECT_REPLY: {
+ if (INETP(desc)->select_state & FD_CONNECT)
+ OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST);
+ break;
+ }
+ case SO_EVENT_ACCEPT_REPLY: {
+ if (INETP(desc)->select_state & FD_ACCEPT)
+ OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST);
+ break;
+ }
+ case SO_EVENT_ERROR_REPLY: {
+ if (INETP(desc)->select_state & SOCK_FD_ERROR)
+ OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST);
+ break;
+ }
+
+ }
+ DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n",
+ (long)INETP(desc)->port));
+ }
+
+ if (INETP(desc)->select_state != prev_select_state) {
+ /* If the select state has changed we have to issue signals for
+ the state parts that have changed. */
+ int xor_select_state = INETP(desc)->select_state ^ prev_select_state;
+ DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d select change\r\n",
+ (long)INETP(desc)->port,INETP(desc)->s));
+ if ((xor_select_state & FD_READ) &&
+ (INETP(desc)->select_state & FD_READ)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST);
+ }
+ if ((xor_select_state & FD_WRITE) &&
+ (INETP(desc)->select_state & FD_WRITE)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST);
+ }
+ if ((xor_select_state & FD_CONNECT) &&
+ (INETP(desc)->select_state & FD_CONNECT)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST);
+ }
+ if ((xor_select_state & FD_ACCEPT) &&
+ (INETP(desc)->select_state & FD_ACCEPT)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST);
+ }
+ if ((xor_select_state & SOCK_FD_ERROR) &&
+ (INETP(desc)->select_state & SOCK_FD_ERROR)) {
+ OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST);
+ }
+
+ DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n",
+ (long)INETP(desc)->port));
+ }
+}
+
+#endif /* __OSE__ */
/* socket has input:
@@ -9643,7 +10291,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
unsigned int len;
inet_address remote;
inet_async_op *this_op = desc->inet.opt;
-
+
len = sizeof(desc->inet.remote);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
@@ -9712,7 +10360,6 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
len = sizeof(desc->inet.remote);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
-
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
/* Just try again, no real error, keep the last return code */
goto done;
@@ -10038,6 +10685,49 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len)
return 0;
}
+#ifdef __OSE__
+
+static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event)
+{
+ union SIGNAL *event_sig = erl_drv_ose_get_signal(event);
+
+ while (event_sig) {
+ int prev_select_state = INETP((tcp_descriptor*)data)->select_state;
+ int res = tcp_inet_output((tcp_descriptor*)data, (HANDLE)event_sig);
+ if (res != -1) {
+ tcp_inet_ose_dispatch_signals((tcp_descriptor*)data,
+ prev_select_state,event_sig);
+ free_buf(&event_sig);
+ event_sig = erl_drv_ose_get_signal(event);
+ } else {
+ /* NOTE: here the event object could have been deallocated!!!!
+ inet_stop_select is called when doing driver_select(ERL_DRV_USE,0)
+ */
+ free_buf(&event_sig);
+ return;
+ }
+ }
+}
+
+static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event)
+{
+ union SIGNAL *event_sig = erl_drv_ose_get_signal(event);
+
+ while (event_sig) {
+ int prev_select_state = INETP((tcp_descriptor*)data)->select_state;
+ int res = tcp_inet_input((tcp_descriptor*)data, (HANDLE)event);
+ if (res != -1) {
+ tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, prev_select_state,
+ event_sig);
+ free_buf(&event_sig);
+ event_sig = erl_drv_ose_get_signal(event);
+ } else {
+ free_buf(&event_sig);
+ return;
+ }
+ }
+}
+#else
static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event)
{
(void)tcp_inet_output((tcp_descriptor*)data, (HANDLE)event);
@@ -10047,6 +10737,7 @@ static void tcp_inet_drv_input(ErlDrvData data, ErlDrvEvent event)
{
(void)tcp_inet_input((tcp_descriptor*)data, (HANDLE)event);
}
+#endif
/* socket ready for ouput:
** 1. INET_STATE_CONNECTING => non block connect ?
@@ -10112,6 +10803,13 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
ssize_t n;
SysIOVec* iov;
+#ifdef __OSE__
+ /* For large size buffers case the amount of data that the stack is
+ able to send out (received in the .extra field) should be passed
+ down to writev_fallback */
+ n = event ? ((union SIGNAL*)event)->async.event.extra : 0;
+#endif
+
if ((iov = driver_peekq(ix, &vsize)) == NULL) {
sock_select(INETP(desc), FD_WRITE, 0);
send_empty_out_q_msgs(INETP(desc));
@@ -10123,8 +10821,8 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s, iov, vsize, &n, 0))) {
write_error:
if ((sock_errno() != ERRNO_BLOCK) && (sock_errno() != EINTR)) {
- DEBUGF(("tcp_inet_output(%ld): sock_sendv(%d) errno = %d\r\n",
- (long)desc->inet.port, vsize, sock_errno()));
+ DEBUGF(("tcp_inet_output(%ld): sock_sendv(%d) errno = %d (errno %d)\r\n",
+ (long)desc->inet.port, vsize, sock_errno(), errno));
ret = tcp_send_error(desc, sock_errno());
goto done;
}
@@ -10137,6 +10835,12 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
sizes > (max 32 bit signed int) */
size_t howmuch = 0x7FFFFFFF; /* max signed 32 bit */
int x;
+#ifdef __OSE__
+ /* For EWOULDBLOCK sock_sendv returns 0 so we have to be sure it
+ wasn't the case */
+ if(sock_errno() == ERRNO_BLOCK)
+ goto done;
+#endif
for(x = 0; x < vsize && iov[x].iov_len == 0; ++x)
;
if (x < vsize) {
@@ -10281,6 +10985,7 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err)
+#ifdef HAVE_UDP
static int packet_inet_init()
{
return 0;
@@ -10311,6 +11016,7 @@ static ErlDrvData udp_inet_start(ErlDrvPort port, char *args)
set_default_msgq_limits(port);
return data;
}
+#endif
#ifdef HAVE_SCTP
static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args)
@@ -10321,6 +11027,7 @@ static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args)
}
#endif
+#ifdef HAVE_UDP
static void packet_inet_stop(ErlDrvData e)
{
/* There should *never* be any "empty out q" subscribers on
@@ -10831,7 +11538,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
else
inet_reply_ok(desc);
}
-
+#endif
#ifdef __WIN32__
static void packet_inet_event(ErlDrvData e, ErlDrvEvent event)
@@ -10853,6 +11560,7 @@ static void packet_inet_event(ErlDrvData e, ErlDrvEvent event)
#endif
+#ifdef HAVE_UDP
static void packet_inet_drv_input(ErlDrvData e, ErlDrvEvent event)
{
(void) packet_inet_input((udp_descriptor*)e, (HANDLE)event);
@@ -11109,6 +11817,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
DEBUGF(("packet_inet_output(%ld) }\r\n", (long)desc->port));
return ret;
}
+#endif
/*---------------------------------------------------------------------------*/
diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c
index 3fe5d282dc..3143e4511d 100644
--- a/erts/emulator/drivers/common/zlib_drv.c
+++ b/erts/emulator/drivers/common/zlib_drv.c
@@ -21,6 +21,9 @@
* ZLib interface for erlang
*
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include <stdio.h>
#include <zlib.h>
#include <errno.h>
diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c
new file mode 100644
index 0000000000..035ff81a9b
--- /dev/null
+++ b/erts/emulator/drivers/ose/ose_efile.c
@@ -0,0 +1,1124 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1997-2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Purpose: Provides file and directory operations for OSE.
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if defined(HAVE_POSIX_FALLOCATE) && !defined(__sun) && !defined(__sun__)
+#define _XOPEN_SOURCE 600
+#endif
+#if !defined(_GNU_SOURCE) && defined(HAVE_LINUX_FALLOC_H)
+#define _GNU_SOURCE
+#endif
+#include "sys.h"
+#include "erl_driver.h"
+#include "erl_efile.h"
+#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE)
+#include "fcntl.h"
+#endif
+#include "ose.h"
+#include "unistd.h"
+#include "sys/stat.h"
+#include "dirent.h"
+#include "sys/time.h"
+#include "time.h"
+#include "assert.h"
+
+/* Find a definition of MAXIOV, that is used in the code later. */
+#if defined IOV_MAX
+#define MAXIOV IOV_MAX
+#elif defined UIO_MAXIOV
+#define MAXIOV UIO_MAXIOV
+#else
+#define MAXIOV 16
+#endif
+
+/*
+ * Macros for testing file types.
+ */
+
+#define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR)
+#define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG)
+#define ISDEV(st) \
+ (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
+#define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK)
+#ifdef NO_UMASK
+#define FILE_MODE 0644
+#define DIR_MODE 0755
+#else
+#define FILE_MODE 0666
+#define DIR_MODE 0777
+#endif
+
+#define IS_DOT_OR_DOTDOT(s) \
+ (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')))
+
+/*
+ * Macros for handling local file descriptors
+ * and mutexes.
+ *
+ * Handling of files like this is necessary because OSE
+ * does not allow seeking after the end of a file. So
+ * what we do it emulate this by keeping track of the size
+ * of the file and where the file's positions is. If a
+ * write happens after eof then we pad it.
+ *
+ * Given time this should be rewritten to get rid of the
+ * mutex and use the port lock to protect the data. This
+ * could be done be done by adapting the efile api for some
+ * calls to allow some meta-data to be associated with the
+ * open file.
+ */
+
+#define L_FD_IS_VALID(fd_data) ((fd_data)->beyond_eof > 0)
+#define L_FD_INVALIDATE(fd_data) (fd_data)->beyond_eof = 0
+#define L_FD_CUR(fd_data) (fd_data)->pos
+#define L_FD_OFFS_BEYOND_EOF(fd_data, offs) \
+ (((fd_data)->size > offs) ? 0 : 1)
+
+#define L_FD_FAIL -1
+#define L_FD_SUCCESS 1
+#define L_FD_PAD_SIZE 255
+
+struct fd_meta {
+ ErlDrvMutex *meta_mtx;
+ struct fd_data *fd_data_list;
+};
+
+struct fd_data {
+ int fd;
+ struct fd_data *next;
+ struct fd_data *prev;
+ int pos;
+ int beyond_eof;
+ size_t size;
+#ifdef DEBUG
+ PROCESS owner;
+#endif
+};
+
+static int l_invalidate_local_fd(int fd);
+static int l_pad_file(struct fd_data *fd_data, off_t offset);
+static int check_error(int result, Efile_error* errInfo);
+static struct fd_data* l_new_fd(void);
+static int l_remove_local_fd(int fd);
+static struct fd_data* l_find_local_fd(int fd);
+static int l_update_local_fd(int fd, int pos, int size);
+
+static struct fd_meta* fdm = NULL;
+
+
+/***************************************************************************/
+
+static int
+l_remove_local_fd(int fd)
+{
+ struct fd_data *fd_data;
+ fd_data = l_find_local_fd(fd);
+
+ if (fd_data == NULL) {
+ return L_FD_FAIL;
+ }
+#ifdef DEBUG
+ assert(fd_data->owner == current_process());
+#endif
+ erl_drv_mutex_lock(fdm->meta_mtx);
+ /* head ? */
+ if (fd_data == fdm->fd_data_list) {
+ if (fd_data->next != NULL) {
+ /* remove link to head */
+ fd_data->next->prev = NULL;
+ /* set new head */
+ fdm->fd_data_list = fd_data->next;
+ }
+ else {
+ /* head is lonely */
+ fdm->fd_data_list = NULL;
+ }
+ }
+ else { /* not head */
+ if (fd_data->prev == NULL) {
+ erl_drv_mutex_unlock(fdm->meta_mtx);
+ return L_FD_FAIL;
+ }
+ else {
+ if (fd_data->next != NULL) {
+ fd_data->next->prev = fd_data->prev;
+ fd_data->prev->next = fd_data->next;
+ }
+ else {
+ fd_data->prev->next = NULL;
+ }
+ }
+ }
+
+ /* scramble values */
+ fd_data->beyond_eof = -1;
+ fd_data->next = NULL;
+ fd_data->prev = NULL;
+ fd_data->fd = -1;
+
+ /* unlock and clean */
+ driver_free(fd_data);
+ erl_drv_mutex_unlock(fdm->meta_mtx);
+
+ return L_FD_SUCCESS;
+}
+
+/***************************************************************************/
+
+static int
+l_invalidate_local_fd(int fd) {
+ struct fd_data *fd_data;
+
+ if ((fd_data = l_find_local_fd(fd)) == NULL) {
+ return L_FD_FAIL;
+ }
+
+ fd_data->beyond_eof = 0;
+ return L_FD_SUCCESS;
+}
+
+/****************************************************************************/
+
+static struct fd_data*
+l_find_local_fd(int fd) {
+ struct fd_data *fd_data;
+
+ fd_data = NULL;
+ erl_drv_mutex_lock(fdm->meta_mtx);
+ for (fd_data = fdm->fd_data_list; fd_data != NULL; ) {
+ if (fd_data->fd == fd) {
+#ifdef DEBUG
+ assert(fd_data->owner == current_process());
+#endif
+ break;
+ }
+ fd_data = fd_data->next;
+ }
+ erl_drv_mutex_unlock(fdm->meta_mtx);
+ return fd_data;
+}
+
+/***************************************************************************/
+
+static struct fd_data*
+l_new_fd(void) {
+ struct fd_data *fd_data;
+
+ fd_data = driver_alloc(sizeof(struct fd_data));
+ if (fd_data == NULL) {
+ return NULL;
+ }
+ erl_drv_mutex_lock(fdm->meta_mtx);
+ if (fdm->fd_data_list == NULL) {
+ fdm->fd_data_list = fd_data;
+ fdm->fd_data_list->prev = NULL;
+ fdm->fd_data_list->next = NULL;
+ }
+ else {
+ fd_data->next = fdm->fd_data_list;
+ fdm->fd_data_list = fd_data;
+ fdm->fd_data_list->prev = NULL;
+ }
+#ifdef DEBUG
+ fd_data->owner = current_process();
+#endif
+ erl_drv_mutex_unlock(fdm->meta_mtx);
+ return fd_data;
+}
+
+/***************************************************************************/
+
+static int
+l_update_local_fd(int fd, int pos, int size) {
+ struct fd_data *fd_data = NULL;
+
+ fd_data = l_find_local_fd(fd);
+ /* new fd to handle? */
+ if (fd_data == NULL) {
+ fd_data = l_new_fd();
+ if (fd_data == NULL) {
+ /* out of memory */
+ return L_FD_FAIL;
+ }
+ }
+ fd_data->size = size;
+ fd_data->pos = pos;
+ fd_data->fd = fd;
+ fd_data->beyond_eof = 1;
+
+ return L_FD_SUCCESS;
+}
+
+/***************************************************************************/
+
+static int
+l_pad_file(struct fd_data *fd_data, off_t offset) {
+ int size_dif;
+ int written = 0;
+ int ret_val = L_FD_SUCCESS;
+ char padding[L_FD_PAD_SIZE];
+
+ size_dif = (offset - fd_data->size);
+ memset(&padding, '\0', L_FD_PAD_SIZE);
+
+ while (size_dif > 0) {
+ written = write(fd_data->fd, padding,
+ (size_dif < L_FD_PAD_SIZE) ?
+ size_dif : L_FD_PAD_SIZE);
+ if (written < 0 && errno != EINTR && errno != EAGAIN) {
+ ret_val = -1;
+ break;
+ }
+ size_dif -= written;
+ }
+ L_FD_INVALIDATE(fd_data);
+ return ret_val;
+}
+
+/***************************************************************************/
+
+static int
+check_error(int result, Efile_error *errInfo) {
+ if (result < 0) {
+ errInfo->posix_errno = errInfo->os_errno = errno;
+ return 0;
+ }
+ return 1;
+}
+
+/***************************************************************************/
+
+int
+efile_init() {
+ fdm = driver_alloc(sizeof(struct fd_meta));
+ if (fdm == NULL) {
+ return L_FD_FAIL;
+ }
+ fdm->meta_mtx = erl_drv_mutex_create("ose_efile local fd mutex\n");
+ erl_drv_mutex_lock(fdm->meta_mtx);
+ fdm->fd_data_list = NULL;
+ erl_drv_mutex_unlock(fdm->meta_mtx);
+ return L_FD_SUCCESS;
+}
+
+/***************************************************************************/
+
+int
+efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */
+ char* name) /* Name of directory to create. */
+{
+#ifdef NO_MKDIR_MODE
+ return check_error(mkdir(name), errInfo);
+#else
+ int res = mkdir(name, DIR_MODE);
+ if (res < 0 && errno == EINVAL) {
+ errno = ENOENT;
+ }
+ return check_error(res, errInfo);
+#endif
+}
+
+/***************************************************************************/
+
+int
+efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */
+ char* name) /* Name of directory to delete. */
+{
+ if (rmdir(name) == 0) {
+ return 1;
+ }
+ if (errno == ENOTEMPTY) {
+ errno = EEXIST;
+ }
+ if (errno == EEXIST || errno == EINVAL) {
+ int saved_errno = errno;
+ struct stat file_stat;
+ struct stat cwd_stat;
+
+ if(stat(name, &file_stat) != 0) {
+ errno = ENOENT;
+ return check_error(-1, errInfo);
+ }
+ /*
+ * The error code might be wrong if this is the current directory.
+ */
+ if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 &&
+ file_stat.st_ino == cwd_stat.st_ino &&
+ file_stat.st_dev == cwd_stat.st_dev) {
+ saved_errno = EACCES;
+ }
+ errno = saved_errno;
+ }
+ return check_error(-1, errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */
+ char* name) /* Name of file to delete. */
+{
+ struct stat statbuf;
+
+ if (stat(name, &statbuf) >= 0) {
+ /* Do not let unlink() remove directories */
+ if (ISDIR(statbuf)) {
+ errno = EPERM;
+ return check_error(-1, errInfo);
+ }
+
+ if (unlink(name) == 0) {
+ return 1;
+ }
+
+ if (errno == EISDIR) {
+ errno = EPERM;
+ return check_error(-1, errInfo);
+ }
+ }
+ else {
+ if (errno == EINVAL) {
+ errno = ENOENT;
+ return check_error(-1, errInfo);
+ }
+ }
+ return check_error(-1, errInfo);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Changes the name of an existing file or directory, from src to dst.
+ * If src and dst refer to the same file or directory, does nothing
+ * and returns success. Otherwise if dst already exists, it will be
+ * deleted and replaced by src subject to the following conditions:
+ * If src is a directory, dst may be an empty directory.
+ * If src is a file, dst may be a file.
+ * In any other situation where dst already exists, the rename will
+ * fail.
+ *
+ * Results:
+ * If the directory was successfully created, returns 1.
+ * Otherwise the return value is 0 and errno is set to
+ * indicate the error. Some possible values for errno are:
+ *
+ * EACCES: src or dst parent directory can't be read and/or written.
+ * EEXIST: dst is a non-empty directory.
+ * EINVAL: src is a root directory or dst is a subdirectory of src.
+ * EISDIR: dst is a directory, but src is not.
+ * ENOENT: src doesn't exist, or src or dst is "".
+ * ENOTDIR: src is a directory, but dst is not.
+ * EXDEV: src and dst are on different filesystems.
+ *
+ * Side effects:
+ * The implementation of rename may allow cross-filesystem renames,
+ * but the caller should be prepared to emulate it with copy and
+ * delete if errno is EXDEV.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+efile_rename(Efile_error* errInfo, /* Where to return error codes. */
+ char* src, /* Original name. */
+ char* dst) /* New name. */
+{
+
+ /* temporary fix AFM does not recognize ./<file name>
+ * in destination remove pending on adaption of AFM fix
+ */
+
+ char *dot_str;
+ if (dst != NULL) {
+ dot_str = strchr(dst, '.');
+ if (dot_str && dot_str == dst && dot_str[1] == '/') {
+ dst = dst+2;
+ }
+ }
+
+ if (rename(src, dst) == 0) {
+ return 1;
+ }
+ if (errno == ENOTEMPTY) {
+ errno = EEXIST;
+ }
+ if (errno == EINVAL) {
+ struct stat file_stat;
+
+ if (stat(dst, &file_stat)== 0) {
+ if (ISDIR(file_stat)) {
+ errno = EISDIR;
+ }
+ else if (ISREG(file_stat)) {
+ errno = ENOTDIR;
+ }
+ else {
+ errno = EINVAL;
+ }
+ }
+ else {
+ errno = EINVAL;
+ }
+ }
+
+ if (strcmp(src, "/") == 0) {
+ errno = EINVAL;
+ }
+ return check_error(-1, errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_chdir(Efile_error* errInfo, /* Where to return error codes. */
+ char* name) /* Name of directory to make current. */
+{
+ return check_error(chdir(name), errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */
+ int drive, /* 0 - current, 1 - A, 2 - B etc. */
+ char* buffer, /* Where to return the current
+ directory. */
+ size_t size) /* Size of buffer. */
+{
+ if (drive == 0) {
+ if (getcwd(buffer, size) == NULL)
+ return check_error(-1, errInfo);
+
+ return 1;
+ }
+
+ /*
+ * Drives other than 0 is not supported on Unix.
+ */
+
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_readdir(Efile_error* errInfo, /* Where to return error codes. */
+ char* name, /* Name of directory to open. */
+ EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory
+ handle of
+ open directory.*/
+ char* buffer, /* Pointer to buffer for
+ one filename. */
+ size_t *size) /* in-out Size of buffer, length
+ of name. */
+{
+ DIR *dp; /* Pointer to directory structure. */
+ struct dirent* dirp; /* Pointer to directory entry. */
+
+ /*
+ * If this is the first call, we must open the directory.
+ */
+
+ if (*p_dir_handle == NULL) {
+ dp = opendir(name);
+ if (dp == NULL)
+ return check_error(-1, errInfo);
+ *p_dir_handle = (EFILE_DIR_HANDLE) dp;
+ }
+
+ /*
+ * Retrieve the name of the next file using the directory handle.
+ */
+
+ dp = *((DIR **)((void *)p_dir_handle));
+ for (;;) {
+ dirp = readdir(dp);
+ if (dirp == NULL) {
+ closedir(dp);
+ return 0;
+ }
+ if (IS_DOT_OR_DOTDOT(dirp->d_name))
+ continue;
+ buffer[0] = '\0';
+ strncat(buffer, dirp->d_name, (*size)-1);
+ *size = strlen(dirp->d_name);
+ return 1;
+ }
+}
+
+/***************************************************************************/
+
+int
+efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
+ char* name, /* Name of directory to open. */
+ int flags, /* Flags to user for opening. */
+ int* pfd, /* Where to store the file
+ descriptor. */
+ Sint64 *pSize) /* Where to store the size of the
+ file. */
+{
+ struct stat statbuf;
+ int fd;
+ int mode; /* Open mode. */
+
+ if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) {
+ errno = EISDIR;
+ return check_error(-1, errInfo);
+ }
+
+ switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) {
+ case EFILE_MODE_READ:
+ mode = O_RDONLY;
+ break;
+ case EFILE_MODE_WRITE:
+ if (flags & EFILE_NO_TRUNCATE)
+ mode = O_WRONLY | O_CREAT;
+ else
+ mode = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case EFILE_MODE_READ_WRITE:
+ mode = O_RDWR | O_CREAT;
+ break;
+ default:
+ errno = EINVAL;
+ return check_error(-1, errInfo);
+ }
+
+
+ if (flags & EFILE_MODE_APPEND) {
+ mode &= ~O_TRUNC;
+ mode |= O_APPEND;
+ }
+
+ if (flags & EFILE_MODE_EXCL) {
+ mode |= O_EXCL;
+ }
+
+ fd = open(name, mode, FILE_MODE);
+
+ if (!check_error(fd, errInfo))
+ return 0;
+
+ *pfd = fd;
+ if (pSize) {
+ *pSize = statbuf.st_size;
+ }
+ return 1;
+}
+
+/***************************************************************************/
+
+int
+efile_may_openfile(Efile_error* errInfo, char *name) {
+ struct stat statbuf; /* Information about the file */
+ int result;
+
+ result = stat(name, &statbuf);
+ if (!check_error(result, errInfo))
+ return 0;
+ if (!ISREG(statbuf)) {
+ errno = EISDIR;
+ return check_error(-1, errInfo);
+ }
+ return 1;
+}
+
+/***************************************************************************/
+
+void
+efile_closefile(int fd)
+{
+ if (l_find_local_fd(fd) != NULL) {
+ l_remove_local_fd(fd);
+ }
+ close(fd);
+}
+
+/***************************************************************************/
+
+int
+efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */
+ int fd) /* File descriptor for file to sync data. */
+{
+ return efile_fsync(errInfo, fd);
+}
+
+/***************************************************************************/
+
+int
+efile_fsync(Efile_error *errInfo, /* Where to return error codes. */
+ int fd) /* File descriptor for file to sync. */
+{
+ return check_error(fsync(fd), errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
+ char* name, int info_for_link)
+{
+ struct stat statbuf; /* Information about the file */
+ int result;
+
+ result = stat(name, &statbuf);
+ if (!check_error(result, errInfo)) {
+ return 0;
+ }
+
+#if SIZEOF_OFF_T == 4
+ pInfo->size_high = 0;
+#else
+ pInfo->size_high = (Uint32)(statbuf.st_size >> 32);
+#endif
+ pInfo->size_low = (Uint32)statbuf.st_size;
+
+#ifdef NO_ACCESS
+ /* Just look at read/write access for owner. */
+
+ pInfo->access = ((statbuf.st_mode >> 6) & 07) >> 1;
+
+#else
+ pInfo->access = FA_NONE;
+ if (access(name, R_OK) == 0)
+ pInfo->access |= FA_READ;
+ if (access(name, W_OK) == 0)
+ pInfo->access |= FA_WRITE;
+
+#endif
+
+ if (ISDEV(statbuf))
+ pInfo->type = FT_DEVICE;
+ else if (ISDIR(statbuf))
+ pInfo->type = FT_DIRECTORY;
+ else if (ISREG(statbuf))
+ pInfo->type = FT_REGULAR;
+ else if (ISLNK(statbuf))
+ pInfo->type = FT_SYMLINK;
+ else
+ pInfo->type = FT_OTHER;
+
+ pInfo->accessTime = statbuf.st_atime;
+ pInfo->modifyTime = statbuf.st_mtime;
+ pInfo->cTime = statbuf.st_ctime;
+
+ pInfo->mode = statbuf.st_mode;
+ pInfo->links = statbuf.st_nlink;
+ pInfo->major_device = statbuf.st_dev;
+ pInfo->inode = statbuf.st_ino;
+ pInfo->uid = statbuf.st_uid;
+ pInfo->gid = statbuf.st_gid;
+
+ return 1;
+}
+
+/***************************************************************************/
+
+int
+efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name)
+{
+ /*
+ * On some systems chown will always fail for a non-root user unless
+ * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as
+ * you don't try to chown a file to someone besides youself.
+ */
+ if (pInfo->mode != -1) {
+ mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID |
+ S_IRWXU | S_IRWXG | S_IRWXO);
+ if (chmod(name, newMode)) {
+ newMode &= ~(S_ISUID | S_ISGID);
+ if (chmod(name, newMode)) {
+ return check_error(-1, errInfo);
+ }
+ }
+ }
+
+ return 1;
+}
+
+/***************************************************************************/
+
+int
+efile_write(Efile_error* errInfo, /* Where to return error codes. */
+ int flags, /* Flags given when file was
+ opened. */
+ int fd, /* File descriptor to write to. */
+ char* buf, /* Buffer to write. */
+ size_t count) /* Number of bytes to write. */
+{
+ ssize_t written; /* Bytes written in last operation. */
+ struct fd_data *fd_data;
+
+ if ((fd_data = l_find_local_fd(fd)) != NULL) {
+ if (L_FD_IS_VALID(fd_data)) {
+ /* we are beyond eof and need to pad*/
+ if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) {
+ return check_error(-1, errInfo);
+ }
+ }
+ }
+
+ while (count > 0) {
+ if ((written = write(fd, buf, count)) < 0) {
+ if (errno != EINTR) {
+ return check_error(-1, errInfo);
+ }
+ else {
+ written = 0;
+ }
+ }
+ ASSERT(written <= count);
+ buf += written;
+ count -= written;
+ }
+ return 1;
+}
+
+/***************************************************************************/
+
+int
+efile_writev(Efile_error* errInfo, /* Where to return error codes */
+ int flags, /* Flags given when file was
+ * opened */
+ int fd, /* File descriptor to write to */
+ SysIOVec* iov, /* Vector of buffer structs.
+ * The structs may be changed i.e.
+ * due to incomplete writes */
+ int iovcnt) /* Number of structs in vector */
+{
+ struct fd_data *fd_data;
+ int cnt = 0; /* Buffers so far written */
+
+ ASSERT(iovcnt >= 0);
+ if ((fd_data = l_find_local_fd(fd)) != NULL) {
+ if (L_FD_IS_VALID(fd_data)) {
+ /* we are beyond eof and need to pad*/
+ if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) {
+ return check_error(-1, errInfo);
+ }
+ }
+ }
+ while (cnt < iovcnt) {
+ if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) {
+ /* Empty buffer - skip */
+ cnt++;
+ }
+ else { /* Non-empty buffer */
+ ssize_t w; /* Bytes written in this call */
+ do {
+ w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len);
+ } while (w < 0 && errno == EINTR);
+
+ ASSERT(w <= iov[cnt].iov_len || w == -1);
+
+ if (w < 0) {
+ return check_error(-1, errInfo);
+ }
+ /* Move forward to next buffer to write */
+ for (; cnt < iovcnt && w > 0; cnt++) {
+ if (iov[cnt].iov_base && iov[cnt].iov_len > 0) {
+ if (w < iov[cnt].iov_len) {
+ /* Adjust the buffer for next write */
+ iov[cnt].iov_len -= w;
+ iov[cnt].iov_base += w;
+ w = 0;
+ break;
+ }
+ else {
+ w -= iov[cnt].iov_len;
+ }
+ }
+ }
+ ASSERT(w == 0);
+ } /* else Non-empty buffer */
+ } /* while (cnt< iovcnt) */
+ return 1;
+}
+
+/***************************************************************************/
+
+int
+efile_read(Efile_error* errInfo, /* Where to return error codes. */
+ int flags, /* Flags given when file was opened. */
+ int fd, /* File descriptor to read from. */
+ char* buf, /* Buffer to read into. */
+ size_t count, /* Number of bytes to read. */
+ size_t *pBytesRead) /* Where to return number of
+ bytes read. */
+{
+ ssize_t n;
+ struct fd_data *fd_data;
+
+ if ((fd_data = l_find_local_fd(fd)) != NULL) {
+ if (L_FD_IS_VALID(fd_data)) {
+ *pBytesRead = 0;
+ return 1;
+ }
+ }
+ for (;;) {
+ if ((n = read(fd, buf, count)) >= 0) {
+ break;
+ }
+ else if (errno != EINTR) {
+ return check_error(-1, errInfo);
+ }
+ }
+ if (fd_data != NULL && L_FD_IS_VALID(fd_data)) {
+ L_FD_INVALIDATE(fd_data);
+ }
+ *pBytesRead = (size_t) n;
+ return 1;
+}
+
+/* pread() and pwrite() */
+/* Some unix systems, notably Solaris has these syscalls */
+/* It is especially nice for i.e. the dets module to have support */
+/* for this, even if the underlying OS dosn't support it, it is */
+/* reasonably easy to work around by first calling seek, and then */
+/* calling read(). */
+/* This later strategy however changes the file pointer, which pread() */
+/* does not do. We choose to ignore this and say that the location */
+/* of the file pointer is undefined after a call to any of the p functions*/
+
+
+int
+efile_pread(Efile_error* errInfo, /* Where to return error codes. */
+ int fd, /* File descriptor to read from. */
+ Sint64 offset, /* Offset in bytes from BOF. */
+ char* buf, /* Buffer to read into. */
+ size_t count, /* Number of bytes to read. */
+ size_t *pBytesRead) /* Where to return
+ number of bytes read. */
+{
+ int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL);
+ if (res) {
+ return efile_read(errInfo, 0, fd, buf, count, pBytesRead);
+ } else {
+ return res;
+ }
+}
+
+
+/***************************************************************************/
+
+int
+efile_pwrite(Efile_error* errInfo, /* Where to return error codes. */
+ int fd, /* File descriptor to write to. */
+ char* buf, /* Buffer to write. */
+ size_t count, /* Number of bytes to write. */
+ Sint64 offset) /* where to write it */
+{
+ int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL);
+
+ if (res) {
+ return efile_write(errInfo, 0, fd, buf, count);
+ } else {
+ return res;
+ }
+}
+
+/***************************************************************************/
+
+int
+efile_seek(Efile_error* errInfo, /* Where to return error codes. */
+ int fd, /* File descriptor to do the seek on. */
+ Sint64 offset, /* Offset in bytes from the given
+ origin. */
+ int origin, /* Origin of seek (SEEK_SET, SEEK_CUR,
+ SEEK_END). */
+ Sint64 *new_location) /* Resulting new location in file. */
+{
+ off_t off, result;
+ off = (off_t) offset;
+
+ switch (origin) {
+ case EFILE_SEEK_SET:
+ origin = SEEK_SET;
+ break;
+ case EFILE_SEEK_CUR:
+ origin = SEEK_CUR;
+ break;
+ case EFILE_SEEK_END:
+ origin = SEEK_END;
+ break;
+ default:
+ errno = EINVAL;
+ return check_error(-1, errInfo);
+ }
+
+ if (off != offset) {
+ errno = EINVAL;
+ return check_error(-1, errInfo);
+ }
+
+ errno = 0;
+ result = lseek(fd, off, origin);
+
+ if (result >= 0) {
+ l_invalidate_local_fd(fd);
+ }
+
+ if (result < 0)
+ {
+ if (errno == ENOSYS) {
+ int size, cur_pos;
+
+ if (off < 0) {
+ errno = EINVAL;
+ return check_error(-1, errInfo);
+ }
+
+ cur_pos = lseek(fd, 0, SEEK_CUR);
+ size = lseek(fd, 0, SEEK_END);
+
+ if (origin == SEEK_SET) {
+ result = offset;
+ }
+ else if (origin == SEEK_CUR) {
+ result = offset + cur_pos;
+ }
+ else if (origin == SEEK_END) {
+ result = size + offset;
+ }
+
+ /* sanity check our result */
+ if (size > result) {
+ return check_error(-1, errInfo);
+ }
+
+ /* store the data localy */
+ l_update_local_fd(fd, result, size);
+
+ /* reset the original file position */
+ if (origin != SEEK_END) {
+ lseek(fd, cur_pos, SEEK_SET);
+ }
+ }
+ else if (errno == 0) {
+ errno = EINVAL;
+ }
+ }
+
+ if (new_location) {
+ *new_location = result;
+ }
+
+ return 1;
+}
+
+/***************************************************************************/
+
+int
+efile_truncate_file(Efile_error* errInfo, int *fd, int flags)
+{
+ off_t offset;
+ struct fd_data *fd_data;
+
+ if ((fd_data = l_find_local_fd(*fd)) != NULL && L_FD_IS_VALID(fd_data)) {
+ offset = L_FD_CUR(fd_data);
+ }
+ else {
+ offset = lseek(*fd, 0, SEEK_CUR);
+ }
+
+ return check_error(((offset >= 0) &&
+ (ftruncate(*fd, offset) == 0)) ? 1 : -1, errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
+{
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size)
+{
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_link(Efile_error* errInfo, char* old, char* new)
+{
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_symlink(Efile_error* errInfo, char* old, char* new)
+{
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+}
+
+/***************************************************************************/
+
+int
+efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
+ Sint64 length, int advise)
+{
+ return check_error(posix_fadvise(fd, offset, length, advise), errInfo);
+}
+
+/***************************************************************************/
+
+static int
+call_posix_fallocate(int fd, Sint64 offset, Sint64 length)
+{
+ int ret;
+
+ /*
+ * On Linux and Solaris for example, posix_fallocate() returns
+ * a positive error number on error and it does not set errno.
+ * On FreeBSD however (9.0 at least), it returns -1 on error
+ * and it sets errno.
+ */
+ do {
+ ret = posix_fallocate(fd, (off_t) offset, (off_t) length);
+ if (ret > 0) {
+ errno = ret;
+ ret = -1;
+ }
+ } while (ret != 0 && errno == EINTR);
+
+ return ret;
+}
+
+/***************************************************************************/
+
+int
+efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length)
+{
+ return check_error(call_posix_fallocate(fd, offset, length), errInfo);
+}
diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c
new file mode 100644
index 0000000000..4929b53856
--- /dev/null
+++ b/erts/emulator/drivers/ose/ose_signal_drv.c
@@ -0,0 +1,896 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2013-2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "errno.h"
+#include "stdio.h"
+#include "string.h"
+#include "stddef.h"
+
+#include "sys.h"
+#include "erl_driver.h"
+#include "ose.h"
+
+
+#ifdef HAVE_OSE_SPI_H
+#include "ose_spi/ose_spi.h"
+#endif
+
+#define DEBUG_ATTACH 0
+#define DEBUG_HUNT 0
+#define DEBUG_SEND 0
+#define DEBUG_LISTEN 0
+
+#if 0
+#define DEBUGP(FMT,...) printf(FMT, __VA_ARGS__)
+#else
+#define DEBUGP(FMT,...)
+#endif
+
+#if DEBUG_ATTACH
+#define DEBUGP_ATTACH(...) DEBUGP( __VA_ARGS__)
+#else
+#define DEBUGP_ATTACH(...)
+#endif
+
+#if DEBUG_HUNT
+#define DEBUGP_HUNT(...) DEBUGP( __VA_ARGS__)
+#else
+#define DEBUGP_HUNT(...)
+#endif
+
+#if DEBUG_LISTEN
+#define DEBUGP_LISTEN(...) DEBUGP( __VA_ARGS__)
+#else
+#define DEBUGP_LISTEN(...)
+#endif
+
+#if DEBUG_SEND
+#define DEBUGP_SEND(...) DEBUGP( __VA_ARGS__)
+#else
+#define DEBUGP_SEND(...)
+#endif
+
+
+#define DRIVER_NAME "ose_signal_drv"
+#define GET_SPID 1
+#define GET_NAME 2
+#define HUNT 100
+#define DEHUNT 101
+#define ATTACH 102
+#define DETACH 103
+#define SEND 104
+#define SEND_W_S 105
+#define LISTEN 106
+#define OPEN 200
+
+#define REF_SEGMENT_SIZE 8
+
+struct async {
+ SIGSELECT signo;
+ ErlDrvTermData port;
+ ErlDrvTermData proc;
+ PROCESS spid;
+ PROCESS target;
+ Uint32 ref;
+};
+
+/**
+ * OSE signals
+ **/
+union SIGNAL {
+ SIGSELECT signo;
+ struct async async;
+};
+
+/**
+ * The driver's context
+ **/
+typedef struct _driver_context {
+ ErlDrvPort port;
+ PROCESS spid;
+ ErlDrvEvent perm_events[2];
+ ErlDrvEvent *events;
+ Uint32 event_cnt;
+ Uint32 ref;
+ Uint32 *outstanding_refs;
+ Uint32 outstanding_refs_max;
+ Uint32 outstanding_refs_cnt;
+} driver_context_t;
+
+/**
+ * Global variables
+ **/
+static ErlDrvTermData a_ok;
+static ErlDrvTermData a_error;
+static ErlDrvTermData a_enomem;
+static ErlDrvTermData a_enoent;
+static ErlDrvTermData a_badarg;
+static ErlDrvTermData a_mailbox_up;
+static ErlDrvTermData a_mailbox_down;
+static ErlDrvTermData a_ose_drv_reply;
+static ErlDrvTermData a_message;
+static PROCESS proxy_proc;
+
+
+/**
+ * Serialize/unserialize unsigned 32-bit values
+ **/
+static char *put_u32(unsigned int value, char *ptr) {
+ *ptr++ = (value & 0xff000000) >> 24;
+ *ptr++ = (value & 0x00ff0000) >> 16;
+ *ptr++ = (value & 0x0000ff00) >> 8;
+ *ptr++ = (value & 0xff);
+
+ return ptr;
+}
+
+static unsigned int get_u32(char *ptr) {
+ unsigned int result = 0;
+ result += (ptr[0] & 0xff) << 24;
+ result += (ptr[1] & 0xff) << 16;
+ result += (ptr[2] & 0xff) << 8;
+ result += (ptr[3] & 0xff);
+
+ return result;
+}
+
+
+/* Stolen from efile_drv.c */
+
+/* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */
+#define EV_CHAR_P(ev, p, q) \
+ (((char *)(ev)->iov[(q)].iov_base) + (p))
+
+/* int EV_GET_CHAR(ErlIOVec *ev, char *p, int *pp, int *qp) */
+#define EV_GET_CHAR(ev, p, pp, qp) ev_get_char(ev, p ,pp, qp)
+static int
+ev_get_char(ErlIOVec *ev, char *p, int *pp, int *qp) {
+ if (*(pp)+1 <= (ev)->iov[*(qp)].iov_len) {
+ *(p) = *EV_CHAR_P(ev, *(pp), *(qp));
+ if (*(pp)+1 < (ev)->iov[*(qp)].iov_len)
+ *(pp) = *(pp)+1;
+ else {
+ (*(qp))++;
+ *pp = 0;
+ }
+ return !0;
+ }
+ return 0;
+}
+
+/* Uint32 EV_UINT32(ErlIOVec *ev, int p, int q)*/
+#define EV_UINT32(ev, p, q) \
+ ((Uint32) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p)))
+
+/* int EV_GET_UINT32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) */
+#define EV_GET_UINT32(ev, p, pp, qp) ev_get_uint32(ev,(Uint32*)(p),pp,qp)
+static int
+ev_get_uint32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) {
+ if (*(pp)+4 <= (ev)->iov[*(qp)].iov_len) {
+ *(p) = (EV_UINT32(ev, *(pp), *(qp)) << 24)
+ | (EV_UINT32(ev, *(pp)+1, *(qp)) << 16)
+ | (EV_UINT32(ev, *(pp)+2, *(qp)) << 8)
+ | (EV_UINT32(ev, *(pp)+3, *(qp)));
+ if (*(pp)+4 < (ev)->iov[*(qp)].iov_len)
+ *(pp) = *(pp)+4;
+ else {
+ (*(qp))++;
+ *pp = 0;
+ }
+ return !0;
+ }
+ return 0;
+}
+
+/**
+ * Convinience macros
+ **/
+#define send_response(port,output) erl_drv_send_term(driver_mk_port(port),\
+ driver_caller(port), output, sizeof(output) / sizeof(output[0]));
+
+void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off);
+void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off) {
+ int i;
+ memcpy(dest,ev->iov[ind].iov_base+off,ev->iov[ind].iov_len-off);
+ for (i = ind+1; i < ev->vsize; i++)
+ memcpy(dest,ev->iov[i].iov_base,ev->iov[i].iov_len);
+}
+
+/**
+ * Reference handling
+ **/
+
+static int add_reference(driver_context_t *ctxt, Uint32 ref) {
+
+ /*
+ * Premature optimizations may be evil, but they sure are fun.
+ */
+
+ if (ctxt->outstanding_refs == NULL) {
+ /* First ref to be ignored */
+ ctxt->outstanding_refs = driver_alloc(REF_SEGMENT_SIZE*sizeof(Uint32));
+ if (!ctxt->outstanding_refs)
+ return 1;
+
+ memset(ctxt->outstanding_refs,0,REF_SEGMENT_SIZE*sizeof(Uint32));
+ ctxt->outstanding_refs_max += REF_SEGMENT_SIZE;
+ ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref;
+ } else if (ctxt->outstanding_refs_cnt == ctxt->outstanding_refs_max) {
+ /* Expand ref array */
+ Uint32 *new_array;
+ ctxt->outstanding_refs_max += REF_SEGMENT_SIZE;
+ new_array = driver_realloc(ctxt->outstanding_refs,
+ ctxt->outstanding_refs_max*sizeof(Uint32));
+
+ if (!new_array) {
+ ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE;
+ return 1;
+ }
+
+ ctxt->outstanding_refs = new_array;
+
+ memset(ctxt->outstanding_refs+ctxt->outstanding_refs_cnt,0,
+ REF_SEGMENT_SIZE*sizeof(Uint32));
+ ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref;
+
+ } else {
+ /* Find an empty slot:
+ * First we try current index,
+ * then we scan for a slot.
+ */
+ if (!ctxt->outstanding_refs[ctxt->outstanding_refs_cnt]) {
+ ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref;
+ } else {
+ int i;
+ ASSERT(ctxt->outstanding_refs_cnt < ctxt->outstanding_refs_max);
+ for (i = 0; i < ctxt->outstanding_refs_max; i++)
+ if (!ctxt->outstanding_refs[i])
+ break;
+ ASSERT(ctxt->outstanding_refs[i] == 0);
+ ctxt->outstanding_refs[i] = ref;
+ ctxt->outstanding_refs_cnt++;
+ }
+ }
+ return 0;
+}
+
+/* Return 0 if removed, 1 if does not exist, */
+static int remove_reference(driver_context_t *ctxt, Uint32 ref) {
+ int i,j;
+
+ if (ctxt->outstanding_refs_max == 0 && ctxt->outstanding_refs_cnt == 0) {
+ ASSERT(ctxt->outstanding_refs == NULL);
+ return 1;
+ }
+
+ for (i = 0; i < ctxt->outstanding_refs_max; i++) {
+ if (ctxt->outstanding_refs[i] == ref) {
+ ctxt->outstanding_refs[i] = 0;
+ ctxt->outstanding_refs_cnt--;
+ i = -1;
+ break;
+ }
+ }
+
+ if (i != -1)
+ return 1;
+
+ if (ctxt->outstanding_refs_cnt == 0) {
+ driver_free(ctxt->outstanding_refs);
+ ctxt->outstanding_refs = NULL;
+ ctxt->outstanding_refs_max = 0;
+ } else if (ctxt->outstanding_refs_cnt == (ctxt->outstanding_refs_max - REF_SEGMENT_SIZE)) {
+ Uint32 *new_array;
+ for (i = 0, j = 0; i < ctxt->outstanding_refs_cnt; i++) {
+ if (ctxt->outstanding_refs[i] == 0) {
+ for (j = i+1; j < ctxt->outstanding_refs_max; j++)
+ if (ctxt->outstanding_refs[j]) {
+ ctxt->outstanding_refs[i] = ctxt->outstanding_refs[j];
+ ctxt->outstanding_refs[j] = 0;
+ break;
+ }
+ }
+ }
+ ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE;
+ new_array = driver_realloc(ctxt->outstanding_refs,
+ ctxt->outstanding_refs_max*sizeof(Uint32));
+ if (!new_array) {
+ ctxt->outstanding_refs_max += REF_SEGMENT_SIZE;
+ return 2;
+ }
+
+ ctxt->outstanding_refs = new_array;
+
+ }
+
+ return 0;
+}
+
+/**
+ * The OSE proxy process. This only handles ERTS_SIGNAL_OSE_DRV_ATTACH.
+ * The process is needed because signals triggered by attach ignore
+ * redir tables.
+ *
+ * We have one global proxy process to save memory. An attempt to make each
+ * port phantom into a proxy was made, but that used way to much memory.
+ */
+static OS_PROCESS(driver_proxy_process) {
+ SIGSELECT sigs[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH};
+ PROCESS master = 0;
+
+ while (1) {
+ union SIGNAL *sig = receive(sigs);
+
+ if (sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) {
+
+ /* The first message is used to determine who to send messages to. */
+ if (master == 0)
+ master = sender(&sig);
+
+ if (sig->async.target == 0) {
+ PROCESS from = sender(&sig);
+ restore(sig);
+ DEBUGP_ATTACH("0x%x: got attach 0x%x, sending to 0x%x\n",
+ current_process(),from,master);
+ sig->async.target = from;
+ send(&sig,master);
+ } else {
+ PROCESS target = sig->async.target;
+ restore(sig);
+ sig->async.target = 0;
+ DEBUGP_ATTACH("0x%x: doing attach on 0x%x\n",current_process(),target);
+ attach(&sig,target);
+ }
+ }
+ }
+}
+
+
+/**
+ * Init routine for the driver
+ **/
+static int drv_init(void) {
+
+ a_ok = driver_mk_atom("ok");
+ a_error = driver_mk_atom("error");
+ a_enomem = driver_mk_atom("enomem");
+ a_enoent = driver_mk_atom("enoent");
+ a_badarg = driver_mk_atom("badarg");
+ a_mailbox_up = driver_mk_atom("mailbox_up");
+ a_mailbox_down = driver_mk_atom("mailbox_down");
+ a_ose_drv_reply = driver_mk_atom("ose_drv_reply");
+ a_message = driver_mk_atom("message");
+
+ proxy_proc = create_process(get_ptype(current_process()),
+ "ose_signal_driver_proxy",
+ driver_proxy_process, 10000,
+ get_pri(current_process()),
+ 0, 0, NULL, 0, 0);
+
+#ifdef DEBUG
+ efs_clone(proxy_proc);
+#endif
+ start(proxy_proc);
+
+ return 0;
+}
+
+/* Signal resolution callback */
+static ErlDrvOseEventId resolve_signal(union SIGNAL* osig) {
+ union SIGNAL *sig = osig;
+ if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT ||
+ sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) {
+ return sig->async.spid;
+ }
+ DEBUGP("%p: Got signal %d sent to %p from 0x%p\n",
+ current_process(),sig->signo,addressee(&sig),sender(&sig));
+ return addressee(&sig);
+}
+
+
+/**
+ * Start routine for the driver
+ **/
+static ErlDrvData drv_start(ErlDrvPort port, char *command)
+{
+ driver_context_t *ctxt = driver_alloc(sizeof(driver_context_t));
+
+ ctxt->perm_events[0] = NULL;
+ ctxt->perm_events[1] = NULL;
+
+ ctxt->spid = 0;
+ ctxt->port = port;
+ ctxt->event_cnt = 0;
+ ctxt->events = NULL;
+ ctxt->ref = 0;
+ ctxt->outstanding_refs = NULL;
+ ctxt->outstanding_refs_max = 0;
+ ctxt->outstanding_refs_cnt = 0;
+
+
+ /* Set the communication protocol to Erlang to be binary */
+ set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
+
+ /* Everything ok */
+ return (ErlDrvData)ctxt;
+}
+
+/**
+ * Stop routine for the driver
+ **/
+static void drv_stop(ErlDrvData driver_data)
+{
+ driver_context_t *ctxt = (driver_context_t *)driver_data;
+ int i;
+
+ /* HUNT + ATTACH */
+ if (ctxt->perm_events[0])
+ driver_select(ctxt->port, ctxt->perm_events[0],
+ ERL_DRV_USE|ERL_DRV_READ, 0);
+ if (ctxt->perm_events[1])
+ driver_select(ctxt->port, ctxt->perm_events[1],
+ ERL_DRV_USE|ERL_DRV_READ, 0);
+
+ for (i = 0; i < ctxt->event_cnt; i++) {
+ driver_select(ctxt->port, ctxt->events[i], ERL_DRV_USE|ERL_DRV_READ, 0);
+ }
+
+ if (ctxt->spid != 0)
+ kill_proc(ctxt->spid);
+ DEBUGP("0x%x: stopped\n",ctxt->spid);
+ if (ctxt->events)
+ driver_free(ctxt->events);
+ if (ctxt->outstanding_refs)
+ driver_free(ctxt->outstanding_refs);
+
+ driver_free(ctxt);
+}
+
+/**
+ * Output from Erlang
+ **/
+static void outputv(ErlDrvData driver_data, ErlIOVec *ev)
+{
+ driver_context_t *ctxt = (driver_context_t *)driver_data;
+ int p = 0, q = 1;
+ char cmd;
+
+ if (! EV_GET_CHAR(ev,&cmd,&p,&q)) {
+ ErlDrvTermData output[] = {
+ ERL_DRV_ATOM, a_ose_drv_reply,
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_ATOM, a_badarg,
+ ERL_DRV_TUPLE, 3};
+ send_response(ctxt->port, output);
+ return;
+ }
+
+ /* Command is in the buffer's first byte */
+ switch(cmd) {
+
+ case OPEN: {
+ char *name = driver_alloc(ev->size - 1+1);
+ struct OS_redir_entry redir[2];
+
+ redir[0].sig = 1;
+ redir[0].pid = current_process();
+
+ iov_memcpy(name,ev,q,p);
+ name[ev->size-1] = '\0';
+
+ ctxt->spid = create_process(OS_PHANTOM, name, NULL, 0,
+ 0, 0, 0, redir, 0, 0);
+
+ DEBUGP("0x%x: open\n",ctxt->spid);
+
+ ctxt->perm_events[1] =
+ erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid,
+ resolve_signal, NULL);
+ driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1);
+
+ ctxt->perm_events[0] =
+ erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid,
+ resolve_signal, NULL);
+ driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1);
+
+ start(ctxt->spid);
+
+ {
+ ErlDrvTermData output[] = {
+ ERL_DRV_ATOM, a_ose_drv_reply,
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_ATOM, a_ok,
+ ERL_DRV_TUPLE, 3};
+
+ send_response(ctxt->port, output);
+ }
+
+ break;
+
+ }
+
+ case ATTACH:
+ case HUNT:
+ {
+ union SIGNAL *sig = alloc(sizeof(union SIGNAL),
+ cmd == HUNT ? ERTS_SIGNAL_OSE_DRV_HUNT:ERTS_SIGNAL_OSE_DRV_ATTACH);
+
+ sig->async.port = driver_mk_port(ctxt->port);
+ sig->async.proc = driver_caller(ctxt->port);
+ sig->async.spid = ctxt->spid;
+ sig->async.ref = ++ctxt->ref;
+
+ if (add_reference(ctxt,ctxt->ref)) {
+ ErlDrvTermData output[] = {
+ ERL_DRV_ATOM, a_ose_drv_reply,
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_ATOM, a_enomem,
+ ERL_DRV_TUPLE, 3};
+ send_response(ctxt->port, output);
+ free_buf(&sig);
+ } else {
+ ErlDrvTermData output[] = {
+ ERL_DRV_ATOM, a_ose_drv_reply,
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_INT, (ErlDrvUInt)ctxt->ref,
+ ERL_DRV_TUPLE, 2,
+ ERL_DRV_TUPLE, 3};
+ send_response(ctxt->port, output);
+
+ if (cmd == HUNT) {
+ char *huntname = driver_alloc(sizeof(char)*((ev->size-1)+1));
+
+ iov_memcpy(huntname,ev,q,p);
+ huntname[ev->size-1] = '\0';
+
+ DEBUGP_HUNT("0x%x: hunt %s -> %u (%u,%u)\n",
+ ctxt->spid,huntname,ctxt->ref,
+ ctxt->outstanding_refs_cnt,
+ ctxt->outstanding_refs_max);
+
+ hunt(huntname, 0, NULL, &sig);
+
+ driver_free(huntname);
+ } else {
+ EV_GET_UINT32(ev,&sig->async.target,&p,&q);
+ DEBUGP_ATTACH("0x%x: attach %u -> %u (%u,%u)\n",
+ ctxt->spid,sig->async.target,
+ ctxt->ref,
+ ctxt->outstanding_refs_cnt,
+ ctxt->outstanding_refs_max);
+
+ send(&sig,proxy_proc);
+ }
+
+ }
+
+ break;
+ }
+
+ case DETACH:
+ case DEHUNT:
+ {
+
+ Uint32 ref;
+
+ EV_GET_UINT32(ev,&ref,&p,&q);
+ if (cmd == DETACH) {
+ DEBUGP_ATTACH("0x%x: detach %u (%u,%u)\n",ctxt->spid,ref,
+ ctxt->outstanding_refs_cnt,
+ ctxt->outstanding_refs_max);
+ } else {
+ DEBUGP_HUNT("0x%x: dehunt %u (%u,%u)\n",ctxt->spid,ref,
+ ctxt->outstanding_refs_cnt,
+ ctxt->outstanding_refs_max);
+ }
+
+ if (remove_reference(ctxt,ref)) {
+ ErlDrvTermData output[] = {
+ ERL_DRV_ATOM, a_ose_drv_reply,
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_ATOM, a_error,
+ ERL_DRV_ATOM, a_enoent,
+ ERL_DRV_TUPLE, 2,
+ ERL_DRV_TUPLE, 3};
+
+ send_response(ctxt->port, output);
+ } else {
+ ErlDrvTermData output[] = {
+ ERL_DRV_ATOM, a_ose_drv_reply,
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_ATOM, a_ok,
+ ERL_DRV_TUPLE, 3};
+
+ send_response(ctxt->port, output);
+ }
+
+ break;
+ }
+
+ case SEND:
+ case SEND_W_S:
+ {
+ PROCESS spid;
+ PROCESS sender;
+ SIGSELECT signo;
+ OSBUFSIZE size = ev->size-9;
+ union SIGNAL *sig;
+
+ EV_GET_UINT32(ev,&spid,&p,&q);
+
+ if (cmd == SEND_W_S) {
+ EV_GET_UINT32(ev,&sender,&p,&q);
+ size -= 4;
+ } else {
+ sender = ctxt->spid;
+ }
+
+ EV_GET_UINT32(ev,&signo,&p,&q);
+
+ sig = alloc(size + sizeof(SIGSELECT),signo);
+
+ if (cmd == SEND_W_S) {
+ DEBUGP_SEND("0x%x: send_w_s(%u,%u,%u)\n",ctxt->spid,spid,signo,sender);
+ } else {
+ DEBUGP_SEND("0x%x: send(%u,%u)\n",ctxt->spid,spid,signo);
+ }
+
+ iov_memcpy(((char *)&sig->signo) + sizeof(SIGSELECT),ev,q,p);
+
+ send_w_s(&sig, sender, spid);
+
+ break;
+ }
+
+ case LISTEN:
+ {
+ int i,j,event_cnt = (ev->size - 1)/4;
+ ErlDrvEvent *events = NULL;
+ SIGSELECT signo,tmp_signo;
+
+ if (event_cnt == 0) {
+ for (i = 0; i < ctxt->event_cnt; i++)
+ driver_select(ctxt->port,ctxt->events[i],ERL_DRV_READ|ERL_DRV_USE,0);
+ if (ctxt->events)
+ driver_free(ctxt->events);
+ } else {
+ events = driver_alloc(sizeof(ErlDrvEvent)*event_cnt);
+ EV_GET_UINT32(ev,&signo,&p,&q);
+ for (i = 0, j = 0; i < event_cnt || j < ctxt->event_cnt; ) {
+
+ if (ctxt->events)
+ erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL,NULL);
+
+ if (signo == tmp_signo) {
+ events[i++] = ctxt->events[j++];
+ EV_GET_UINT32(ev,&signo,&p,&q);
+ } else if (signo < tmp_signo || !ctxt->events) {
+ /* New signal to select on */
+ events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid,
+ resolve_signal, NULL);
+ driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1);
+ EV_GET_UINT32(ev,&signo,&p,&q);
+ } else {
+ /* Remove old signal to select on */
+ driver_select(ctxt->port,ctxt->events[j++],ERL_DRV_READ|ERL_DRV_USE,0);
+ }
+ }
+ if (ctxt->events)
+ driver_free(ctxt->events);
+ }
+ ctxt->events = events;
+ ctxt->event_cnt = event_cnt;
+
+ {
+ ErlDrvTermData output[] = {
+ ERL_DRV_ATOM, a_ose_drv_reply,
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_ATOM, a_ok,
+ ERL_DRV_TUPLE, 3};
+ send_response(ctxt->port, output);
+ }
+ break;
+ }
+
+ default:
+ {
+ DEBUGP("Warning: 'ose_signal_drv' unknown command '%d'\n", cmd);
+ break;
+ }
+ }
+}
+
+/**
+ * Handler for when OSE signal arrives
+ **/
+static void ready_input(ErlDrvData driver_data, ErlDrvEvent event)
+{
+ driver_context_t *ctxt = (driver_context_t *)driver_data;
+ union SIGNAL *sig = erl_drv_ose_get_signal(event);
+
+ while (sig != NULL) {
+
+ switch(sig->signo)
+ {
+ /* Remote process is available */
+ case ERTS_SIGNAL_OSE_DRV_HUNT:
+ {
+ const PROCESS spid = sender(&sig);
+
+ if (remove_reference(ctxt,sig->async.ref)) {
+ DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (CANCELLED) (%u,%u)\n",
+ ctxt->spid,spid,sig->async.ref,
+ ctxt->outstanding_refs_cnt,
+ ctxt->outstanding_refs_max);
+ /* Already removed by dehunt */
+ } else {
+ ErlDrvTermData reply[] = {
+ ERL_DRV_ATOM, a_mailbox_up,
+ ERL_DRV_PORT, sig->async.port,
+ ERL_DRV_PORT, sig->async.port,
+ ERL_DRV_UINT, (ErlDrvUInt)sig->async.ref,
+ ERL_DRV_TUPLE, 2,
+ ERL_DRV_UINT, (ErlDrvUInt)spid,
+ ERL_DRV_TUPLE, 4};
+ DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (%u,%u)\n",
+ ctxt->spid,spid,sig->async.ref,
+ ctxt->outstanding_refs_cnt,
+ ctxt->outstanding_refs_max);
+ erl_drv_send_term(sig->async.port, sig->async.proc, reply,
+ sizeof(reply) / sizeof(reply[0]));
+ }
+ break;
+ }
+
+ /* Remote process is down */
+ case ERTS_SIGNAL_OSE_DRV_ATTACH:
+ {
+ PROCESS spid = sig->async.target;
+
+ if (remove_reference(ctxt,sig->async.ref)) {
+ DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (CANCELLED) (%u,%u)\n",
+ ctxt->spid,spid,sig->async.ref,
+ ctxt->outstanding_refs_cnt,
+ ctxt->outstanding_refs_max);
+ /* Already removed by detach */
+ } else {
+ ErlDrvTermData reply[] = {
+ ERL_DRV_ATOM, a_mailbox_down,
+ ERL_DRV_PORT, sig->async.port,
+ ERL_DRV_PORT, sig->async.port,
+ ERL_DRV_UINT, sig->async.ref,
+ ERL_DRV_TUPLE, 2,
+ ERL_DRV_UINT, (ErlDrvUInt)spid,
+ ERL_DRV_TUPLE, 4};
+ DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (%u,%u)\n",
+ ctxt->spid,spid,sig->async.ref,
+ ctxt->outstanding_refs_cnt,
+ ctxt->outstanding_refs_max);
+ erl_drv_send_term(sig->async.port, sig->async.proc, reply,
+ sizeof(reply) / sizeof(reply[0]));
+ }
+ break;
+ }
+
+ /* Received user defined signal */
+ default:
+ {
+ const PROCESS spid = sender(&sig);
+ const OSBUFSIZE size = sigsize(&sig) - sizeof(SIGSELECT);
+ const char *sig_data = ((char *)&sig->signo) + sizeof(SIGSELECT);
+
+ ErlDrvTermData reply[] = {
+ ERL_DRV_ATOM, a_message,
+ ERL_DRV_PORT, driver_mk_port(ctxt->port),
+ ERL_DRV_UINT, (ErlDrvUInt)spid,
+ ERL_DRV_UINT, (ErlDrvUInt)ctxt->spid,
+ ERL_DRV_UINT, (ErlDrvUInt)sig->signo,
+ ERL_DRV_BUF2BINARY, (ErlDrvTermData)sig_data, (ErlDrvUInt)size,
+ ERL_DRV_TUPLE, 4,
+ ERL_DRV_TUPLE, 3};
+
+ DEBUGP_SEND("0x%x: Got 0x%u\r\n", spid, sig->signo);
+
+ erl_drv_output_term(driver_mk_port(ctxt->port), reply,
+ sizeof(reply) / sizeof(reply[0]));
+ break;
+ }
+ }
+
+ free_buf(&sig);
+ sig = erl_drv_ose_get_signal(event);
+ }
+}
+
+/**
+ * Handler for 'port_control'
+ **/
+static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen)
+{
+ driver_context_t *ctxt = (driver_context_t *)driver_data;
+
+ switch(cmd)
+ {
+ case GET_SPID:
+ {
+ const PROCESS spid = ctxt->spid;
+ put_u32(spid, *rbuf);
+ return sizeof(PROCESS);
+ }
+
+#ifdef HAVE_OSE_SPI_H
+ case GET_NAME:
+ {
+ const PROCESS spid = get_u32(buf);
+ char *name = (char*)get_pid_info(spid,OSE_PI_NAME);
+ int n;
+ if (!name) {
+ *rbuf = NULL;
+ return 0;
+ }
+
+ if (rlen < (n = strlen(name))) {
+ ErlDrvBinary *bin = driver_alloc_binary(n);
+ strncpy(bin->orig_bytes,name,n);
+ *rbuf = (char*)bin;
+ } else
+ strncpy(*rbuf,name,n);
+ free_buf((union SIGNAL**)&name);
+
+ return n;
+ }
+#endif
+ default:
+ {
+ /* Unknown command */
+ return (ErlDrvSSizeT)ERL_DRV_ERROR_GENERAL;
+ break;
+ }
+ }
+}
+
+static void stop_select(ErlDrvEvent event, void *reserved)
+{
+ erl_drv_ose_event_free(event);
+}
+
+/**
+ * Setup the driver entry for the Erlang runtime
+ **/
+ErlDrvEntry ose_signal_driver_entry = {
+ .init = drv_init,
+ .start = drv_start,
+ .stop = drv_stop,
+ .outputv = outputv,
+ .ready_input = ready_input,
+ .driver_name = DRIVER_NAME,
+ .control = control,
+ .extended_marker = ERL_DRV_EXTENDED_MARKER,
+ .major_version = ERL_DRV_EXTENDED_MAJOR_VERSION,
+ .minor_version = ERL_DRV_EXTENDED_MINOR_VERSION,
+ .driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING,
+ .stop_select = stop_select
+};
+
diff --git a/erts/emulator/drivers/ose/ttsl_drv.c b/erts/emulator/drivers/ose/ttsl_drv.c
new file mode 100644
index 0000000000..8af2ce6af3
--- /dev/null
+++ b/erts/emulator/drivers/ose/ttsl_drv.c
@@ -0,0 +1,68 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Stub tty driver because group/user depend on this.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "erl_driver.h"
+
+static int ttysl_init(void);
+static ErlDrvData ttysl_start(ErlDrvPort, char*);
+
+/* Define the driver table entry. */
+struct erl_drv_entry ttsl_driver_entry = {
+ ttysl_init,
+ ttysl_start,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "tty_sl",
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* timeout */
+ NULL, /* outputv */
+ NULL, /* ready_async */
+ NULL, /* flush */
+ NULL, /* call */
+ NULL, /* event */
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0, /* ERL_DRV_FLAGs */
+ NULL,
+ NULL, /* process_exit */
+ NULL
+};
+
+
+static int ttysl_init(void)
+{
+ return 0;
+}
+
+static ErlDrvData ttysl_start(ErlDrvPort port, char* buf)
+{
+ return ERL_DRV_ERROR_GENERAL;
+}
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 55539b44dd..42f41c5f3d 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -102,6 +102,11 @@ check_error(int result, Efile_error *errInfo)
}
int
+efile_init() {
+ return 1;
+}
+
+int
efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */
char* name) /* Name of directory to create. */
{
@@ -405,6 +410,15 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
mode |= O_EXCL;
}
+ if (flags & EFILE_MODE_SYNC) {
+#ifdef O_SYNC
+ mode |= O_SYNC;
+#else
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+#endif
+ }
+
fd = open(name, mode, FILE_MODE);
if (!check_error(fd, errInfo))
@@ -620,7 +634,8 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */
do {
w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len);
} while (w < 0 && errno == EINTR);
- ASSERT(w <= iov[cnt].iov_len);
+ ASSERT(w <= iov[cnt].iov_len ||
+ (w == -1 && errno != EINTR));
}
if (w < 0) return check_error(-1, errInfo);
/* Move forward to next buffer to write */
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index 319065f57b..a321bb9641 100644
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -29,12 +29,27 @@
#include <wchar.h>
#include "erl_efile.h"
+#define DBG_TRACE_MASK 0
+/* 1 = file name ops
+ * 2 = file descr ops
+ * 4 = errors
+ * 8 = path name conversion
+ */
+#if !DBG_TRACE_MASK
+# define DBG_TRACE(M,S)
+# define DBG_TRACE1(M,FMT,A)
+# define DBG_TRACE2(M,FMT,A,B)
+#else
+# define DBG_TRACE(M,S) do { if ((M)&DBG_TRACE_MASK) fwprintf(stderr, L"DBG_TRACE %d: %s\r\n", __LINE__, (WCHAR*)(S)); }while(0)
+# define DBG_TRACE1(M,FMT,A) do { if ((M)&DBG_TRACE_MASK) fwprintf(stderr, L"DBG_TRACE %d: " L##FMT L"\r\n", __LINE__, (A)); }while(0)
+# define DBG_TRACE2(M,FMT,A,B) do { if ((M)&DBG_TRACE_MASK) fwprintf(stderr, L"DBG_TRACE %d: " L##FMT L"\r\n", __LINE__, (A), (B)); }while(0)
+#endif
+
/*
* Microsoft-specific function to map a WIN32 error code to a Posix errno.
*/
#define ISSLASH(a) ((a) == L'\\' || (a) == L'/')
-
#define ISDIR(st) (((st).st_mode&S_IFMT) == S_IFDIR)
#define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG)
@@ -69,10 +84,92 @@
static int check_error(int result, Efile_error* errInfo);
static int set_error(Efile_error* errInfo);
+static int set_os_errno(Efile_error* errInfo, DWORD os_errno);
static int is_root_unc_name(const WCHAR *path);
static int extract_root(WCHAR *name);
static unsigned short dos_to_posix_mode(int attr, const WCHAR *name);
+
+struct wpath_tmp_buffer {
+ struct wpath_tmp_buffer* next;
+ WCHAR buffer[1];
+};
+
+typedef struct {
+ Efile_error* errInfo;
+ struct wpath_tmp_buffer* buf_list;
+}Efile_call_state;
+
+static void call_state_init(Efile_call_state* state, Efile_error* errInfo)
+{
+ state->errInfo = errInfo;
+ state->buf_list = NULL;
+}
+static WCHAR* wpath_tmp_alloc(Efile_call_state* state, size_t len)
+{
+ size_t sz = offsetof(struct wpath_tmp_buffer, buffer)
+ + (len+1)*sizeof(WCHAR);
+ struct wpath_tmp_buffer* p = driver_alloc(sz);
+ p->next = state->buf_list;
+ state->buf_list = p;
+ return p->buffer;
+}
+static void call_state_free(Efile_call_state* state)
+{
+ while(state->buf_list) {
+ struct wpath_tmp_buffer* next = state->buf_list->next;
+ driver_free(state->buf_list);
+ state->buf_list = next;
+ }
+}
+static WCHAR* get_cwd_wpath_tmp(Efile_call_state* state)
+{
+ WCHAR dummy;
+ DWORD size = GetCurrentDirectoryW(0, &dummy);
+ WCHAR* ret = NULL;
+
+ if (size) {
+ ret = wpath_tmp_alloc(state, size);
+ if (!GetCurrentDirectoryW(size, ret)) {
+ ret = NULL;
+ }
+ }
+ return ret;
+}
+static WCHAR* get_full_wpath_tmp(Efile_call_state* state,
+ const WCHAR* file,
+ WCHAR** file_part,
+ DWORD extra)
+{
+ WCHAR dummy;
+ DWORD size = GetFullPathNameW(file, 0, &dummy, NULL);
+ WCHAR* ret = NULL;
+
+ if (size) {
+ int ok;
+ ret = wpath_tmp_alloc(state, size + extra);
+ if (file_part) {
+ ok = (GetFullPathNameW(file, size, ret, file_part) != 0);
+ }
+ else {
+ ok = (_wfullpath(ret, file, size) != NULL);
+ }
+ if (!ok) {
+ ret = NULL;
+ }
+ }
+ return ret;
+}
+
+static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max);
+static int do_rmdir(Efile_call_state*, char* name);
+static int do_rename(Efile_call_state*, char* src, char* dst);
+static int do_readdir(Efile_call_state*, char* name, EFILE_DIR_HANDLE*, char* buffer, size_t *size);
+static int do_fileinfo(Efile_call_state*, Efile_info*, char* orig_name, int info_for_link);
+static char* do_readlink(Efile_call_state*, char* name, char* buffer, size_t size);
+static int do_altname(Efile_call_state*, char* orig_name, char* buffer, size_t size);
+
+
static int errno_map(DWORD last_error) {
switch (last_error) {
@@ -154,6 +251,8 @@ static int errno_map(DWORD last_error) {
return EAGAIN;
case ERROR_CANT_RESOLVE_FILENAME:
return EMLINK;
+ case ERROR_PRIVILEGE_NOT_HELD:
+ return EPERM;
case ERROR_ARENA_TRASHED:
case ERROR_INVALID_BLOCK:
case ERROR_BAD_ENVIRONMENT:
@@ -176,11 +275,23 @@ check_error(int result, Efile_error* errInfo)
if (result < 0) {
errInfo->posix_errno = errno;
errInfo->os_errno = GetLastError();
+ DBG_TRACE2(4, "ERROR os_error=%d errno=%d @@@@@@@@@@@@@@@@@@@@@@@@@@@@",
+ errInfo->os_errno, errInfo->posix_errno);
return 0;
}
return 1;
}
+static void
+save_last_error(Efile_error* errInfo)
+{
+ errInfo->posix_errno = errno;
+ errInfo->os_errno = GetLastError();
+ DBG_TRACE2(4, "ERROR os_error=%d errno=%d $$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
+ errInfo->os_errno, errInfo->posix_errno);
+}
+
+
/*
* Fills the provided error information structure with information
* with the error code given by GetLastError() and its corresponding
@@ -192,10 +303,26 @@ check_error(int result, Efile_error* errInfo)
static int
set_error(Efile_error* errInfo)
{
- errInfo->posix_errno = errno_map(errInfo->os_errno = GetLastError());
+ set_os_errno(errInfo, GetLastError());
return 0;
}
+
+static int
+set_os_errno(Efile_error* errInfo, DWORD os_errno)
+{
+ errInfo->os_errno = os_errno;
+ errInfo->posix_errno = errno_map(os_errno);
+ DBG_TRACE2(4, "ERROR os_error=%d errno=%d ############################",
+ errInfo->os_errno, errInfo->posix_errno);
+ return 0;
+}
+
+int
+efile_init() {
+ return 1;
+}
+
/*
* A writev with Unix semantics, but with Windows arguments
*/
@@ -221,21 +348,151 @@ win_writev(Efile_error* errInfo,
}
+/* Check '*pathp' and convert it if needed to something that windows will accept.
+ * Typically use UNC path with \\?\ prefix if absolute path is longer than 260.
+ */
+static void ensure_wpath(Efile_call_state* state, WCHAR** pathp)
+{
+ ensure_wpath_max(state, pathp, MAX_PATH);
+}
+
+static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max)
+{
+ WCHAR* path = *pathp;
+ WCHAR* p;
+ size_t len = wcslen(path);
+ int unc_fixup = 0;
+
+ if (path[0] == 0) {
+ DBG_TRACE(8, L"Let empty path pass through");
+ return;
+ }
+
+ DBG_TRACE1(8,"IN: %s", path);
+
+ if (path[1] == L':' && ISSLASH(path[2])) { /* absolute path */
+ if (len >= max) {
+ WCHAR *src, *dst;
+
+ *pathp = wpath_tmp_alloc(state, 4+len+1);
+ dst = *pathp;
+ wcscpy(dst, L"\\\\?\\");
+ for (src=path,dst+=4; *src; src++) {
+ if (*src == L'/') {
+ if (dst[-1] != L'\\') {
+ *dst++ = L'\\';
+ }
+ /*else ignore redundant slashes */
+ }
+ else
+ *dst++ = *src;
+ }
+ *dst = 0;
+ unc_fixup = 1;
+ }
+ }
+ else if (!(ISSLASH(path[0]) && ISSLASH(path[1]))) { /* relative path */
+ DWORD cwdLen = GetCurrentDirectoryW(0, NULL);
+ DWORD absLen = cwdLen + 1 + len;
+ if (absLen >= max) {
+ WCHAR *fullPath = wpath_tmp_alloc(state, 4+4+absLen);
+ DWORD fullLen;
+
+ fullLen = GetFullPathNameW(path, 4 + absLen, fullPath+4, NULL);
+ if (fullLen >= 4+absLen) {
+ *pathp = path;
+ DBG_TRACE2(8,"ensure_wpath FAILED absLen=%u %s", (int)absLen, path);
+ return;
+ }
+ /* GetFullPathNameW can return paths longer than MAX_PATH without the \\?\ prefix.
+ * At least seen on Windows 7. Go figure...
+ */
+ if (fullLen >= max && wcsncmp(fullPath+4, L"\\\\?\\", 4) != 0) {
+ wcsncpy(fullPath, L"\\\\?\\", 4);
+ *pathp = fullPath;
+ }
+ else {
+ *pathp = fullPath + 4;
+ }
+ }
+ }
+
+ if (unc_fixup) {
+ WCHAR* endp;
+
+ p = *pathp;
+ len = wcslen(p);
+ endp = p + len;
+ if (len > 4) {
+ p += 4;
+ while (*p) {
+ if (p[0] == L'\\' && p[1] == L'.') {
+ if (p[2] == L'\\' || !p[2]) { /* single dot */
+ wmemmove(p, p+2, (&endp[1] - &p[2]));
+ endp -= 2;
+ }
+ else if (p[2] == L'.' && (p[3] == L'\\' || !p[3])) { /* double dot */
+ WCHAR* r;
+ for (r=p-1; *r == L'\\'; --r)
+ /*skip redundant slashes*/;
+ for (; *r != L'\\'; --r)
+ /*find start of prev directory*/;
+ if (r < *pathp + 6)
+ break;
+ wmemmove(r, p+3, (&endp[1] - &p[3]));
+ p = r;
+ }
+ else p += 3;
+ }
+ else ++p;
+ }
+ }
+ }
+ DBG_TRACE1(8,"OUT: %s", *pathp);
+}
int
efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */
char* name) /* Name of directory to create. */
{
- return check_error(_wmkdir((WCHAR *) name), errInfo);
+ Efile_call_state state;
+ WCHAR* wname = (WCHAR*)name;
+ int ret;
+
+ DBG_TRACE(1, name);
+ call_state_init(&state, errInfo);
+ ensure_wpath_max(&state, &wname, 248); /* Yes, 248 limit for normal paths */
+
+ ret = (int) CreateDirectoryW(wname, NULL);
+ if (!ret)
+ set_error(errInfo);
+
+ call_state_free(&state);
+ return ret;
}
int
efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */
char* name) /* Name of directory to delete. */
{
+ Efile_call_state state;
+ int ret;
+
+ DBG_TRACE(1, name);
+ call_state_init(&state, errInfo);
+ ret = do_rmdir(&state, name);
+ call_state_free(&state);
+ return ret;
+}
+
+static int do_rmdir(Efile_call_state* state, char* name)
+{
OSVERSIONINFO os;
DWORD attr;
WCHAR *wname = (WCHAR *) name;
+ WCHAR *buffer = NULL;
+
+ ensure_wpath(state, &wname);
if (RemoveDirectoryW(wname) != FALSE) {
return 1;
@@ -265,10 +522,9 @@ efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */
if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
HANDLE handle;
WIN32_FIND_DATAW data;
- WCHAR buffer[2*MAX_PATH];
- int len;
+ int len = wcslen(wname);
- len = wcslen(wname);
+ buffer = wpath_tmp_alloc(state, len + 4);
wcscpy(buffer, wname);
if (buffer[0] && buffer[len-1] != L'\\' && buffer[len-1] != L'/') {
wcscat(buffer, L"\\");
@@ -306,16 +562,30 @@ efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */
}
end:
- return check_error(-1, errInfo);
+ save_last_error(state->errInfo);
+ return 0;
}
int
efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */
char* name) /* Name of file to delete. */
{
+ Efile_call_state state;
+ int ret;
+ DBG_TRACE(1, name);
+ call_state_init(&state, errInfo);
+ ret = do_delete_file(&state, name);
+ call_state_free(&state);
+ return ret;
+}
+
+static int do_delete_file(Efile_call_state* state, char* name)
+{
DWORD attr;
WCHAR *wname = (WCHAR *) name;
+ ensure_wpath(state, &wname);
+
if (DeleteFileW(wname) != FALSE) {
return 1;
}
@@ -354,7 +624,7 @@ efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */
errno = EACCES;
}
- return check_error(-1, errInfo);
+ return check_error(-1, state->errInfo);
}
/*
@@ -388,14 +658,29 @@ efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */
*/
int
-efile_rename(Efile_error* errInfo, /* Where to return error codes. */
- char* src, /* Original name. */
- char* dst) /* New name. */
+efile_rename(Efile_error* errInfo, char* src, char* dst)
+{
+ Efile_call_state state;
+ int ret;
+ DBG_TRACE(1, src);
+ call_state_init(&state, errInfo);
+ ret = do_rename(&state, src, dst);
+ call_state_free(&state);
+ return ret;
+}
+
+static int
+do_rename(Efile_call_state* state,
+ char* src, /* Original name. */
+ char* dst) /* New name. */
{
DWORD srcAttr, dstAttr;
WCHAR *wsrc = (WCHAR *) src;
WCHAR *wdst = (WCHAR *) dst;
-
+
+ ensure_wpath(state, &wsrc);
+ ensure_wpath(state, &wdst);
+
if (MoveFileW(wsrc, wdst) != FALSE) {
return 1;
}
@@ -412,23 +697,27 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */
if (errno == EBADF) {
errno = EACCES;
- return check_error(-1, errInfo);
+ return check_error(-1, state->errInfo);
}
if (errno == EACCES) {
decode:
if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
- WCHAR srcPath[MAX_PATH], dstPath[MAX_PATH];
+ WCHAR *srcPath, *dstPath;
WCHAR *srcRest, *dstRest;
int size;
- size = GetFullPathNameW(wsrc, MAX_PATH, srcPath, &srcRest);
- if ((size == 0) || (size > MAX_PATH)) {
- return check_error(-1, errInfo);
+ srcPath = get_full_wpath_tmp(state, wsrc, &srcRest, 0);
+ if (!srcPath) {
+ save_last_error(state->errInfo);
+ return 0;
}
- size = GetFullPathNameW(wdst, MAX_PATH, dstPath, &dstRest);
- if ((size == 0) || (size > MAX_PATH)) {
- return check_error(-1, errInfo);
+
+ dstPath = get_full_wpath_tmp(state, wdst, &dstRest, 0);
+ if (!dstPath) {
+ save_last_error(state->errInfo);
+ return 0;
}
+
if (srcRest == NULL) {
srcRest = srcPath + wcslen(srcPath);
}
@@ -533,14 +822,16 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */
* put temp file back to old name.
*/
- WCHAR tempName[MAX_PATH];
- int result, size;
+ WCHAR *tempName;
+ int result;
WCHAR *rest;
- size = GetFullPathNameW(wdst, MAX_PATH, tempName, &rest);
- if ((size == 0) || (size > MAX_PATH) || (rest == NULL)) {
- return check_error(-1, errInfo);
+ tempName = get_full_wpath_tmp(state, wdst, &rest, 14);
+ if (!tempName || !rest) {
+ save_last_error(state->errInfo);
+ return 0;
}
+
*rest = L'\0';
result = -1;
if (GetTempFileNameW(tempName, L"erlr", 0, tempName) != 0) {
@@ -573,7 +864,6 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */
/*
* Decode the EACCES to a more meaningful error.
*/
-
goto decode;
}
}
@@ -581,16 +871,20 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */
}
}
}
- return check_error(-1, errInfo);
+ return check_error(-1, state->errInfo);
}
int
efile_chdir(Efile_error* errInfo, /* Where to return error codes. */
char* name) /* Name of directory to make current. */
-{
- int success = check_error(_wchdir((WCHAR *) name), errInfo);
- if (!success && errInfo->posix_errno == EINVAL)
- /* POSIXification of errno */
+{
+ /* We don't even try to handle long paths here
+ * as current working directory is always limited to MAX_PATH
+ * even if we use UNC paths and SetCurrentDirectoryW()
+ */
+ int success = check_error(_wchdir((WCHAR *) name), errInfo);
+ if (!success && errInfo->posix_errno == EINVAL)
+ /* POSIXification of errno */
errInfo->posix_errno = ENOENT;
return success;
}
@@ -603,28 +897,45 @@ efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */
{
WCHAR *wbuffer = (WCHAR *) buffer;
size_t wbuffer_size = size / 2;
- if (_wgetdcwd(drive, wbuffer, wbuffer_size) == NULL)
+ DBG_TRACE(1, L"#getdcwd#");
+ if (_wgetdcwd(drive, wbuffer, wbuffer_size) == NULL) {
return check_error(-1, errInfo);
+ }
+ DBG_TRACE1(8, "getdcwd OS=%s", wbuffer);
+ if (wcsncmp(wbuffer, L"\\\\?\\", 4) == 0) {
+ wmemmove(wbuffer, wbuffer+4, wcslen(wbuffer+4)+1);
+ }
for ( ; *wbuffer; wbuffer++)
if (*wbuffer == L'\\')
*wbuffer = L'/';
+ DBG_TRACE1(8, "getdcwd ERLANG=%s", (WCHAR*)buffer);
return 1;
}
int
-efile_readdir(Efile_error* errInfo, /* Where to return error codes. */
- char* name, /* Name of directory to list */
- EFILE_DIR_HANDLE* dir_handle, /* Handle of opened directory or NULL */
- char* buffer, /* Buffer to put one filename in */
- size_t *size) /* in-out size of buffer/size of filename excluding zero
- termination in bytes*/
+efile_readdir(Efile_error* errInfo, char* name, EFILE_DIR_HANDLE* dir_handle,
+ char* buffer, size_t *size)
+{
+ Efile_call_state state;
+ int ret;
+ DBG_TRACE(dir_handle?2:1, name);
+ call_state_init(&state, errInfo);
+ ret = do_readdir(&state, name, dir_handle, buffer, size);
+ call_state_free(&state);
+ return ret;
+}
+
+static int do_readdir(Efile_call_state* state,
+ char* name, /* Name of directory to list */
+ EFILE_DIR_HANDLE* dir_handle, /* Handle of opened directory or NULL */
+ char* buffer, /* Buffer to put one filename in */
+ size_t *size) /* in-out size of buffer/size of filename excluding zero
+ termination in bytes*/
{
HANDLE dir; /* Handle to directory. */
- WCHAR wildcard[MAX_PATH]; /* Wildcard to search for. */
WIN32_FIND_DATAW findData; /* Data found by FindFirstFile() or FindNext(). */
/* Alignment is not honored, this works on x86 because of alignment fixup by processor.
Not perfect, but faster than alinging by hand (really) */
- WCHAR *wname = (WCHAR *) name;
WCHAR *wbuffer = (WCHAR *) buffer;
/*
@@ -632,13 +943,15 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */
*/
if (*dir_handle == NULL) {
- int length = wcslen(wname);
+ WCHAR *wname = (WCHAR *) name;
+ WCHAR* wildcard;
+ int length;
WCHAR* s;
- if (length+3 >= MAX_PATH) {
- errno = ENAMETOOLONG;
- return check_error(-1, errInfo);
- }
+ ensure_wpath_max(state, &wname, MAX_PATH-2);
+ length = wcslen(wname);
+
+ wildcard = wpath_tmp_alloc(state, length+3);
wcscpy(wildcard, wname);
s = wildcard+length-1;
@@ -648,8 +961,10 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */
*++s = L'\0';
DEBUGF(("Reading %ws\n", wildcard));
dir = FindFirstFileW(wildcard, &findData);
- if (dir == INVALID_HANDLE_VALUE)
- return set_error(errInfo);
+ if (dir == INVALID_HANDLE_VALUE) {
+ set_error(state->errInfo);
+ return 0;
+ }
*dir_handle = (EFILE_DIR_HANDLE) dir;
if (!IS_DOT_OR_DOTDOT(findData.cFileName)) {
@@ -659,7 +974,6 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */
}
}
-
/*
* Retrieve the name of the next file using the directory handle.
*/
@@ -676,28 +990,41 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */
}
if (GetLastError() == ERROR_NO_MORE_FILES) {
- FindClose(dir);
- errInfo->posix_errno = errInfo->os_errno = 0;
- return 0;
+ state->errInfo->posix_errno = state->errInfo->os_errno = 0;
+ }
+ else {
+ set_error(state->errInfo);
}
-
- set_error(errInfo);
FindClose(dir);
return 0;
}
}
int
-efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
- char* name, /* Name of directory to open. */
- int flags, /* Flags to use for opening. */
- int* pfd, /* Where to store the file descriptor. */
- Sint64* pSize) /* Where to store the size of the file. */
+efile_openfile(Efile_error* errInfo, char* name, int flags, int* pfd, Sint64* pSize)
{
+ Efile_call_state state;
+ int ret;
+ DBG_TRACE1(1, "openfile(%s)", name);
+ call_state_init(&state, errInfo);
+ ret = do_openfile(&state, name, flags, pfd, pSize);
+ call_state_free(&state);
+ return ret;
+}
+
+static
+int do_openfile(Efile_call_state* state, /* Where to return error codes. */
+ char* name, /* Name of directory to open. */
+ int flags, /* Flags to use for opening. */
+ int* pfd, /* Where to store the file descriptor. */
+ Sint64* pSize) /* Where to store the size of the file. */
+{
+ Efile_error* errInfo = state->errInfo;
BY_HANDLE_FILE_INFORMATION fileInfo; /* File information from a handle. */
HANDLE fd; /* Handle to open file. */
DWORD access; /* Access mode: GENERIC_READ, GENERIC_WRITE. */
DWORD crFlags;
+ DWORD flagsAndAttrs = FILE_ATTRIBUTE_NORMAL;
WCHAR *wname = (WCHAR *) name;
switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) {
@@ -719,15 +1046,20 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
return 0;
}
+ if (flags & EFILE_MODE_SYNC) {
+ flagsAndAttrs = FILE_FLAG_WRITE_THROUGH;
+ }
+
if (flags & EFILE_MODE_APPEND) {
crFlags = OPEN_ALWAYS;
}
if (flags & EFILE_MODE_EXCL) {
crFlags = CREATE_NEW;
}
+ ensure_wpath(state, &wname);
fd = CreateFileW(wname, access,
FILE_SHARE_FLAGS,
- NULL, crFlags, FILE_ATTRIBUTE_NORMAL, NULL);
+ NULL, crFlags, flagsAndAttrs, NULL);
/*
* Check for errors.
@@ -767,34 +1099,56 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
}
int
-efile_may_openfile(Efile_error* errInfo, char *name) {
+efile_may_openfile(Efile_error* errInfo, char *name)
+{
+ Efile_call_state state;
WCHAR *wname = (WCHAR *) name;
DWORD attr;
+ int ret;
+ DBG_TRACE(1, name);
+ call_state_init(&state, errInfo);
+ ensure_wpath(&state, &wname);
if ((attr = GetFileAttributesW(wname)) == INVALID_FILE_ATTRIBUTES) {
errno = ENOENT;
- return check_error(-1, errInfo);
+ ret = check_error(-1, errInfo);
}
-
- if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+ else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
errno = EISDIR;
- return check_error(-1, errInfo);
+ ret = check_error(-1, errInfo);
}
- return 1;
+ else ret = 1;
+
+ call_state_free(&state);
+ return ret;
}
void
efile_closefile(fd)
int fd; /* File descriptor for file to close. */
{
+ DBG_TRACE(2, L"");
CloseHandle((HANDLE) fd);
}
+FILE* efile_wfopen(const WCHAR* name, const WCHAR* mode)
+{
+ Efile_call_state state;
+ Efile_error dummy;
+ FILE* f;
+ call_state_init(&state, &dummy);
+ ensure_wpath(&state, (WCHAR**)&name);
+ f = _wfopen(name, mode);
+ call_state_free(&state);
+ return f;
+}
+
int
efile_fdatasync(errInfo, fd)
Efile_error* errInfo; /* Where to return error codes. */
int fd; /* File descriptor for file to sync. */
{
+ DBG_TRACE(2, L"");
/* Not available in Windows, just call regular fsync */
return efile_fsync(errInfo, fd);
}
@@ -804,6 +1158,7 @@ efile_fsync(errInfo, fd)
Efile_error* errInfo; /* Where to return error codes. */
int fd; /* File descriptor for file to sync. */
{
+ DBG_TRACE(2, L"");
if (!FlushFileBuffers((HANDLE) fd)) {
return check_error(-1, errInfo);
}
@@ -814,64 +1169,87 @@ int
efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
char* orig_name, int info_for_link)
{
+ Efile_call_state state;
+ int ret;
+ DBG_TRACE(1, L"");
+ call_state_init(&state, errInfo);
+ ret = do_fileinfo(&state, pInfo, orig_name, info_for_link);
+ call_state_free(&state);
+ return ret;
+}
+
+static int
+do_fileinfo(Efile_call_state* state, Efile_info* pInfo,
+ char* orig_name, int info_for_link)
+{
+ Efile_error* errInfo = state->errInfo;
HANDLE findhandle; /* Handle returned by FindFirstFile(). */
WIN32_FIND_DATAW findbuf; /* Data return by FindFirstFile(). */
- WCHAR name[_MAX_PATH];
+ WCHAR* name = NULL;
+ WCHAR* win_path;
int name_len;
- WCHAR *path;
- WCHAR pathbuf[_MAX_PATH];
int drive; /* Drive for filename (1 = A:, 2 = B: etc). */
- WCHAR *worig_name = (WCHAR *) orig_name;
+ WCHAR *worig_name = (WCHAR *) orig_name;
+ ensure_wpath(state, &worig_name);
/* Don't allow wildcards to be interpreted by system */
- if (wcspbrk(worig_name, L"?*")) {
- enoent:
- errInfo->posix_errno = ENOENT;
- errInfo->os_errno = ERROR_FILE_NOT_FOUND;
- return 0;
- }
/*
* Move the name to a buffer and make sure to remove a trailing
* slash, because it causes FindFirstFile() to fail on Win95.
*/
- if ((name_len = wcslen(worig_name)) >= _MAX_PATH) {
- goto enoent;
- } else {
- wcscpy(name, worig_name);
- if (name_len > 2 && ISSLASH(name[name_len-1]) &&
- name[name_len-2] != L':') {
- name[name_len-1] = L'\0';
- }
+ name_len = wcslen(worig_name);
+
+ name = wpath_tmp_alloc(state, name_len+1);
+ wcscpy(name, worig_name);
+ if (name_len > 2 && ISSLASH(name[name_len-1]) &&
+ name[name_len-2] != L':') {
+ name[name_len-1] = L'\0';
}
-
+
+ win_path = name;
+ if (wcsncmp(name, L"\\\\?\\", 4) == 0) {
+ win_path += 4;
+ }
+
+ if (wcspbrk(win_path, L"?*")) {
+ enoent:
+ errInfo->posix_errno = ENOENT;
+ errInfo->os_errno = ERROR_FILE_NOT_FOUND;
+ return 0;
+ }
+
/* Try to get disk from name. If none, get current disk. */
- if (name[1] != L':') {
+ if (win_path[1] != L':') {
+ WCHAR* cwd_path = get_cwd_wpath_tmp(state);
drive = 0;
- if (GetCurrentDirectoryW(_MAX_PATH, pathbuf) &&
- pathbuf[1] == L':') {
- drive = towlower(pathbuf[0]) - L'a' + 1;
+ if (cwd_path[1] == L':') {
+ drive = towlower(cwd_path[0]) - L'a' + 1;
}
- } else if (*name && name[2] == L'\0') {
+ } else if (*win_path && win_path[2] == L'\0') {
/*
* X: and nothing more is an error.
*/
errInfo->posix_errno = ENOENT;
errInfo->os_errno = ERROR_FILE_NOT_FOUND;
return 0;
- } else
- drive = towlower(*name) - L'a' + 1;
+ } else {
+ drive = towlower(*win_path) - L'a' + 1;
+ }
findhandle = FindFirstFileW(name, &findbuf);
if (findhandle == INVALID_HANDLE_VALUE) {
+ WCHAR* path = NULL;
+
if (!(wcspbrk(name, L"./\\") &&
- (path = _wfullpath(pathbuf, name, _MAX_PATH)) &&
+ (path = get_full_wpath_tmp(state, name, NULL, 0)) &&
/* root dir. ('C:\') or UNC root dir. ('\\server\share\') */
((wcslen(path) == 3) || is_root_unc_name(path)) &&
(GetDriveTypeW(path) > 1) ) ) {
+
errInfo->posix_errno = ENOENT;
errInfo->os_errno = ERROR_FILE_NOT_FOUND;
return 0;
@@ -898,13 +1276,11 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
/*
* given that we know this is a symlink,
we should be able to find its target */
- WCHAR target_name[_MAX_PATH];
- if (efile_readlink(errInfo, (char *) name,
- (char *) target_name,
- _MAX_PATH * sizeof(WCHAR)) == 1) {
+ WCHAR* target_name = (WCHAR*) do_readlink(state, (char *) name, NULL, 0);
+ if (target_name) {
FindClose(findhandle);
- return efile_fileinfo(errInfo, pInfo,
- (char *) target_name, info_for_link);
+ return do_fileinfo(state, pInfo,
+ (char *) target_name, info_for_link);
}
}
@@ -971,6 +1347,20 @@ efile_write_info(Efile_error* errInfo,
Efile_info* pInfo,
char* name)
{
+ Efile_call_state state;
+ int ret;
+ call_state_init(&state, errInfo);
+ ret = do_write_info(&state, pInfo, name);
+ call_state_free(&state);
+ return ret;
+}
+
+static int
+do_write_info(Efile_call_state* state,
+ Efile_info* pInfo,
+ char* name)
+{
+ Efile_error* errInfo = state->errInfo;
SYSTEMTIME timebuf;
FILETIME ModifyFileTime;
FILETIME AccessFileTime;
@@ -980,6 +1370,10 @@ efile_write_info(Efile_error* errInfo,
DWORD tempAttr;
WCHAR *wname = (WCHAR *) name;
+ DBG_TRACE(1, name);
+
+ ensure_wpath(state, &wname);
+
/*
* Get the attributes for the file.
*/
@@ -1056,7 +1450,9 @@ char* buf; /* Buffer to write. */
size_t count; /* Number of bytes to write. */
Sint64 offset; /* where to write it */
{
- int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL);
+ int res;
+ DBG_TRACE(2, L"");
+ res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL);
if (res) {
return efile_write(errInfo, EFILE_MODE_WRITE, fd, buf, count);
} else {
@@ -1074,7 +1470,9 @@ char* buf; /* Buffer to read into. */
size_t count; /* Number of bytes to read. */
size_t* pBytesRead; /* Where to return number of bytes read. */
{
- int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL);
+ int res;
+ DBG_TRACE(2, L"");
+ res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL);
if (res) {
return efile_read(errInfo, EFILE_MODE_READ, fd, buf, count, pBytesRead);
} else {
@@ -1096,6 +1494,7 @@ size_t count; /* Number of bytes to write. */
OVERLAPPED overlapped;
OVERLAPPED* pOverlapped = NULL;
+ DBG_TRACE(2, L"");
if (flags & EFILE_MODE_APPEND) {
memset(&overlapped, 0, sizeof(overlapped));
overlapped.Offset = 0xffffffff;
@@ -1125,6 +1524,7 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */
OVERLAPPED overlapped;
OVERLAPPED* pOverlapped = NULL;
+ DBG_TRACE(2, L"");
ASSERT(iovcnt >= 0);
if (flags & EFILE_MODE_APPEND) {
@@ -1161,6 +1561,8 @@ size_t count; /* Number of bytes to read. */
size_t* pBytesRead; /* Where to return number of bytes read. */
{
DWORD nbytes = 0;
+
+ DBG_TRACE(2, L"");
if (!ReadFile((HANDLE) fd, buf, count, &nbytes, NULL))
return set_error(errInfo);
@@ -1180,6 +1582,7 @@ Sint64* new_location; /* Resulting new location in file. */
{
LARGE_INTEGER off, new_loc;
+ DBG_TRACE(2, L"");
switch (origin) {
case EFILE_SEEK_SET: origin = FILE_BEGIN; break;
case EFILE_SEEK_CUR: origin = FILE_CURRENT; break;
@@ -1211,6 +1614,7 @@ Efile_error* errInfo; /* Where to return error codes. */
int *fd; /* File descriptor for file to truncate. */
int flags;
{
+ DBG_TRACE(2, L"");
if (!SetEndOfFile((HANDLE) (*fd)))
return set_error(errInfo);
return 1;
@@ -1363,9 +1767,24 @@ dos_to_posix_mode(int attr, const WCHAR *name)
return uxmode;
}
+
int
efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
{
+ Efile_call_state state;
+ int ret;
+ DBG_TRACE(1, name);
+ call_state_init(&state, errInfo);
+ ret = !!do_readlink(&state, name, buffer, size);
+ call_state_free(&state);
+ return ret;
+}
+
+/* If buffer==0, return buffer allocated by wpath_tmp_allocate
+*/
+static char*
+do_readlink(Efile_call_state* state, char* name, char* buffer, size_t size)
+{
/*
* load dll and see if we have CreateSymbolicLink at runtime:
* (Vista only)
@@ -1373,6 +1792,9 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
HINSTANCE hModule = NULL;
WCHAR *wname = (WCHAR *) name;
WCHAR *wbuffer = (WCHAR *) buffer;
+ DWORD wsize = size / sizeof(WCHAR);
+ char* ret = NULL;
+
if ((hModule = LoadLibrary("kernel32.dll")) != NULL) {
typedef DWORD (WINAPI * GETFINALPATHNAMEBYHANDLEPTR)(
HANDLE hFile,
@@ -1383,58 +1805,84 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
GETFINALPATHNAMEBYHANDLEPTR pGetFinalPathNameByHandle =
(GETFINALPATHNAMEBYHANDLEPTR)GetProcAddress(hModule, "GetFinalPathNameByHandleW");
- if (pGetFinalPathNameByHandle == NULL) {
- FreeLibrary(hModule);
- } else {
+ if (pGetFinalPathNameByHandle != NULL) {
+ DWORD fileAttributes;
+ ensure_wpath(state, &wname);
/* first check if file is a symlink; {error, einval} otherwise */
- DWORD fileAttributes = GetFileAttributesW(wname);
+ fileAttributes = GetFileAttributesW(wname);
if ((fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
- BOOLEAN success = 0;
+ DWORD success = 0;
HANDLE h = CreateFileW(wname, GENERIC_READ, FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
int len;
if(h != INVALID_HANDLE_VALUE) {
- success = pGetFinalPathNameByHandle(h, wbuffer, size / sizeof(WCHAR),0);
- /* GetFinalPathNameByHandle prepends path with "\\?\": */
- len = wcslen(wbuffer);
- wmemmove(wbuffer,wbuffer+4,len-3);
- if (len - 4 >= 2 && wbuffer[1] == L':' && wbuffer[0] >= L'A' &&
- wbuffer[0] <= L'Z') {
- wbuffer[0] = wbuffer[0] + L'a' - L'A';
+ if (!wbuffer) { /* dynamic allocation */
+ WCHAR dummy;
+ wsize = pGetFinalPathNameByHandle(h, &dummy, 0, 0);
+ if (wsize) {
+ wbuffer = wpath_tmp_alloc(state, wsize);
+ }
}
+ if (wbuffer
+ && (success = pGetFinalPathNameByHandle(h, wbuffer, wsize, 0))
+ && success < wsize) {
+ WCHAR* wp;
+
+ /* GetFinalPathNameByHandle prepends path with "\\?\": */
+ len = wcslen(wbuffer);
+ wmemmove(wbuffer,wbuffer+4,len-3);
+ if (len - 4 >= 2 && wbuffer[1] == L':' && wbuffer[0] >= L'A' &&
+ wbuffer[0] <= L'Z') {
+ wbuffer[0] = wbuffer[0] + L'a' - L'A';
+ }
- for ( ; *wbuffer; wbuffer++)
- if (*wbuffer == L'\\')
- *wbuffer = L'/';
+ for (wp=wbuffer ; *wp; wp++)
+ if (*wp == L'\\')
+ *wp = L'/';
+ }
CloseHandle(h);
- }
- FreeLibrary(hModule);
+ }
if (success) {
- return 1;
+ ret = (char*) wbuffer;
} else {
- return set_error(errInfo);
+ set_error(state->errInfo);
}
} else {
- FreeLibrary(hModule);
errno = EINVAL;
- return check_error(-1, errInfo);
+ save_last_error(state->errInfo);
}
+ goto done;
}
}
errno = ENOTSUP;
- return check_error(-1, errInfo);
+ save_last_error(state->errInfo);
+
+done:
+ if (hModule)
+ FreeLibrary(hModule);
+ return ret;
}
int
efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size)
{
+ Efile_call_state state;
+ int ret;
+ DBG_TRACE(1, orig_name);
+ call_state_init(&state, errInfo);
+ ret = do_altname(&state, orig_name, buffer, size);
+ call_state_free(&state);
+ return ret;
+}
+
+static int
+do_altname(Efile_call_state* state, char* orig_name, char* buffer, size_t size)
+{
WIN32_FIND_DATAW wfd;
HANDLE fh;
- WCHAR name[_MAX_PATH+1];
+ WCHAR* name;
int name_len;
- WCHAR* path;
- WCHAR pathbuf[_MAX_PATH+1]; /* Unclear weather GetCurrentDirectory will access one char after
- _MAX_PATH */
+ WCHAR* full_path = NULL;
WCHAR *worig_name = (WCHAR *) orig_name;
WCHAR *wbuffer = (WCHAR *) buffer;
int drive; /* Drive for filename (1 = A:, 2 = B: etc). */
@@ -1443,8 +1891,8 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size)
if (wcspbrk(worig_name, L"?*")) {
enoent:
- errInfo->posix_errno = ENOENT;
- errInfo->os_errno = ERROR_FILE_NOT_FOUND;
+ state->errInfo->posix_errno = ENOENT;
+ state->errInfo->os_errno = ERROR_FILE_NOT_FOUND;
return 0;
}
@@ -1452,24 +1900,23 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size)
* Move the name to a buffer and make sure to remove a trailing
* slash, because it causes FindFirstFile() to fail on Win95.
*/
-
- if ((name_len = wcslen(worig_name)) >= _MAX_PATH) {
- goto enoent;
- } else {
- wcscpy(name, worig_name);
- if (name_len > 2 && ISSLASH(name[name_len-1]) &&
- name[name_len-2] != L':') {
- name[name_len-1] = L'\0';
- }
+ ensure_wpath(state, &worig_name);
+ name_len = wcslen(worig_name);
+
+ name = wpath_tmp_alloc(state, name_len + 1);
+ wcscpy(name, worig_name);
+ if (name_len > 2 && ISSLASH(name[name_len-1]) &&
+ name[name_len-2] != L':') {
+ name[name_len-1] = L'\0';
}
/* Try to get disk from name. If none, get current disk. */
if (name[1] != L':') {
+ WCHAR* cwd_path = get_cwd_wpath_tmp(state);
drive = 0;
- if (GetCurrentDirectoryW(_MAX_PATH, pathbuf) &&
- pathbuf[1] == L':') {
- drive = towlower(pathbuf[0]) - L'a' + 1;
+ if (cwd_path[1] == L':') {
+ drive = towlower(cwd_path[0]) - L'a' + 1;
}
} else if (*name && name[2] == L'\0') {
/*
@@ -1481,13 +1928,15 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size)
}
fh = FindFirstFileW(name,&wfd);
if (fh == INVALID_HANDLE_VALUE) {
+ DWORD fff_error = GetLastError();
if (!(wcspbrk(name, L"./\\") &&
- (path = _wfullpath(pathbuf, name, _MAX_PATH)) &&
+ (full_path = get_full_wpath_tmp(state, name, NULL, 0)) &&
/* root dir. ('C:\') or UNC root dir. ('\\server\share\') */
- ((wcslen(path) == 3) || is_root_unc_name(path)) &&
- (GetDriveTypeW(path) > 1) ) ) {
- errno = errno_map(GetLastError());
- return check_error(-1, errInfo);
+ ((wcslen(full_path) == 3) || is_root_unc_name(full_path)) &&
+ (GetDriveTypeW(full_path) > 1) ) ) {
+
+ set_os_errno(state->errInfo, fff_error);
+ return 0;
}
/*
* Root directories (such as C:\ or \\server\share\ are fabricated.
@@ -1508,17 +1957,37 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size)
int
efile_link(Efile_error* errInfo, char* old, char* new)
{
+ Efile_call_state state;
WCHAR *wold = (WCHAR *) old;
WCHAR *wnew = (WCHAR *) new;
+ int ret;
+ DBG_TRACE(1, old);
+ call_state_init(&state, errInfo);
+ ensure_wpath(&state, &wold);
+ ensure_wpath(&state, &wnew);
if(!CreateHardLinkW(wnew, wold, NULL)) {
- return set_error(errInfo);
+ ret = set_error(errInfo);
}
- return 1;
+ else ret =1;
+ call_state_free(&state);
+ return ret;
}
int
efile_symlink(Efile_error* errInfo, char* old, char* new)
{
+ Efile_call_state state;
+ int ret;
+ DBG_TRACE2(1, "symlink(%s <- %s)", old, new);
+ call_state_init(&state, errInfo);
+ ret = do_symlink(&state, old, new);
+ call_state_free(&state);
+ return ret;
+}
+
+static int
+do_symlink(Efile_call_state* state, char* old, char* new)
+{
/*
* Load dll and see if we have CreateSymbolicLink at runtime:
* (Vista only)
@@ -1526,6 +1995,8 @@ efile_symlink(Efile_error* errInfo, char* old, char* new)
HINSTANCE hModule = NULL;
WCHAR *wold = (WCHAR *) old;
WCHAR *wnew = (WCHAR *) new;
+
+ DBG_TRACE(1, old);
if ((hModule = LoadLibrary("kernel32.dll")) != NULL) {
typedef BOOLEAN (WINAPI * CREATESYMBOLICLINKFUNCPTR) (
LPCWSTR lpSymlinkFileName,
@@ -1537,6 +2008,9 @@ efile_symlink(Efile_error* errInfo, char* old, char* new)
"CreateSymbolicLinkW");
/* A for MBCS, W for UNICODE... char* above implies 'W'! */
if (pCreateSymbolicLink != NULL) {
+ ensure_wpath(state, &wold);
+ ensure_wpath(state, &wnew);
+ {
DWORD attr = GetFileAttributesW(wold);
int flag = (attr != INVALID_FILE_ATTRIBUTES &&
attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
@@ -1547,19 +2021,21 @@ efile_symlink(Efile_error* errInfo, char* old, char* new)
if (success) {
return 1;
} else {
- return set_error(errInfo);
+ return set_error(state->errInfo);
}
+ }
} else
FreeLibrary(hModule);
}
errno = ENOTSUP;
- return check_error(-1, errInfo);
+ return check_error(-1, state->errInfo);
}
int
efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
Sint64 length, int advise)
{
+ DBG_TRACE(2, L"");
/* posix_fadvise is not available on Windows, do nothing */
errno = ERROR_SUCCESS;
return check_error(0, errInfo);
@@ -1568,6 +2044,7 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
int
efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length)
{
+ DBG_TRACE(2, L"");
/* No file preallocation method available in Windows. */
errno = errno_map(ERROR_NOT_SUPPORTED);
SetLastError(ERROR_NOT_SUPPORTED);