blob: 4be679ccd8783233deda183bc885cfaf4f25ea93 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
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 <roth@uiuc.edu>
9** Campus Information Technologies and Educational Services
10** University of Illinois at Urbana-Champaign
11*/
12
13#include <internal.h>
14
15#include <stdio.h>
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050016#include <stdlib.h>
17#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050018#include <errno.h>
19#include <fcntl.h>
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050020#include <time.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050021#include <sys/param.h>
22#include <sys/types.h>
23
24#ifdef STDC_HEADERS
25# include <stdlib.h>
26# include <string.h>
27#endif
28
29#ifdef HAVE_UNISTD_H
30# include <unistd.h>
31#endif
32
Ethan Yonker50381972014-02-11 11:44:06 -060033#ifdef HAVE_SELINUX
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050034# include "selinux/selinux.h"
Ethan Yonker50381972014-02-11 11:44:06 -060035#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050036
37struct tar_dev
38{
39 dev_t td_dev;
40 libtar_hash_t *td_h;
41};
42typedef struct tar_dev tar_dev_t;
43
44struct tar_ino
45{
46 ino_t ti_ino;
47 char ti_name[MAXPATHLEN];
48};
49typedef struct tar_ino tar_ino_t;
50
51
52/* free memory associated with a tar_dev_t */
53void
54tar_dev_free(tar_dev_t *tdp)
55{
56 libtar_hash_free(tdp->td_h, free);
57 free(tdp);
58}
59
60
61/* appends a file to the tar archive */
62int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050063tar_append_file(TAR *t, const char *realname, const char *savename)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050064{
65 struct stat s;
66 int i;
67 libtar_hashptr_t hp;
68 tar_dev_t *td = NULL;
69 tar_ino_t *ti = NULL;
70 char path[MAXPATHLEN];
71
72#ifdef DEBUG
73 printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
74 "savename=\"%s\")\n", t, t->pathname, realname,
75 (savename ? savename : "[NULL]"));
76#endif
77
78 if (lstat(realname, &s) != 0)
79 {
80#ifdef DEBUG
81 perror("lstat()");
82#endif
83 return -1;
84 }
85
86 /* set header block */
87#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050088 puts("tar_append_file(): setting header block...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -050089#endif
90 memset(&(t->th_buf), 0, sizeof(struct tar_header));
91 th_set_from_stat(t, &s);
92
93 /* set the header path */
94#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050095 puts("tar_append_file(): setting header path...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -050096#endif
97 th_set_path(t, (savename ? savename : realname));
98
Vojtech Bocek25fd68d2013-08-27 03:10:10 +020099#ifdef HAVE_SELINUX
100 /* get selinux context */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500101 if (t->options & TAR_STORE_SELINUX)
102 {
103 if (t->th_buf.selinux_context != NULL)
104 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200105 free(t->th_buf.selinux_context);
106 t->th_buf.selinux_context = NULL;
107 }
108
109 security_context_t selinux_context = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500110 if (lgetfilecon(realname, &selinux_context) >= 0)
111 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200112 t->th_buf.selinux_context = strdup(selinux_context);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500113 printf(" ==> set selinux context: %s\n", selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200114 freecon(selinux_context);
115 }
116 else
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500117 {
118#ifdef DEBUG
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200119 perror("Failed to get selinux context");
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500120#endif
121 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200122 }
123#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500124
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500125 /* check if it's a hardlink */
126#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500127 puts("tar_append_file(): checking inode cache for hardlink...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500128#endif
129 libtar_hashptr_reset(&hp);
130 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
131 (libtar_matchfunc_t)dev_match) != 0)
132 td = (tar_dev_t *)libtar_hashptr_data(&hp);
133 else
134 {
135#ifdef DEBUG
136 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
137 major(s.st_dev), minor(s.st_dev));
138#endif
139 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
140 td->td_dev = s.st_dev;
141 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
142 if (td->td_h == NULL)
143 return -1;
144 if (libtar_hash_add(t->h, td) == -1)
145 return -1;
146 }
147 libtar_hashptr_reset(&hp);
148 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
149 (libtar_matchfunc_t)ino_match) != 0)
150 {
151 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
152#ifdef DEBUG
153 printf(" tar_append_file(): encoding hard link \"%s\" "
154 "to \"%s\"...\n", realname, ti->ti_name);
155#endif
156 t->th_buf.typeflag = LNKTYPE;
157 th_set_link(t, ti->ti_name);
158 }
159 else
160 {
161#ifdef DEBUG
162 printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
163 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
164 s.st_ino, realname);
165#endif
166 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
167 if (ti == NULL)
168 return -1;
169 ti->ti_ino = s.st_ino;
170 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
171 savename ? savename : realname);
172 libtar_hash_add(td->td_h, ti);
173 }
174
175 /* check if it's a symlink */
176 if (TH_ISSYM(t))
177 {
178 i = readlink(realname, path, sizeof(path));
179 if (i == -1)
180 return -1;
181 if (i >= MAXPATHLEN)
182 i = MAXPATHLEN - 1;
183 path[i] = '\0';
184#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500185 printf("tar_append_file(): encoding symlink \"%s\" -> "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500186 "\"%s\"...\n", realname, path);
187#endif
188 th_set_link(t, path);
189 }
190
191 /* print file info */
192 if (t->options & TAR_VERBOSE)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500193 printf("%s\n", th_get_pathname(t));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500194
195#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500196 puts("tar_append_file(): writing header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500197#endif
198 /* write header */
199 if (th_write(t) != 0)
200 {
201#ifdef DEBUG
202 printf("t->fd = %d\n", t->fd);
203#endif
204 return -1;
205 }
206#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500207 puts("tar_append_file(): back from th_write()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500208#endif
209
210 /* if it's a regular file, write the contents as well */
211 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
212 return -1;
213
214 return 0;
215}
216
217
218/* write EOF indicator */
219int
220tar_append_eof(TAR *t)
221{
222 int i, j;
223 char block[T_BLOCKSIZE];
224
225 memset(&block, 0, T_BLOCKSIZE);
226 for (j = 0; j < 2; j++)
227 {
228 i = tar_block_write(t, &block);
229 if (i != T_BLOCKSIZE)
230 {
231 if (i != -1)
232 errno = EINVAL;
233 return -1;
234 }
235 }
236
237 return 0;
238}
239
240
241/* add file contents to a tarchive */
242int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500243tar_append_regfile(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500244{
245 char block[T_BLOCKSIZE];
246 int filefd;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500247 int64_t i, size;
248 ssize_t j;
249 int rv = -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500250
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500251#if defined(O_BINARY)
252 filefd = open(realname, O_RDONLY|O_BINARY);
253#else
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500254 filefd = open(realname, O_RDONLY);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500255#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500256 if (filefd == -1)
257 {
258#ifdef DEBUG
259 perror("open()");
260#endif
261 return -1;
262 }
263
264 size = th_get_size(t);
265 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
266 {
267 j = read(filefd, &block, T_BLOCKSIZE);
268 if (j != T_BLOCKSIZE)
269 {
270 if (j != -1)
271 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500272 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500273 }
274 if (tar_block_write(t, &block) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500275 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500276 }
277
278 if (i > 0)
279 {
280 j = read(filefd, &block, i);
281 if (j == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500282 goto fail;
283 memset(&(block[i]), 0, T_BLOCKSIZE - i);
284 if (tar_block_write(t, &block) == -1)
285 goto fail;
286 }
287
288 /* success! */
289 rv = 0;
290fail:
291 close(filefd);
292
293 return rv;
294}
295
296
297/* add file contents to a tarchive */
298int
299tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
300 uid_t uid, gid_t gid, void *buf, size_t len)
301{
302 struct stat st;
303
304 memset(&st, 0, sizeof(st));
305 st.st_mode = S_IFREG | mode;
306 st.st_uid = uid;
307 st.st_gid = gid;
308 st.st_mtime = time(NULL);
309 st.st_size = len;
310
311 th_set_from_stat(t, &st);
312 th_set_path(t, savename);
313
314 /* write header */
315 if (th_write(t) != 0)
316 {
317#ifdef DEBUG
318 fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %d\n", t->fd);
319#endif
320 return -1;
321 }
322
323 return tar_append_buffer(t, buf, len);
324}
325
326int
327tar_append_buffer(TAR *t, void *buf, size_t len)
328{
329 char block[T_BLOCKSIZE];
330 int filefd;
331 int i, j;
332 size_t size = len;
333
334 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
335 {
336 if (tar_block_write(t, buf) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500337 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500338 buf = (char *)buf + T_BLOCKSIZE;
339 }
340
341 if (i > 0)
342 {
343 memcpy(block, buf, i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500344 memset(&(block[i]), 0, T_BLOCKSIZE - i);
345 if (tar_block_write(t, &block) == -1)
346 return -1;
347 }
348
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500349 return 0;
350}
351