summaryrefslogtreecommitdiffstats
path: root/stream.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2020-04-16 06:04:33 -0700
committerKaz Kylheku <kaz@kylheku.com>2020-04-16 06:04:33 -0700
commit6b7374d7179d9be8ef2fb39928917cc3fd37453a (patch)
treefa4abaf583aa589750b317bbe88930a890205115 /stream.c
parent9e9513462ff0f82854dbc9d3f8bd42cd2ed8766e (diff)
downloadtxr-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.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/stream.c b/stream.c
index 15da2d25..ce3f02b9 100644
--- a/stream.c
+++ b/stream.c
@@ -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
}