diff options
author | jilles <jilles@FreeBSD.org> | 2011-01-08 00:03:18 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2011-01-08 00:03:18 +0000 |
commit | 6ef9696fb44fbc1b12fdac123542630a9bec6bad (patch) | |
tree | b86c1734dc9ae41a27d4271519188d0056277885 | |
parent | 16de4d95f52c6e680c13464902c761f154b200af (diff) | |
download | FreeBSD-src-6ef9696fb44fbc1b12fdac123542630a9bec6bad.zip FreeBSD-src-6ef9696fb44fbc1b12fdac123542630a9bec6bad.tar.gz |
sed: Try hard links to make -i target available continually.
When creating a backup file, sed renamed the original before renaming the
changed copy into place, leading to a short time when no file with the
original name was present (usually only visible on SMP systems). Try
creating the backup file using a hard link instead, avoiding this problem.
If creating the hard link fails for any reason, fall back to the old rename
method.
When not creating a backup file, sed already renamed the changed copy onto
the original. This remains unchanged.
I am not adding the suppression of redundant fchown/fchmod to this commit,
because FreeBSD appears to check this in the kernel (for msdosfs at least).
PR: bin/153261
Submitted by: Pedro F. Giffuni
Reviewed by: dds (older version)
Obtained from: Illumos
MFC after: 2 weeks
-rw-r--r-- | usr.bin/sed/main.c | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c index 8d4fe95..049d2ea 100644 --- a/usr.bin/sed/main.c +++ b/usr.bin/sed/main.c @@ -338,18 +338,35 @@ mf_fgets(SPACE *sp, enum e_spflag spflag) if (infile != NULL) { fclose(infile); if (*oldfname != '\0') { - if (rename(fname, oldfname) != 0) { + /* if there was a backup file, remove it */ + unlink(oldfname); + /* + * Backup the original. Note that hard links + * are not supported on all filesystems. + */ + if ((link(fname, oldfname) != 0) && + (rename(fname, oldfname) != 0)) { warn("rename()"); - unlink(tmpfname); + if (*tmpfname) + unlink(tmpfname); exit(1); } *oldfname = '\0'; } if (*tmpfname != '\0') { if (outfile != NULL && outfile != stdout) - fclose(outfile); + if (fclose(outfile) != 0) { + warn("fclose()"); + unlink(tmpfname); + exit(1); + } outfile = NULL; - rename(tmpfname, fname); + if (rename(tmpfname, fname) != 0) { + /* this should not happen really! */ + warn("rename()"); + unlink(tmpfname); + exit(1); + } *tmpfname = '\0'; } outfname = NULL; |