2a2c77d
diff -Burp sed-4.1.5-orig/lib/utils.c sed-4.1.5-follow/lib/utils.c
2a2c77d
--- sed-4.1.5-orig/lib/utils.c	2005-06-21 16:09:40.000000000 +0200
2a2c77d
+++ sed-4.1.5-follow/lib/utils.c	2006-12-07 19:08:02.000000000 +0100
2a2c77d
@@ -35,6 +35,12 @@
2a2c77d
 # include <stdlib.h>
2a2c77d
 #endif /* HAVE_STDLIB_H */
2a2c77d
 
2a2c77d
+#include <sys/types.h>
2a2c77d
+#include <sys/stat.h>
2a2c77d
+#include <unistd.h>
2a2c77d
+#include <sys/sendfile.h>
2a2c77d
+#include <fcntl.h>
2a2c77d
+
2a2c77d
 #include "utils.h"
2a2c77d
 
2a2c77d
 const char *myname;
2a2c77d
@@ -315,32 +321,99 @@ do_ck_fclose(fp)
2a2c77d
 }
2a2c77d
 
2a2c77d
 
2a2c77d
-/* Panic on failing rename */
2a2c77d
-void
2a2c77d
-ck_rename (from, to, unlink_if_fail)
2a2c77d
-  const char *from, *to;
2a2c77d
-  const char *unlink_if_fail;
2a2c77d
+#include <libgen.h>
2a2c77d
+
2a2c77d
+/* Follow symlink and panic if something fails.  Returned value is
2a2c77d
+   ultimate symlink target, stored in malloc'd buffer.*/
2a2c77d
+const char*
2a2c77d
+ck_follow_symlink(const char * fname)
2a2c77d
 {
2a2c77d
-  int rd = rename (from, to);
2a2c77d
-  if (rd != -1)
2a2c77d
-    return;
2a2c77d
+  static struct stat statbuf;
2a2c77d
+  int err;
2a2c77d
+  char * dir;
2a2c77d
+
2a2c77d
+  static size_t bufsize = 1024;
2a2c77d
+  char * buf = malloc (bufsize);
2a2c77d
+  char * buf2 = alloca (bufsize);
2a2c77d
+
2a2c77d
+  if (strlen (fname) >= bufsize)
2a2c77d
+    panic("ck_follow_symlink: file name too long");
2a2c77d
+  strcpy (buf, fname);
2a2c77d
 
2a2c77d
-  if (unlink_if_fail)
2a2c77d
+  while (1)
2a2c77d
     {
2a2c77d
-      int save_errno = errno;
2a2c77d
-      errno = 0;
2a2c77d
-      unlink (unlink_if_fail);
2a2c77d
+      err = lstat (buf, &statbuf);
2a2c77d
+
2a2c77d
+      if (err != 0)
2a2c77d
+	panic("ck_follow_symlink: couldn't lstat %s: %s", buf, strerror(errno));
2a2c77d
 
2a2c77d
-      /* Failure to remove the temporary file is more severe, so trigger it first.  */
2a2c77d
-      if (errno != 0)
2a2c77d
-        panic (_("cannot remove %s: %s"), unlink_if_fail, strerror (errno));
2a2c77d
+      if ((statbuf.st_mode & S_IFLNK) == S_IFLNK)
2a2c77d
+	{
2a2c77d
+	  err = readlink (buf, buf2, bufsize);
2a2c77d
+
2a2c77d
+	  if (err < 0)
2a2c77d
+	    panic("ck_follow_symlink: readlink failed on %s: %s", buf, strerror(errno));
2a2c77d
+	  else if (err == bufsize)
2a2c77d
+	    panic("ck_follow_symlink: pointee name too long");
2a2c77d
+	  else
2a2c77d
+	    buf2 [err] = '\0';
2a2c77d
+
2a2c77d
+	  /* need to handle relative paths with care */
2a2c77d
+	  if (buf2[0] != '/')
2a2c77d
+	    {
2a2c77d
+	      dir = dirname (buf);    // dir part of orig path
2a2c77d
+	      int len = strlen (dir); // orig path len
2a2c77d
+	      buf[len] = '/';
2a2c77d
+	      strncpy (buf+len+1, buf2, bufsize - len - 1);
2a2c77d
+	      if (buf[bufsize-1] != 0)
2a2c77d
+		panic("ck_follow_symlink: pointee name too long");
2a2c77d
+	    }
2a2c77d
+	  else
2a2c77d
+	    {
2a2c77d
+	      strcpy (buf, buf2);
2a2c77d
+	    }
2a2c77d
+	}
2a2c77d
+      else
2a2c77d
+	break;
2a2c77d
+    }
2a2c77d
+
2a2c77d
+  return buf;
2a2c77d
+}
2a2c77d
 
2a2c77d
+/* Panic on failing unlink */
2a2c77d
+void
2a2c77d
+ck_unlink (name)
2a2c77d
+  const char *name;
2a2c77d
+{
2a2c77d
+  if (unlink (name) == -1)
2a2c77d
+    panic (_("cannot remove %s: %s"), name, strerror (errno));
2a2c77d
+}
2a2c77d
+
2a2c77d
+/* Attempt to unlink denoted file if operation rd failed. */
2a2c77d
+static int
2a2c77d
+_unlink_if_fail (rd, unlink_if_fail)
2a2c77d
+  int rd;
2a2c77d
+  const char *unlink_if_fail;
2a2c77d
+{
2a2c77d
+  if (rd == -1 && unlink_if_fail)
2a2c77d
+    {
2a2c77d
+      int save_errno = errno;
2a2c77d
+      ck_unlink (unlink_if_fail);
2a2c77d
       errno = save_errno;
2a2c77d
     }
2a2c77d
 
2a2c77d
-  panic (_("cannot rename %s: %s"), from, strerror (errno));
2a2c77d
+  return rd != -1;
2a2c77d
 }
2a2c77d
 
2a2c77d
+/* Panic on failing rename */
2a2c77d
+void
2a2c77d
+ck_rename (from, to, unlink_if_fail)
2a2c77d
+  const char *from, *to;
2a2c77d
+  const char *unlink_if_fail;
2a2c77d
+{
2a2c77d
+  if (!_unlink_if_fail (rename (from, to), unlink_if_fail))
2a2c77d
+  panic (_("cannot rename %s: %s"), from, strerror (errno));
2a2c77d
+}
2a2c77d
 
2a2c77d
 
2a2c77d
 
2a2c77d
diff -Burp sed-4.1.5-orig/lib/utils.h sed-4.1.5-follow/lib/utils.h
2a2c77d
--- sed-4.1.5-orig/lib/utils.h	2005-06-21 16:09:40.000000000 +0200
2a2c77d
+++ sed-4.1.5-follow/lib/utils.h	2006-12-07 19:00:11.000000000 +0100
2a2c77d
@@ -29,6 +29,7 @@ void ck_fflush P_((FILE *stream));
2a2c77d
 void ck_fclose P_((FILE *stream));
2a2c77d
 size_t ck_getline P_((char **text, size_t *buflen, FILE *stream));
2a2c77d
 FILE * ck_mkstemp P_((char **p_filename, char *tmpdir, char *base));
2a2c77d
+const char* ck_follow_symlink P_((const char * fname));
2a2c77d
 void ck_rename P_((const char *from, const char *to, const char *unlink_if_fail));
2a2c77d
 
2a2c77d
 VOID *ck_malloc P_((size_t size));
2a2c77d
--- sed-4.1.5-orig/sed/execute.c	2006-12-08 16:33:20.000000000 +0100
2a2c77d
+++ sed-4.1.5-follow/sed/execute.c	2006-12-07 18:53:11.000000000 +0100
2a2c77d
@@ -712,16 +712,18 @@
2a2c77d
 
2a2c77d
   if (in_place_extension && output_file.fp != NULL)
2a2c77d
     {
2a2c77d
+      char * target_name = ck_strdup (ck_follow_symlink (input->in_file_name));
2a2c77d
       ck_fclose (output_file.fp);
2a2c77d
       if (strcmp(in_place_extension, "*") != 0)
2a2c77d
         {
2a2c77d
+          char *backup_file_name = get_backup_file_name(target_name);
2a2c77d
+	  ck_rename (target_name, backup_file_name, input->out_file_name);
2a2c77d
-          char *backup_file_name = get_backup_file_name(input->in_file_name);
2a2c77d
-	  ck_rename (input->in_file_name, backup_file_name, input->out_file_name);
2a2c77d
           free (backup_file_name);
2a2c77d
 	}
2a2c77d
 
2a2c77d
+      ck_rename (input->out_file_name, target_name, input->out_file_name);
2a2c77d
-      ck_rename (input->out_file_name, input->in_file_name, input->out_file_name);
2a2c77d
       free (input->out_file_name);
2a2c77d
+      free (target_name);
2a2c77d
     }
2a2c77d
 
2a2c77d
   input->fp = NULL;