blob: 7c679f66d0e221141b5f9cdef6c5d25e3cd9ff99 [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
Ethan Yonker71187742017-01-13 13:30:10 -060025#include <sys/capability.h>
26#include <sys/xattr.h>
27#include <linux/xattr.h>
28
bigbiff bigbiff9c754052013-01-09 09:09:08 -050029#ifdef STDC_HEADERS
30# include <stdlib.h>
31# include <string.h>
32#endif
33
34#ifdef HAVE_UNISTD_H
35# include <unistd.h>
36#endif
37
Ethan Yonker50381972014-02-11 11:44:06 -060038#ifdef HAVE_SELINUX
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050039# include "selinux/selinux.h"
Ethan Yonker50381972014-02-11 11:44:06 -060040#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050041
Ethan Yonker79f88bd2016-12-09 14:52:12 -060042#ifdef HAVE_EXT4_CRYPT
43# include "ext4crypt_tar.h"
44#endif
45
bigbiff bigbiff9c754052013-01-09 09:09:08 -050046struct tar_dev
47{
48 dev_t td_dev;
49 libtar_hash_t *td_h;
50};
51typedef struct tar_dev tar_dev_t;
52
53struct tar_ino
54{
55 ino_t ti_ino;
56 char ti_name[MAXPATHLEN];
57};
58typedef struct tar_ino tar_ino_t;
59
60
61/* free memory associated with a tar_dev_t */
62void
63tar_dev_free(tar_dev_t *tdp)
64{
65 libtar_hash_free(tdp->td_h, free);
66 free(tdp);
67}
68
69
70/* appends a file to the tar archive */
71int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050072tar_append_file(TAR *t, const char *realname, const char *savename)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050073{
74 struct stat s;
75 int i;
76 libtar_hashptr_t hp;
77 tar_dev_t *td = NULL;
78 tar_ino_t *ti = NULL;
79 char path[MAXPATHLEN];
80
81#ifdef DEBUG
82 printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
83 "savename=\"%s\")\n", t, t->pathname, realname,
84 (savename ? savename : "[NULL]"));
85#endif
86
87 if (lstat(realname, &s) != 0)
88 {
89#ifdef DEBUG
90 perror("lstat()");
91#endif
92 return -1;
93 }
94
95 /* set header block */
96#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050097 puts("tar_append_file(): setting header block...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -050098#endif
99 memset(&(t->th_buf), 0, sizeof(struct tar_header));
100 th_set_from_stat(t, &s);
101
102 /* set the header path */
103#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500104 puts("tar_append_file(): setting header path...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500105#endif
106 th_set_path(t, (savename ? savename : realname));
107
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200108#ifdef HAVE_SELINUX
109 /* get selinux context */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500110 if (t->options & TAR_STORE_SELINUX)
111 {
112 if (t->th_buf.selinux_context != NULL)
113 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200114 free(t->th_buf.selinux_context);
115 t->th_buf.selinux_context = NULL;
116 }
117
118 security_context_t selinux_context = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500119 if (lgetfilecon(realname, &selinux_context) >= 0)
120 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200121 t->th_buf.selinux_context = strdup(selinux_context);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500122 printf(" ==> set selinux context: %s\n", selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200123 freecon(selinux_context);
124 }
125 else
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500126 {
127#ifdef DEBUG
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200128 perror("Failed to get selinux context");
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500129#endif
130 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200131 }
132#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500133
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600134#ifdef HAVE_EXT4_CRYPT
135 if (TH_ISDIR(t) && t->options & TAR_STORE_EXT4_POL)
136 {
137 if (t->th_buf.e4crypt_policy != NULL)
138 {
139 free(t->th_buf.e4crypt_policy);
140 t->th_buf.e4crypt_policy = NULL;
141 }
142
143 char e4crypt_policy[EXT4_KEY_DESCRIPTOR_SIZE];
144 if (e4crypt_policy_get(realname, e4crypt_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
145 {
146 char tar_policy[EXT4_KEY_DESCRIPTOR_SIZE];
147 memset(tar_policy, 0, sizeof(tar_policy));
148 char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
149 policy_to_hex(e4crypt_policy, policy_hex);
150 if (lookup_ref_key(e4crypt_policy, &tar_policy)) {
151 printf("found policy '%s' - '%s' - '%s'\n", realname, tar_policy, policy_hex);
152 t->th_buf.e4crypt_policy = strdup(tar_policy);
153 } else {
154 printf("failed to lookup tar policy for '%s' - '%s'\n", realname, policy_hex);
155 return -1;
156 }
157 } // else no policy found, but this is not an error as not all dirs will have a policy
158 }
159#endif
160
Ethan Yonker71187742017-01-13 13:30:10 -0600161 /* get posix file capabilities */
162 if (TH_ISREG(t) && t->options & TAR_STORE_POSIX_CAP)
163 {
164 if (t->th_buf.has_cap_data)
165 {
166 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
167 t->th_buf.has_cap_data = 0;
168 }
169
170 if (getxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data)) >= 0)
171 {
172 t->th_buf.has_cap_data = 1;
173#if 1 //def DEBUG
174 print_caps(&t->th_buf.cap_data);
175#endif
176 }
177 }
178
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500179 /* check if it's a hardlink */
180#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500181 puts("tar_append_file(): checking inode cache for hardlink...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500182#endif
183 libtar_hashptr_reset(&hp);
184 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
185 (libtar_matchfunc_t)dev_match) != 0)
186 td = (tar_dev_t *)libtar_hashptr_data(&hp);
187 else
188 {
189#ifdef DEBUG
190 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
191 major(s.st_dev), minor(s.st_dev));
192#endif
193 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
194 td->td_dev = s.st_dev;
195 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
196 if (td->td_h == NULL)
197 return -1;
198 if (libtar_hash_add(t->h, td) == -1)
199 return -1;
200 }
201 libtar_hashptr_reset(&hp);
202 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
203 (libtar_matchfunc_t)ino_match) != 0)
204 {
205 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
206#ifdef DEBUG
207 printf(" tar_append_file(): encoding hard link \"%s\" "
208 "to \"%s\"...\n", realname, ti->ti_name);
209#endif
210 t->th_buf.typeflag = LNKTYPE;
211 th_set_link(t, ti->ti_name);
212 }
213 else
214 {
215#ifdef DEBUG
216 printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
217 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
218 s.st_ino, realname);
219#endif
220 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
221 if (ti == NULL)
222 return -1;
223 ti->ti_ino = s.st_ino;
224 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
225 savename ? savename : realname);
226 libtar_hash_add(td->td_h, ti);
227 }
228
229 /* check if it's a symlink */
230 if (TH_ISSYM(t))
231 {
232 i = readlink(realname, path, sizeof(path));
233 if (i == -1)
234 return -1;
235 if (i >= MAXPATHLEN)
236 i = MAXPATHLEN - 1;
237 path[i] = '\0';
238#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500239 printf("tar_append_file(): encoding symlink \"%s\" -> "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500240 "\"%s\"...\n", realname, path);
241#endif
242 th_set_link(t, path);
243 }
244
245 /* print file info */
246 if (t->options & TAR_VERBOSE)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500247 printf("%s\n", th_get_pathname(t));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500248
249#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500250 puts("tar_append_file(): writing header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500251#endif
252 /* write header */
253 if (th_write(t) != 0)
254 {
255#ifdef DEBUG
256 printf("t->fd = %d\n", t->fd);
257#endif
258 return -1;
259 }
260#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500261 puts("tar_append_file(): back from th_write()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500262#endif
263
264 /* if it's a regular file, write the contents as well */
265 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
266 return -1;
267
268 return 0;
269}
270
271
272/* write EOF indicator */
273int
274tar_append_eof(TAR *t)
275{
276 int i, j;
277 char block[T_BLOCKSIZE];
278
279 memset(&block, 0, T_BLOCKSIZE);
280 for (j = 0; j < 2; j++)
281 {
282 i = tar_block_write(t, &block);
283 if (i != T_BLOCKSIZE)
284 {
285 if (i != -1)
286 errno = EINVAL;
287 return -1;
288 }
289 }
290
291 return 0;
292}
293
294
295/* add file contents to a tarchive */
296int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500297tar_append_regfile(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500298{
299 char block[T_BLOCKSIZE];
300 int filefd;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500301 int64_t i, size;
302 ssize_t j;
303 int rv = -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500304
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500305#if defined(O_BINARY)
306 filefd = open(realname, O_RDONLY|O_BINARY);
307#else
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500308 filefd = open(realname, O_RDONLY);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500309#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500310 if (filefd == -1)
311 {
312#ifdef DEBUG
313 perror("open()");
314#endif
315 return -1;
316 }
317
318 size = th_get_size(t);
319 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
320 {
321 j = read(filefd, &block, T_BLOCKSIZE);
322 if (j != T_BLOCKSIZE)
323 {
324 if (j != -1)
325 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500326 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500327 }
328 if (tar_block_write(t, &block) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500329 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500330 }
331
332 if (i > 0)
333 {
334 j = read(filefd, &block, i);
335 if (j == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500336 goto fail;
337 memset(&(block[i]), 0, T_BLOCKSIZE - i);
338 if (tar_block_write(t, &block) == -1)
339 goto fail;
340 }
341
342 /* success! */
343 rv = 0;
344fail:
345 close(filefd);
346
347 return rv;
348}
349
350
351/* add file contents to a tarchive */
352int
353tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
354 uid_t uid, gid_t gid, void *buf, size_t len)
355{
356 struct stat st;
357
358 memset(&st, 0, sizeof(st));
359 st.st_mode = S_IFREG | mode;
360 st.st_uid = uid;
361 st.st_gid = gid;
362 st.st_mtime = time(NULL);
363 st.st_size = len;
364
365 th_set_from_stat(t, &st);
366 th_set_path(t, savename);
367
368 /* write header */
369 if (th_write(t) != 0)
370 {
371#ifdef DEBUG
372 fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %d\n", t->fd);
373#endif
374 return -1;
375 }
376
377 return tar_append_buffer(t, buf, len);
378}
379
380int
381tar_append_buffer(TAR *t, void *buf, size_t len)
382{
383 char block[T_BLOCKSIZE];
384 int filefd;
385 int i, j;
386 size_t size = len;
387
388 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
389 {
390 if (tar_block_write(t, buf) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500391 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500392 buf = (char *)buf + T_BLOCKSIZE;
393 }
394
395 if (i > 0)
396 {
397 memcpy(block, buf, i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500398 memset(&(block[i]), 0, T_BLOCKSIZE - i);
399 if (tar_block_write(t, &block) == -1)
400 return -1;
401 }
402
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500403 return 0;
404}
405