From 5f79c9e91b5748a4dfe072a848573579d4ac839d Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Sat, 20 Jul 1996 05:24:09 +0000 Subject: (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. --- src/cp.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'src') 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); } } -- cgit v1.2.3-70-g09d2