Ensure noclobber redirection terminate (#46053)
@@ -23,6 +23,8 @@ | ||
23 | 23 | = The "array" built-in is now completely ignored in the POSIXly- |
24 | 24 | correct mode. The built-in, formerly a regular built-in, is now |
25 | 25 | categorized as an "extension" built-in. |
26 | + * The ">" redirection with the noclobber option no longer hangs | |
27 | + when the operand names a symbolic link to a non-existing file. | |
26 | 28 | |
27 | 29 | ---------------------------------------------------------------------- |
28 | 30 | Yash 2.53 (2022-08-23) |
@@ -1,6 +1,6 @@ | ||
1 | 1 | /* Yash: yet another shell */ |
2 | 2 | /* redir.c: manages file descriptors and provides functions for redirections */ |
3 | -/* (C) 2007-2020 magicant */ | |
3 | +/* (C) 2007-2022 magicant */ | |
4 | 4 | |
5 | 5 | /* This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
@@ -484,7 +484,6 @@ | ||
484 | 484 | const mode_t mode = |
485 | 485 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; |
486 | 486 | |
487 | -start:; | |
488 | 487 | int fd = open(path, oflag, mode); |
489 | 488 | |
490 | 489 | // Support the no-clobber mode. |
@@ -492,10 +491,15 @@ | ||
492 | 491 | fd = open(path, oflag & ~(O_CREAT | O_EXCL | O_TRUNC), mode); |
493 | 492 | if (fd < 0) { |
494 | 493 | if (errno == ENOENT) { |
495 | - // A file existed on the first open but not on the second. | |
496 | - // Somebody must have removed it between the two opens. | |
497 | - // Start over as we might be able to create one this time. | |
498 | - goto start; | |
494 | + // There are two possibilities now: One is that a file existed | |
495 | + // on the first open call and had been removed before the | |
496 | + // second. In this case, we might be able to create another if | |
497 | + // we start over. The other is that there is a symbolic link | |
498 | + // pointing to nothing, in which case retrying would only lead | |
499 | + // to the same result. Since there is no reliable way to tell | |
500 | + // the situations apart atomically, we give up and return the | |
501 | + // initial error. | |
502 | + errno = EEXIST; | |
499 | 503 | } |
500 | 504 | } else { |
501 | 505 | struct stat st; |