Subject: bin/30624: cp(1) strips too many trailing slashes
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <rillig@NetBSD.org>
List: netbsd-bugs
Date: 06/28/2005 16:51:00
>Number: 30624
>Category: bin
>Synopsis: cp(1) strips too many trailing slashes
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Jun 28 16:51:00 +0000 2005
>Originator: rillig@NetBSD.org
>Release: NetBSD 3.99.4
>Organization:
>Environment:
>Description:
touch foo
/bin/cp foo bar/
These commands copy the foo file into the bar file, although
according to SUSv3, the string "bar/" should have been
interpreted like "bar/.".
>Fix:
Index: cp.c
===================================================================
RCS file: /cvsroot/src/bin/cp/cp.c,v
retrieving revision 1.36
diff -u -p -r1.36 cp.c
--- cp.c 26 Jun 2005 19:10:48 -0000 1.36
+++ cp.c 28 Jun 2005 16:45:15 -0000
@@ -76,13 +76,8 @@ __RCSID("$NetBSD: cp.c,v 1.36 2005/06/26
#include "extern.h"
-#define STRIP_TRAILING_SLASH(p) { \
- while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \
- *--(p).p_end = '\0'; \
-}
-
static char empty[] = "";
-PATH_T to = { to.p_path, empty };
+PATH_T to = { to.p_path, empty, "" };
uid_t myuid;
int Rflag, fflag, iflag, pflag, rflag, vflag;
@@ -93,6 +88,7 @@ enum op { FILE_TO_FILE, FILE_TO_DIR, DIR
int main(int, char *[]);
int copy(char *[], enum op, int);
int mastercmp(const FTSENT **, const FTSENT **);
+static void strip_trailing_slash(PATH_T *);
int
main(int argc, char *argv[])
@@ -195,7 +191,7 @@ main(int argc, char *argv[])
*to.p_end++ = '.';
*to.p_end = 0;
}
- STRIP_TRAILING_SLASH(to);
+ strip_trailing_slash(&to);
to.target_end = to.p_end;
/* Set end of argument list for fts(3). */
@@ -347,7 +343,7 @@ copy(char *argv[], enum op type, int fts
(void)strncat(tmp, p, nlen);
to.p_end = tmp + nlen;
*to.p_end = 0;
- STRIP_TRAILING_SLASH(to);
+ strip_trailing_slash(&to);
}
/* Not an error but need to remember it happened */
@@ -503,3 +499,16 @@ mastercmp(const FTSENT **a, const FTSENT
return (1);
return (0);
}
+
+static void
+strip_trailing_slash(PATH_T *p)
+{
+ struct stat st;
+
+ /* only strip the path for existing directories */
+ if (stat(p->p_path, &st) == -1 || !S_ISDIR(st.st_mode))
+ return;
+
+ while (p->p_end > p->p_path + 1 && p->p_end[-1] == '/')
+ *--(p->p_end) = '\0';
+}