ls.c 6.1 KB

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