sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit 8b3a9c197109fdfdd399c050e9cca038bfeee00b
parent 8e8d8ff2428879fa055f6ec044ddd305533cd26d
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Wed Jul  9 21:28:43 +0000

cp: add -a, -d, -p

Diffstat:
cp.1 | 12+++++++++++-
cp.c | 14+++++++++++++-
fs.h | 4++++
util/cp.c | 95++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
4 files changed, 96 insertions(+), 29 deletions(-)
diff --git a/cp.1 b/cp.1 @@ -8,7 +8,7 @@ cp \- copy files and directories .RI [ name ] .P .B cp -.RB [ \-Rr ] +.RB [ \-adpRr ] .RI [ file ...] .RI [ directory ] .SH DESCRIPTION @@ -17,6 +17,16 @@ copies a given file, naming it the given name. If multiple files are listed they will be copied into the given directory. .SH OPTIONS .TP +.B \-a +preserve mode, timestamp, links and permissions. +Implies \-d, \-p, \-r. +.TP +.B \-d +don't dereference links. preserve links. +.TP +.B \-p +preserve mode, timestamp, links and permissions. +.TP .B \-f if an existing destination file cannot be opened, remove it and try again. .TP diff --git a/cp.c b/cp.c @@ -8,7 +8,7 @@ static void usage(void) { - eprintf("usage: %s [-fRr] source... dest\n", argv0); + eprintf("usage: %s [-adfpRr] source... dest\n", argv0); } int @@ -17,6 +17,18 @@ main(int argc, char *argv[]) struct stat st; ARGBEGIN { + case 'a': + cp_aflag = true; /* implies -dpr */ + cp_dflag = true; + cp_pflag = true; + cp_rflag = true; + break; + case 'd': + cp_dflag = true; + break; + case 'p': + cp_pflag = true; + break; case 'f': cp_fflag = true; break; diff --git a/fs.h b/fs.h @@ -1,8 +1,12 @@ /* See LICENSE file for copyright and license details. */ #include <stdbool.h> +extern bool cp_aflag; +extern bool cp_dflag; extern bool cp_fflag; +extern bool cp_pflag; extern bool cp_rflag; + extern bool rm_fflag; extern bool rm_rflag; diff --git a/util/cp.c b/util/cp.c @@ -7,12 +7,18 @@ #include <string.h> #include <unistd.h> #include <sys/stat.h> +#include <sys/types.h> +#include <limits.h> +#include <utime.h> #include "../fs.h" #include "../text.h" #include "../util.h" +bool cp_aflag = false; +bool cp_dflag = false; bool cp_fflag = false; +bool cp_pflag = false; bool cp_rflag = false; int @@ -23,42 +29,65 @@ cp(const char *s1, const char *s2) long size1, size2; struct dirent *d; struct stat st; + struct utimbuf ut; + char buf[PATH_MAX]; DIR *dp; int r; - if (stat(s1, &st) == 0 && S_ISDIR(st.st_mode)) { - if (!cp_rflag) - eprintf("%s: is a directory\n", s1); + if(cp_dflag == true) + r = lstat(s1, &st); + else + r = stat(s1, &st); - if(!(dp = opendir(s1))) - eprintf("opendir %s:", s1); + if(r == 0) { + if(cp_dflag == true && S_ISLNK(st.st_mode)) { + if(cp_fflag == true) + remove(s2); + if(readlink(s1, buf, sizeof(buf) - 1) >= 0) + symlink(buf, s2); - if (mkdir(s2, st.st_mode) == -1 && errno != EEXIST) - eprintf("mkdir %s:", s2); + /* preserve owner ? */ + if(cp_aflag == true || cp_pflag == true) { + if(lchown(s2, st.st_uid, st.st_gid) == -1) + weprintf("cp: can't preserve ownership of '%s':", s2); + } + return 0; + } + if(S_ISDIR(st.st_mode)) { + if (!cp_rflag) + eprintf("%s: is a directory\n", s1); - apathmax(&ns1, &size1); - apathmax(&ns2, &size2); - while((d = readdir(dp))) { - if(strcmp(d->d_name, ".") - && strcmp(d->d_name, "..")) { - r = snprintf(ns1, size1, "%s/%s", s1, d->d_name); - if(r >= size1 || r < 0) { - eprintf("%s/%s: filename too long\n", - s1, d->d_name); - } - r = snprintf(ns2, size2, "%s/%s", s2, d->d_name); - if(r >= size2 || r < 0) { - eprintf("%s/%s: filename too long\n", - s2, d->d_name); + if(!(dp = opendir(s1))) + eprintf("opendir %s:", s1); + + if (mkdir(s2, st.st_mode) == -1 && errno != EEXIST) + eprintf("mkdir %s:", s2); + + apathmax(&ns1, &size1); + apathmax(&ns2, &size2); + while((d = readdir(dp))) { + if(strcmp(d->d_name, ".") + && strcmp(d->d_name, "..")) { + r = snprintf(ns1, size1, "%s/%s", s1, d->d_name); + if(r >= size1 || r < 0) { + eprintf("%s/%s: filename too long\n", + s1, d->d_name); + } + r = snprintf(ns2, size2, "%s/%s", s2, d->d_name); + if(r >= size2 || r < 0) { + eprintf("%s/%s: filename too long\n", + s2, d->d_name); + } + fnck(ns1, ns2, cp); } - fnck(ns1, ns2, cp); } - } - closedir(dp); - free(ns1); - free(ns2); - return 0; + closedir(dp); + free(ns1); + free(ns2); + goto preserve; + return 0; + } } if(!(f1 = fopen(s1, "r"))) eprintf("fopen %s:", s1); @@ -78,5 +107,17 @@ cp(const char *s1, const char *s2) fclose(f2); fclose(f1); +preserve: + if(cp_aflag == true || cp_pflag == true) { + /* timestamp */ + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + utime(s2, &ut); + + /* preserve owner ? */ + if(chown(s2, st.st_uid, st.st_gid) == -1) + weprintf("cp: can't preserve ownership of '%s':", s2); + } + return 0; }