From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 3890 invoked from network); 8 Jun 2020 09:31:26 -0000 Received: from ns1.primenet.com.au (HELO primenet.com.au) (203.24.36.2) by inbox.vuxu.org with ESMTPUTF8; 8 Jun 2020 09:31:26 -0000 Received: (qmail 20518 invoked by alias); 8 Jun 2020 09:31:14 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: List-Unsubscribe: X-Seq: 46026 Received: (qmail 14953 invoked by uid 1010); 8 Jun 2020 09:31:14 -0000 X-Qmail-Scanner-Diagnostics: from smtpq2.tb.ukmail.iss.as9143.net by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.102.3/25835. spamassassin: 3.4.4. Clear:RC:0(212.54.57.97):SA:0(-2.7/5.0):. Processed in 3.111932 secs); 08 Jun 2020 09:31:14 -0000 X-Envelope-From: p.w.stephenson@ntlworld.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _mailcloud.virginmedia.com designates 212.54.57.97 as permitted sender) X-Env-Mailfrom: p.w.stephenson@ntlworld.com X-Env-Rcptto: zsh-workers@zsh.org X-SourceIP: 172.25.160.136 X-CNFS-Analysis: v=2.3 cv=T8IXs8CQ c=1 sm=1 tr=0 a=4AIt8OzuWET5BS7mAkvERw==:117 a=KEnZaF_ea6UA:10 a=IkcTkHD0fZMA:10 a=DoY9bV0jb9AA:10 a=TqktBdowkmKlCRTO4QcA:9 a=QEXdDO2ut3YA:10 X-Authenticated-Sender: p.w.stephenson@ntlworld.com Date: Mon, 8 Jun 2020 10:30:32 +0100 (BST) From: Peter Stephenson To: zsh-workers@zsh.org Message-ID: <1300207061.4910.1591608632997@mail2.virginmedia.com> In-Reply-To: <20200608032730.614e197c@tarpaulin.shahaf.local2> References: <89aed74d-db7b-47ad-b218-8158838049e9@www.fastmail.com> <94e73ebcf39d4d3f9c7ae257b1d75d16@CAMSVWEXC01.scsc.local> <20200605020748.635b9bb3@tarpaulin.shahaf.local2> <1941572212.466119.1591360860372@mail2.virginmedia.com> <13acd486e6457c1f708304026c3e1b59521ad328.camel@ntlworld.com> <20200607115515.6624e240@tarpaulin.shahaf.local2> <15816a8422ec6889dda0f62bf80b11a88163ea3b.camel@ntlworld.com> <20200608032730.614e197c@tarpaulin.shahaf.local2> Subject: Re: Any way to allow clobbering empty files when noclobber is set? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Priority: 3 Importance: Medium X-Mailer: Open-Xchange Mailer v7.8.4-Rev70 X-Originating-IP: 165.225.81.56 X-Originating-Client: open-xchange-appsuite X-CMAE-Envelope: MS4wfM/YPTmcicPYDFv3QCuGj8Ro9PuaxnMBJG9iz/VFnQ7v6iO/4X7ZmuKitn2q/raXJunHIEkOXNsfa4xEBXEyEpkhCuuirJBxoYnFr557kVn8AzcGIlkj xyqJjTPloZ2QyUmft016jeDi7KLQsJJjPMsuTz7G5cfkcB3pNN5hePw6mQHTKPQ47dkOM7zg80aCjstzHDpCyU7Yt0f1NRUem6U= Here's an updated patch, which I think incorporates the current thinking, which seems pretty much to have iterated to a conclusion. The effective change is in fact now trivial --- an "if" with a return. Webmail again, as it seemed pretty non-invasive last time... pws diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index 2b7637ff4..6da68308f 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -1168,6 +1168,22 @@ If the option is not set, and the option tt(APPEND_CREATE) is also not set, `tt(>>!)' or `tt(>>|)' must be used to create a file. If either option is set, `tt(>>)' may be used. ) +pindex(CLOBBER_EMPTY) +pindex(NO_CLOBBER_EMPTY) +pindex(CLOBBEREMPTY) +pindex(NOCLOBBEREMPTY) +cindex(clobbering, of empty files) +cindex(file clobbering, of empty files) +item(tt(CLOBBER_EMPTY))( +This option is only used if the option tt(CLOBBER) is not set: note that +it is set by default. + +If this option is set, then regular files of zero length may be +ovewritten (`clobbered'). Note that it is possible another process +has written to the file between this test and use of the file by +the current process. This option should therefore not be used in +cases where files to be clobbered may be written to asynchronously. +) pindex(CORRECT) pindex(NO_CORRECT) pindex(NOCORRECT) diff --git a/Src/exec.c b/Src/exec.c index 29f4fc5ca..7b087f3b0 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, diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst index d60519064..993138e7d 100644 --- a/Test/A04redirect.ztst +++ b/Test/A04redirect.ztst @@ -708,3 +708,17 @@ cat <&$testfd 0:Regression test for here document with fd declarator > This is, in some sense, a here document. + + (setopt noclobber clobberempty + rm -f foo + touch foo + print Works >foo + cat foo + print Works not >foo + # Make sure the file was not harmed + cat foo + ) +0:CLOBBER_EMPTY +>Works +>Works +?(eval):6: file exists: foo