aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toys/cp.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/toys/cp.c b/toys/cp.c
index 444fd81f..4809a778 100644
--- a/toys/cp.c
+++ b/toys/cp.c
@@ -7,13 +7,13 @@
* See http://www.opengroup.org/onlinepubs/009695399/utilities/cp.html
*
* "R+ra+d+p+r"
-USE_CP(NEWTOY(cp, "<2rR+rdpa+d+p+rHLPif", TOYFLAG_BIN))
+USE_CP(NEWTOY(cp, "<2slrR+rdpa+d+p+rHLPif", TOYFLAG_BIN))
config CP
bool "cp"
default n
help
- usage: cp -f SOURCE... DEST
+ usage: cp -fpr SOURCE... DEST
Copy files from SOURCE to DEST. If more than one SOURCE, DEST must
be a directory.
@@ -27,15 +27,17 @@ config CP
#include "toys.h"
#define FLAG_f 1
-#define FLAG_i 2
-#define FLAG_P 4
-#define FLAG_L 8
-#define FLAG_H 16
+#define FLAG_i 2 // todo
+#define FLAG_P 4 // todo
+#define FLAG_L 8 // todo
+#define FLAG_H 16 // todo
#define FLAG_a 32
#define FLAG_p 64
-#define FLAG_d 128
+#define FLAG_d 128 // todo
#define FLAG_R 256
#define FLAG_r 512
+#define FLAG_s 1024 // todo
+#define FLAG_l 2048 // todo
DEFINE_GLOBALS(
char *destname;
@@ -47,20 +49,20 @@ DEFINE_GLOBALS(
// Copy an individual file or directory to target.
-void cp_file(char *src, struct stat *srcst, int topdir)
+void cp_file(char *src, struct stat *srcst, int depth)
{
char *s = NULL;
- int fdout;
+ int fdout = -1;
// Trim path from name if necessary.
-
- if (topdir) s = strrchr(src, '/');
- if (!s) s=src;
+ if (!depth) s = strrchr(src, '/');
+ if (s) s++;
+ else s=src;
// Determine location to create new file/directory at.
- if (TT.destisdir || !topdir) s = xmsprintf("%s/%s", TT.destname, s);
+ if (TT.destisdir || depth) s = xmsprintf("%s/%s", TT.destname, s);
else s = xstrdup(TT.destname);
// Copy directory or file to destination.
@@ -80,6 +82,16 @@ void cp_file(char *src, struct stat *srcst, int topdir)
{
perror_exit("mkdir '%s'", s);
}
+ } else if ((depth || (toys.optflags & FLAG_d)) && S_ISLNK(srcst->st_mode)) {
+ struct stat st2;
+ char *link = xreadlink(src);
+
+ // Note: -p currently has no effect on symlinks. How do you get a
+ // filehandle to them? O_NOFOLLOW causes the open to fail.
+ if (!link || symlink(link, s)) perror_msg("link '%s'",s);
+ free(link);
+ } else if (toys.optflags & FLAG_l) {
+ if (link(src, s)) perror_msg("link '%s'");
} else {
int fdin, i;
@@ -117,18 +129,20 @@ int cp_node(char *path, struct dirtree *node)
{
char *s = path+strlen(path);
struct dirtree *n = node;
+ int depth = 0;
// Find appropriate chunk of path for destination.
for (;;) {
if (*(--s) == '/') {
+ depth++;
if (!n->parent) break;
n = n->parent;
}
}
s++;
- cp_file(s, &(node->st), 0);
+ cp_file(s, &(node->st), depth);
return 0;
}
@@ -173,12 +187,12 @@ void cp_main(void)
if (S_ISDIR(st.st_mode)) {
if (toys.optflags & FLAG_r) {
- cp_file(src, &st, 1);
+ cp_file(src, &st, 0);
strncpy(toybuf, src, sizeof(toybuf)-1);
toybuf[sizeof(toybuf)-1]=0;
dirtree_read(toybuf, NULL, cp_node);
} else error_msg("Skipped dir '%s'", src);
- } else cp_file(src, &st, 1);
+ } else cp_file(src, &st, 0);
}
return;