git: 9front

Download patch

ref: 67651770270a9e9aece68586a9e15e321bfdcbc3
parent: 10a96be1b13426e85d22b4c7457484b94af95e6c
author: taruti <taruti@violetti.org>
date: Mon May 23 09:55:05 EDT 2011

Add ape/cp + ape/mv

--- /dev/null
+++ b/sys/src/ape/cmd/cp.c
@@ -1,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;
+}
--- a/sys/src/ape/cmd/mkfile
+++ b/sys/src/ape/cmd/mkfile
@@ -3,8 +3,10 @@
 
 TARG=basename\
 	cc\
+	cp\
 	dirname\
 	kill\
+	mv\
 	uname
 
 DIRS=\
@@ -50,7 +52,18 @@
 $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
--- /dev/null
+++ b/sys/src/ape/cmd/mv.c
@@ -1,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)
+		;
+}
--