diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2020-04-16 06:04:33 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-04-16 06:04:33 -0700 |
commit | 6b7374d7179d9be8ef2fb39928917cc3fd37453a (patch) | |
tree | fa4abaf583aa589750b317bbe88930a890205115 /stream.c | |
parent | 9e9513462ff0f82854dbc9d3f8bd42cd2ed8766e (diff) | |
download | txr-6b7374d7179d9be8ef2fb39928917cc3fd37453a.tar.gz txr-6b7374d7179d9be8ef2fb39928917cc3fd37453a.tar.bz2 txr-6b7374d7179d9be8ef2fb39928917cc3fd37453a.zip |
open-file: allow async signals.
With this patch, if open-file blocks (for instance on a FIFO
or device), it is interruptible. In the listener, the
operation can be aborted with Ctrl-C now.
* stream.c (w_fopen_mode): If we HAVE_FCNTL, then handle all
file opening via open + fdopen, rather than fopen. On
platforms where we use fopen, interruptibility won't work.
The fopen function cannot be abandoned via an exception thrown
from a signal handler because it performs memory allocation.
Because we need a temporary UTF-8 string to do the open,
which might be abandoned by a signal, let's move the string to
the stack via alloca, and free the original, so we don't have
to set up unwinding to free it.
Diffstat (limited to 'stream.c')
-rw-r--r-- | stream.c | 34 |
1 files changed, 20 insertions, 14 deletions
@@ -1085,26 +1085,32 @@ static struct strm_ops stdio_sock_ops; static FILE *w_fopen_mode(const wchar_t *wname, const wchar_t *mode, const struct stdio_mode m) { - if (m.notrunc || m.nonblock) { #if HAVE_FCNTL - char *name = utf8_dup_to(wname); - int flags = (if3(m.read && m.write, O_RDWR, 0) | - if3(m.read && !m.write, O_RDONLY, 0) | - if3(!m.read && m.write, - if3(!m.notrunc, O_TRUNC, 0) | O_WRONLY | O_CREAT, 0) | - if3(m.nonblock, O_NONBLOCK, 0)); - int fd = open(name, flags, 0666); - free(name); - if (fd < 0) - return NULL; - return (fd < 0) ? NULL : w_fdopen(fd, mode); + char *name = utf8_dup_to(wname); + size_t nsiz = strlen(name) + 1; + int flags = (if3(m.read && m.write, O_RDWR, 0) | + if3(m.read && !m.write, O_RDONLY, 0) | + if3(!m.read && m.write, + if3(!m.notrunc, O_TRUNC, 0) | O_WRONLY | O_CREAT, 0) | + if3(m.nonblock, O_NONBLOCK, 0)); + char *stkname = coerce(char *, alloca(nsiz)); + int fd; + + memcpy(stkname, name, nsiz); + free(name); + + sig_save_enable; + fd = open(stkname, flags, 0666); + sig_restore_enable; + + return (fd < 0) ? NULL : w_fdopen(fd, mode); #else + if (m.notrunc || m.nonblock) uw_throwf(file_error_s, lit("open-file: specified mode not supported on this system"), nao); -#endif - } return w_fopen(wname, mode); +#endif } |