list.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. /* $Source: /u/mark/src/pax/RCS/list.c,v $
  2. *
  3. * $Revision: 1.2 $
  4. *
  5. * list.c - List all files on an archive
  6. *
  7. * DESCRIPTION
  8. *
  9. * These function are needed to support archive table of contents and
  10. * verbose mode during extraction and creation of achives.
  11. *
  12. * AUTHOR
  13. *
  14. * Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
  15. *
  16. * Sponsored by The USENIX Association for public distribution.
  17. *
  18. * Copyright (c) 1989 Mark H. Colburn.
  19. * All rights reserved.
  20. *
  21. * Redistribution and use in source and binary forms are permitted
  22. * provided that the above copyright notice is duplicated in all such
  23. * forms and that any documentation, advertising materials, and other
  24. * materials related to such distribution and use acknowledge that the
  25. * software was developed * by Mark H. Colburn and sponsored by The
  26. * USENIX Association.
  27. *
  28. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  29. * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  30. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  31. *
  32. * $Log: list.c,v $
  33. * Revision 1.2 89/02/12 10:04:43 mark
  34. * 1.2 release fixes
  35. *
  36. * Revision 1.1 88/12/23 18:02:14 mark
  37. * Initial revision
  38. *
  39. */
  40. #ifndef lint
  41. static char *ident = "$Id: list.c,v 1.2 89/02/12 10:04:43 mark Exp $";
  42. static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
  43. #endif /* ! lint */
  44. /* Headers */
  45. #include "pax.h"
  46. /* Defines */
  47. /*
  48. * isodigit returns non zero iff argument is an octal digit, zero otherwise
  49. */
  50. #define ISODIGIT(c) (((c) >= '0') && ((c) <= '7'))
  51. /* Function Prototypes */
  52. #ifdef __STDC__
  53. static void cpio_entry(char *, Stat *);
  54. static void tar_entry(char *, Stat *);
  55. static void pax_entry(char *, Stat *);
  56. static void print_mode(ushort);
  57. static long from_oct(int digs, char *where);
  58. #else /* !__STDC__ */
  59. static void cpio_entry();
  60. static void tar_entry();
  61. static void pax_entry();
  62. static void print_mode();
  63. static long from_oct();
  64. #endif /* __STDC__ */
  65. /* Internal Identifiers */
  66. static char *monnames[] = {
  67. "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  68. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  69. };
  70. /* read_header - read a header record
  71. *
  72. * DESCRIPTION
  73. *
  74. * Read a record that's supposed to be a header record. Return its
  75. * address in "head", and if it is good, the file's size in
  76. * asb->sb_size. Decode things from a file header record into a "Stat".
  77. * Also set "head_standard" to !=0 or ==0 depending whether header record
  78. * is "Unix Standard" tar format or regular old tar format.
  79. *
  80. * PARAMETERS
  81. *
  82. * char *name - pointer which will contain name of file
  83. * Stat *asb - pointer which will contain stat info
  84. *
  85. * RETURNS
  86. *
  87. * Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
  88. * record full of zeros (EOF marker).
  89. */
  90. #ifdef __STDC__
  91. int read_header(char *name, Stat *asb)
  92. #else
  93. int read_header(name, asb)
  94. char *name;
  95. Stat *asb;
  96. #endif
  97. {
  98. int i;
  99. long sum;
  100. long recsum;
  101. Link *link;
  102. char *p;
  103. char hdrbuf[BLOCKSIZE];
  104. memset((char *)asb, 0, sizeof(Stat));
  105. /* read the header from the buffer */
  106. if (buf_read(hdrbuf, BLOCKSIZE) != 0) {
  107. return (EOF);
  108. }
  109. strcpy(name, hdrbuf);
  110. recsum = from_oct(8, &hdrbuf[148]);
  111. sum = 0;
  112. p = hdrbuf;
  113. for (i = 0 ; i < 500; i++) {
  114. /*
  115. * We can't use unsigned char here because of old compilers, e.g. V7.
  116. */
  117. sum += 0xFF & *p++;
  118. }
  119. /* Adjust checksum to count the "chksum" field as blanks. */
  120. for (i = 0; i < 8; i++) {
  121. sum -= 0xFF & hdrbuf[148 + i];
  122. }
  123. sum += ' ' * 8;
  124. if (sum == 8 * ' ') {
  125. /*
  126. * This is a zeroed record...whole record is 0's except for the 8
  127. * blanks we faked for the checksum field.
  128. */
  129. return (2);
  130. }
  131. if (sum == recsum) {
  132. /*
  133. * Good record. Decode file size and return.
  134. */
  135. if (hdrbuf[156] != LNKTYPE) {
  136. asb->sb_size = from_oct(1 + 12, &hdrbuf[124]);
  137. }
  138. asb->sb_mtime = from_oct(1 + 12, &hdrbuf[136]);
  139. asb->sb_mode = from_oct(8, &hdrbuf[100]);
  140. if (strcmp(&hdrbuf[257], TMAGIC) == 0) {
  141. /* Unix Standard tar archive */
  142. head_standard = 1;
  143. #ifdef NONAMES
  144. asb->sb_uid = from_oct(8, &hdrbuf[108]);
  145. asb->sb_gid = from_oct(8, &hdrbuf[116]);
  146. #else
  147. asb->sb_uid = finduid(&hdrbuf[265]);
  148. asb->sb_gid = findgid(&hdrbuf[297]);
  149. #endif
  150. switch (hdrbuf[156]) {
  151. case BLKTYPE:
  152. case CHRTYPE:
  153. #ifndef _POSIX_SOURCE
  154. asb->sb_rdev = makedev(from_oct(8, &hdrbuf[329]),
  155. from_oct(8, &hdrbuf[337]));
  156. #endif
  157. break;
  158. default:
  159. /* do nothing... */
  160. break;
  161. }
  162. } else {
  163. /* Old fashioned tar archive */
  164. head_standard = 0;
  165. asb->sb_uid = from_oct(8, &hdrbuf[108]);
  166. asb->sb_gid = from_oct(8, &hdrbuf[116]);
  167. }
  168. switch (hdrbuf[156]) {
  169. case REGTYPE:
  170. case AREGTYPE:
  171. /*
  172. * Berkeley tar stores directories as regular files with a
  173. * trailing /
  174. */
  175. if (name[strlen(name) - 1] == '/') {
  176. name[strlen(name) - 1] = '\0';
  177. asb->sb_mode |= S_IFDIR;
  178. } else {
  179. asb->sb_mode |= S_IFREG;
  180. }
  181. break;
  182. case LNKTYPE:
  183. asb->sb_nlink = 2;
  184. linkto(&hdrbuf[157], asb);
  185. linkto(name, asb);
  186. asb->sb_mode |= S_IFREG;
  187. break;
  188. case BLKTYPE:
  189. asb->sb_mode |= S_IFBLK;
  190. break;
  191. case CHRTYPE:
  192. asb->sb_mode |= S_IFCHR;
  193. break;
  194. case DIRTYPE:
  195. asb->sb_mode |= S_IFDIR;
  196. break;
  197. #ifdef S_IFLNK
  198. case SYMTYPE:
  199. asb->sb_mode |= S_IFLNK;
  200. strcpy(asb->sb_link, &hdrbuf[157]);
  201. break;
  202. #endif
  203. #ifdef S_IFIFO
  204. case FIFOTYPE:
  205. asb->sb_mode |= S_IFIFO;
  206. break;
  207. #endif
  208. #ifdef S_IFCTG
  209. case CONTTYPE:
  210. asb->sb_mode |= S_IFCTG;
  211. break;
  212. #endif
  213. }
  214. return (1);
  215. }
  216. return (0);
  217. }
  218. /* print_entry - print a single table-of-contents entry
  219. *
  220. * DESCRIPTION
  221. *
  222. * Print_entry prints a single line of file information. The format
  223. * of the line is the same as that used by the LS command. For some
  224. * archive formats, various fields may not make any sense, such as
  225. * the link count on tar archives. No error checking is done for bad
  226. * or invalid data.
  227. *
  228. * PARAMETERS
  229. *
  230. * char *name - pointer to name to print an entry for
  231. * Stat *asb - pointer to the stat structure for the file
  232. */
  233. #ifdef __STDC__
  234. void print_entry(char *name, Stat *asb)
  235. #else
  236. void print_entry(name, asb)
  237. char *name;
  238. Stat *asb;
  239. #endif
  240. {
  241. switch (ar_interface) {
  242. case TAR:
  243. tar_entry(name, asb);
  244. break;
  245. case CPIO:
  246. cpio_entry(name, asb);
  247. break;
  248. case PAX: pax_entry(name, asb);
  249. break;
  250. }
  251. }
  252. /* cpio_entry - print a verbose cpio-style entry
  253. *
  254. * DESCRIPTION
  255. *
  256. * Print_entry prints a single line of file information. The format
  257. * of the line is the same as that used by the traditional cpio
  258. * command. No error checking is done for bad or invalid data.
  259. *
  260. * PARAMETERS
  261. *
  262. * char *name - pointer to name to print an entry for
  263. * Stat *asb - pointer to the stat structure for the file
  264. */
  265. #ifdef __STDC__
  266. static void cpio_entry(char *name, Stat *asb)
  267. #else
  268. static void cpio_entry(name, asb)
  269. char *name;
  270. Stat *asb;
  271. #endif
  272. {
  273. struct tm *atm;
  274. Link *from;
  275. struct passwd *pwp;
  276. struct group *grp;
  277. if (f_list && f_verbose) {
  278. fprintf(msgfile, "%-7o", asb->sb_mode);
  279. atm = localtime(&asb->sb_mtime);
  280. if (pwp = getpwuid((int) USH(asb->sb_uid))) {
  281. fprintf(msgfile, "%-6s", pwp->pw_name);
  282. } else {
  283. fprintf(msgfile, "%-6u", USH(asb->sb_uid));
  284. }
  285. fprintf(msgfile,"%7ld %3s %2d %02d:%02d:%02d %4d ",
  286. asb->sb_size, monnames[atm->tm_mon],
  287. atm->tm_mday, atm->tm_hour, atm->tm_min,
  288. atm->tm_sec, atm->tm_year + 1900);
  289. }
  290. fprintf(msgfile, "%s", name);
  291. if ((asb->sb_nlink > 1) && (from = islink(name, asb))) {
  292. fprintf(msgfile, " linked to %s", from->l_name);
  293. }
  294. #ifdef S_IFLNK
  295. if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
  296. fprintf(msgfile, " symbolic link to %s", asb->sb_link);
  297. }
  298. #endif /* S_IFLNK */
  299. putc('\n', msgfile);
  300. }
  301. /* tar_entry - print a tar verbose mode entry
  302. *
  303. * DESCRIPTION
  304. *
  305. * Print_entry prints a single line of tar file information. The format
  306. * of the line is the same as that produced by the traditional tar
  307. * command. No error checking is done for bad or invalid data.
  308. *
  309. * PARAMETERS
  310. *
  311. * char *name - pointer to name to print an entry for
  312. * Stat *asb - pointer to the stat structure for the file
  313. */
  314. #ifdef __STDC__
  315. static void tar_entry(char *name, Stat *asb)
  316. #else
  317. static void tar_entry(name, asb)
  318. char *name;
  319. Stat *asb;
  320. #endif
  321. {
  322. struct tm *atm;
  323. int i;
  324. int mode;
  325. char *symnam = "NULL";
  326. Link *link;
  327. if ((mode = asb->sb_mode & S_IFMT) == S_IFDIR) {
  328. return; /* don't print directories */
  329. }
  330. if (f_extract) {
  331. switch (mode) {
  332. #ifdef S_IFLNK
  333. case S_IFLNK: /* This file is a symbolic link */
  334. i = readlink(name, symnam, PATH_MAX - 1);
  335. if (i < 0) { /* Could not find symbolic link */
  336. warn("can't read symbolic link", strerror());
  337. } else { /* Found symbolic link filename */
  338. symnam[i] = '\0';
  339. fprintf(msgfile, "x %s symbolic link to %s\n", name, symnam);
  340. }
  341. break;
  342. #endif
  343. case S_IFREG: /* It is a link or a file */
  344. if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
  345. fprintf(msgfile, "%s linked to %s\n", name, link->l_name);
  346. } else {
  347. fprintf(msgfile, "x %s, %ld bytes, %d tape blocks\n",
  348. name, asb->sb_size, ROUNDUP(asb->sb_size,
  349. BLOCKSIZE) / BLOCKSIZE);
  350. }
  351. }
  352. } else if (f_append || f_create) {
  353. switch (mode) {
  354. #ifdef S_IFLNK
  355. case S_IFLNK: /* This file is a symbolic link */
  356. i = readlink(name, symnam, PATH_MAX - 1);
  357. if (i < 0) { /* Could not find symbolic link */
  358. warn("can't read symbolic link", strerror());
  359. } else { /* Found symbolic link filename */
  360. symnam[i] = '\0';
  361. fprintf(msgfile, "a %s symbolic link to %s\n", name, symnam);
  362. }
  363. break;
  364. #endif
  365. case S_IFREG: /* It is a link or a file */
  366. fprintf(msgfile, "a %s ", name);
  367. if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
  368. fprintf(msgfile, "link to %s\n", link->l_name);
  369. } else {
  370. fprintf(msgfile, "%ld Blocks\n",
  371. ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
  372. }
  373. break;
  374. }
  375. } else if (f_list) {
  376. if (f_verbose) {
  377. atm = localtime(&asb->sb_mtime);
  378. print_mode(asb->sb_mode);
  379. fprintf(msgfile," %d/%d %6d %3s %2d %02d:%02d %4d %s",
  380. asb->sb_uid, asb->sb_gid, asb->sb_size,
  381. monnames[atm->tm_mon], atm->tm_mday, atm->tm_hour,
  382. atm->tm_min, atm->tm_year + 1900, name);
  383. } else {
  384. fprintf(msgfile, "%s", name);
  385. }
  386. switch (mode) {
  387. #ifdef S_IFLNK
  388. case S_IFLNK: /* This file is a symbolic link */
  389. i = readlink(name, symnam, PATH_MAX - 1);
  390. if (i < 0) { /* Could not find symbolic link */
  391. warn("can't read symbolic link", strerror());
  392. } else { /* Found symbolic link filename */
  393. symnam[i] = '\0';
  394. fprintf(msgfile, " symbolic link to %s", symnam);
  395. }
  396. break;
  397. #endif
  398. case S_IFREG: /* It is a link or a file */
  399. if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
  400. fprintf(msgfile, " linked to %s", link->l_name);
  401. }
  402. break; /* Do not print out directories */
  403. }
  404. fputc('\n', msgfile);
  405. } else {
  406. fprintf(msgfile, "? %s %ld blocks\n", name,
  407. ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
  408. }
  409. }
  410. /* pax_entry - print a verbose cpio-style entry
  411. *
  412. * DESCRIPTION
  413. *
  414. * Print_entry prints a single line of file information. The format
  415. * of the line is the same as that used by the LS command.
  416. * No error checking is done for bad or invalid data.
  417. *
  418. * PARAMETERS
  419. *
  420. * char *name - pointer to name to print an entry for
  421. * Stat *asb - pointer to the stat structure for the file
  422. */
  423. #ifdef __STDC__
  424. static void pax_entry(char *name, Stat *asb)
  425. #else
  426. static void pax_entry(name, asb)
  427. char *name;
  428. Stat *asb;
  429. #endif
  430. {
  431. struct tm *atm;
  432. Link *from;
  433. struct passwd *pwp;
  434. struct group *grp;
  435. if (f_list && f_verbose) {
  436. print_mode(asb->sb_mode);
  437. fprintf(msgfile, " %2d", asb->sb_nlink);
  438. atm = localtime(&asb->sb_mtime);
  439. if (pwp = getpwuid((int) USH(asb->sb_uid))) {
  440. fprintf(msgfile, " %-8s", pwp->pw_name);
  441. } else {
  442. fprintf(msgfile, " %-8u", USH(asb->sb_uid));
  443. }
  444. if (grp = getgrgid((int) USH(asb->sb_gid))) {
  445. fprintf(msgfile, " %-8s", grp->gr_name);
  446. } else {
  447. fprintf(msgfile, " %-8u", USH(asb->sb_gid));
  448. }
  449. switch (asb->sb_mode & S_IFMT) {
  450. case S_IFBLK:
  451. case S_IFCHR:
  452. fprintf(msgfile, "\t%3d, %3d",
  453. major(asb->sb_rdev), minor(asb->sb_rdev));
  454. break;
  455. case S_IFREG:
  456. fprintf(msgfile, "\t%8ld", asb->sb_size);
  457. break;
  458. default:
  459. fprintf(msgfile, "\t ");
  460. }
  461. fprintf(msgfile," %3s %2d %02d:%02d ",
  462. monnames[atm->tm_mon], atm->tm_mday,
  463. atm->tm_hour, atm->tm_min);
  464. }
  465. fprintf(msgfile, "%s", name);
  466. if ((asb->sb_nlink > 1) && (from = islink(name, asb))) {
  467. fprintf(msgfile, " == %s", from->l_name);
  468. }
  469. #ifdef S_IFLNK
  470. if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
  471. fprintf(msgfile, " -> %s", asb->sb_link);
  472. }
  473. #endif /* S_IFLNK */
  474. putc('\n', msgfile);
  475. }
  476. /* print_mode - fancy file mode display
  477. *
  478. * DESCRIPTION
  479. *
  480. * Print_mode displays a numeric file mode in the standard unix
  481. * representation, ala ls (-rwxrwxrwx). No error checking is done
  482. * for bad mode combinations. FIFOS, sybmbolic links, sticky bits,
  483. * block- and character-special devices are supported if supported
  484. * by the hosting implementation.
  485. *
  486. * PARAMETERS
  487. *
  488. * ushort mode - The integer representation of the mode to print.
  489. */
  490. #ifdef __STDC__
  491. static void print_mode(ushort mode)
  492. #else
  493. static void print_mode(mode)
  494. ushort mode;
  495. #endif
  496. {
  497. /* Tar does not print the leading identifier... */
  498. if (ar_interface != TAR) {
  499. switch (mode & S_IFMT) {
  500. case S_IFDIR:
  501. putc('d', msgfile);
  502. break;
  503. #ifdef S_IFLNK
  504. case S_IFLNK:
  505. putc('l', msgfile);
  506. break;
  507. #endif /* S_IFLNK */
  508. case S_IFBLK:
  509. putc('b', msgfile);
  510. break;
  511. case S_IFCHR:
  512. putc('c', msgfile);
  513. break;
  514. #ifdef S_IFIFO
  515. case S_IFIFO:
  516. putc('p', msgfile);
  517. break;
  518. #endif /* S_IFIFO */
  519. case S_IFREG:
  520. default:
  521. putc('-', msgfile);
  522. break;
  523. }
  524. }
  525. putc(mode & 0400 ? 'r' : '-', msgfile);
  526. putc(mode & 0200 ? 'w' : '-', msgfile);
  527. putc(mode & 0100
  528. ? mode & 04000 ? 's' : 'x'
  529. : mode & 04000 ? 'S' : '-', msgfile);
  530. putc(mode & 0040 ? 'r' : '-', msgfile);
  531. putc(mode & 0020 ? 'w' : '-', msgfile);
  532. putc(mode & 0010
  533. ? mode & 02000 ? 's' : 'x'
  534. : mode & 02000 ? 'S' : '-', msgfile);
  535. putc(mode & 0004 ? 'r' : '-', msgfile);
  536. putc(mode & 0002 ? 'w' : '-', msgfile);
  537. putc(mode & 0001
  538. ? mode & 01000 ? 't' : 'x'
  539. : mode & 01000 ? 'T' : '-', msgfile);
  540. }
  541. /* from_oct - quick and dirty octal conversion
  542. *
  543. * DESCRIPTION
  544. *
  545. * From_oct will convert an ASCII representation of an octal number
  546. * to the numeric representation. The number of characters to convert
  547. * is given by the parameter "digs". If there are less numbers than
  548. * specified by "digs", then the routine returns -1.
  549. *
  550. * PARAMETERS
  551. *
  552. * int digs - Number to of digits to convert
  553. * char *where - Character representation of octal number
  554. *
  555. * RETURNS
  556. *
  557. * The value of the octal number represented by the first digs
  558. * characters of the string where. Result is -1 if the field
  559. * is invalid (all blank, or nonoctal).
  560. *
  561. * ERRORS
  562. *
  563. * If the field is all blank, then the value returned is -1.
  564. *
  565. */
  566. #ifdef __STDC__
  567. static long from_oct(int digs, char *where)
  568. #else
  569. static long from_oct(digs, where)
  570. int digs; /* number of characters to convert */
  571. char *where; /* character representation of octal number */
  572. #endif
  573. {
  574. long value;
  575. while (isspace(*where)) { /* Skip spaces */
  576. where++;
  577. if (--digs <= 0) {
  578. return(-1); /* All blank field */
  579. }
  580. }
  581. value = 0;
  582. while (digs > 0 && ISODIGIT(*where)) { /* Scan til nonoctal */
  583. value = (value << 3) | (*where++ - '0');
  584. --digs;
  585. }
  586. if (digs > 0 && *where && !isspace(*where)) {
  587. return(-1); /* Ended on non-space/nul */
  588. }
  589. return(value);
  590. }