block.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. ** Copyright 1998-2003 University of Illinois Board of Trustees
  3. ** Copyright 1998-2003 Mark D. Roth
  4. ** All rights reserved.
  5. **
  6. ** block.c - libtar code to handle tar archive header blocks
  7. **
  8. ** Mark D. Roth <[email protected]>
  9. ** Campus Information Technologies and Educational Services
  10. ** University of Illinois at Urbana-Champaign
  11. */
  12. #include <libtarint/internal.h>
  13. #include <errno.h>
  14. #ifdef STDC_HEADERS
  15. # include <string.h>
  16. # include <stdlib.h>
  17. #endif
  18. #define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
  19. /* read a header block */
  20. int
  21. th_read_internal(TAR *t)
  22. {
  23. int i;
  24. int num_zero_blocks = 0;
  25. #ifdef DEBUG
  26. printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
  27. #endif
  28. while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE)
  29. {
  30. /* two all-zero blocks mark EOF */
  31. if (t->th_buf.name[0] == '\0')
  32. {
  33. num_zero_blocks++;
  34. if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
  35. && num_zero_blocks >= 2)
  36. return 0; /* EOF */
  37. else
  38. continue;
  39. }
  40. /* verify magic and version */
  41. if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
  42. && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
  43. {
  44. #ifdef DEBUG
  45. puts("!!! unknown magic value in tar header");
  46. #endif
  47. return -2;
  48. }
  49. if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
  50. && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
  51. {
  52. #ifdef DEBUG
  53. puts("!!! unknown version value in tar header");
  54. #endif
  55. return -2;
  56. }
  57. /* check chksum */
  58. if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
  59. && !th_crc_ok(t))
  60. {
  61. #ifdef DEBUG
  62. puts("!!! tar header checksum error");
  63. #endif
  64. return -2;
  65. }
  66. break;
  67. }
  68. #ifdef DEBUG
  69. printf("<== th_read_internal(): returning %d\n", i);
  70. #endif
  71. return i;
  72. }
  73. /* wrapper function for th_read_internal() to handle GNU extensions */
  74. int
  75. th_read(TAR *t)
  76. {
  77. int i, j;
  78. size_t sz;
  79. char *ptr;
  80. #ifdef DEBUG
  81. printf("==> th_read(t=0x%lx)\n", t);
  82. #endif
  83. if (t->th_buf.gnu_longname != NULL)
  84. free(t->th_buf.gnu_longname);
  85. if (t->th_buf.gnu_longlink != NULL)
  86. free(t->th_buf.gnu_longlink);
  87. memset(&(t->th_buf), 0, sizeof(struct tar_header));
  88. i = th_read_internal(t);
  89. if (i == 0)
  90. return 1;
  91. else if (i != T_BLOCKSIZE)
  92. {
  93. if (i != -1)
  94. errno = EINVAL;
  95. return -1;
  96. }
  97. /* check for GNU long link extention */
  98. if (TH_ISLONGLINK(t))
  99. {
  100. sz = th_get_size(t);
  101. j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
  102. #ifdef DEBUG
  103. printf(" th_read(): GNU long linkname detected "
  104. "(%ld bytes, %d blocks)\n", sz, j);
  105. #endif
  106. t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE);
  107. if (t->th_buf.gnu_longlink == NULL)
  108. return -1;
  109. for (ptr = t->th_buf.gnu_longlink; j > 0;
  110. j--, ptr += T_BLOCKSIZE)
  111. {
  112. #ifdef DEBUG
  113. printf(" th_read(): reading long linkname "
  114. "(%d blocks left, ptr == %ld)\n", j, ptr);
  115. #endif
  116. i = tar_block_read(t, ptr);
  117. if (i != T_BLOCKSIZE)
  118. {
  119. if (i != -1)
  120. errno = EINVAL;
  121. return -1;
  122. }
  123. #ifdef DEBUG
  124. printf(" th_read(): read block == \"%s\"\n", ptr);
  125. #endif
  126. }
  127. #ifdef DEBUG
  128. printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
  129. t->th_buf.gnu_longlink);
  130. #endif
  131. i = th_read_internal(t);
  132. if (i != T_BLOCKSIZE)
  133. {
  134. if (i != -1)
  135. errno = EINVAL;
  136. return -1;
  137. }
  138. }
  139. /* check for GNU long name extention */
  140. if (TH_ISLONGNAME(t))
  141. {
  142. sz = th_get_size(t);
  143. j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
  144. #ifdef DEBUG
  145. printf(" th_read(): GNU long filename detected "
  146. "(%ld bytes, %d blocks)\n", sz, j);
  147. #endif
  148. t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE);
  149. if (t->th_buf.gnu_longname == NULL)
  150. return -1;
  151. for (ptr = t->th_buf.gnu_longname; j > 0;
  152. j--, ptr += T_BLOCKSIZE)
  153. {
  154. #ifdef DEBUG
  155. printf(" th_read(): reading long filename "
  156. "(%d blocks left, ptr == %ld)\n", j, ptr);
  157. #endif
  158. i = tar_block_read(t, ptr);
  159. if (i != T_BLOCKSIZE)
  160. {
  161. if (i != -1)
  162. errno = EINVAL;
  163. return -1;
  164. }
  165. #ifdef DEBUG
  166. printf(" th_read(): read block == \"%s\"\n", ptr);
  167. #endif
  168. }
  169. #ifdef DEBUG
  170. printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
  171. t->th_buf.gnu_longname);
  172. #endif
  173. i = th_read_internal(t);
  174. if (i != T_BLOCKSIZE)
  175. {
  176. if (i != -1)
  177. errno = EINVAL;
  178. return -1;
  179. }
  180. }
  181. #if 0
  182. /*
  183. ** work-around for old archive files with broken typeflag fields
  184. ** NOTE: I fixed this in the TH_IS*() macros instead
  185. */
  186. /*
  187. ** (directories are signified with a trailing '/')
  188. */
  189. if (t->th_buf.typeflag == AREGTYPE
  190. && t->th_buf.name[strlen(t->th_buf.name) - 1] == '/')
  191. t->th_buf.typeflag = DIRTYPE;
  192. /*
  193. ** fallback to using mode bits
  194. */
  195. if (t->th_buf.typeflag == AREGTYPE)
  196. {
  197. mode = (mode_t)oct_to_int(t->th_buf.mode);
  198. if (S_ISREG(mode))
  199. t->th_buf.typeflag = REGTYPE;
  200. else if (S_ISDIR(mode))
  201. t->th_buf.typeflag = DIRTYPE;
  202. else if (S_ISFIFO(mode))
  203. t->th_buf.typeflag = FIFOTYPE;
  204. else if (S_ISCHR(mode))
  205. t->th_buf.typeflag = CHRTYPE;
  206. else if (S_ISBLK(mode))
  207. t->th_buf.typeflag = BLKTYPE;
  208. else if (S_ISLNK(mode))
  209. t->th_buf.typeflag = SYMTYPE;
  210. }
  211. #endif
  212. return 0;
  213. }
  214. /* write a header block */
  215. int
  216. th_write(TAR *t)
  217. {
  218. int i, j;
  219. char type2;
  220. size_t sz, sz2;
  221. char *ptr;
  222. char buf[T_BLOCKSIZE];
  223. #ifdef DEBUG
  224. printf("==> th_write(TAR=\"%s\")\n", t->pathname);
  225. th_print(t);
  226. #endif
  227. if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
  228. {
  229. #ifdef DEBUG
  230. printf("th_write(): using gnu_longlink (\"%s\")\n",
  231. t->th_buf.gnu_longlink);
  232. #endif
  233. /* save old size and type */
  234. type2 = t->th_buf.typeflag;
  235. sz2 = th_get_size(t);
  236. /* write out initial header block with fake size and type */
  237. t->th_buf.typeflag = GNU_LONGLINK_TYPE;
  238. sz = strlen(t->th_buf.gnu_longlink);
  239. th_set_size(t, sz);
  240. th_finish(t);
  241. i = tar_block_write(t, &(t->th_buf));
  242. if (i != T_BLOCKSIZE)
  243. {
  244. if (i != -1)
  245. errno = EINVAL;
  246. return -1;
  247. }
  248. /* write out extra blocks containing long name */
  249. for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
  250. ptr = t->th_buf.gnu_longlink; j > 1;
  251. j--, ptr += T_BLOCKSIZE)
  252. {
  253. i = tar_block_write(t, ptr);
  254. if (i != T_BLOCKSIZE)
  255. {
  256. if (i != -1)
  257. errno = EINVAL;
  258. return -1;
  259. }
  260. }
  261. memset(buf, 0, T_BLOCKSIZE);
  262. strncpy(buf, ptr, T_BLOCKSIZE);
  263. i = tar_block_write(t, &buf);
  264. if (i != T_BLOCKSIZE)
  265. {
  266. if (i != -1)
  267. errno = EINVAL;
  268. return -1;
  269. }
  270. /* reset type and size to original values */
  271. t->th_buf.typeflag = type2;
  272. th_set_size(t, sz2);
  273. }
  274. if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
  275. {
  276. #ifdef DEBUG
  277. printf("th_write(): using gnu_longname (\"%s\")\n",
  278. t->th_buf.gnu_longname);
  279. #endif
  280. /* save old size and type */
  281. type2 = t->th_buf.typeflag;
  282. sz2 = th_get_size(t);
  283. /* write out initial header block with fake size and type */
  284. t->th_buf.typeflag = GNU_LONGNAME_TYPE;
  285. sz = strlen(t->th_buf.gnu_longname);
  286. th_set_size(t, sz);
  287. th_finish(t);
  288. i = tar_block_write(t, &(t->th_buf));
  289. if (i != T_BLOCKSIZE)
  290. {
  291. if (i != -1)
  292. errno = EINVAL;
  293. return -1;
  294. }
  295. /* write out extra blocks containing long name */
  296. for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
  297. ptr = t->th_buf.gnu_longname; j > 1;
  298. j--, ptr += T_BLOCKSIZE)
  299. {
  300. i = tar_block_write(t, ptr);
  301. if (i != T_BLOCKSIZE)
  302. {
  303. if (i != -1)
  304. errno = EINVAL;
  305. return -1;
  306. }
  307. }
  308. memset(buf, 0, T_BLOCKSIZE);
  309. strncpy(buf, ptr, T_BLOCKSIZE);
  310. i = tar_block_write(t, &buf);
  311. if (i != T_BLOCKSIZE)
  312. {
  313. if (i != -1)
  314. errno = EINVAL;
  315. return -1;
  316. }
  317. /* reset type and size to original values */
  318. t->th_buf.typeflag = type2;
  319. th_set_size(t, sz2);
  320. }
  321. th_finish(t);
  322. #ifdef DEBUG
  323. /* print tar header */
  324. th_print(t);
  325. #endif
  326. i = tar_block_write(t, &(t->th_buf));
  327. if (i != T_BLOCKSIZE)
  328. {
  329. if (i != -1)
  330. errno = EINVAL;
  331. return -1;
  332. }
  333. #ifdef DEBUG
  334. puts("th_write(): returning 0");
  335. #endif
  336. return 0;
  337. }