xref: /plan9-contrib/sys/src/cmd/mv.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 
4 void	split(char *, char **, char **);
5 int	samefile(char *, char *);
6 int	mv(char *from, char *todir, char *toelem);
7 int	copy1(int fdf, int fdt, char *from, char *to);
8 void	hardremove(char *);
9 
10 void
11 main(int argc, char *argv[])
12 {
13 	int i;
14 	Dir dirto, dirfrom;
15 	char *todir, *toelem;
16 
17 	if(argc<3){
18 		fprint(2, "usage: mv fromfile tofile\n");
19 		fprint(2, "	  mv fromfile ... todir\n");
20 		exits("bad usage");
21 	}
22 	if(dirstat(argv[argc-1], &dirto) >= 0 && (dirto.mode&CHDIR)){
23 		if(argc == 3 && dirstat(argv[1], &dirfrom) >= 0 &&
24 				(dirfrom.mode&CHDIR)){
25 			split(argv[argc-1], &todir, &toelem);
26 		}else{
27 			todir = argv[argc-1];
28 			toelem = 0;	/* toelem will be fromelem */
29 		}
30 	}else
31 		split(argv[argc-1], &todir, &toelem);
32 	if(argc>3 && toelem != 0){
33 		fprint(2, "mv: %s not a directory\n", argv[argc-1]);
34 		exits("bad usage");
35 	}
36 	for(i=1; i < argc-1; i++)
37 		if (mv(argv[i], todir, toelem) < 0)
38 			exits("failure");
39 	exits(0);
40 }
41 
42 int
43 mv(char *from, char *todir, char *toelem)
44 {
45 	Dir dirb, dirt;
46 	char toname[1024], fromname[1024];
47 	int fdf, fdt, i, j;
48 	int stat;
49 	char *fromdir, *fromelem;
50 
51 	if(dirstat(from, &dirb)!=0){
52 		fprint(2, "mv: can't stat %s: ", from);
53 		perror("");
54 		return -1;
55 	}
56 	strncpy(fromname, from, sizeof fromname);
57 	split(from, &fromdir, &fromelem);
58 	if(toelem == 0)
59 		toelem = fromelem;
60 	i = strlen(toelem);
61 	if(i==0){
62 		fprint(2, "mv: null last name element moving %s\n", fromname);
63 		return -1;
64 	}
65 	if(i >= NAMELEN){
66 		fprint(2, "mv: name too big: %s\n", toelem);
67 		return -1;
68 	}
69 	j = strlen(todir);
70 	if(i + j + 2 > sizeof toname){
71 		fprint(2, "mv: path too big: %s/%s\n", todir, toelem);
72 		return -1;
73 	}
74 	memmove(toname, todir, j);
75 	toname[j] = '/';
76 	memmove(toname+j+1, toelem, i);
77 	toname[i+j+1] = 0;
78 	if(samefile(fromdir, todir)){
79 		if(samefile(fromname, toname)){
80 			fprint(2, "mv: %s and %s are the same\n", fromname, toname);
81 			return -1;
82 		}
83 		if(dirstat(toname, &dirt) == 0)
84 			hardremove(toname);
85 		strcpy(dirb.name, toelem);
86 		if(dirwstat(fromname, &dirb) >= 0)
87 			return 0;
88 		if(dirb.mode&CHDIR){
89 			fprint(2, "mv: can't rename directory %s: ", fromname);
90 			perror("");
91 			return -1;
92 		}
93 	}
94 	/*
95 	 * Renaming won't work --- have to copy
96 	 */
97 	if(dirb.mode&CHDIR){
98 		fprint(2, "mv: %s is a directory, not copied to %s\n", fromname, toname);
99 		return -1;
100 	}
101 	fdf = open(fromname, OREAD);
102 	if(fdf<0){
103 		fprint(2, "mv: can't open %s:", fromname);
104 		perror("");
105 		return -1;
106 	}
107 	if(dirstat(toname, &dirt)==0 && (dirt.mode&CHAPPEND))
108 		hardremove(toname);	/* because create() won't truncate file */
109 	fdt = create(toname, OWRITE, dirb.mode);
110 	if(fdt < 0){
111 		fprint(2, "mv: can't create %s:", toname);
112 		perror("");
113 		close(fdf);
114 		return -1;
115 	}
116 	if ((stat = copy1(fdf, fdt, fromname, toname)) != -1)
117 		if (remove(fromname) < 0) {
118 			fprint(2, "mv: can't remove %s", fromname);
119 			perror("");
120 			return -1;
121 		}
122 	close(fdf);
123 	close(fdt);
124 	return stat;
125 }
126 
127 int
128 copy1(int fdf, int fdt, char *from, char *to)
129 {
130 	char buf[8192];
131 	long n, n1;
132 
133 	for(;;) {
134 		n = read(fdf, buf, sizeof buf);
135 		if(n >= 0) {
136 			if(n == 0)
137 				break;
138 			n1 = write(fdt, buf, n);
139 			if(n1 != n) {
140 				fprint(2, "mv: error writing %s:", to);
141 				perror("");
142 				return -1;
143 			}
144 		}
145 	}
146 	if(n < 0) {
147 		fprint(2, "mv: error reading %s:", from);
148 		perror("");
149 		return -1;
150 	}
151 	return 0;
152 }
153 
154 void
155 split(char *name, char **pdir, char **pelem)
156 {
157 	char *s;
158 
159 	s = utfrrune(name, '/');
160 	if(s){
161 		*s = 0;
162 		*pelem = s+1;
163 		*pdir = name;
164 	}else if(strcmp(name, "..") == 0){
165 		*pdir = "..";
166 		*pelem = ".";
167 	}else{
168 		*pdir = ".";
169 		*pelem = name;
170 	}
171 }
172 
173 int
174 samefile(char *a, char *b)
175 {
176 	Dir da, db;
177 
178 	if(strcmp(a, b) == 0)
179 		return 1;
180 	if(dirstat(a, &da) < 0 || dirstat(b, &db) < 0)
181 		return 0;
182 	return (da.qid.path==db.qid.path && da.qid.vers==db.qid.vers &&
183 		da.dev==db.dev && da.type==db.type);
184 }
185 
186 void
187 hardremove(char *a)
188 {
189 	if(remove(a) == -1){
190 		fprint(2, "mv: can't remove %s\n", a);
191 		exits("mv");
192 	}
193 	do; while(remove(a) != -1);
194 }
195