From 3df604a4be76db6ccf285eda6b4b3f5f6ec7497d Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Tue, 9 Jun 2020 18:04:46 +0100
Subject: 46026: Add CLOBBER_EMPTY option.
---
Src/exec.c | 27 ++++++++++++++++++++++-----
Src/options.c | 1 +
Src/zsh.h | 1 +
3 files changed, 24 insertions(+), 5 deletions(-)
(limited to 'Src')
diff --git a/Src/exec.c b/Src/exec.c
index c72d485b2..045b5d2b9 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2143,14 +2143,15 @@ clobber_open(struct redir *f)
{
struct stat buf;
int fd, oerrno;
+ char *ufname = unmeta(f->name);
/* If clobbering, just open. */
if (isset(CLOBBER) || IS_CLOBBER_REDIR(f->type))
- return open(unmeta(f->name),
+ return open(ufname,
O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY, 0666);
/* If not clobbering, attempt to create file exclusively. */
- if ((fd = open(unmeta(f->name),
+ if ((fd = open(ufname,
O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0666)) >= 0)
return fd;
@@ -2158,11 +2159,27 @@ clobber_open(struct redir *f)
* Try opening, and if it's a regular file then close it again *
* because we weren't supposed to open it. */
oerrno = errno;
- if ((fd = open(unmeta(f->name), O_WRONLY | O_NOCTTY)) != -1) {
- if(!fstat(fd, &buf) && !S_ISREG(buf.st_mode))
- return fd;
+ if ((fd = open(ufname, O_WRONLY | O_NOCTTY)) != -1) {
+ if(!fstat(fd, &buf)) {
+ if (!S_ISREG(buf.st_mode))
+ return fd;
+ /*
+ * If CLOBBER_EMPTY is in effect and the file is empty,
+ * we are allowed to re-use it.
+ *
+ * Note: there is an intrinsic race here because another
+ * process can write to this file at any time. The only fix
+ * would be file locking, which we wish to avoid in basic
+ * file operations at this level. This would not be
+ * fixed. just additionally complicated, by re-opening the
+ * file and truncating.
+ */
+ if (isset(CLOBBEREMPTY) && buf.st_size == 0)
+ return fd;
+ }
close(fd);
}
+
errno = oerrno;
return -1;
}
diff --git a/Src/options.c b/Src/options.c
index 7586d21d2..fba021e7d 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -114,6 +114,7 @@ static struct optname optns[] = {
{{NULL, "checkjobs", OPT_EMULATE|OPT_ZSH}, CHECKJOBS},
{{NULL, "checkrunningjobs", OPT_EMULATE|OPT_ZSH}, CHECKRUNNINGJOBS},
{{NULL, "clobber", OPT_EMULATE|OPT_ALL}, CLOBBER},
+{{NULL, "clobberempty", 0}, CLOBBEREMPTY},
{{NULL, "combiningchars", 0}, COMBININGCHARS},
{{NULL, "completealiases", 0}, COMPLETEALIASES},
{{NULL, "completeinword", 0}, COMPLETEINWORD},
diff --git a/Src/zsh.h b/Src/zsh.h
index 1f2d774a1..ed123f2b9 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2378,6 +2378,7 @@ enum {
CHECKJOBS,
CHECKRUNNINGJOBS,
CLOBBER,
+ CLOBBEREMPTY,
APPENDCREATE,
COMBININGCHARS,
COMPLETEALIASES,
--
cgit 1.4.1