Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

650 lines
18 KiB

  1. /* ls - fancy schmancy dir list program
  2. *
  3. * HISTORY:
  4. * 17-Mar-87 danl Added q switch
  5. * 4/15/86 daniel lipkie Allow /s as well as /1 (one) to do single col
  6. * 4/23/86 daniel lipkie Add /v switch
  7. * 5/02/86 daniel lipkie savepath, do strlen(pat), not strlen(*pat)
  8. * 5/05/86 daniel lipkie Allow - as well as / as switch char
  9. *
  10. * 31-Jul-1986 mz Add in net aware-ness. ls \\mach\path works now.
  11. * Discard bogus C stat() function and do times correctly.
  12. * 01-Aug-1986 dl If invokes as l, then do ls /l
  13. * 23-Jan-1987 bw Add 286DOS support
  14. * 30-Oct-1987 bw Changed 'DOS5' to 'OS2'
  15. * 08-Dec-1988 mz Chance to use OS2.H
  16. *
  17. * 03-Aug-1990 davegi Removed 'F' from [s]printf format
  18. * descriptors (OS/2 2.0)
  19. * Changed Move to memmove
  20. * Removed redundant check for '-' switch character
  21. * 18-Oct-1990 w-barry Removed 'dead' code.
  22. */
  23. #include <sys\types.h>
  24. #include <sys\stat.h>
  25. #include <malloc.h>
  26. #include <stdlib.h>
  27. #include <ctype.h>
  28. #include <string.h>
  29. #include <time.h>
  30. #include <stdio.h>
  31. #include <stdio.h>
  32. #include <windows.h>
  33. #include <tools.h>
  34. char *attrs = "drahsoecp";
  35. int amsk[] = {
  36. FILE_ATTRIBUTE_DIRECTORY,
  37. FILE_ATTRIBUTE_READONLY,
  38. FILE_ATTRIBUTE_ARCHIVE,
  39. FILE_ATTRIBUTE_HIDDEN,
  40. FILE_ATTRIBUTE_SYSTEM,
  41. FILE_ATTRIBUTE_OFFLINE,
  42. FILE_ATTRIBUTE_ENCRYPTED,
  43. FILE_ATTRIBUTE_COMPRESSED,
  44. FILE_ATTRIBUTE_REPARSE_POINT,
  45. 0
  46. };
  47. char *prattrs[] = {
  48. "%s*"
  49. };
  50. char pramsk[] = {
  51. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY,
  52. 0
  53. };
  54. flagType fD = FALSE; /* TRUE => do only specified dir not sub */
  55. flagType fSubDir = FALSE; /* TRUE => recurse on subdirs */
  56. flagType fL = FALSE; /* TRUE => long listing */
  57. flagType fSingle = FALSE; /* TRUE => single column output */
  58. flagType fVisOnly = FALSE; /* TRUE => ignore FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM FILE_ATTRIBUTE_VOLUME_LABEL, no * */
  59. flagType fQuiet = FALSE; /* TRUE => no summary */
  60. flagType fFull = FALSE; /* TRUE => display full names */
  61. flagType fUTC = FALSE; /* TRUE => display using UTC */
  62. /* Sort type */
  63. #define TYS_ALPHA 0
  64. #define TYS_SIZE 1
  65. #define TYS_TIME 2
  66. int tySort = TYS_ALPHA; /* type of sort */
  67. flagType fReverse = FALSE; /* TRUE => sort is reversed */
  68. struct fppath {
  69. struct fppath far *next;
  70. struct fppat far *pat;
  71. struct fpfile far *first;
  72. int maxlen;
  73. int cntFiles;
  74. int cntEntries;
  75. long bytes;
  76. long bytesAlloc;
  77. long bPerA;
  78. int fToLower;
  79. int cchName;
  80. char name[1];
  81. };
  82. struct fppat {
  83. struct fppat far *next;
  84. int cchName;
  85. char name[1];
  86. };
  87. struct fpfile {
  88. struct fpfile far *next;
  89. long len;
  90. DWORD attr;
  91. time_t mtime;
  92. int cchName;
  93. char name[1];
  94. };
  95. struct fppath far *toppath, far *curpath;
  96. unsigned totalloc = 0;
  97. char tmpfile1[MAX_PATH], tmpfile2[MAX_PATH];
  98. char szStarDotStar[] = "*.*";
  99. /** Procedure prototypes
  100. */
  101. char far *alloc (int nb);
  102. long AllocSize (char *p);
  103. void savefile (char *p, struct findType *b, void *dummy);
  104. void savepath (char *p, char *pat);
  105. void savepat (struct fppath far *toppath, char *pat);
  106. struct fppath far *freepath (struct fppath far *p);
  107. struct fppat far *freepat (struct fppat far *p);
  108. struct fpfile far *freefile (struct fpfile far *p);
  109. struct fpfile far *nfile (int n, struct fpfile far *p);
  110. flagType fIsDir (char *p);
  111. /* alloc - allocate random memory. Die cleanly if no more memory is
  112. * available.
  113. *
  114. * nb number of bytes to allocate
  115. *
  116. * returns: pointer to bytes allocated if successful
  117. * displays error message and dies otherwise
  118. */
  119. char far *alloc (int nb)
  120. {
  121. char far *p;
  122. p = (char far *) malloc (nb);
  123. if (p != NULL) {
  124. memset (p, 0, nb);
  125. totalloc += nb;
  126. return p;
  127. }
  128. printf ("alloc out of memory - used: %u need: %d\n", totalloc, nb);
  129. exit (1);
  130. return NULL;
  131. }
  132. /* AllocSize - determine size of allocation granularity
  133. *
  134. * p character pointer to name string
  135. *
  136. * Returns long number of bytes per allocation unit
  137. */
  138. long AllocSize (char *p)
  139. {
  140. DWORD dwSecPerClus;
  141. DWORD dwBytePerSec;
  142. DWORD dwFreeClus;
  143. DWORD dwTotalClus;
  144. if (!GetDiskFreeSpace (p, &dwSecPerClus, &dwBytePerSec, &dwFreeClus, &dwTotalClus)) {
  145. // fprintf (stderr, "GetDiskFreeSpace (%s) returned %d\n", p, GetLastError ());
  146. return 1;
  147. }
  148. return dwBytePerSec * dwSecPerClus;
  149. }
  150. void savefile (char *p, struct findType *b, void * dummy)
  151. {
  152. int i, j;
  153. register struct fpfile far *tmp, far *tmp1;
  154. struct fpfile far *tmp2;
  155. char *psz;
  156. SYSTEMTIME DateTime;
  157. if (!curpath)
  158. return;
  159. if (TESTFLAG (b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
  160. if (!strcmp (b->fbuf.cFileName, "..") || !strcmp (b->fbuf.cFileName, "."))
  161. return;
  162. if (fVisOnly) {
  163. if (TESTFLAG (b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | 8 ))
  164. return;
  165. RSETFLAG (b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_READONLY);
  166. }
  167. if (fFull)
  168. psz = p;
  169. else
  170. psz = b->fbuf.cFileName;
  171. i = strlen (psz);
  172. if (TESTFLAG (b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
  173. i += 2;
  174. tmp = (struct fpfile far *) alloc (sizeof (*tmp) + i);
  175. if (TESTFLAG (b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
  176. sprintf (tmpfile1, "[%s]", psz);
  177. else
  178. strcpy (tmpfile1, psz);
  179. tmp->cchName = strlen (tmpfile1) + 1;
  180. memmove (tmp->name, tmpfile1, tmp->cchName);
  181. if (curpath->fToLower)
  182. lower (tmp->name);
  183. tmp->next = NULL;
  184. tmp->attr = b->fbuf.dwFileAttributes;
  185. tmp->len = b->fbuf.nFileSizeLow;
  186. if (fL || tySort == TYS_TIME) {
  187. if ( fUTC ) {
  188. FileTimeToSystemTime( &b->fbuf.ftLastWriteTime, &DateTime );
  189. }
  190. else {
  191. FILETIME LocalFileTime;
  192. FileTimeToLocalFileTime( &b->fbuf.ftLastWriteTime, &LocalFileTime );
  193. FileTimeToSystemTime( &LocalFileTime, &DateTime );
  194. }
  195. tmp->mtime = (time_t)date2l( DateTime.wYear,
  196. DateTime.wMonth,
  197. DateTime.wDay,
  198. DateTime.wHour,
  199. DateTime.wMinute,
  200. DateTime.wSecond
  201. );
  202. }
  203. if (TESTFLAG (tmp->attr, pramsk[0]))
  204. for (j = 1; pramsk[j]; j++)
  205. if (TESTFLAG (tmp->attr, pramsk[j])) {
  206. i += strlen (prattrs[j-1]) - 3;
  207. break;
  208. }
  209. curpath->maxlen = max (curpath->maxlen, i);
  210. if (!TESTFLAG (tmp->attr, FILE_ATTRIBUTE_DIRECTORY))
  211. curpath->cntFiles++;
  212. curpath->cntEntries++;
  213. tmp1 = curpath->first;
  214. tmp2 = NULL;
  215. while (tmp1) {
  216. switch (tySort) {
  217. case TYS_SIZE:
  218. i = tmp1->len > tmp->len;
  219. break;
  220. case TYS_ALPHA:
  221. memmove (tmpfile1, tmp1->name, tmp1->cchName);
  222. memmove (tmpfile2, tmp->name, tmp->cchName);
  223. i = _strcmpi (tmpfile1, tmpfile2) > 0;
  224. break;
  225. case TYS_TIME:
  226. i = (unsigned long)tmp1->mtime < (unsigned long)tmp->mtime;
  227. break;
  228. }
  229. if ((i && !fReverse) || (!i && fReverse))
  230. break;
  231. tmp2 = tmp1;
  232. tmp1 = tmp1->next;
  233. }
  234. tmp->next = tmp1;
  235. if (tmp2)
  236. tmp2->next = tmp;
  237. else
  238. curpath->first = tmp;
  239. if (fSubDir && TESTFLAG (tmp->attr, FILE_ATTRIBUTE_DIRECTORY))
  240. savepath (p, szStarDotStar);
  241. dummy;
  242. }
  243. /* savepat - make sure that pat is in the top-level path set */
  244. void savepat (struct fppath far *toppath, char *pat)
  245. {
  246. int i;
  247. struct fppat far *tmp, far *tmp1, far *tmp2;
  248. if (!pat)
  249. pat = szStarDotStar;
  250. i = strlen (pat);
  251. tmp = (struct fppat far *) alloc (sizeof (*tmp) +i);
  252. tmp->cchName = strlen (pat) + 1;
  253. memmove (tmp->name, pat, tmp->cchName);
  254. tmp->next = NULL;
  255. tmp1 = toppath->pat;
  256. tmp2 = NULL;
  257. while (tmp1) {
  258. memmove (tmpfile1, tmp1->name, tmp1->cchName);
  259. if (!_strcmpi (pat, tmpfile1)) {
  260. free (tmp);
  261. return;
  262. }
  263. else {
  264. tmp2 = tmp1;
  265. tmp1 = tmp1->next;
  266. }
  267. }
  268. if (tmp2)
  269. tmp2->next = tmp;
  270. else
  271. toppath->pat = tmp;
  272. }
  273. /* savepath - add a path and matching files into the file set
  274. *
  275. * p directory for files
  276. * pat pattern to match
  277. */
  278. void savepath (char *p, char *pat)
  279. {
  280. static char dirbuf[MAX_PATH], nambuf[14];
  281. int i;
  282. struct fppath far *tmp, far *tmp1, far *tmp2;
  283. char far *fp;
  284. DWORD dwFileSystemFlags;
  285. if (p)
  286. rootpath (p, dirbuf);
  287. else
  288. if (fPathChr (*pat) || *pat == '.' || (strlen (pat) >= 2 && pat[1] == ':')) {
  289. rootpath (pat, dirbuf);
  290. fileext (dirbuf, nambuf);
  291. path (dirbuf+2, dirbuf+2);
  292. pat = nambuf;
  293. }
  294. else
  295. curdir (dirbuf, 0);
  296. p = dirbuf + strlen (dirbuf) - 1;
  297. if (fPathChr (*p)) {
  298. if (fPathChr (*pat) || !*pat)
  299. *p = 0;
  300. }
  301. else
  302. if (*pat && !fPathChr (*pat))
  303. strcpy (++p, "\\");
  304. i = strlen (dirbuf);
  305. tmp = (struct fppath far *) alloc (sizeof (*tmp) + i);
  306. tmp->cchName = strlen (dirbuf) + 1;
  307. memmove (fp = tmp->name, dirbuf, tmp->cchName);
  308. tmp->next = NULL;
  309. tmp->pat = NULL;
  310. tmp->first = NULL;
  311. tmp->cntFiles = 0;
  312. tmp->cntEntries = 0;
  313. tmp->maxlen = 0;
  314. tmp->bytes = 0L;
  315. tmp->bytesAlloc = 0L;
  316. tmp->bPerA = AllocSize (dirbuf);
  317. Retry:
  318. if (!GetVolumeInformation (dirbuf, NULL, 0, NULL, NULL,
  319. &dwFileSystemFlags, NULL, 0)) {
  320. if (GetLastError() == ERROR_DIR_NOT_ROOT) {
  321. p = dirbuf + strlen (dirbuf) - 1;
  322. if (fPathChr(*p)) {
  323. *p = 0;
  324. p = strrchr(dirbuf, '\\');
  325. if (p) {
  326. p[1] = 0;
  327. goto Retry;
  328. }
  329. }
  330. }
  331. dwFileSystemFlags = 0;
  332. }
  333. tmp->fToLower = dwFileSystemFlags != 0 ? FALSE : TRUE;
  334. while (*fp)
  335. if (fPathChr (*fp++)) {
  336. fp[-1] = '\\';
  337. }
  338. tmp1 = toppath;
  339. tmp2 = NULL;
  340. while (tmp1) {
  341. memmove (tmpfile1, tmp1->name, tmp1->cchName);
  342. memmove ( tmpfile2, tmp->name, tmp->cchName);
  343. switch (_strcmpi (tmpfile1, tmpfile2)) {
  344. case 0:
  345. free (tmp);
  346. tmp = NULL;
  347. break;
  348. case 1:
  349. break;
  350. default:
  351. tmp2 = tmp1;
  352. tmp1 = tmp1->next;
  353. continue;
  354. }
  355. break;
  356. }
  357. if (tmp) {
  358. tmp->next = tmp1;
  359. if (tmp2)
  360. tmp2->next = tmp;
  361. else
  362. toppath = tmp;
  363. }
  364. else
  365. tmp = tmp1;
  366. savepat (tmp, pat);
  367. sprintf (dirbuf, "%s%s", tmp->name, pat);
  368. tmp2 = curpath;
  369. curpath = tmp;
  370. forfile(dirbuf, -1, savefile, NULL);
  371. curpath = tmp2;
  372. }
  373. struct fppath far *freepath (struct fppath far *p)
  374. {
  375. struct fppath far *p1;
  376. p1 = p->next;
  377. free (p);
  378. return p1;
  379. }
  380. struct fppat far *freepat (struct fppat far *p)
  381. {
  382. struct fppat far *p1;
  383. p1 = p->next;
  384. free (p);
  385. return p1;
  386. }
  387. struct fpfile far *freefile (struct fpfile far *p)
  388. {
  389. struct fpfile far *p1;
  390. p1 = p->next;
  391. free (p);
  392. return p1;
  393. }
  394. struct fpfile far *nfile (int n, struct fpfile far *p)
  395. {
  396. while (n--)
  397. if ((p = p->next) == NULL)
  398. break;
  399. return p;
  400. }
  401. flagType fIsDir (char *p)
  402. {
  403. int a = GetFileAttributes( p );
  404. if (a != -1)
  405. return (flagType) TESTFLAG (a, FILE_ATTRIBUTE_DIRECTORY);
  406. return FALSE;
  407. }
  408. int __cdecl main (int c, char *v[])
  409. {
  410. int i, j, k, rows, cols, len;
  411. flagType fGrand;
  412. char buf[MAX_PATH], buf2[MAX_PATH], tbuf[MAX_PATH];
  413. struct fppat far *pat;
  414. struct fpfile far *file;
  415. char *p;
  416. long totbytes, totalloc, t;
  417. time_t mtime;
  418. unsigned totfiles;
  419. /* Make a call to set the video buffering to null */
  420. //setvbuf( stdout, NULL, _IONBF, 0 );
  421. ConvertAppToOem( c, v );
  422. filename (*v, buf); /* remove path part, if any */
  423. if (!strcmpis (buf, "l"))
  424. fL = TRUE;
  425. SHIFT (c, v);
  426. while (c != 0 && fSwitChr (* (p = *v))) {
  427. while (*++p)
  428. switch (*p) {
  429. case 'F':
  430. fFull = TRUE;
  431. break;
  432. case 'u':
  433. fUTC = TRUE;
  434. break;
  435. case 'r':
  436. fReverse = TRUE;
  437. break;
  438. case 'q':
  439. fQuiet = TRUE;
  440. break;
  441. case 'R':
  442. fSubDir = TRUE;
  443. break;
  444. case 'd':
  445. fD = TRUE;
  446. break;
  447. case 'l':
  448. fL = TRUE;
  449. break;
  450. case 't':
  451. tySort = TYS_TIME;
  452. break;
  453. case '1':
  454. case 's':
  455. fSingle = TRUE;
  456. break;
  457. case 'S':
  458. tySort = TYS_SIZE;
  459. break;
  460. case 'v':
  461. fVisOnly = TRUE;
  462. break;
  463. default:
  464. printf ("Usage: LS [/FrqRdlt1sSvu] [files]\n");
  465. exit (1);
  466. }
  467. SHIFT (c, v);
  468. }
  469. if (c == 0) {
  470. c++; v--;
  471. *v = szStarDotStar;
  472. }
  473. curpath = toppath = NULL;
  474. while (c) {
  475. pname (*v);
  476. p = *v + strlen (*v) - 1;
  477. if (fPathChr (*p))
  478. savepath (*v, szStarDotStar);
  479. else
  480. if (*p == ':') {
  481. if (strlen (*v) != 2)
  482. break;
  483. savepath (*v, szStarDotStar);
  484. }
  485. else
  486. if (fIsDir (*v))
  487. savepath (*v, fD ? "" : szStarDotStar);
  488. else
  489. savepath (NULL, *v);
  490. SHIFT (c, v);
  491. }
  492. curpath = toppath;
  493. totbytes = 0L;
  494. totalloc = 0L;
  495. totfiles = 0;
  496. fGrand = FALSE;
  497. while (curpath) {
  498. len = curpath->maxlen;
  499. /* only do the space padding if we are going to print
  500. * more than one file per line
  501. */
  502. cols = len+2;
  503. if (fL)
  504. cols += 17 + 1 + STAMPLEN;
  505. cols = min (cols, 78);
  506. /* (cols) = columns of text per item
  507. * (len) = length of name field
  508. *
  509. * convert from columns of text to columns per screen
  510. */
  511. cols = 79 / (cols + 1);
  512. if (fSingle || cols == 1) {
  513. strcpy (buf, "%s");
  514. cols = 1;
  515. }
  516. else
  517. sprintf (buf, "%%-%ds ", len+1);
  518. rows = (curpath->cntEntries + cols - 1) / cols; /* number of rows */
  519. if (curpath != toppath) {
  520. fGrand = TRUE;
  521. putchar ('\n');
  522. }
  523. if (!fQuiet) {
  524. pat = curpath->pat;
  525. printf (" %s%s", curpath->name, pat->name);
  526. while (pat = freepat (pat))
  527. printf (" %s", pat->name);
  528. putchar('\n');
  529. }
  530. if (!curpath->first)
  531. printf ("no files\n");
  532. else {
  533. for (i = 0; i < rows; i++) {
  534. for (j = 0; j < cols; j++) {
  535. if ((file = nfile (i+j*rows, curpath->first)) == NULL)
  536. break;
  537. if (fL) {
  538. char *pTime;
  539. for (k=0; amsk[k]; k++)
  540. if (TESTFLAG (file->attr, amsk[k]))
  541. putchar(attrs[k]);
  542. else
  543. putchar('-');
  544. mtime = file->mtime;
  545. pTime = ctime(&mtime);
  546. if ( pTime ) {
  547. strcpy(tbuf, ctime (&mtime));
  548. } else {
  549. strcpy(tbuf, "??? ??? ?? ??:??:?? ????\n");
  550. }
  551. tbuf[strlen (tbuf) -1] = '\0';
  552. printf (" %9ld %s ", file->len, tbuf);
  553. }
  554. if (TESTFLAG (file->attr, pramsk[0])) {
  555. sprintf(buf2, "%s*", file->name);
  556. } else {
  557. sprintf(buf2, "%s", file->name);
  558. }
  559. curpath->bytes += file->len;
  560. t = file->len + curpath->bPerA - 1;
  561. t = t / curpath->bPerA;
  562. t = t * curpath->bPerA;
  563. curpath->bytesAlloc += t;
  564. printf (buf, buf2);
  565. }
  566. putchar('\n');
  567. }
  568. }
  569. if (!fQuiet && curpath->cntFiles) {
  570. printf (" %ld (%ld) bytes in %d files\n", curpath->bytesAlloc,
  571. curpath->bytes, curpath->cntFiles);
  572. totbytes += curpath->bytes;
  573. totalloc += curpath->bytesAlloc;
  574. totfiles += curpath->cntFiles;
  575. }
  576. curpath = freepath (curpath);
  577. }
  578. if (!fQuiet && fGrand)
  579. printf ("\nTotal of %ld (%ld) bytes in %d files\n", totalloc, totbytes, totfiles);
  580. return 0;
  581. }