Upstream-Status: Inappropriate [legacy version]

The install command doesn't over write the dangling symlink, for
example:

$ install fileA /tmp/fileA

If /tmp/fileA is a dangling symlink, there would be an error:

install: cannot create regular file '/tmp/fileA': File exists

This is because of the following code in copy.c:

  if (!new_dst)
    {
      if (XSTAT (x, dst_name, &dst_sb) != 0)
        {
          if (errno != ENOENT)
            {
              error (0, errno, _("cannot stat %s"), quote (dst_name));
              return false;
            }
          else
            {
              new_dst = true;
            }
        }

XSTAT() use stat() for dst_name(the dangling symlink /tmp/fileA) when
install.c invokes it, and stat will set errno to ENOENT, and then
new_dst will be set to true which means that /tmp/fileA doesn't exist,
then we will create /tmp/fileA without remove it first, so the error
comes.

This is fixed in a way which adds the member cmd_install in
struct cp_options to make sure my change only affected to the install
command and use lstat to fix the problem.
    
Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Signed-off-by: Mark Hatle <mark.hatle@windriver.com>

---
 src/copy.c    |   10 +++++++++-
 src/copy.h    |    3 +++
 src/install.c |    1 +
 3 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/src/copy.c b/src/copy.c
--- a/src/copy.c
+++ b/src/copy.c
@@ -1029,6 +1029,7 @@ copy_internal (char const *src_name, char const *dst_name,
   bool delayed_ok;
   bool copied_as_regular = false;
   bool preserve_metadata;
+  int dst_stat_result;
 
   if (x->move_mode && rename_succeeded)
     *rename_succeeded = false;
@@ -1069,7 +1070,14 @@ copy_internal (char const *src_name, char const *dst_name,
 
   if (!new_dst)
     {
-      if (XSTAT (x, dst_name, &dst_sb) != 0)
+      if ( x->cmd_install && ( x->backup_type == no_backups))
+        dst_stat_result = lstat (dst_name, &dst_sb);
+      else
+        {
+          dst_stat_result = XSTAT (x, dst_name, &dst_sb);
+        }
+
+      if (dst_stat_result != 0)
 	{
 	  if (errno != ENOENT)
 	    {
diff --git a/src/copy.h b/src/copy.h
--- a/src/copy.h
+++ b/src/copy.h
@@ -114,6 +114,9 @@ struct cp_options
      If that fails, then resort to copying.  */
   bool move_mode;
 
+  /* For the install command */
+  bool cmd_install;
+
   /* Whether this process has appropriate privileges to chown a file
      whose owner is not the effective user ID.  */
   bool chown_privileges;
diff --git a/src/install.c b/src/install.c
--- a/src/install.c
+++ b/src/install.c
@@ -149,6 +149,7 @@ cp_option_init (struct cp_options *x)
   x->hard_link = false;
   x->interactive = I_UNSPECIFIED;
   x->move_mode = false;
+  x->cmd_install = true;
   x->chown_privileges = chown_privileges ();
   x->one_file_system = false;
   x->preserve_ownership = false;
-- 
1.7.0.1

