summaryrefslogtreecommitdiff
path: root/src/cp.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1996-07-20 05:24:09 +0000
committerJim Meyering <jim@meyering.net>1996-07-20 05:24:09 +0000
commit5f79c9e91b5748a4dfe072a848573579d4ac839d (patch)
treec5408e2663efbf19178d8f1579cc69fbb31d796c /src/cp.c
parent16c56c7d730046448cd8d4f498c4d82383d9e7b8 (diff)
downloadcoreutils-5f79c9e91b5748a4dfe072a848573579d4ac839d.tar.xz
(path_concat): Rewrite to return new parameter.
(do_copy): Update uses of path_concat to use new parameter. Use that new pointer to compute correct offset for make_path_private. Before, cp --recursive --parents SRC DEST failed when SRC was an absolute file name. E.g., % cd /tmp; rm -rf d f; mkdir d; touch f; cp -PR /tmp/f d cp: tmp: No such file or directory Reported by Horst von Brand vonbrand@sleipnir.valparaiso.cl.
Diffstat (limited to 'src/cp.c')
-rw-r--r--src/cp.c41
1 files changed, 27 insertions, 14 deletions
diff --git a/src/cp.c b/src/cp.c
index 2be3a3a68..fba54affc 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -367,23 +367,33 @@ main (int argc, char **argv)
/* Concatenate two pathname components, DIR and BASE, in newly-allocated
storage and return the result. Be careful that in the result they are
- separated by a slash. That is, if DIR ends with a slash or if BASE
- begins with one, don't add a separating slash. Otherwise, add one. */
+ separated by a slash. That is, if DIR ends with a slash and BASE
+ begins with one, elide one slash at the end of DIR. If DIR doesn't end
+ with a slash and BASE doesn't begin with one, insert a slash between
+ them in the concatenation. Otherwise, simply concatenate DIR and BASE.
+ In any case, if BASE_IN_RESULT is non-NULL, set *BASE_IN_RESULT to point
+ to the copy of BASE in the returned concatenation. */
static char *
-path_concat (const char *dir, const char *base)
+path_concat (const char *dir, const char *base, char **base_in_result)
{
- char *dir_end;
+ char *p;
char *p_concat;
assert (strlen (dir) > 0);
p_concat = xmalloc (strlen (dir) + strlen (base) + 2);
- dir_end = stpcpy (p_concat, dir);
- if (*(dir_end - 1) == '/')
- --dir_end;
- else if (*base == '/')
- ++base;
- stpcpy (stpcpy (dir_end, "/"), base);
+ p = stpcpy (p_concat, dir);
+
+ if (*(p - 1) == '/' && *base == '/')
+ --p;
+ else if (*(p - 1) != '/' && *base != '/')
+ p = stpcpy (p, "/");
+
+ if (base_in_result)
+ *base_in_result = p;
+
+ stpcpy (p, base);
+
return p_concat;
}
@@ -439,6 +449,7 @@ do_copy (int argc, char **argv)
char *dst_path;
int parent_exists = 1; /* True if dirname (dst_path) exists. */
struct dir_attr *attr_list;
+ char *arg_in_concat = NULL;
arg = argv[optind];
@@ -447,13 +458,14 @@ do_copy (int argc, char **argv)
if (flag_path)
{
/* Append all of `arg' to `dest'. */
- dst_path = path_concat (dest, arg);
+ dst_path = path_concat (dest, arg, &arg_in_concat);
/* For --parents, we have to make sure that the directory
dirname (dst_path) exists. We may have to create a few
leading directories. */
parent_exists = !make_path_private (dst_path,
- strlen (dest) + 1, 0700,
+ arg_in_concat - dst_path,
+ 0700,
(flag_verbose
? "%s -> %s\n" : NULL),
&attr_list, &new_dst);
@@ -466,7 +478,7 @@ do_copy (int argc, char **argv)
/* For `cp -R source/.. dest', don't copy into `dest/..'. */
dst_path = (STREQ (ap, "..")
? xstrdup (dest)
- : path_concat (dest, ap));
+ : path_concat (dest, ap, NULL));
}
if (!parent_exists)
@@ -481,7 +493,8 @@ do_copy (int argc, char **argv)
if (flag_path)
{
- ret |= re_protect (dst_path, strlen (dest) + 1, attr_list);
+ ret |= re_protect (dst_path, arg_in_concat - dst_path,
+ attr_list);
}
}