tar.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /* Virtual File System: GNU Tar file system.
  2. Copyright (C) 1995 The Free Software Foundation
  3. Written by: 1995 Jakub Jelinek
  4. Rewritten by: 1998 Pavel Machek
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public License
  7. as published by the Free Software Foundation; either version 2 of
  8. the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  16. /* Namespace: vfs_tarfs_ops */
  17. #include "xdirentry.h"
  18. #include <errno.h>
  19. #ifdef SCO_FLAVOR
  20. #include <sys/timeb.h> /* alex: for struct timeb definition */
  21. #endif /* SCO_FLAVOR */
  22. #include <time.h>
  23. #include "../src/fs.h"
  24. #include "../src/util.h"
  25. #include "../src/dialog.h" /* For MSG_ERROR */
  26. #include "tar.h"
  27. #include "names.h"
  28. int tar_gzipped_memlimit; /* unused, to be killed, soon */
  29. #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
  30. /*
  31. * Quick and dirty octal conversion.
  32. *
  33. * Result is -1 if the field is invalid (all blank, or nonoctal).
  34. */
  35. static long from_oct (int digs, char *where)
  36. {
  37. register long value;
  38. while (isspace (*where)) { /* Skip spaces */
  39. where++;
  40. if (--digs <= 0)
  41. return -1; /* All blank field */
  42. }
  43. value = 0;
  44. while (digs > 0 && isodigit (*where)) { /* Scan till nonoctal */
  45. value = (value << 3) | (*where++ - '0');
  46. --digs;
  47. }
  48. if (digs > 0 && *where && !isspace (*where))
  49. return -1; /* Ended on non-space/nul */
  50. return value;
  51. }
  52. static struct stat hstat; /* Stat struct corresponding */
  53. static void tar_free_archive (vfs *me, vfs_s_super *archive)
  54. {
  55. if (archive->u.tar.fd != -1)
  56. mc_close(archive->u.tar.fd);
  57. }
  58. struct tar_super {
  59. };
  60. #define SUPER_DATA ((struct tar_super *) super->data)
  61. /* As we open one archive at a time, it is safe to have this static */
  62. static int current_tar_position = 0;
  63. /* Returns fd of the open tar file */
  64. static int tar_open_archive (vfs *me, char *name, vfs_s_super *archive)
  65. {
  66. int result, type;
  67. long size;
  68. mode_t mode;
  69. struct vfs_s_inode *root;
  70. result = mc_open (name, O_RDONLY);
  71. if (result == -1) {
  72. message_2s (1, MSG_ERROR, _("Couldn't open tar archive\n%s"), name);
  73. ERRNOR (ENOENT, -1);
  74. }
  75. archive->name = strdup (name);
  76. mc_stat (name, &(archive->u.tar.tarstat));
  77. archive->u.tar.fd = -1;
  78. /* Find out the method to handle this tar file */
  79. size = is_gunzipable (result, &type);
  80. mc_lseek (result, 0, SEEK_SET);
  81. if (size > 0) {
  82. char *s;
  83. mc_close( result );
  84. s = copy_strings( archive->name, decompress_extension (type), NULL );
  85. result = mc_open (s, O_RDONLY);
  86. if (result == -1)
  87. message_2s (1, MSG_ERROR, _("Couldn't open tar archive\n%s"), s);
  88. free(s);
  89. if (result == -1)
  90. ERRNOR (ENOENT, -1);
  91. }
  92. archive->u.tar.fd = result;
  93. mode = archive->u.tar.tarstat.st_mode & 07777;
  94. if (mode & 0400) mode |= 0100;
  95. if (mode & 0040) mode |= 0010;
  96. if (mode & 0004) mode |= 0001;
  97. mode |= S_IFDIR;
  98. root = vfs_s_new_inode (me, archive, &archive->u.tar.tarstat);
  99. root->st.st_mode = mode;
  100. root->u.tar.data_offset = -1;
  101. root->st.st_nlink++;
  102. vfs_s_add_dots (me, root, NULL);
  103. archive->root = root;
  104. return result;
  105. }
  106. static union record rec_buf;
  107. static union record *get_next_record (vfs_s_super *archive, int tard)
  108. {
  109. if (mc_read (tard, rec_buf.charptr, RECORDSIZE) != RECORDSIZE)
  110. return NULL; /* An error has occurred */
  111. current_tar_position += RECORDSIZE;
  112. return &rec_buf;
  113. }
  114. static void skip_n_records (vfs_s_super *archive, int tard, int n)
  115. {
  116. mc_lseek (tard, n * RECORDSIZE, SEEK_CUR);
  117. current_tar_position += n * RECORDSIZE;
  118. }
  119. static void fill_stat_from_header (vfs *me, struct stat *st, union record *header)
  120. {
  121. st->st_mode = from_oct (8, header->header.mode);
  122. /* Adjust st->st_mode because there are tar-files with
  123. * linkflag==LF_SYMLINK and S_ISLNK(mod)==0. I don't
  124. * know about the other modes but I think I cause no new
  125. * problem when I adjust them, too. -- Norbert.
  126. */
  127. if (header->header.linkflag == LF_DIR) {
  128. st->st_mode |= S_IFDIR;
  129. } else if (header->header.linkflag == LF_SYMLINK) {
  130. st->st_mode |= S_IFLNK;
  131. } else if (header->header.linkflag == LF_CHR) {
  132. st->st_mode |= S_IFCHR;
  133. } else if (header->header.linkflag == LF_BLK) {
  134. st->st_mode |= S_IFBLK;
  135. } else if (header->header.linkflag == LF_FIFO) {
  136. st->st_mode |= S_IFIFO;
  137. } else
  138. st->st_mode |= S_IFREG;
  139. st->st_rdev = 0;
  140. if (!strcmp (header->header.magic, TMAGIC)) {
  141. st->st_uid = *header->header.uname ? finduid (header->header.uname) :
  142. from_oct (8, header->header.uid);
  143. st->st_gid = *header->header.gname ? findgid (header->header.gname) :
  144. from_oct (8, header->header.gid);
  145. switch (header->header.linkflag) {
  146. case LF_BLK:
  147. case LF_CHR:
  148. st->st_rdev = (from_oct (8, header->header.devmajor) << 8) |
  149. from_oct (8, header->header.devminor);
  150. }
  151. } else { /* Old Unix tar */
  152. st->st_uid = from_oct (8, header->header.uid);
  153. st->st_gid = from_oct (8, header->header.gid);
  154. }
  155. st->st_size = hstat.st_size;
  156. st->st_mtime = from_oct (1 + 12, header->header.mtime);
  157. st->st_atime = from_oct (1 + 12, header->header.atime);
  158. st->st_ctime = from_oct (1 + 12, header->header.ctime);
  159. }
  160. /*
  161. * Return 1 for success, 0 if the checksum is bad, EOF on eof,
  162. * 2 for a record full of zeros (EOF marker).
  163. *
  164. */
  165. static int read_header (vfs *me, vfs_s_super *archive, int tard)
  166. {
  167. register int i;
  168. register long sum, signed_sum, recsum;
  169. register char *p;
  170. register union record *header;
  171. char **longp;
  172. char *bp, *data;
  173. int size, written;
  174. static char *next_long_name = NULL, *next_long_link = NULL;
  175. char *current_file_name, *current_link_name;
  176. recurse:
  177. header = get_next_record (archive, tard);
  178. if (NULL == header)
  179. return EOF;
  180. recsum = from_oct (8, header->header.chksum);
  181. sum = 0; signed_sum = 0;
  182. p = header->charptr;
  183. for (i = sizeof (*header); --i >= 0;) {
  184. /*
  185. * We can't use unsigned char here because of old compilers,
  186. * e.g. V7.
  187. */
  188. signed_sum += *p;
  189. sum += 0xFF & *p++;
  190. }
  191. /* Adjust checksum to count the "chksum" field as blanks. */
  192. for (i = sizeof (header->header.chksum); --i >= 0;) {
  193. sum -= 0xFF & header->header.chksum[i];
  194. signed_sum -= (char) header->header.chksum[i];
  195. }
  196. sum += ' ' * sizeof header->header.chksum;
  197. signed_sum += ' ' * sizeof header->header.chksum;
  198. if (sum == 8 * ' ') {
  199. /*
  200. * This is a zeroed record...whole record is 0's except
  201. * for the 8 blanks we faked for the checksum field.
  202. */
  203. return 2;
  204. }
  205. if (sum != recsum && signed_sum != recsum)
  206. return 0;
  207. /*
  208. * linkflag on BSDI tar (pax) always '\000'
  209. */
  210. if(header->header.linkflag == '\000' &&
  211. strlen(header->header.arch_name) &&
  212. header->header.arch_name[strlen(header->header.arch_name) - 1] == '/')
  213. header->header.linkflag = LF_DIR;
  214. /*
  215. * Good record. Decode file size and return.
  216. */
  217. if (header->header.linkflag == LF_LINK || header->header.linkflag == LF_DIR)
  218. hstat.st_size = 0; /* Links 0 size on tape */
  219. else
  220. hstat.st_size = from_oct (1 + 12, header->header.size);
  221. header->header.arch_name[NAMSIZ - 1] = '\0';
  222. if (header->header.linkflag == LF_LONGNAME
  223. || header->header.linkflag == LF_LONGLINK) {
  224. longp = ((header->header.linkflag == LF_LONGNAME)
  225. ? &next_long_name
  226. : &next_long_link);
  227. if (*longp)
  228. free (*longp);
  229. bp = *longp = (char *) xmalloc (hstat.st_size, "Tar: Long name");
  230. for (size = hstat.st_size;
  231. size > 0;
  232. size -= written) {
  233. data = get_next_record (archive, tard)->charptr;
  234. if (data == NULL) {
  235. message_1s (1, MSG_ERROR, _("Unexpected EOF on archive file"));
  236. return 0;
  237. }
  238. written = RECORDSIZE;
  239. if (written > size)
  240. written = size;
  241. bcopy (data, bp, written);
  242. bp += written;
  243. }
  244. #if 0
  245. if (hstat.st_size > 1)
  246. bp [hstat.st_size - 1] = 0; /* just to make sure */
  247. #endif
  248. goto recurse;
  249. } else {
  250. struct stat st;
  251. struct vfs_s_entry *entry;
  252. struct vfs_s_inode *inode, *parent;
  253. long data_position;
  254. char *p, *q;
  255. int len;
  256. int isdir = 0;
  257. current_file_name = (next_long_name
  258. ? next_long_name
  259. : strdup (header->header.arch_name));
  260. len = strlen (current_file_name);
  261. if (current_file_name[len - 1] == '/') {
  262. current_file_name[len - 1] = 0;
  263. isdir = 1;
  264. }
  265. current_link_name = (next_long_link
  266. ? next_long_link
  267. : strdup (header->header.arch_linkname));
  268. len = strlen (current_link_name);
  269. if (len && current_link_name [len - 1] == '/')
  270. current_link_name[len - 1] = 0;
  271. next_long_link = next_long_name = NULL;
  272. data_position = current_tar_position;
  273. p = strrchr (current_file_name, '/');
  274. if (p == NULL) {
  275. p = current_file_name;
  276. q = current_file_name + strlen (current_file_name); /* "" */
  277. } else {
  278. *(p++) = 0;
  279. q = current_file_name;
  280. }
  281. parent = vfs_s_find_inode (me, archive->root, q, NO_FOLLOW, FL_MKDIR);
  282. if (parent == NULL) {
  283. message_1s (1, MSG_ERROR, _("Inconsistent tar archive"));
  284. return 0;
  285. }
  286. if (header->header.linkflag == LF_LINK) {
  287. parent = vfs_s_find_inode (me, archive->root, current_link_name, NO_FOLLOW, 0);
  288. if (parent == NULL) {
  289. message_1s (1, MSG_ERROR, _("Inconsistent tar archive"));
  290. } else {
  291. inode = parent;
  292. entry = vfs_s_new_entry(me, p, inode);
  293. vfs_s_insert_entry(me, parent, entry);
  294. free (current_link_name);
  295. goto done;
  296. }
  297. }
  298. fill_stat_from_header (me, &st, header);
  299. inode = vfs_s_new_inode (me, archive, &st);
  300. inode->u.tar.data_offset = data_position;
  301. if (*current_link_name)
  302. inode->linkname = current_link_name;
  303. entry = vfs_s_new_entry (me, p, inode);
  304. vfs_s_insert_entry (me, parent, entry);
  305. free (current_file_name);
  306. done:
  307. if (header->header.isextended) {
  308. while (get_next_record (archive, tard)->ext_hdr.isextended);
  309. inode->u.tar.data_offset = current_tar_position;
  310. }
  311. return 1;
  312. }
  313. }
  314. /*
  315. * Main loop for reading an archive.
  316. * Returns 0 on success, -1 on error.
  317. */
  318. static int open_archive (vfs *me, vfs_s_super *archive, char *name, char *op)
  319. {
  320. int status = 3; /* Initial status at start of archive */
  321. int prev_status;
  322. int tard;
  323. current_tar_position = 0;
  324. if ((tard = tar_open_archive (me, name, archive)) == -1) /* Open for reading */
  325. return -1;
  326. for (;;) {
  327. prev_status = status;
  328. status = read_header (me, archive, tard);
  329. switch (status) {
  330. case 1: /* Valid header */
  331. skip_n_records (archive, tard, (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE);
  332. continue;
  333. /*
  334. * If the previous header was good, tell them
  335. * that we are skipping bad ones.
  336. */
  337. case 0: /* Invalid header */
  338. switch (prev_status) {
  339. case 3: /* Error on first record */
  340. message_2s (1, MSG_ERROR, _("Hmm,...\n%s\ndoesn't look like a tar archive."), name);
  341. /* FALL THRU */
  342. case 2: /* Error after record of zeroes */
  343. case 1: /* Error after header rec */
  344. #if 0
  345. message_1s (0, " Warning ", "Skipping to next file header...");
  346. #endif
  347. case 0: /* Error after error */
  348. return -1;
  349. }
  350. case 2: /* Record of zeroes */
  351. status = prev_status; /* If error after 0's */
  352. /* FALL THRU */
  353. case EOF: /* End of archive */
  354. break;
  355. }
  356. break;
  357. };
  358. return 0;
  359. }
  360. void *tar_super_check(vfs *me, char *archive_name, char *op)
  361. {
  362. static struct stat stat_buf;
  363. if (mc_stat (archive_name, &stat_buf))
  364. return NULL;
  365. return &stat_buf;
  366. }
  367. int tar_super_same(vfs *me, struct vfs_s_super *parc, char *archive_name, char *op, void *cookie)
  368. {
  369. struct stat *archive_stat = cookie; /* stat of main archive */
  370. if (strcmp (parc->name, archive_name)) return 0;
  371. if (vfs_uid && (!(archive_stat->st_mode & 0004)))
  372. if ((archive_stat->st_gid != vfs_gid) || !(archive_stat->st_mode & 0040))
  373. if ((archive_stat->st_uid != vfs_uid) || !(archive_stat->st_mode & 0400))
  374. return 0;
  375. /* Has the cached archive been changed on the disk? */
  376. if (parc->u.tar.tarstat.st_mtime < archive_stat->st_mtime) { /* Yes, reload! */
  377. (*vfs_tarfs_ops.free) ((vfsid) parc);
  378. vfs_rmstamp (&vfs_tarfs_ops, (vfsid) parc, 0);
  379. return 2;
  380. }
  381. /* Hasn't been modified, give it a new timeout */
  382. vfs_stamp (&vfs_tarfs_ops, (vfsid) parc);
  383. return 1;
  384. }
  385. static int tar_read (void *fh, char *buffer, int count)
  386. {
  387. off_t begin = FH->ino->u.tar.data_offset;
  388. int fd = FH_SUPER->u.tar.fd;
  389. vfs *me = FH_SUPER->me;
  390. if (mc_lseek (fd, begin + FH->pos, SEEK_SET) !=
  391. begin + FH->pos) ERRNOR (EIO, -1);
  392. count = VFS_MIN(count, FH->ino->st.st_size - FH->pos);
  393. if ((count = mc_read (fd, buffer, count)) == -1) ERRNOR (errno, -1);
  394. FH->pos += count;
  395. return count;
  396. }
  397. static void tar_ungetlocalcopy (vfs *me, char *path, char *local, int has_changed)
  398. {
  399. /* We do just nothing. (We are read only and do not need to free local,
  400. since it will be freed when tar archive will be freed */
  401. }
  402. static int tar_fh_open (vfs *me, vfs_s_fh *fh, int flags, int mode)
  403. {
  404. if ((flags & O_ACCMODE) != O_RDONLY) ERRNOR (EROFS, -1);
  405. return 0;
  406. }
  407. static struct vfs_s_data tarfs_data = {
  408. NULL,
  409. 0,
  410. 0,
  411. NULL, /* logfile */
  412. NULL, /* init_inode */
  413. NULL, /* free_inode */
  414. NULL, /* init_entry */
  415. tar_super_check,
  416. tar_super_same,
  417. open_archive,
  418. tar_free_archive,
  419. tar_fh_open, /* fh_open */
  420. NULL, /* fh_close */
  421. vfs_s_find_entry_tree,
  422. NULL,
  423. NULL
  424. };
  425. vfs vfs_tarfs_ops =
  426. {
  427. NULL, /* This is place of next pointer */
  428. "TApe aRchiver decompressor",
  429. 0, /* flags */
  430. "utar", /* prefix */
  431. &tarfs_data,
  432. 0, /* errno */
  433. NULL,
  434. NULL,
  435. vfs_s_fill_names,
  436. NULL,
  437. vfs_s_open,
  438. vfs_s_close,
  439. tar_read,
  440. NULL,
  441. vfs_s_opendir,
  442. vfs_s_readdir,
  443. vfs_s_closedir,
  444. vfs_s_telldir,
  445. vfs_s_seekdir,
  446. vfs_s_stat,
  447. vfs_s_lstat,
  448. vfs_s_fstat,
  449. NULL,
  450. NULL,
  451. NULL,
  452. vfs_s_readlink,
  453. NULL,
  454. NULL,
  455. NULL,
  456. NULL,
  457. vfs_s_chdir,
  458. vfs_s_ferrno,
  459. vfs_s_lseek,
  460. NULL,
  461. vfs_s_getid,
  462. vfs_s_nothingisopen,
  463. vfs_s_free,
  464. vfs_s_getlocalcopy,
  465. tar_ungetlocalcopy,
  466. NULL, /* mkdir */
  467. NULL,
  468. NULL,
  469. NULL
  470. MMAPNULL
  471. };