123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <fcall.h>
- typedef struct NDir NDir;
- struct NDir
- {
- Dir *d;
- char *prefix;
- };
- int errs = 0;
- int dflag;
- int lflag;
- int mflag;
- int nflag;
- int pflag;
- int qflag;
- int Qflag;
- int rflag;
- int sflag;
- int tflag;
- int Tflag;
- int uflag;
- int Fflag;
- int ndirbuf;
- int ndir;
- NDir* dirbuf;
- int ls(char*, int);
- int compar(NDir*, NDir*);
- char* asciitime(long);
- char* darwx(long);
- void rwx(long, char*);
- void growto(long);
- void dowidths(Dir*);
- void format(Dir*, char*);
- void output(void);
- char* xcleanname(char*);
- ulong clk;
- int swidth; /* max width of -s size */
- int qwidth; /* max width of -q version */
- int vwidth; /* max width of dev */
- int uwidth; /* max width of userid */
- int mwidth; /* max width of muid */
- int glwidth; /* max width of groupid and length */
- Biobuf bin;
- void
- main(int argc, char *argv[])
- {
- int i;
- Binit(&bin, 1, OWRITE);
- ARGBEGIN{
- case 'F': Fflag++; break;
- case 'd': dflag++; break;
- case 'l': lflag++; break;
- case 'm': mflag++; break;
- case 'n': nflag++; break;
- case 'p': pflag++; break;
- case 'q': qflag++; break;
- case 'Q': Qflag++; break;
- case 'r': rflag++; break;
- case 's': sflag++; break;
- case 't': tflag++; break;
- case 'T': Tflag++; break;
- case 'u': uflag++; break;
- default: fprint(2, "usage: ls [-dlmnpqrstuFQT] [file ...]\n");
- exits("usage");
- }ARGEND
- doquote = needsrcquote;
- quotefmtinstall();
- fmtinstall('M', dirmodefmt);
- if(lflag)
- clk = time(0);
- if(argc == 0)
- errs = ls(".", 0);
- else for(i=0; i<argc; i++)
- errs |= ls(argv[i], 1);
- output();
- exits(errs? "errors" : 0);
- }
- int
- ls(char *s, int multi)
- {
- int fd;
- long i, n;
- char *p;
- Dir *db;
- db = dirstat(s);
- if(db == nil){
- error:
- fprint(2, "ls: %s: %r\n", s);
- return 1;
- }
- if((db->qid.type&QTDIR) && dflag==0){
- free(db);
- output();
- fd = open(s, OREAD);
- if(fd == -1)
- goto error;
- n = dirreadall(fd, &db);
- if(n < 0)
- goto error;
- xcleanname(s);
- growto(ndir+n);
- for(i=0; i<n; i++){
- dirbuf[ndir+i].d = db+i;
- dirbuf[ndir+i].prefix = multi? s : 0;
- }
- ndir += n;
- close(fd);
- output();
- }else{
- growto(ndir+1);
- dirbuf[ndir].d = db;
- dirbuf[ndir].prefix = 0;
- xcleanname(s);
- p = utfrrune(s, '/');
- if(p){
- dirbuf[ndir].prefix = s;
- *p = 0;
- }
- ndir++;
- }
- return 0;
- }
- void
- output(void)
- {
- int i;
- char buf[4096];
- char *s;
- if(!nflag)
- qsort(dirbuf, ndir, sizeof dirbuf[0], (int (*)(void*, void*))compar);
- for(i=0; i<ndir; i++)
- dowidths(dirbuf[i].d);
- for(i=0; i<ndir; i++) {
- if(!pflag && (s = dirbuf[i].prefix)) {
- if(strcmp(s, "/") ==0) /* / is a special case */
- s = "";
- sprint(buf, "%s/%s", s, dirbuf[i].d->name);
- format(dirbuf[i].d, buf);
- } else
- format(dirbuf[i].d, dirbuf[i].d->name);
- }
- ndir = 0;
- Bflush(&bin);
- }
- void
- dowidths(Dir *db)
- {
- char buf[256];
- int n;
- if(sflag) {
- n = sprint(buf, "%llud", (db->length+1023)/1024);
- if(n > swidth)
- swidth = n;
- }
- if(qflag) {
- n = sprint(buf, "%lud", db->qid.vers);
- if(n > qwidth)
- qwidth = n;
- }
- if(mflag) {
- n = snprint(buf, sizeof buf, "[%s]", db->muid);
- if(n > mwidth)
- mwidth = n;
- }
- if(lflag) {
- n = sprint(buf, "%ud", db->dev);
- if(n > vwidth)
- vwidth = n;
- n = strlen(db->uid);
- if(n > uwidth)
- uwidth = n;
- n = sprint(buf, "%llud", db->length);
- n += strlen(db->gid);
- if(n > glwidth)
- glwidth = n;
- }
- }
- char*
- fileflag(Dir *db)
- {
- if(Fflag == 0)
- return "";
- if(QTDIR & db->qid.type)
- return "/";
- if(0111 & db->mode)
- return "*";
- return "";
- }
- void
- format(Dir *db, char *name)
- {
- int i;
- if(sflag)
- Bprint(&bin, "%*llud ",
- swidth, (db->length+1023)/1024);
- if(mflag){
- Bprint(&bin, "[%s] ", db->muid);
- for(i=2+strlen(db->muid); i<mwidth; i++)
- Bprint(&bin, " ");
- }
- if(qflag)
- Bprint(&bin, "(%.16llux %*lud %.2ux) ",
- db->qid.path,
- qwidth, db->qid.vers,
- db->qid.type);
- if(Tflag)
- Bprint(&bin, "%c ", (db->mode&DMTMP) ? 't' : '-');
- if(lflag)
- Bprint(&bin,
- Qflag? "%M %C %*ud %*s %s %*llud %s %s\n" : "%M %C %*ud %*s %s %*llud %s %q\n",
- db->mode, db->type,
- vwidth, db->dev,
- -uwidth, db->uid,
- db->gid,
- (int)(glwidth-strlen(db->gid)), db->length,
- asciitime(uflag? db->atime : db->mtime), name);
- else
- Bprint(&bin,
- Qflag? "%s%s\n" : "%q%s\n",
- name, fileflag(db));
- }
- void
- growto(long n)
- {
- if(n <= ndirbuf)
- return;
- ndirbuf = n;
- dirbuf=(NDir *)realloc(dirbuf, ndirbuf*sizeof(NDir));
- if(dirbuf == 0){
- fprint(2, "ls: malloc fail\n");
- exits("malloc fail");
- }
- }
- int
- compar(NDir *a, NDir *b)
- {
- long i;
- Dir *ad, *bd;
- ad = a->d;
- bd = b->d;
- if(tflag){
- if(uflag)
- i = bd->atime-ad->atime;
- else
- i = bd->mtime-ad->mtime;
- }else{
- if(a->prefix && b->prefix){
- i = strcmp(a->prefix, b->prefix);
- if(i == 0)
- i = strcmp(ad->name, bd->name);
- }else if(a->prefix){
- i = strcmp(a->prefix, bd->name);
- if(i == 0)
- i = 1; /* a is longer than b */
- }else if(b->prefix){
- i = strcmp(ad->name, b->prefix);
- if(i == 0)
- i = -1; /* b is longer than a */
- }else
- i = strcmp(ad->name, bd->name);
- }
- if(i == 0)
- i = (a<b? -1 : 1);
- if(rflag)
- i = -i;
- return i;
- }
- char*
- asciitime(long l)
- {
- static char buf[32];
- char *t;
- t = ctime(l);
- /* 6 months in the past or a day in the future */
- if(l<clk-180L*24*60*60 || clk+24L*60*60<l){
- memmove(buf, t+4, 7); /* month and day */
- memmove(buf+7, t+23, 5); /* year */
- }else
- memmove(buf, t+4, 12); /* skip day of week */
- buf[12] = 0;
- return buf;
- }
- /*
- * Compress slashes, remove trailing slash. Don't worry about . and ..
- */
- char*
- xcleanname(char *name)
- {
- char *r, *w;
-
- for(r=w=name; *r; r++){
- if(*r=='/' && r>name && *(r-1)=='/')
- continue;
- *w++ = *r;
- }
- while(w-1>name && *(w-1)=='/')
- *--w = 0;
- return name;
- }
|