cp: add -a, -d, -p

This commit is contained in:
Hiltjo Posthuma 2014-07-09 21:28:43 +00:00 committed by sin
parent 8e8d8ff242
commit 8b3a9c1971
4 changed files with 97 additions and 30 deletions

12
cp.1
View File

@ -8,7 +8,7 @@ cp \- copy files and directories
.RI [ name ] .RI [ name ]
.P .P
.B cp .B cp
.RB [ \-Rr ] .RB [ \-adpRr ]
.RI [ file ...] .RI [ file ...]
.RI [ directory ] .RI [ directory ]
.SH DESCRIPTION .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. they will be copied into the given directory.
.SH OPTIONS .SH OPTIONS
.TP .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 .B \-f
if an existing destination file cannot be opened, remove it and try again. if an existing destination file cannot be opened, remove it and try again.
.TP .TP

14
cp.c
View File

@ -8,7 +8,7 @@
static void static void
usage(void) usage(void)
{ {
eprintf("usage: %s [-fRr] source... dest\n", argv0); eprintf("usage: %s [-adfpRr] source... dest\n", argv0);
} }
int int
@ -17,6 +17,18 @@ main(int argc, char *argv[])
struct stat st; struct stat st;
ARGBEGIN { 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': case 'f':
cp_fflag = true; cp_fflag = true;
break; break;

4
fs.h
View File

@ -1,8 +1,12 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
#include <stdbool.h> #include <stdbool.h>
extern bool cp_aflag;
extern bool cp_dflag;
extern bool cp_fflag; extern bool cp_fflag;
extern bool cp_pflag;
extern bool cp_rflag; extern bool cp_rflag;
extern bool rm_fflag; extern bool rm_fflag;
extern bool rm_rflag; extern bool rm_rflag;

View File

@ -7,12 +7,18 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <utime.h>
#include "../fs.h" #include "../fs.h"
#include "../text.h" #include "../text.h"
#include "../util.h" #include "../util.h"
bool cp_aflag = false;
bool cp_dflag = false;
bool cp_fflag = false; bool cp_fflag = false;
bool cp_pflag = false;
bool cp_rflag = false; bool cp_rflag = false;
int int
@ -23,42 +29,65 @@ cp(const char *s1, const char *s2)
long size1, size2; long size1, size2;
struct dirent *d; struct dirent *d;
struct stat st; struct stat st;
struct utimbuf ut;
char buf[PATH_MAX];
DIR *dp; DIR *dp;
int r; int r;
if (stat(s1, &st) == 0 && S_ISDIR(st.st_mode)) { if(cp_dflag == true)
if (!cp_rflag) r = lstat(s1, &st);
eprintf("%s: is a directory\n", s1); else
r = stat(s1, &st);
if(!(dp = opendir(s1))) if(r == 0) {
eprintf("opendir %s:", s1); 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) /* preserve owner ? */
eprintf("mkdir %s:", s2); if(cp_aflag == true || cp_pflag == true) {
if(lchown(s2, st.st_uid, st.st_gid) == -1)
apathmax(&ns1, &size1); weprintf("cp: can't preserve ownership of '%s':", s2);
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);
} }
return 0;
} }
if(S_ISDIR(st.st_mode)) {
if (!cp_rflag)
eprintf("%s: is a directory\n", s1);
closedir(dp); if(!(dp = opendir(s1)))
free(ns1); eprintf("opendir %s:", s1);
free(ns2);
return 0; 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);
}
}
closedir(dp);
free(ns1);
free(ns2);
goto preserve;
return 0;
}
} }
if(!(f1 = fopen(s1, "r"))) if(!(f1 = fopen(s1, "r")))
eprintf("fopen %s:", s1); eprintf("fopen %s:", s1);
@ -78,5 +107,17 @@ cp(const char *s1, const char *s2)
fclose(f2); fclose(f2);
fclose(f1); 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; return 0;
} }