xref: /plan9/sys/src/cmd/mv.c (revision ee17ab8015e4a168cf53c39988aec397b589220f)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier int	copy1(int fdf, int fdt, char *from, char *to);
5219b2ee8SDavid du Colombier void	hardremove(char *);
6*ee17ab80SDavid du Colombier int	mv(char *from, char *todir, char *toelem);
7*ee17ab80SDavid du Colombier int	mv1(char *from, Dir *dirb, char *todir, char *toelem);
8*ee17ab80SDavid du Colombier int	samefile(char *, char *);
9*ee17ab80SDavid du Colombier void	split(char *, char **, char **);
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier void
main(int argc,char * argv[])123e12c5d1SDavid du Colombier main(int argc, char *argv[])
133e12c5d1SDavid du Colombier {
14*ee17ab80SDavid du Colombier 	int i, failed;
159a747e4fSDavid du Colombier 	Dir *dirto, *dirfrom;
163e12c5d1SDavid du Colombier 	char *todir, *toelem;
173e12c5d1SDavid du Colombier 
183e12c5d1SDavid du Colombier 	if(argc<3){
193e12c5d1SDavid du Colombier 		fprint(2, "usage: mv fromfile tofile\n");
203e12c5d1SDavid du Colombier 		fprint(2, "	  mv fromfile ... todir\n");
213e12c5d1SDavid du Colombier 		exits("bad usage");
223e12c5d1SDavid du Colombier 	}
23*ee17ab80SDavid du Colombier 
24*ee17ab80SDavid du Colombier 	/* prepass to canonicalise names before splitting, etc. */
25*ee17ab80SDavid du Colombier 	for(i=1; i < argc; i++)
26*ee17ab80SDavid du Colombier 		cleanname(argv[i]);
27*ee17ab80SDavid du Colombier 
289a747e4fSDavid du Colombier 	if((dirto = dirstat(argv[argc-1])) != nil && (dirto->mode&DMDIR)){
29*ee17ab80SDavid du Colombier 		dirfrom = nil;
309a747e4fSDavid du Colombier 		if(argc == 3
319a747e4fSDavid du Colombier 		&& (dirfrom = dirstat(argv[1])) != nil
329a747e4fSDavid du Colombier 		&& (dirfrom->mode & DMDIR))
33*ee17ab80SDavid du Colombier 			split(argv[argc-1], &todir, &toelem); /* mv dir1 dir2 */
34*ee17ab80SDavid du Colombier 		else{				/* mv file... dir */
353e12c5d1SDavid du Colombier 			todir = argv[argc-1];
36*ee17ab80SDavid du Colombier 			toelem = nil;		/* toelem will be fromelem */
373e12c5d1SDavid du Colombier 		}
38*ee17ab80SDavid du Colombier 		free(dirfrom);
393e12c5d1SDavid du Colombier 	}else
40*ee17ab80SDavid du Colombier 		split(argv[argc-1], &todir, &toelem);	/* mv file1 file2 */
41*ee17ab80SDavid du Colombier 	free(dirto);
42*ee17ab80SDavid du Colombier 	if(argc>3 && toelem != nil){
433e12c5d1SDavid du Colombier 		fprint(2, "mv: %s not a directory\n", argv[argc-1]);
443e12c5d1SDavid du Colombier 		exits("bad usage");
453e12c5d1SDavid du Colombier 	}
46*ee17ab80SDavid du Colombier 
477dd7cddfSDavid du Colombier 	failed = 0;
483e12c5d1SDavid du Colombier 	for(i=1; i < argc-1; i++)
493e12c5d1SDavid du Colombier 		if(mv(argv[i], todir, toelem) < 0)
507dd7cddfSDavid du Colombier 			failed++;
517dd7cddfSDavid du Colombier 	if(failed)
523e12c5d1SDavid du Colombier 		exits("failure");
533e12c5d1SDavid du Colombier 	exits(0);
543e12c5d1SDavid du Colombier }
553e12c5d1SDavid du Colombier 
563e12c5d1SDavid du Colombier int
mv(char * from,char * todir,char * toelem)573e12c5d1SDavid du Colombier mv(char *from, char *todir, char *toelem)
583e12c5d1SDavid du Colombier {
593e12c5d1SDavid du Colombier 	int stat;
60*ee17ab80SDavid du Colombier 	Dir *dirb;
613e12c5d1SDavid du Colombier 
629a747e4fSDavid du Colombier 	dirb = dirstat(from);
639a747e4fSDavid du Colombier 	if(dirb == nil){
649a747e4fSDavid du Colombier 		fprint(2, "mv: can't stat %s: %r\n", from);
653e12c5d1SDavid du Colombier 		return -1;
663e12c5d1SDavid du Colombier 	}
67*ee17ab80SDavid du Colombier 	stat = mv1(from, dirb, todir, toelem);
68*ee17ab80SDavid du Colombier 	free(dirb);
69*ee17ab80SDavid du Colombier 	return stat;
70*ee17ab80SDavid du Colombier }
71*ee17ab80SDavid du Colombier 
72*ee17ab80SDavid du Colombier int
mv1(char * from,Dir * dirb,char * todir,char * toelem)73*ee17ab80SDavid du Colombier mv1(char *from, Dir *dirb, char *todir, char *toelem)
74*ee17ab80SDavid du Colombier {
75*ee17ab80SDavid du Colombier 	int fdf, fdt, i, j, stat;
76*ee17ab80SDavid du Colombier 	char toname[4096], fromname[4096];
77*ee17ab80SDavid du Colombier 	char *fromdir, *fromelem;
78*ee17ab80SDavid du Colombier 	Dir *dirt, null;
79*ee17ab80SDavid du Colombier 
803e12c5d1SDavid du Colombier 	strncpy(fromname, from, sizeof fromname);
813e12c5d1SDavid du Colombier 	split(from, &fromdir, &fromelem);
823e12c5d1SDavid du Colombier 	if(toelem == 0)
833e12c5d1SDavid du Colombier 		toelem = fromelem;
843e12c5d1SDavid du Colombier 	i = strlen(toelem);
853e12c5d1SDavid du Colombier 	if(i==0){
863e12c5d1SDavid du Colombier 		fprint(2, "mv: null last name element moving %s\n", fromname);
873e12c5d1SDavid du Colombier 		return -1;
883e12c5d1SDavid du Colombier 	}
893e12c5d1SDavid du Colombier 	j = strlen(todir);
903e12c5d1SDavid du Colombier 	if(i + j + 2 > sizeof toname){
91*ee17ab80SDavid du Colombier 		fprint(2, "mv: path too big (max %d): %s/%s\n",
92*ee17ab80SDavid du Colombier 			sizeof toname, todir, toelem);
933e12c5d1SDavid du Colombier 		return -1;
943e12c5d1SDavid du Colombier 	}
953e12c5d1SDavid du Colombier 	memmove(toname, todir, j);
963e12c5d1SDavid du Colombier 	toname[j] = '/';
973e12c5d1SDavid du Colombier 	memmove(toname+j+1, toelem, i);
983e12c5d1SDavid du Colombier 	toname[i+j+1] = 0;
99*ee17ab80SDavid du Colombier 
1003e12c5d1SDavid du Colombier 	if(samefile(fromdir, todir)){
1013e12c5d1SDavid du Colombier 		if(samefile(fromname, toname)){
102*ee17ab80SDavid du Colombier 			fprint(2, "mv: %s and %s are the same\n",
103*ee17ab80SDavid du Colombier 				fromname, toname);
1043e12c5d1SDavid du Colombier 			return -1;
1053e12c5d1SDavid du Colombier 		}
106*ee17ab80SDavid du Colombier 
107*ee17ab80SDavid du Colombier 		/* remove target if present */
1089a747e4fSDavid du Colombier 		dirt = dirstat(toname);
1099a747e4fSDavid du Colombier 		if(dirt != nil) {
110219b2ee8SDavid du Colombier 			hardremove(toname);
111*ee17ab80SDavid du Colombier 			free(dirt);
1129a747e4fSDavid du Colombier 		}
113*ee17ab80SDavid du Colombier 
114*ee17ab80SDavid du Colombier 		/* try wstat */
1159a747e4fSDavid du Colombier 		nulldir(&null);
1169a747e4fSDavid du Colombier 		null.name = toelem;
1179a747e4fSDavid du Colombier 		if(dirwstat(fromname, &null) >= 0)
1183e12c5d1SDavid du Colombier 			return 0;
1199a747e4fSDavid du Colombier 		if(dirb->mode & DMDIR){
120*ee17ab80SDavid du Colombier 			fprint(2, "mv: can't rename directory %s: %r\n",
121*ee17ab80SDavid du Colombier 				fromname);
1223e12c5d1SDavid du Colombier 			return -1;
1233e12c5d1SDavid du Colombier 		}
1243e12c5d1SDavid du Colombier 	}
1253e12c5d1SDavid du Colombier 	/*
1269a747e4fSDavid du Colombier 	 * Renaming won't work --- must copy
1273e12c5d1SDavid du Colombier 	 */
1289a747e4fSDavid du Colombier 	if(dirb->mode & DMDIR){
129*ee17ab80SDavid du Colombier 		fprint(2, "mv: %s is a directory, not copied to %s\n",
130*ee17ab80SDavid du Colombier 			fromname, toname);
1313e12c5d1SDavid du Colombier 		return -1;
1323e12c5d1SDavid du Colombier 	}
1333e12c5d1SDavid du Colombier 	fdf = open(fromname, OREAD);
1343e12c5d1SDavid du Colombier 	if(fdf < 0){
1359a747e4fSDavid du Colombier 		fprint(2, "mv: can't open %s: %r\n", fromname);
1363e12c5d1SDavid du Colombier 		return -1;
1373e12c5d1SDavid du Colombier 	}
138*ee17ab80SDavid du Colombier 
1399a747e4fSDavid du Colombier 	dirt = dirstat(toname);
1409a747e4fSDavid du Colombier 	if(dirt != nil && (dirt->mode & DMAPPEND))
141219b2ee8SDavid du Colombier 		hardremove(toname);  /* because create() won't truncate file */
1429a747e4fSDavid du Colombier 	free(dirt);
143*ee17ab80SDavid du Colombier 
1449a747e4fSDavid du Colombier 	fdt = create(toname, OWRITE, dirb->mode);
1453e12c5d1SDavid du Colombier 	if(fdt < 0){
1469a747e4fSDavid du Colombier 		fprint(2, "mv: can't create %s: %r\n", toname);
1473e12c5d1SDavid du Colombier 		close(fdf);
1483e12c5d1SDavid du Colombier 		return -1;
1493e12c5d1SDavid du Colombier 	}
150766ccd67SDavid du Colombier 	stat = copy1(fdf, fdt, fromname, toname);
151766ccd67SDavid du Colombier 	close(fdf);
152*ee17ab80SDavid du Colombier 
153766ccd67SDavid du Colombier 	if(stat >= 0){
1549a747e4fSDavid du Colombier 		nulldir(&null);
1559a747e4fSDavid du Colombier 		null.mtime = dirb->mtime;
1569a747e4fSDavid du Colombier 		null.mode = dirb->mode;
1579a747e4fSDavid du Colombier 		dirfwstat(fdt, &null);	/* ignore errors; e.g. user none always fails */
1583e12c5d1SDavid du Colombier 		if(remove(fromname) < 0){
1599a747e4fSDavid du Colombier 			fprint(2, "mv: can't remove %s: %r\n", fromname);
160766ccd67SDavid du Colombier 			stat = -1;
1613e12c5d1SDavid du Colombier 		}
1629a747e4fSDavid du Colombier 	}
1633e12c5d1SDavid du Colombier 	close(fdt);
1643e12c5d1SDavid du Colombier 	return stat;
1653e12c5d1SDavid du Colombier }
1663e12c5d1SDavid du Colombier 
1673e12c5d1SDavid du Colombier int
copy1(int fdf,int fdt,char * from,char * to)1683e12c5d1SDavid du Colombier copy1(int fdf, int fdt, char *from, char *to)
1693e12c5d1SDavid du Colombier {
1703e12c5d1SDavid du Colombier 	char buf[8192];
1713e12c5d1SDavid du Colombier 	long n, n1;
1723e12c5d1SDavid du Colombier 
173*ee17ab80SDavid du Colombier 	while ((n = read(fdf, buf, sizeof buf)) > 0) {
1743e12c5d1SDavid du Colombier 		n1 = write(fdt, buf, n);
1753e12c5d1SDavid du Colombier 		if(n1 != n){
1769a747e4fSDavid du Colombier 			fprint(2, "mv: error writing %s: %r\n", to);
1773e12c5d1SDavid du Colombier 			return -1;
1783e12c5d1SDavid du Colombier 		}
1793e12c5d1SDavid du Colombier 	}
1803e12c5d1SDavid du Colombier 	if(n < 0){
1819a747e4fSDavid du Colombier 		fprint(2, "mv: error reading %s: %r\n", from);
1823e12c5d1SDavid du Colombier 		return -1;
1833e12c5d1SDavid du Colombier 	}
1843e12c5d1SDavid du Colombier 	return 0;
1853e12c5d1SDavid du Colombier }
1863e12c5d1SDavid du Colombier 
1873e12c5d1SDavid du Colombier void
split(char * name,char ** pdir,char ** pelem)1883e12c5d1SDavid du Colombier split(char *name, char **pdir, char **pelem)
1893e12c5d1SDavid du Colombier {
1903e12c5d1SDavid du Colombier 	char *s;
1913e12c5d1SDavid du Colombier 
1923e12c5d1SDavid du Colombier 	s = utfrrune(name, '/');
1933e12c5d1SDavid du Colombier 	if(s){
1943e12c5d1SDavid du Colombier 		*s = 0;
1953e12c5d1SDavid du Colombier 		*pelem = s+1;
1963e12c5d1SDavid du Colombier 		*pdir = name;
197219b2ee8SDavid du Colombier 	}else if(strcmp(name, "..") == 0){
198219b2ee8SDavid du Colombier 		*pdir = "..";
199219b2ee8SDavid du Colombier 		*pelem = ".";
2003e12c5d1SDavid du Colombier 	}else{
2013e12c5d1SDavid du Colombier 		*pdir = ".";
2023e12c5d1SDavid du Colombier 		*pelem = name;
2033e12c5d1SDavid du Colombier 	}
2043e12c5d1SDavid du Colombier }
2053e12c5d1SDavid du Colombier 
2063e12c5d1SDavid du Colombier int
samefile(char * a,char * b)2073e12c5d1SDavid du Colombier samefile(char *a, char *b)
2083e12c5d1SDavid du Colombier {
2099a747e4fSDavid du Colombier 	Dir *da, *db;
2109a747e4fSDavid du Colombier 	int ret;
2113e12c5d1SDavid du Colombier 
2123e12c5d1SDavid du Colombier 	if(strcmp(a, b) == 0)
2133e12c5d1SDavid du Colombier 		return 1;
2149a747e4fSDavid du Colombier 	da = dirstat(a);
2159a747e4fSDavid du Colombier 	db = dirstat(b);
216*ee17ab80SDavid du Colombier 	ret = (da != nil && db != nil &&
217*ee17ab80SDavid du Colombier 		da->qid.type==db->qid.type &&
218*ee17ab80SDavid du Colombier 		da->qid.path==db->qid.path &&
219*ee17ab80SDavid du Colombier 		da->qid.vers==db->qid.vers &&
220*ee17ab80SDavid du Colombier 		da->dev==db->dev &&
221*ee17ab80SDavid du Colombier 		da->type==db->type);
2229a747e4fSDavid du Colombier 	free(da);
2239a747e4fSDavid du Colombier 	free(db);
2249a747e4fSDavid du Colombier 	return ret;
2253e12c5d1SDavid du Colombier }
2263e12c5d1SDavid du Colombier 
227219b2ee8SDavid du Colombier void
hardremove(char * a)228219b2ee8SDavid du Colombier hardremove(char *a)
229219b2ee8SDavid du Colombier {
230219b2ee8SDavid du Colombier 	if(remove(a) == -1){
2319a747e4fSDavid du Colombier 		fprint(2, "mv: can't remove %s: %r\n", a);
232219b2ee8SDavid du Colombier 		exits("mv");
233219b2ee8SDavid du Colombier 	}
234*ee17ab80SDavid du Colombier 	while(remove(a) != -1)
235*ee17ab80SDavid du Colombier 		;
236219b2ee8SDavid du Colombier }
237