append.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. ** Copyright 1998-2003 University of Illinois Board of Trustees
  3. ** Copyright 1998-2003 Mark D. Roth
  4. ** All rights reserved.
  5. **
  6. ** append.c - libtar code to append files to a tar archive
  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 <stdio.h>
  14. #include <errno.h>
  15. #include <fcntl.h>
  16. #if defined(_WIN32) && !defined(__CYGWIN__)
  17. # include <libtar/compat.h>
  18. #else
  19. # ifdef HAVE_SYS_PARAM_H
  20. # include <sys/param.h>
  21. # endif
  22. #endif
  23. #include <libtar/compat.h>
  24. #include <sys/types.h>
  25. #ifdef STDC_HEADERS
  26. # include <stdlib.h>
  27. # include <string.h>
  28. #endif
  29. #ifdef HAVE_UNISTD_H
  30. # include <unistd.h>
  31. #endif
  32. #ifdef HAVE_IO_H
  33. # include <io.h>
  34. #endif
  35. struct tar_dev
  36. {
  37. dev_t td_dev;
  38. libtar_hash_t *td_h;
  39. };
  40. typedef struct tar_dev tar_dev_t;
  41. struct tar_ino
  42. {
  43. ino_t ti_ino;
  44. char ti_name[TAR_MAXPATHLEN];
  45. };
  46. typedef struct tar_ino tar_ino_t;
  47. /* free memory associated with a tar_dev_t */
  48. void
  49. tar_dev_free(tar_dev_t *tdp)
  50. {
  51. libtar_hash_free(tdp->td_h, free);
  52. free(tdp);
  53. }
  54. /* appends a file to the tar archive */
  55. int
  56. tar_append_file(TAR *t, char *realname, char *savename)
  57. {
  58. struct stat s;
  59. libtar_hashptr_t hp;
  60. tar_dev_t *td;
  61. tar_ino_t *ti;
  62. #if !defined(_WIN32) || defined(__CYGWIN__)
  63. int i;
  64. #else
  65. size_t plen;
  66. #endif
  67. char path[TAR_MAXPATHLEN];
  68. #ifdef DEBUG
  69. printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
  70. "savename=\"%s\")\n", t, t->pathname, realname,
  71. (savename ? savename : "[NULL]"));
  72. #endif
  73. #if defined(_WIN32) && !defined(__CYGWIN__)
  74. strncpy(path, realname, sizeof(path)-1);
  75. path[sizeof(path)-1] = 0;
  76. plen = strlen(path);
  77. if (path[plen-1] == '/' )
  78. {
  79. path[plen-1] = 0;
  80. }
  81. if (stat(path, &s) != 0)
  82. #else
  83. if (lstat(realname, &s) != 0)
  84. #endif
  85. {
  86. #ifdef DEBUG
  87. perror("lstat()");
  88. #endif
  89. return -1;
  90. }
  91. /* set header block */
  92. #ifdef DEBUG
  93. puts(" tar_append_file(): setting header block...");
  94. #endif
  95. memset(&(t->th_buf), 0, sizeof(struct tar_header));
  96. th_set_from_stat(t, &s);
  97. /* set the header path */
  98. #ifdef DEBUG
  99. puts(" tar_append_file(): setting header path...");
  100. #endif
  101. th_set_path(t, (savename ? savename : realname));
  102. /* check if it's a hardlink */
  103. #ifdef DEBUG
  104. puts(" tar_append_file(): checking inode cache for hardlink...");
  105. #endif
  106. libtar_hashptr_reset(&hp);
  107. if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
  108. (libtar_matchfunc_t)dev_match) != 0)
  109. td = (tar_dev_t *)libtar_hashptr_data(&hp);
  110. else
  111. {
  112. #ifdef DEBUG
  113. printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
  114. major(s.st_dev), minor(s.st_dev));
  115. #endif
  116. td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
  117. td->td_dev = s.st_dev;
  118. td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
  119. if (td->td_h == NULL)
  120. return -1;
  121. if (libtar_hash_add(t->h, td) == -1)
  122. return -1;
  123. }
  124. libtar_hashptr_reset(&hp);
  125. #if !defined(_WIN32) || defined(__CYGWIN__)
  126. if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
  127. (libtar_matchfunc_t)ino_match) != 0)
  128. {
  129. ti = (tar_ino_t *)libtar_hashptr_data(&hp);
  130. #ifdef DEBUG
  131. printf(" tar_append_file(): encoding hard link \"%s\" "
  132. "to \"%s\"...\n", realname, ti->ti_name);
  133. #endif
  134. t->th_buf.typeflag = LNKTYPE;
  135. th_set_link(t, ti->ti_name);
  136. }
  137. else
  138. #endif
  139. {
  140. #ifdef DEBUG
  141. printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
  142. "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
  143. s.st_ino, realname);
  144. #endif
  145. ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
  146. if (ti == NULL)
  147. return -1;
  148. ti->ti_ino = s.st_ino;
  149. snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
  150. savename ? savename : realname);
  151. libtar_hash_add(td->td_h, ti);
  152. }
  153. #if !defined(_WIN32) || defined(__CYGWIN__)
  154. /* check if it's a symlink */
  155. if (TH_ISSYM(t))
  156. {
  157. #if defined(_WIN32) && !defined(__CYGWIN__)
  158. i = -1;
  159. #else
  160. i = readlink(realname, path, sizeof(path));
  161. #endif
  162. if (i == -1)
  163. return -1;
  164. if (i >= TAR_MAXPATHLEN)
  165. i = TAR_MAXPATHLEN - 1;
  166. path[i] = '\0';
  167. #ifdef DEBUG
  168. printf(" tar_append_file(): encoding symlink \"%s\" -> "
  169. "\"%s\"...\n", realname, path);
  170. #endif
  171. th_set_link(t, path);
  172. }
  173. #endif
  174. /* print file info */
  175. if (t->options & TAR_VERBOSE)
  176. th_print_long_ls(t);
  177. #ifdef DEBUG
  178. puts(" tar_append_file(): writing header");
  179. #endif
  180. /* write header */
  181. if (th_write(t) != 0)
  182. {
  183. #ifdef DEBUG
  184. printf("t->fd = %d\n", t->fd);
  185. #endif
  186. return -1;
  187. }
  188. #ifdef DEBUG
  189. puts(" tar_append_file(): back from th_write()");
  190. #endif
  191. /* if it's a regular file, write the contents as well */
  192. if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
  193. return -1;
  194. return 0;
  195. }
  196. /* write EOF indicator */
  197. int
  198. tar_append_eof(TAR *t)
  199. {
  200. ssize_t i, j;
  201. char block[T_BLOCKSIZE];
  202. memset(&block, 0, T_BLOCKSIZE);
  203. for (j = 0; j < 2; j++)
  204. {
  205. i = tar_block_write(t, &block);
  206. if (i != T_BLOCKSIZE)
  207. {
  208. if (i != -1)
  209. errno = EINVAL;
  210. return -1;
  211. }
  212. }
  213. return 0;
  214. }
  215. /* add file contents to a tarchive */
  216. int
  217. tar_append_regfile(TAR *t, char *realname)
  218. {
  219. char block[T_BLOCKSIZE];
  220. int filefd;
  221. ssize_t i, j;
  222. size_t size;
  223. #if defined( _WIN32 ) || defined(__CYGWIN__)
  224. filefd = open(realname, O_RDONLY | O_BINARY);
  225. #else
  226. filefd = open(realname, O_RDONLY);
  227. #endif
  228. if (filefd == -1)
  229. {
  230. #ifdef DEBUG
  231. perror("open()");
  232. #endif
  233. return -1;
  234. }
  235. size = th_get_size(t);
  236. for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
  237. {
  238. j = read(filefd, &block, T_BLOCKSIZE);
  239. if (j != T_BLOCKSIZE)
  240. {
  241. if (j != -1)
  242. {
  243. fprintf(stderr, "Unexpected size of read data: %d <> %d for file: %s\n",
  244. (int)j, T_BLOCKSIZE, realname);
  245. errno = EINVAL;
  246. }
  247. return -1;
  248. }
  249. if (tar_block_write(t, &block) == -1)
  250. return -1;
  251. }
  252. if (i > 0)
  253. {
  254. j = (size_t)read(filefd, &block, (unsigned int)i);
  255. if (j == -1)
  256. return -1;
  257. memset(&(block[i]), 0, T_BLOCKSIZE - i);
  258. if (tar_block_write(t, &block) == -1)
  259. return -1;
  260. }
  261. close(filefd);
  262. return 0;
  263. }