blob: 4388297531c690c72aefbeeefc3837ed7cb00d06 [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>
Ethan Yonker79f88bd2016-12-09 14:52:12 -060023#include <stdbool.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050024
25#ifdef STDC_HEADERS
26# include <stdlib.h>
27# include <string.h>
28#endif
29
30#ifdef HAVE_UNISTD_H
31# include <unistd.h>
32#endif
33
Ethan Yonker50381972014-02-11 11:44:06 -060034#ifdef HAVE_SELINUX
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050035# include "selinux/selinux.h"
Ethan Yonker50381972014-02-11 11:44:06 -060036#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050037
Ethan Yonker79f88bd2016-12-09 14:52:12 -060038#ifdef HAVE_EXT4_CRYPT
39# include "ext4crypt_tar.h"
40#endif
41
bigbiff bigbiff9c754052013-01-09 09:09:08 -050042struct tar_dev
43{
44 dev_t td_dev;
45 libtar_hash_t *td_h;
46};
47typedef struct tar_dev tar_dev_t;
48
49struct tar_ino
50{
51 ino_t ti_ino;
52 char ti_name[MAXPATHLEN];
53};
54typedef struct tar_ino tar_ino_t;
55
56
57/* free memory associated with a tar_dev_t */
58void
59tar_dev_free(tar_dev_t *tdp)
60{
61 libtar_hash_free(tdp->td_h, free);
62 free(tdp);
63}
64
65
66/* appends a file to the tar archive */
67int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050068tar_append_file(TAR *t, const char *realname, const char *savename)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050069{
70 struct stat s;
71 int i;
72 libtar_hashptr_t hp;
73 tar_dev_t *td = NULL;
74 tar_ino_t *ti = NULL;
75 char path[MAXPATHLEN];
76
77#ifdef DEBUG
78 printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
79 "savename=\"%s\")\n", t, t->pathname, realname,
80 (savename ? savename : "[NULL]"));
81#endif
82
83 if (lstat(realname, &s) != 0)
84 {
85#ifdef DEBUG
86 perror("lstat()");
87#endif
88 return -1;
89 }
90
91 /* set header block */
92#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050093 puts("tar_append_file(): setting header block...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -050094#endif
95 memset(&(t->th_buf), 0, sizeof(struct tar_header));
96 th_set_from_stat(t, &s);
97
98 /* set the header path */
99#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500100 puts("tar_append_file(): setting header path...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500101#endif
102 th_set_path(t, (savename ? savename : realname));
103
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200104#ifdef HAVE_SELINUX
105 /* get selinux context */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500106 if (t->options & TAR_STORE_SELINUX)
107 {
108 if (t->th_buf.selinux_context != NULL)
109 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200110 free(t->th_buf.selinux_context);
111 t->th_buf.selinux_context = NULL;
112 }
113
114 security_context_t selinux_context = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500115 if (lgetfilecon(realname, &selinux_context) >= 0)
116 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200117 t->th_buf.selinux_context = strdup(selinux_context);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500118 printf(" ==> set selinux context: %s\n", selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200119 freecon(selinux_context);
120 }
121 else
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500122 {
123#ifdef DEBUG
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200124 perror("Failed to get selinux context");
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500125#endif
126 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200127 }
128#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500129
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600130#ifdef HAVE_EXT4_CRYPT
131 if (TH_ISDIR(t) && t->options & TAR_STORE_EXT4_POL)
132 {
133 if (t->th_buf.e4crypt_policy != NULL)
134 {
135 free(t->th_buf.e4crypt_policy);
136 t->th_buf.e4crypt_policy = NULL;
137 }
138
139 char e4crypt_policy[EXT4_KEY_DESCRIPTOR_SIZE];
140 if (e4crypt_policy_get(realname, e4crypt_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
141 {
142 char tar_policy[EXT4_KEY_DESCRIPTOR_SIZE];
143 memset(tar_policy, 0, sizeof(tar_policy));
144 char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
145 policy_to_hex(e4crypt_policy, policy_hex);
146 if (lookup_ref_key(e4crypt_policy, &tar_policy)) {
147 printf("found policy '%s' - '%s' - '%s'\n", realname, tar_policy, policy_hex);
148 t->th_buf.e4crypt_policy = strdup(tar_policy);
149 } else {
150 printf("failed to lookup tar policy for '%s' - '%s'\n", realname, policy_hex);
151 return -1;
152 }
153 } // else no policy found, but this is not an error as not all dirs will have a policy
154 }
155#endif
156
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500157 /* check if it's a hardlink */
158#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500159 puts("tar_append_file(): checking inode cache for hardlink...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500160#endif
161 libtar_hashptr_reset(&hp);
162 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
163 (libtar_matchfunc_t)dev_match) != 0)
164 td = (tar_dev_t *)libtar_hashptr_data(&hp);
165 else
166 {
167#ifdef DEBUG
168 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
169 major(s.st_dev), minor(s.st_dev));
170#endif
171 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
172 td->td_dev = s.st_dev;
173 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
174 if (td->td_h == NULL)
175 return -1;
176 if (libtar_hash_add(t->h, td) == -1)
177 return -1;
178 }
179 libtar_hashptr_reset(&hp);
180 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
181 (libtar_matchfunc_t)ino_match) != 0)
182 {
183 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
184#ifdef DEBUG
185 printf(" tar_append_file(): encoding hard link \"%s\" "
186 "to \"%s\"...\n", realname, ti->ti_name);
187#endif
188 t->th_buf.typeflag = LNKTYPE;
189 th_set_link(t, ti->ti_name);
190 }
191 else
192 {
193#ifdef DEBUG
194 printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
195 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
196 s.st_ino, realname);
197#endif
198 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
199 if (ti == NULL)
200 return -1;
201 ti->ti_ino = s.st_ino;
202 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
203 savename ? savename : realname);
204 libtar_hash_add(td->td_h, ti);
205 }
206
207 /* check if it's a symlink */
208 if (TH_ISSYM(t))
209 {
210 i = readlink(realname, path, sizeof(path));
211 if (i == -1)
212 return -1;
213 if (i >= MAXPATHLEN)
214 i = MAXPATHLEN - 1;
215 path[i] = '\0';
216#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500217 printf("tar_append_file(): encoding symlink \"%s\" -> "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500218 "\"%s\"...\n", realname, path);
219#endif
220 th_set_link(t, path);
221 }
222
223 /* print file info */
224 if (t->options & TAR_VERBOSE)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500225 printf("%s\n", th_get_pathname(t));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500226
227#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500228 puts("tar_append_file(): writing header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500229#endif
230 /* write header */
231 if (th_write(t) != 0)
232 {
233#ifdef DEBUG
234 printf("t->fd = %d\n", t->fd);
235#endif
236 return -1;
237 }
238#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500239 puts("tar_append_file(): back from th_write()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500240#endif
241
242 /* if it's a regular file, write the contents as well */
243 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
244 return -1;
245
246 return 0;
247}
248
249
250/* write EOF indicator */
251int
252tar_append_eof(TAR *t)
253{
254 int i, j;
255 char block[T_BLOCKSIZE];
256
257 memset(&block, 0, T_BLOCKSIZE);
258 for (j = 0; j < 2; j++)
259 {
260 i = tar_block_write(t, &block);
261 if (i != T_BLOCKSIZE)
262 {
263 if (i != -1)
264 errno = EINVAL;
265 return -1;
266 }
267 }
268
269 return 0;
270}
271
272
273/* add file contents to a tarchive */
274int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500275tar_append_regfile(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500276{
277 char block[T_BLOCKSIZE];
278 int filefd;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500279 int64_t i, size;
280 ssize_t j;
281 int rv = -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500282
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500283#if defined(O_BINARY)
284 filefd = open(realname, O_RDONLY|O_BINARY);
285#else
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500286 filefd = open(realname, O_RDONLY);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500287#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500288 if (filefd == -1)
289 {
290#ifdef DEBUG
291 perror("open()");
292#endif
293 return -1;
294 }
295
296 size = th_get_size(t);
297 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
298 {
299 j = read(filefd, &block, T_BLOCKSIZE);
300 if (j != T_BLOCKSIZE)
301 {
302 if (j != -1)
303 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500304 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500305 }
306 if (tar_block_write(t, &block) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500307 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500308 }
309
310 if (i > 0)
311 {
312 j = read(filefd, &block, i);
313 if (j == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500314 goto fail;
315 memset(&(block[i]), 0, T_BLOCKSIZE - i);
316 if (tar_block_write(t, &block) == -1)
317 goto fail;
318 }
319
320 /* success! */
321 rv = 0;
322fail:
323 close(filefd);
324
325 return rv;
326}
327
328
329/* add file contents to a tarchive */
330int
331tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
332 uid_t uid, gid_t gid, void *buf, size_t len)
333{
334 struct stat st;
335
336 memset(&st, 0, sizeof(st));
337 st.st_mode = S_IFREG | mode;
338 st.st_uid = uid;
339 st.st_gid = gid;
340 st.st_mtime = time(NULL);
341 st.st_size = len;
342
343 th_set_from_stat(t, &st);
344 th_set_path(t, savename);
345
346 /* write header */
347 if (th_write(t) != 0)
348 {
349#ifdef DEBUG
350 fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %d\n", t->fd);
351#endif
352 return -1;
353 }
354
355 return tar_append_buffer(t, buf, len);
356}
357
358int
359tar_append_buffer(TAR *t, void *buf, size_t len)
360{
361 char block[T_BLOCKSIZE];
362 int filefd;
363 int i, j;
364 size_t size = len;
365
366 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
367 {
368 if (tar_block_write(t, buf) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500369 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500370 buf = (char *)buf + T_BLOCKSIZE;
371 }
372
373 if (i > 0)
374 {
375 memcpy(block, buf, i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500376 memset(&(block[i]), 0, T_BLOCKSIZE - i);
377 if (tar_block_write(t, &block) == -1)
378 return -1;
379 }
380
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500381 return 0;
382}
383