xref: /inferno-os/appl/cmd/mv.b (revision 3f1f06c5d12b24c4061e5123acabf72348ff45a2)
1implement Mv;
2
3include "sys.m";
4	sys: Sys;
5	stderr: ref Sys->FD;
6
7include "draw.m";
8	draw: Draw;
9
10include "string.m";
11	str: String;
12
13
14Mv: module
15{
16	init: fn(ctxt: ref Draw->Context, argv: list of string);
17};
18
19init(nil: ref Draw->Context, argv: list of string)
20{
21	sys = load Sys Sys->PATH;
22	stderr = sys->fildes(2);
23	str = load String String->PATH;
24	if(str == nil) {
25		sys->fprint(stderr, "mv: can't load %s: %r\n", String->PATH);
26		raise "fail:load";
27	}
28
29	dirto, dirfrom: Sys->Dir;
30	todir, toelem: string;
31	if(len argv<3) {
32		sys->fprint(stderr, "usage: mv fromfile tofile\n");
33		sys->fprint(stderr, "       mv fromfile ... todir\n");
34		raise "fail:usage";
35	}
36	argv = tl argv;
37	arr := array[len argv] of string;
38	for (i:=0; argv!=nil;i++){
39		arr[i]= hd argv;
40		argv = tl argv;
41	}
42	(i,dirto)=sys->stat(arr[len arr-1]);
43	if(i >= 0 && (dirto.mode&Sys->DMDIR)){
44		(i,dirfrom)=sys->stat(arr[0]);
45		if(len arr == 2 && i >= 0 && (dirfrom.mode&Sys->DMDIR))
46			(todir,toelem)=split(arr[len arr-1]);
47		else{
48			todir = arr[len arr -1];
49			toelem = "";	# toelem will be fromelem
50		}
51	}else
52		(todir,toelem)=split(arr[len arr-1]);
53	if(len arr > 2  && toelem != nil) {
54		sys->fprint(stderr, "mv: %s not a directory\n", arr[len arr-1]);
55		raise "fail:error";
56	}
57	failed := 0;
58	for(i=0; i < len arr-1; i++)
59		if (mv(arr[i], todir, toelem) < 0)
60			failed++;
61	if(failed)
62		raise "fail:error";
63}
64
65mv(from,todir,toelem : string): int
66{
67	(i,dirb):=sys->stat(from);
68	if(i != 0) {
69		sys->fprint(stderr, "mv: can't stat %s: %r\n", from);
70		return -1;
71	}
72	(fromdir,fromelem):=split(from);
73	fromname:= fromdir+fromelem;
74	if(toelem == nil){
75		if (todir[len todir-1]!='/')
76			todir[len todir]='/';
77		toelem = fromelem;
78	}
79	i = len toelem;
80	if(i==0){
81		sys->fprint(stderr, "mv: null last name element moving %s\n", fromname);
82		return -1;
83	}
84	toname:=todir+toelem;
85	if(samefile(fromdir, todir)){
86		if(samefile(fromname, toname)){
87			sys->fprint(stderr, "mv: %s and %s are the same\n", fromname, toname);
88			return -1;
89		}
90		(j,dirt):=sys->stat(toname);
91		if( (j == 0) && (dirb.mode&Sys->DMDIR) ){
92			sys->fprint(stderr, "mv: can't rename a directory to an existing name\n");
93			return -1;
94		}
95		if(j == 0)
96			hardremove(toname);
97		dirt = sys->nulldir;
98		dirt.name=toelem;
99		if(sys->wstat(fromname,dirt) >= 0)
100			return 0;
101		if(dirb.mode&Sys->DMDIR){
102			sys->fprint(stderr, "mv: can't rename directory %s: %r\n", fromname);
103			return -1;
104		}
105	}
106	# Renaming won't work --- have to copy
107	if(dirb.mode&Sys->DMDIR){
108		sys->fprint(stderr, "mv: %s is a directory, not copied to %s\n", fromname, toname);
109		return -1;
110	}
111	fdf := sys->open(fromname, Sys->OREAD);
112	if(fdf==nil){
113		sys->fprint(stderr, "mv: can't open %s: %r\n", fromname);
114		return -1;
115	}
116	fdt := sys->create(toname, Sys->OWRITE, dirb.mode);
117	if(fdt == nil){
118		sys->fprint(stderr, "mv: can't create %s: %r\n", toname);
119		return -1;
120	}
121	if ((stat := copy1(fdf, fdt, fromname, toname)) != -1)
122		fdf = nil;	# temp bug: sometimes can't remove open file
123		if (sys->remove(fromname) < 0) {
124			sys->fprint(stderr, "mv: can't remove %s: %r\n", fromname);
125			return -1;
126		}
127	return stat;
128}
129
130
131copy1(fdf, fdt : ref Sys->FD,from, fto : string): int
132{
133	n : int;
134	buf:=array[Sys->ATOMICIO] of byte;
135	for(;;) {
136		n = sys->read(fdf, buf, len buf);
137		if (n<=0)
138			break;
139		n1 := sys->write(fdt, buf, n);
140		if(n1 != n) {
141			sys->fprint(stderr, "mv: error writing %s: %r\n", fto);
142			return -1;
143		}
144	}
145	if(n < 0) {
146		sys->fprint(stderr, "mv: error reading %s: %r\n", from);
147		return -1;
148	}
149	return 0;
150}
151
152split(name : string): (string,string)
153{
154	(d,t) := str->splitr(name, "/");
155	if(d!=nil)
156		return(d,t);
157	else if(name=="..")
158		return("../",".");
159	else
160		return("./",name);
161}
162
163samefile(a,b : string): int
164{
165	if(a==b)
166		return 1;
167	(i,da):=sys->stat(a);
168	(j,db):=sys->stat(b);
169	if(i < 0 || j < 0)
170		return 0;
171	i= (da.qid.path==db.qid.path && da.qid.vers==db.qid.vers &&
172		da.dev==db.dev && da.dtype==db.dtype);
173	return i;
174}
175
176hardremove(a: string)
177{
178	if(sys->remove(a) == -1){
179		sys->fprint(stderr, "mv: can't remove %s: %r\n", a);
180		raise "fail:mv";
181	}
182	do; while(sys->remove(a) != -1);
183}
184