1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-05-11 10:06:19 +02:00

46026: Add CLOBBER_EMPTY option.

This commit is contained in:
Peter Stephenson 2020-06-09 18:04:46 +01:00
parent 172b646a6b
commit 3df604a4be
6 changed files with 59 additions and 5 deletions

View File

@ -1,3 +1,8 @@
2020-06-09 Peter Stephenson <p.stephenson@samsung.com>
* 46026: Doc/Zsh/options.yo, Src/exec.c, Src/options.c,
Src/zsh.h, Test/A04redirect.ztst: Add CLOBBER_EMPTY option.
2020-06-08 Peter Stephenson <p.w.stephenson@ntlworld.com>
* uwers/24909: Src/exec.c: Don't clean up files used for

View File

@ -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)

View File

@ -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;
}

View File

@ -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},

View File

@ -2378,6 +2378,7 @@ enum {
CHECKJOBS,
CHECKRUNNINGJOBS,
CLOBBER,
CLOBBEREMPTY,
APPENDCREATE,
COMBININGCHARS,
COMPLETEALIASES,

View File

@ -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