ash: [REDIR] Replace GPL noclobberopen code with the FreeBSD version
No binary (build failed)
—
(log yok)
| @@ -5174,68 +5174,6 @@ stoppedjobs(void) | |
| #define EMPTY -2 /* marks an unused slot in redirtab */ | |
| #define CLOSED -3 /* marks a slot of previously-closed fd */ | |
| - | /* |
| - | * Open a file in noclobber mode. |
| - | * The code was copied from bash. |
| - | */ |
| - | static int |
| - | noclobberopen(const char *fname) |
| - | { |
| - | int r, fd; |
| - | struct stat finfo, finfo2; |
| - | |
| - | /* |
| - | * If the file exists and is a regular file, return an error |
| - | * immediately. |
| - | */ |
| - | r = stat(fname, &finfo); |
| - | if (r == 0 && S_ISREG(finfo.st_mode)) { |
| - | errno = EEXIST; |
| - | return -1; |
| - | } |
| - | |
| - | /* |
| - | * If the file was not present (r != 0), make sure we open it |
| - | * exclusively so that if it is created before we open it, our open |
| - | * will fail. Make sure that we do not truncate an existing file. |
| - | * Note that we don't turn on O_EXCL unless the stat failed -- if the |
| - | * file was not a regular file, we leave O_EXCL off. |
| - | */ |
| - | if (r != 0) |
| - | return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); |
| - | fd = open(fname, O_WRONLY|O_CREAT, 0666); |
| - | |
| - | /* If the open failed, return the file descriptor right away. */ |
| - | if (fd < 0) |
| - | return fd; |
| - | |
| - | /* |
| - | * OK, the open succeeded, but the file may have been changed from a |
| - | * non-regular file to a regular file between the stat and the open. |
| - | * We are assuming that the O_EXCL open handles the case where FILENAME |
| - | * did not exist and is symlinked to an existing file between the stat |
| - | * and open. |
| - | */ |
| - | |
| - | /* |
| - | * If we can open it and fstat the file descriptor, and neither check |
| - | * revealed that it was a regular file, and the file has not been |
| - | * replaced, return the file descriptor. |
| - | */ |
| - | if (fstat(fd, &finfo2) == 0 |
| - | && !S_ISREG(finfo2.st_mode) |
| - | && finfo.st_dev == finfo2.st_dev |
| - | && finfo.st_ino == finfo2.st_ino |
| - | ) { |
| - | return fd; |
| - | } |
| - | |
| - | /* The file has been replaced. badness. */ |
| - | close(fd); |
| - | errno = EEXIST; |
| - | return -1; |
| - | } |
| - | |
| /* | |
| * Handle here documents. Normally we fork off a process to write the | |
| * data to a pipe. If the document is short, we can stuff the data in | |
| @@ -5280,6 +5218,7 @@ openhere(union node *redir) | |
| static int | |
| openredirect(union node *redir) | |
| { | |
| + | struct stat sb; |
| char *fname; | |
| int f; | |
| @@ -5319,9 +5258,23 @@ openredirect(union node *redir) | |
| #endif | |
| /* Take care of noclobber mode. */ | |
| if (Cflag) { | |
| - | f = noclobberopen(fname); |
| - | if (f < 0) |
| + | if (stat(fname, &sb) < 0) { |
| + | f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); |
| + | if (f < 0) |
| + | goto ecreate; |
| + | } else if (!S_ISREG(sb.st_mode)) { |
| + | f = open(fname, O_WRONLY, 0666); |
| + | if (f < 0) |
| + | goto ecreate; |
| + | if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) { |
| + | close(f); |
| + | errno = EEXIST; |
| + | goto ecreate; |
| + | } |
| + | } else { |
| + | errno = EEXIST; |
| goto ecreate; | |
| + | } |
| break; | |
| } | |
| /* FALLTHROUGH */ | |