ls.c 5.3 KB

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