Index: sed-4.1.5/sed/sed.c =================================================================== --- sed-4.1.5.orig/sed/sed.c +++ sed-4.1.5/sed/sed.c @@ -70,6 +70,11 @@ bool no_default_output = false; /* If set, reset line counts on every new file. */ bool separate_files = false; +#ifdef ENABLE_FOLLOW_SYMLINKS +/* If set, follow symlinks when processing in place */ +bool follow_symlinks = false; +#endif + /* How do we edit files in-place? (we don't if NULL) */ char *in_place_extension = NULL; @@ -105,6 +110,10 @@ Usage: %s [OPTION]... {script-only-if-no add the script to the commands to be executed\n")); fprintf(out, _(" -f script-file, --file=script-file\n\ add the contents of script-file to the commands to be executed\n")); +#ifdef ENABLE_FOLLOW_SYMLINKS + fprintf(out, _(" --follow-symlinks\n\ + follow symlinks when processing in place\n")); +#endif fprintf(out, _(" -i[SUFFIX], --in-place[=SUFFIX]\n\ edit files in place (makes backup if extension supplied)\n")); fprintf(out, _(" -l N, --line-length=N\n\ @@ -163,6 +172,9 @@ main(argc, argv) {"unbuffered", 0, NULL, 'u'}, {"version", 0, NULL, 'v'}, {"help", 0, NULL, 'h'}, +#ifdef ENABLE_FOLLOW_SYMLINKS + {"follow-symlinks", 0, NULL, 'F'}, +#endif {NULL, 0, NULL, 0} }; @@ -215,6 +227,12 @@ main(argc, argv) the_program = compile_file(the_program, optarg); break; +#ifdef ENABLE_FOLLOW_SYMLINKS + case 'F': + follow_symlinks = true; + break; +#endif + case 'i': separate_files = true; if (optarg == NULL) Index: sed-4.1.5/lib/utils.c =================================================================== --- sed-4.1.5.orig/lib/utils.c +++ sed-4.1.5/lib/utils.c @@ -35,6 +35,13 @@ # include #endif /* HAVE_STDLIB_H */ +#ifdef ENABLE_FOLLOW_SYMLINKS +# include +# include +# include +# include +#endif /* ENABLE_FOLLOW_SYMLINKS */ + #include "utils.h" const char *myname; @@ -315,6 +322,65 @@ do_ck_fclose(fp) } +#ifdef ENABLE_FOLLOW_SYMLINKS +static char buf[2048], buf2[2048]; +static size_t bufsize = sizeof (buf); + +/* Follow symlink and panic if something fails. Returned value is + ultimate symlink target, stored in temporary buffer. You need to + strdup the return value, if you intend to use it later.*/ +const char * +ck_follow_symlink(const char * fname) +{ + static struct stat statbuf; + int err; + char * dir; + + if (strlen (fname) >= bufsize) + panic("ck_follow_symlink: file name too long"); + strcpy (buf, fname); + + while (1) + { + err = lstat (buf, &statbuf); + + if (err != 0) + panic("ck_follow_symlink: couldn't lstat %s: %s", buf, strerror(errno)); + + if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) + { + err = readlink (buf, buf2, bufsize); + + if (err < 0) + panic("ck_follow_symlink: readlink failed on %s: %s", buf, strerror(errno)); + else if (err == bufsize) + panic("ck_follow_symlink: pointee name too long"); + else + buf2 [err] = '\0'; + + /* need to handle relative paths with care */ + if (buf2[0] != '/') + { + dir = dirname (buf); // dir part of orig path + int len = strlen (dir); // orig path len + buf[len] = '/'; + strncpy (buf+len+1, buf2, bufsize - len - 1); + if (buf[bufsize-1] != 0) + panic("ck_follow_symlink: pointee name too long"); + } + else + { + strcpy (buf, buf2); + } + } + else + break; + } + + return buf; +} +#endif /* ENABLE_FOLLOW_SYMLINKS */ + /* Panic on failing rename */ void ck_rename (from, to, unlink_if_fail) Index: sed-4.1.5/lib/utils.h =================================================================== --- sed-4.1.5.orig/lib/utils.h +++ sed-4.1.5/lib/utils.h @@ -27,6 +27,9 @@ void ck_fwrite P_((const VOID *ptr, size size_t ck_fread P_((VOID *ptr, size_t size, size_t nmemb, FILE *stream)); void ck_fflush P_((FILE *stream)); void ck_fclose P_((FILE *stream)); +#ifdef ENABLE_FOLLOW_SYMLINKS +const char *ck_follow_symlink P_((const char *path)); +#endif size_t ck_getline P_((char **text, size_t *buflen, FILE *stream)); FILE * ck_mkstemp P_((char **p_filename, char *tmpdir, char *base)); void ck_rename P_((const char *from, const char *to, const char *unlink_if_fail)); Index: sed-4.1.5/sed/execute.c =================================================================== --- sed-4.1.5.orig/sed/execute.c +++ sed-4.1.5/sed/execute.c @@ -711,16 +711,34 @@ closedown(input) if (in_place_extension && output_file.fp != NULL) { +#ifdef ENABLE_FOLLOW_SYMLINKS + char *target_name; + + if (follow_symlinks) + target_name = ck_strdup(ck_follow_symlink(input->in_file_name)); + else + target_name = ck_strdup(input->in_file_name); +#else + const char *target_name; + + target_name = input->in_file_name; +#endif + ck_fclose (output_file.fp); if (strcmp(in_place_extension, "*") != 0) { - char *backup_file_name = get_backup_file_name(input->in_file_name); - ck_rename (input->in_file_name, backup_file_name, input->out_file_name); + char *backup_file_name = get_backup_file_name(target_name); + ck_rename (target_name, backup_file_name, input->out_file_name); + free (backup_file_name); } - ck_rename (input->out_file_name, input->in_file_name, input->out_file_name); + ck_rename (input->out_file_name, target_name, input->out_file_name); + free (input->out_file_name); +#ifdef ENABLE_FOLLOW_SYMLINKS + free (target_name); +#endif } input->fp = NULL; Index: sed-4.1.5/sed/sed.h =================================================================== --- sed-4.1.5.orig/sed/sed.h +++ sed-4.1.5/sed/sed.h @@ -219,6 +219,11 @@ extern bool no_default_output; /* If set, reset line counts on every new file. */ extern bool separate_files; +#ifdef ENABLE_FOLLOW_SYMLINKS +/* If set, follow symlinks when invoked with -i option */ +extern bool follow_symlinks; +#endif + /* Do we need to be pedantically POSIX compliant? */ extern enum posixicity_types posixicity; Index: sed-4.1.5/configure.ac =================================================================== --- sed-4.1.5.orig/configure.ac +++ sed-4.1.5/configure.ac @@ -117,6 +117,13 @@ enable_html=no) AM_CONDITIONAL(BUILD_HTML, test "x$enable_html" != xno) +# follow symlinks +AC_CHECK_FUNC(lstat, have_lstat=yes) +AC_CHECK_FUNC(readlink, have_readlink=yes) +if test "x$have_lstat" = xyes -a "x$have_readlink" = xyes; then + AC_DEFINE(ENABLE_FOLLOW_SYMLINKS, ,[Follow symlinks when processing in place]) +fi + : ${TEXI2HTML=texi2html -monolithic} AC_SUBST(TEXI2HTML)