diff options
author | taruti <taruti@violetti.org> | 2011-05-23 13:55:05 +0000 |
---|---|---|
committer | taruti <taruti@violetti.org> | 2011-05-23 13:55:05 +0000 |
commit | e124ba66c58b5811f9ca02b3bbdaae6a0612280e (patch) | |
tree | 0b1732166bd84e594ab44fcd086c9342e3503a06 /sys/src/ape | |
parent | 2f0635a1596622a0edd4db060f50a4065f26883f (diff) |
Add ape/cp + ape/mv
Diffstat (limited to 'sys/src/ape')
-rw-r--r-- | sys/src/ape/cmd/cp.c | 179 | ||||
-rw-r--r-- | sys/src/ape/cmd/mkfile | 17 | ||||
-rw-r--r-- | sys/src/ape/cmd/mv.c | 244 |
3 files changed, 438 insertions, 2 deletions
diff --git a/sys/src/ape/cmd/cp.c b/sys/src/ape/cmd/cp.c new file mode 100644 index 000000000..c62df2d48 --- /dev/null +++ b/sys/src/ape/cmd/cp.c @@ -0,0 +1,179 @@ +#include <u.h> +#include <libc.h> + +#define DEFB (8*1024) + +int failed; +int gflag; +int uflag; +int xflag; +void copy(char *from, char *to, int todir); +int copy1(int fdf, int fdt, char *from, char *to); + +void +main(int argc, char *argv[]) +{ + Dir *dirb; + int todir, i; + + ARGBEGIN { + case 'g': + gflag++; + break; + case 'u': + uflag++; + gflag++; + break; + case 'x': + xflag++; + break; + case 'p': + break; + default: + goto usage; + } ARGEND + + todir=0; + if(argc < 2) + goto usage; + dirb = dirstat(argv[argc-1]); + if(dirb!=nil && (dirb->mode&DMDIR)) + todir=1; + if(argc>2 && !todir){ + fprint(2, "cp: %s not a directory\n", argv[argc-1]); + exits("bad usage"); + } + for(i=0; i<argc-1; i++) + copy(argv[i], argv[argc-1], todir); + if(failed) + exits("errors"); + exits(0); + +usage: + fprint(2, "usage:\tcp [-gux] fromfile tofile\n"); + fprint(2, "\tcp [-x] fromfile ... todir\n"); + exits("usage"); +} + +int +samefile(Dir *a, char *an, char *bn) +{ + Dir *b; + int ret; + + ret = 0; + b=dirstat(bn); + if(b != nil) + if(b->qid.type==a->qid.type) + if(b->qid.path==a->qid.path) + if(b->qid.vers==a->qid.vers) + if(b->dev==a->dev) + if(b->type==a->type){ + fprint(2, "cp: %s and %s are the same file\n", an, bn); + ret = 1; + } + free(b); + return ret; +} + +void +copy(char *from, char *to, int todir) +{ + Dir *dirb, dirt; + char name[256]; + int fdf, fdt, mode; + + if(todir){ + char *s, *elem; + elem=s=from; + while(*s++) + if(s[-1]=='/') + elem=s; + sprint(name, "%s/%s", to, elem); + to=name; + } + + if((dirb=dirstat(from))==nil){ + fprint(2,"cp: can't stat %s: %r\n", from); + failed = 1; + return; + } + mode = dirb->mode; + if(mode&DMDIR){ + fprint(2, "cp: %s is a directory\n", from); + free(dirb); + failed = 1; + return; + } + if(samefile(dirb, from, to)){ + free(dirb); + failed = 1; + return; + } + mode &= 0777; + fdf=open(from, OREAD); + if(fdf<0){ + fprint(2, "cp: can't open %s: %r\n", from); + free(dirb); + failed = 1; + return; + } + fdt=create(to, OWRITE, mode); + if(fdt<0){ + fprint(2, "cp: can't create %s: %r\n", to); + close(fdf); + free(dirb); + failed = 1; + return; + } + if(copy1(fdf, fdt, from, to)==0 && (xflag || gflag || uflag)){ + nulldir(&dirt); + if(xflag){ + dirt.mtime = dirb->mtime; + dirt.mode = dirb->mode; + } + if(uflag) + dirt.uid = dirb->uid; + if(gflag) + dirt.gid = dirb->gid; + if(dirfwstat(fdt, &dirt) < 0) + fprint(2, "cp: warning: can't wstat %s: %r\n", to); + } + free(dirb); + close(fdf); + close(fdt); +} + +int +copy1(int fdf, int fdt, char *from, char *to) +{ + char *buf; + long n, n1, rcount; + int rv; + char err[ERRMAX]; + + buf = malloc(DEFB); + /* clear any residual error */ + err[0] = '\0'; + errstr(err, ERRMAX); + rv = 0; + for(rcount=0;; rcount++) { + n = read(fdf, buf, DEFB); + if(n <= 0) + break; + n1 = write(fdt, buf, n); + if(n1 != n) { + fprint(2, "cp: error writing %s: %r\n", to); + failed = 1; + rv = -1; + break; + } + } + if(n < 0) { + fprint(2, "cp: error reading %s: %r\n", from); + failed = 1; + rv = -1; + } + free(buf); + return rv; +} diff --git a/sys/src/ape/cmd/mkfile b/sys/src/ape/cmd/mkfile index f0e7463c1..ad8b68d3e 100644 --- a/sys/src/ape/cmd/mkfile +++ b/sys/src/ape/cmd/mkfile @@ -3,8 +3,10 @@ APE=/sys/src/ape TARG=basename\ cc\ + cp\ dirname\ kill\ + mv\ uname DIRS=\ @@ -50,7 +52,18 @@ cc.$O: cc.c $O.cc: cc.$O mk -f /sys/src/cmd/mkfile $O.cc +cp.$O: cp.c + mk -f /sys/src/cmd/mkfile cp.$O + +$O.cp: cp.$O + mk -f /sys/src/cmd/mkfile $O.cp + +mv.$O: mv.c + mk -f /sys/src/cmd/mkfile mv.$O + +$O.mv: mv.$O + mk -f /sys/src/cmd/mkfile $O.mv + + install.rc:V: $BIN/psh -$BIN/%: %.rc - cp -x $stem.rc $BIN/$stem diff --git a/sys/src/ape/cmd/mv.c b/sys/src/ape/cmd/mv.c new file mode 100644 index 000000000..14423c149 --- /dev/null +++ b/sys/src/ape/cmd/mv.c @@ -0,0 +1,244 @@ +#include <u.h> +#include <libc.h> + +int copy1(int fdf, int fdt, char *from, char *to); +void hardremove(char *); +int mv(char *from, char *todir, char *toelem); +int mv1(char *from, Dir *dirb, char *todir, char *toelem); +int samefile(char *, char *); +void split(char *, char **, char **); + +void +main(int argc, char *argv[]) +{ + int i, failed; + Dir *dirto, *dirfrom; + char *todir, *toelem; + + if(argc<3){ + fprint(2, "usage: mv fromfile tofile\n"); + fprint(2, " mv fromfile ... todir\n"); + exits("bad usage"); + } + + /* Skip -f */ + if(argv[1][0] == '-' && argv[1][1] == 'f' && argv[1][2] == 0) { + for(i=2; i<argc; i++) { + argv[i-1] = argv[i]; + } + argc--; + } + + /* prepass to canonicalise names before splitting, etc. */ + for(i=1; i < argc; i++) + cleanname(argv[i]); + + if((dirto = dirstat(argv[argc-1])) != nil && (dirto->mode&DMDIR)){ + dirfrom = nil; + if(argc == 3 + && (dirfrom = dirstat(argv[1])) != nil + && (dirfrom->mode & DMDIR)) + split(argv[argc-1], &todir, &toelem); /* mv dir1 dir2 */ + else{ /* mv file... dir */ + todir = argv[argc-1]; + toelem = nil; /* toelem will be fromelem */ + } + free(dirfrom); + }else + split(argv[argc-1], &todir, &toelem); /* mv file1 file2 */ + free(dirto); + if(argc>3 && toelem != nil){ + fprint(2, "mv: %s not a directory\n", argv[argc-1]); + exits("bad usage"); + } + + failed = 0; + for(i=1; i < argc-1; i++) + if(mv(argv[i], todir, toelem) < 0) + failed++; + if(failed) + exits("failure"); + exits(0); +} + +int +mv(char *from, char *todir, char *toelem) +{ + int stat; + Dir *dirb; + + dirb = dirstat(from); + if(dirb == nil){ + fprint(2, "mv: can't stat %s: %r\n", from); + return -1; + } + stat = mv1(from, dirb, todir, toelem); + free(dirb); + return stat; +} + +int +mv1(char *from, Dir *dirb, char *todir, char *toelem) +{ + int fdf, fdt, i, j, stat; + char toname[4096], fromname[4096]; + char *fromdir, *fromelem; + Dir *dirt, null; + + strncpy(fromname, from, sizeof fromname); + split(from, &fromdir, &fromelem); + if(toelem == 0) + toelem = fromelem; + i = strlen(toelem); + if(i==0){ + fprint(2, "mv: null last name element moving %s\n", fromname); + return -1; + } + j = strlen(todir); + if(i + j + 2 > sizeof toname){ + fprint(2, "mv: path too big (max %d): %s/%s\n", + sizeof toname, todir, toelem); + return -1; + } + memmove(toname, todir, j); + toname[j] = '/'; + memmove(toname+j+1, toelem, i); + toname[i+j+1] = 0; + + if(samefile(fromdir, todir)){ + if(samefile(fromname, toname)){ + fprint(2, "mv: %s and %s are the same\n", + fromname, toname); + return -1; + } + + /* remove target if present */ + dirt = dirstat(toname); + if(dirt != nil) { + hardremove(toname); + free(dirt); + } + + /* try wstat */ + nulldir(&null); + null.name = toelem; + if(dirwstat(fromname, &null) >= 0) + return 0; + if(dirb->mode & DMDIR){ + fprint(2, "mv: can't rename directory %s: %r\n", + fromname); + return -1; + } + } + /* + * Renaming won't work --- must copy + */ + if(dirb->mode & DMDIR){ + fprint(2, "mv: %s is a directory, not copied to %s\n", + fromname, toname); + return -1; + } + fdf = open(fromname, OREAD); + if(fdf < 0){ + fprint(2, "mv: can't open %s: %r\n", fromname); + return -1; + } + + dirt = dirstat(toname); + if(dirt != nil && (dirt->mode & DMAPPEND)) + hardremove(toname); /* because create() won't truncate file */ + free(dirt); + + fdt = create(toname, OWRITE, dirb->mode); + if(fdt < 0){ + fprint(2, "mv: can't create %s: %r\n", toname); + close(fdf); + return -1; + } + stat = copy1(fdf, fdt, fromname, toname); + close(fdf); + + if(stat >= 0){ + nulldir(&null); + null.mtime = dirb->mtime; + null.mode = dirb->mode; + dirfwstat(fdt, &null); /* ignore errors; e.g. user none always fails */ + if(remove(fromname) < 0){ + fprint(2, "mv: can't remove %s: %r\n", fromname); + stat = -1; + } + } + close(fdt); + return stat; +} + +int +copy1(int fdf, int fdt, char *from, char *to) +{ + char buf[8192]; + long n, n1; + + while ((n = read(fdf, buf, sizeof buf)) > 0) { + n1 = write(fdt, buf, n); + if(n1 != n){ + fprint(2, "mv: error writing %s: %r\n", to); + return -1; + } + } + if(n < 0){ + fprint(2, "mv: error reading %s: %r\n", from); + return -1; + } + return 0; +} + +void +split(char *name, char **pdir, char **pelem) +{ + char *s; + + s = utfrrune(name, '/'); + if(s){ + *s = 0; + *pelem = s+1; + *pdir = name; + }else if(strcmp(name, "..") == 0){ + *pdir = ".."; + *pelem = "."; + }else{ + *pdir = "."; + *pelem = name; + } +} + +int +samefile(char *a, char *b) +{ + Dir *da, *db; + int ret; + + if(strcmp(a, b) == 0) + return 1; + da = dirstat(a); + db = dirstat(b); + ret = (da != nil && db != nil && + da->qid.type==db->qid.type && + da->qid.path==db->qid.path && + da->qid.vers==db->qid.vers && + da->dev==db->dev && + da->type==db->type); + free(da); + free(db); + return ret; +} + +void +hardremove(char *a) +{ + if(remove(a) == -1){ + fprint(2, "mv: can't remove %s: %r\n", a); + exits("mv"); + } + while(remove(a) != -1) + ; +} |