From 6b7374d7179d9be8ef2fb39928917cc3fd37453a Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 16 Apr 2020 06:04:33 -0700 Subject: 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. --- stream.c | 34 ++++++++++++++++++++-------------- 1 file 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 } -- cgit v1.2.3