From b4fde270c6cbf2fc30a414428e9c7b7a3e557cc7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 7 Feb 2018 07:27:57 +0000 Subject: [PATCH] Better file-existence test on Unix. Now we don't annoyingly print the 'askappend' prompt if you ask a PuTTY tool to write its packet log to something that's not a regular file, such as /dev/fd/1 or /dev/tty or a named pipe. (In the case of a named pipe, another annoyance fixed by this change is that we also don't open it for reading in the course of the existence test.) --- unix/uxmisc.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/unix/uxmisc.c b/unix/uxmisc.c index 50d385b6..04af45d0 100644 --- a/unix/uxmisc.c +++ b/unix/uxmisc.c @@ -352,11 +352,36 @@ char *make_dir_path(const char *path, mode_t mode) int open_for_write_would_lose_data(const Filename *fn) { - FILE *fp; - if ((fp = f_open(fn, "r", FALSE)) != NULL) { - fclose(fp); - return TRUE; - } else { + struct stat st; + + if (stat(fn->path, &st) < 0) { + /* + * If the file doesn't even exist, we obviously want to return + * false. If we failed to stat it for any other reason, + * ignoring the precise error code and returning false still + * doesn't seem too unreasonable, because then we'll try to + * open the file for writing and report _that_ error, which is + * likely to be more to the point. + */ return FALSE; } + + /* + * OK, something exists at this pathname and we've found out + * something about it. But an open-for-write will only + * destructively truncate it if it's a regular file with nonzero + * size. If it's empty, or some other kind of special thing like a + * character device (e.g. /dev/tty) or a named pipe, then opening + * it for write is already non-destructive and it's pointless and + * annoying to warn about it just because the same file can be + * opened for reading. (Indeed, if it's a named pipe, opening it + * for reading actually _causes inconvenience_ in its own right, + * even before the question of whether it gives misleading + * information.) + */ + if (S_ISREG(st.st_mode) && st.st_size > 0) { + return TRUE; + } + + return FALSE; }