diff options
Diffstat (limited to 'toys/posix/cp.c')
-rw-r--r-- | toys/posix/cp.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/toys/posix/cp.c b/toys/posix/cp.c index 705c4bfb..8f6ab0e1 100644 --- a/toys/posix/cp.c +++ b/toys/posix/cp.c @@ -91,6 +91,7 @@ int cp_node(struct dirtree *try) if (S_ISDIR(try->st.st_dev)) { error_msg("dir at '%s'", s = dirtree_path(try, 0)); free(s); + return 0; } else if (flags & FLAG_n) return 0; else if (flags & FLAG_i) { fprintf(stderr, "cp: overwrite '%s'", s = dirtree_path(try, 0)); @@ -138,6 +139,33 @@ int cp_node(struct dirtree *try) } else if (flags & FLAG_l) { if (!linkat(tfd, try->name, cfd, catch, 0)) err = 0; + // Copy tree as symlinks. For non-absolute paths this involves + // appending the right number of .. entries as you go down the tree. + + } else if (flags & FLAG_s) { + char *s; + struct dirtree *or; + int dotdots = 0; + + s = dirtree_path(try, 0); + for (or = try; or->parent; or = or->parent) dotdots++; + + if (*or->name == '/') dotdots = 0; + if (dotdots) { + char *s2 = xmsprintf("% *c%s", 3*dotdots, ' ', s); + free(s); + s = s2; + while(dotdots--) { + memcpy(s2, "../", 3); + s2 += 3; + } + } + if (!symlinkat(s, cfd, catch)) { + err = 0; + fdout = AT_FDCWD; + } + free(s); + // Do something _other_ than copy contents of a file? } else if (!S_ISREG(try->st.st_mode) && (try->parent || (flags & (FLAG_a|FLAG_r)))) |