Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/cmd/ls.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include <fcall.h>
5
 
6
typedef struct NDir NDir;
7
struct NDir
8
{
9
	Dir *d;
10
	char	*prefix;
11
};
12
 
13
int	errs = 0;
14
int	dflag;
15
int	lflag;
16
int	mflag;
17
int	nflag;
18
int	pflag;
19
int	qflag;
20
int	Qflag;
21
int	rflag;
22
int	sflag;
23
int	tflag;
24
int	Tflag;
25
int	uflag;
26
int	Fflag;
27
int	ndirbuf;
28
int	ndir;
29
NDir*	dirbuf;
30
int	ls(char*, int);
31
int	compar(NDir*, NDir*);
32
char*	asciitime(long);
33
char*	darwx(long);
34
void	rwx(long, char*);
35
void	growto(long);
36
void	dowidths(Dir*);
37
void	format(Dir*, char*);
38
void	output(void);
39
char*	xcleanname(char*);
40
ulong	clk;
41
int	swidth;			/* max width of -s size */
42
int	qwidth;			/* max width of -q version */
43
int	vwidth;			/* max width of dev */
44
int	uwidth;			/* max width of userid */
45
int	mwidth;			/* max width of muid */
46
int	lwidth;			/* max width of length */
47
int	gwidth;			/* max width of groupid */
48
Biobuf	bin;
49
 
50
void
51
main(int argc, char *argv[])
52
{
53
	int i;
54
 
55
	Binit(&bin, 1, OWRITE);
56
	ARGBEGIN{
57
	case 'F':	Fflag++; break;
58
	case 'd':	dflag++; break;
59
	case 'l':	lflag++; break;
60
	case 'm':	mflag++; break;
61
	case 'n':	nflag++; break;
62
	case 'p':	pflag++; break;
63
	case 'q':	qflag++; break;
64
	case 'Q':	Qflag++; break;
65
	case 'r':	rflag++; break;
66
	case 's':	sflag++; break;
67
	case 't':	tflag++; break;
68
	case 'T':	Tflag++; break;
69
	case 'u':	uflag++; break;
70
	default:	fprint(2, "usage: ls [-dlmnpqrstuFQT] [file ...]\n");
71
			exits("usage");
72
	}ARGEND
73
 
74
	doquote = needsrcquote;
75
	quotefmtinstall();
76
	fmtinstall('M', dirmodefmt);
77
 
78
	if(lflag)
79
		clk = time(0);
80
	if(argc == 0)
81
		errs = ls(".", 0);
82
	else for(i=0; i<argc; i++)
83
		errs |= ls(argv[i], 1);
84
	output();
85
	exits(errs? "errors" : 0);
86
}
87
 
88
int
89
ls(char *s, int multi)
90
{
91
	int fd;
92
	long i, n;
93
	char *p;
94
	Dir *db;
95
 
96
	db = dirstat(s);
97
	if(db == nil){
98
    error:
99
		fprint(2, "ls: %s: %r\n", s);
100
		return 1;
101
	}
102
	if((db->qid.type&QTDIR) && dflag==0){
103
		free(db);
104
		output();
105
		fd = open(s, OREAD);
106
		if(fd == -1)
107
			goto error;
108
		n = dirreadall(fd, &db);
109
		if(n < 0)
110
			goto error;
111
		xcleanname(s);
112
		growto(ndir+n);
113
		for(i=0; i<n; i++){
114
			dirbuf[ndir+i].d = db+i;
115
			dirbuf[ndir+i].prefix = multi? s : 0;
116
		}
117
		ndir += n;
118
		close(fd);
119
		output();
120
	}else{
121
		growto(ndir+1);
122
		dirbuf[ndir].d = db;
123
		dirbuf[ndir].prefix = 0;
124
		xcleanname(s);
125
		p = utfrrune(s, '/');
126
		if(p){
127
			dirbuf[ndir].prefix = s;
128
			*p = 0;
129
		}
130
		ndir++;
131
	}
132
	return 0;
133
}
134
 
135
void
136
output(void)
137
{
138
	int i;
139
	char buf[4096];
140
	char *s;
141
 
142
	if(!nflag)
143
		qsort(dirbuf, ndir, sizeof dirbuf[0], (int (*)(void*, void*))compar);
144
	for(i=0; i<ndir; i++)
145
		dowidths(dirbuf[i].d);
146
	for(i=0; i<ndir; i++) {
147
		if(!pflag && (s = dirbuf[i].prefix)) {
148
			if(strcmp(s, "/") ==0)	/* / is a special case */
149
				s = "";
150
			sprint(buf, "%s/%s", s, dirbuf[i].d->name);
151
			format(dirbuf[i].d, buf);
152
		} else
153
			format(dirbuf[i].d, dirbuf[i].d->name);
154
	}
155
	ndir = 0;
156
	Bflush(&bin);
157
}
158
 
159
void
160
dowidths(Dir *db)
161
{
162
	char buf[256];
163
	int n;
164
 
165
	if(sflag) {
166
		n = sprint(buf, "%llud", (db->length+1023)/1024);
167
		if(n > swidth)
168
			swidth = n;
169
	}
170
	if(qflag) {
171
		n = sprint(buf, "%lud", db->qid.vers);
172
		if(n > qwidth)
173
			qwidth = n;
174
	}
175
	if(mflag) {
176
		n = snprint(buf, sizeof buf, "[%q]", db->muid);
177
		if(n > mwidth)
178
			mwidth = n;
179
	}
180
	if(lflag) {
181
		n = sprint(buf, "%ud", db->dev);
182
		if(n > vwidth)
183
			vwidth = n;
184
		n = sprint(buf, "%q", db->uid);
185
		if(n > uwidth)
186
			uwidth = n;
187
		n = sprint(buf, "%q", db->gid);
188
		if(n > gwidth)
189
			gwidth = n;
190
		n = sprint(buf, "%llud", db->length);
191
		if(n > lwidth)
192
			lwidth = n;
193
	}
194
}
195
 
196
char*
197
fileflag(Dir *db)
198
{
199
	if(Fflag == 0)
200
		return "";
201
	if(QTDIR & db->qid.type)
202
		return "/";
203
	if(0111 & db->mode)
204
		return "*";
205
	return "";
206
}
207
 
208
void
209
format(Dir *db, char *name)
210
{
211
	int i;
212
 
213
	if(sflag)
214
		Bprint(&bin, "%*llud ",
215
			swidth, (db->length+1023)/1024);
216
	if(mflag){
217
		Bprint(&bin, "[%q] ", db->muid);
218
		for(i=2+strlen(db->muid); i<mwidth; i++)
219
			Bprint(&bin, " ");
220
	}
221
	if(qflag)
222
		Bprint(&bin, "(%.16llux %*lud %.2ux) ",
223
			db->qid.path,
224
			qwidth, db->qid.vers,
225
			db->qid.type);
226
	if(Tflag)
227
		Bprint(&bin, "%c ", (db->mode&DMTMP)? 't': '-');
228
 
229
	if(lflag)
230
		Bprint(&bin, "%M %C %*ud %*q %*q %*llud %s ",
231
			db->mode, db->type,
232
			vwidth, db->dev,
233
			-uwidth, db->uid,
234
			-gwidth, db->gid,
235
			lwidth, db->length,
236
			asciitime(uflag? db->atime: db->mtime));
237
	Bprint(&bin, Qflag? "%s%s\n": "%q%s\n", name, fileflag(db));
238
}
239
 
240
void
241
growto(long n)
242
{
243
	if(n <= ndirbuf)
244
		return;
245
	ndirbuf = n;
246
	dirbuf=(NDir *)realloc(dirbuf, ndirbuf*sizeof(NDir));
247
	if(dirbuf == 0){
248
		fprint(2, "ls: malloc fail\n");
249
		exits("malloc fail");
250
	}
251
}
252
 
253
int
254
compar(NDir *a, NDir *b)
255
{
256
	long i;
257
	Dir *ad, *bd;
258
 
259
	ad = a->d;
260
	bd = b->d;
261
 
262
	if(tflag){
263
		if(uflag)
264
			i = bd->atime-ad->atime;
265
		else
266
			i = bd->mtime-ad->mtime;
267
	}else{
268
		if(a->prefix && b->prefix){
269
			i = strcmp(a->prefix, b->prefix);
270
			if(i == 0)
271
				i = strcmp(ad->name, bd->name);
272
		}else if(a->prefix){
273
			i = strcmp(a->prefix, bd->name);
274
			if(i == 0)
275
				i = 1;	/* a is longer than b */
276
		}else if(b->prefix){
277
			i = strcmp(ad->name, b->prefix);
278
			if(i == 0)
279
				i = -1;	/* b is longer than a */
280
		}else
281
			i = strcmp(ad->name, bd->name);
282
	}
283
	if(i == 0)
284
		i = (a<b? -1 : 1);
285
	if(rflag)
286
		i = -i;
287
	return i;
288
}
289
 
290
char*
291
asciitime(long l)
292
{
293
	static char buf[32];
294
	char *t;
295
 
296
	t = ctime(l);
297
	/* 6 months in the past or a day in the future */
298
	if(l<clk-180L*24*60*60 || clk+24L*60*60<l){
299
		memmove(buf, t+4, 7);		/* month and day */
300
		memmove(buf+7, t+23, 5);		/* year */
301
	}else
302
		memmove(buf, t+4, 12);		/* skip day of week */
303
	buf[12] = 0;
304
	return buf;
305
}
306
 
307
/*
308
 * Compress slashes, remove trailing slash.  Don't worry about . and ..
309
 */
310
char*
311
xcleanname(char *name)
312
{
313
	char *r, *w;
314
 
315
	for(r=w=name; *r; r++){
316
		if(*r=='/' && r>name && *(r-1)=='/')
317
			continue;
318
		if(w != r)
319
			*w = *r;
320
		w++;
321
	}
322
	*w = 0;
323
	while(w-1>name && *(w-1)=='/')
324
		*--w = 0;
325
	return name;
326
}