Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
 
4
#define	DEFB	(8*1024)
5
 
6
int	failed;
7
int	gflag;
8
int	uflag;
9
int	xflag;
10
void	copy(char *from, char *to, int todir);
11
int	copy1(int fdf, int fdt, char *from, char *to);
12
 
13
void
14
main(int argc, char *argv[])
15
{
16
	Dir *dirb;
17
	int todir, i;
18
 
19
	ARGBEGIN {
20
	case 'g':
21
		gflag++;
22
		break;
23
	case 'u':
24
		uflag++;
25
		gflag++;
26
		break;
27
	case 'x':
28
		xflag++;
29
		break;
30
	default:
31
		goto usage;
32
	} ARGEND
33
 
34
	todir=0;
35
	if(argc < 2)
36
		goto usage;
37
	dirb = dirstat(argv[argc-1]);
38
	if(dirb!=nil && (dirb->mode&DMDIR))
39
		todir=1;
40
	if(argc>2 && !todir){
41
		fprint(2, "cp: %s not a directory\n", argv[argc-1]);
42
		exits("bad usage");
43
	}
44
	for(i=0; i<argc-1; i++)
45
		copy(argv[i], argv[argc-1], todir);
46
	if(failed)
47
		exits("errors");
48
	exits(0);
49
 
50
usage:
51
	fprint(2, "usage:\tcp [-gux] fromfile tofile\n");
52
	fprint(2, "\tcp [-x] fromfile ... todir\n");
53
	exits("usage");
54
}
55
 
56
int
57
samefile(Dir *a, char *an, char *bn)
58
{
59
	Dir *b;
60
	int ret;
61
 
62
	ret = 0;
63
	b=dirstat(bn);
64
	if(b != nil)
65
	if(b->qid.type==a->qid.type)
66
	if(b->qid.path==a->qid.path)
67
	if(b->qid.vers==a->qid.vers)
68
	if(b->dev==a->dev)
69
	if(b->type==a->type){
70
		fprint(2, "cp: %s and %s are the same file\n", an, bn);
71
		ret = 1;
72
	}
73
	free(b);
74
	return ret;
75
}
76
 
77
void
78
copy(char *from, char *to, int todir)
79
{
80
	Dir *dirb, dirt;
81
	char name[256];
82
	int fdf, fdt, mode;
83
 
84
	if(todir){
85
		char *s, *elem;
86
		elem=s=from;
87
		while(*s++)
88
			if(s[-1]=='/')
89
				elem=s;
90
		sprint(name, "%s/%s", to, elem);
91
		to=name;
92
	}
93
 
94
	if((dirb=dirstat(from))==nil){
95
		fprint(2,"cp: can't stat %s: %r\n", from);
96
		failed = 1;
97
		return;
98
	}
99
	mode = dirb->mode;
100
	if(mode&DMDIR){
101
		fprint(2, "cp: %s is a directory\n", from);
102
		free(dirb);
103
		failed = 1;
104
		return;
105
	}
106
	if(samefile(dirb, from, to)){
107
		free(dirb);
108
		failed = 1;
109
		return;
110
	}
111
	mode &= 0777;
112
	fdf=open(from, OREAD);
113
	if(fdf<0){
114
		fprint(2, "cp: can't open %s: %r\n", from);
115
		free(dirb);
116
		failed = 1;
117
		return;
118
	}
119
	fdt=create(to, OWRITE, mode);
120
	if(fdt<0){
121
		fprint(2, "cp: can't create %s: %r\n", to);
122
		close(fdf);
123
		free(dirb);
124
		failed = 1;
125
		return;
126
	}
127
	if(copy1(fdf, fdt, from, to)==0 && (xflag || gflag || uflag)){
128
		nulldir(&dirt);
129
		if(xflag){
130
			dirt.mtime = dirb->mtime;
131
			dirt.mode = dirb->mode;
132
		}
133
		if(uflag)
134
			dirt.uid = dirb->uid;
135
		if(gflag)
136
			dirt.gid = dirb->gid;
137
		if(dirfwstat(fdt, &dirt) < 0)
138
			fprint(2, "cp: warning: can't wstat %s: %r\n", to);
139
	}			
140
	free(dirb);
141
	close(fdf);
142
	close(fdt);
143
}
144
 
145
int
146
copy1(int fdf, int fdt, char *from, char *to)
147
{
148
	char *buf;
149
	long n, n1, rcount;
150
	int rv;
151
	char err[ERRMAX];
152
 
153
	buf = malloc(DEFB);
154
	/* clear any residual error */
155
	err[0] = '\0';
156
	errstr(err, ERRMAX);
157
	rv = 0;
158
	for(rcount=0;; rcount++) {
159
		n = read(fdf, buf, DEFB);
160
		if(n <= 0)
161
			break;
162
		n1 = write(fdt, buf, n);
163
		if(n1 != n) {
164
			fprint(2, "cp: error writing %s: %r\n", to);
165
			failed = 1;
166
			rv = -1;
167
			break;
168
		}
169
	}
170
	if(n < 0) {
171
		fprint(2, "cp: error reading %s: %r\n", from);
172
		failed = 1;
173
		rv = -1;
174
	}
175
	free(buf);
176
	return rv;
177
}