From e23478755d418e5f80384dbfa2536f2aaa3c888b Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 26 May 2022 22:53:51 -0700 Subject: gzio: support more modes in open-file. * gzio.c (w_gzopen_mode): Use w_open_mode if available, in order to support most of the flags (including "x" which Zlib has, but which we are not passing through). * stream.c (w_open_mode): New function formed from w_fopen_mode content. (w_fopen_mode): Call w_open_mode. * stream.c (w_open_mode): Declared. --- gzio.c | 35 +++++++++++++++++++++++++++++++++++ gzio.h | 2 ++ stream.c | 14 +++++++++++--- stream.h | 1 + 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/gzio.c b/gzio.c index fc025e9a..ef1e21ba 100644 --- a/gzio.c +++ b/gzio.c @@ -479,6 +479,13 @@ gzFile w_gzopen_mode(const wchar_t *wname, const wchar_t *wmode, uw_throwf(file_error_s, lit("~a: gzip stream cannot both read and write"), self, nao); } + +#if HAVE_FCNTL + { + int fd = w_open_mode(wname, m); + return (fd < 0) ? NULL : w_gzdopen_mode(fd, wmode, m, self); + } +#else { char *name = utf8_dup_to(wname); char *mode = utf8_dup_to(wmode); @@ -487,6 +494,34 @@ gzFile w_gzopen_mode(const wchar_t *wname, const wchar_t *wmode, free(mode); return f; } +#endif +} + +gzFile w_gzdopen_mode(int fd, const wchar_t *wmode, + const struct stdio_mode m, val self) +{ + if (m.buforder >= 0 || m.nonblock || m.notrunc || m.unbuf || + m.linebuf || m.interactive) + { + goto badmode; + } + + if (m.read && m.write) { + uw_throwf(file_error_s, + lit("~a: gzip stream cannot both read and write"), self, nao); + } + + { + char *mode = utf8_dup_to(wmode); + gzFile f = gzdopen(fd, mode); + free(mode); + if (f) + return f; + } + +badmode: + uw_throwf(file_error_s, + lit("~a: invalid modes for gzip stream"), self, nao); } val make_gzio_stream(gzFile f, int fd, val descr, int is_output) diff --git a/gzio.h b/gzio.h index bbcd1e1a..2f9cf164 100644 --- a/gzio.h +++ b/gzio.h @@ -30,4 +30,6 @@ val gzio_stream_s; void gzio_init(void); gzFile w_gzopen_mode(const wchar_t *wname, const wchar_t *wmode, const struct stdio_mode m, val self); +gzFile w_gzdopen_mode(int fd, const wchar_t *wmode, + const struct stdio_mode m, val self); val make_gzio_stream(gzFile f, int fd, val descr, int is_output); diff --git a/stream.c b/stream.c index d3118955..e336d35f 100644 --- a/stream.c +++ b/stream.c @@ -1127,10 +1127,9 @@ static struct strm_ops stdio_ops = static struct strm_ops stdio_sock_ops; #endif -static FILE *w_fopen_mode(const wchar_t *wname, const wchar_t *mode, - const struct stdio_mode m) -{ #if HAVE_FCNTL +int w_open_mode(const wchar_t *wname, const struct stdio_mode m) +{ char *name = utf8_dup_to(wname); size_t nsiz = strlen(name) + 1; int flags = (if3(m.read && m.write, O_RDWR, 0) | @@ -1150,6 +1149,15 @@ static FILE *w_fopen_mode(const wchar_t *wname, const wchar_t *mode, fd = open(stkname, flags, 0666); sig_restore_enable; + return fd; +} +#endif + +static FILE *w_fopen_mode(const wchar_t *wname, const wchar_t *mode, + const struct stdio_mode m) +{ +#if HAVE_FCNTL + int fd = w_open_mode(wname, m); return (fd < 0) ? NULL : w_fdopen(fd, mode); #else /* TODO: detect if fopen supports "x" in mode */ diff --git a/stream.h b/stream.h index 83534617..b735dd07 100644 --- a/stream.h +++ b/stream.h @@ -167,6 +167,7 @@ void fill_stream_ops(struct strm_ops *ops); void stream_print_op(val stream, val out, val pretty, struct strm_ctx *); void stream_mark_op(val stream); void stream_destroy_op(val stream); +int w_open_mode(const wchar_t *wname, const struct stdio_mode m); struct stdio_mode parse_mode(val mode_str, struct stdio_mode m_dfl, val self); val normalize_mode(struct stdio_mode *m, val mode_str, struct stdio_mode m_dfl, val self); -- cgit v1.2.3