blob: 8f09de26263aec4ba02820cc0093e261bcb8cc01 [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
Matt Mower87413642017-01-17 21:14:46 -060038#include <selinux/selinux.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050039
Ethan Yonker79f88bd2016-12-09 14:52:12 -060040#ifdef HAVE_EXT4_CRYPT
41# include "ext4crypt_tar.h"
42#endif
Ethan Yonker8d039f72017-02-03 14:26:15 -060043#include "android_utils.h"
Ethan Yonker79f88bd2016-12-09 14:52:12 -060044
bigbiff bigbiff9c754052013-01-09 09:09:08 -050045struct tar_dev
46{
47 dev_t td_dev;
48 libtar_hash_t *td_h;
49};
50typedef struct tar_dev tar_dev_t;
51
52struct tar_ino
53{
54 ino_t ti_ino;
55 char ti_name[MAXPATHLEN];
56};
57typedef struct tar_ino tar_ino_t;
58
59
60/* free memory associated with a tar_dev_t */
61void
62tar_dev_free(tar_dev_t *tdp)
63{
64 libtar_hash_free(tdp->td_h, free);
65 free(tdp);
66}
67
68
69/* appends a file to the tar archive */
70int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050071tar_append_file(TAR *t, const char *realname, const char *savename)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050072{
73 struct stat s;
74 int i;
75 libtar_hashptr_t hp;
76 tar_dev_t *td = NULL;
77 tar_ino_t *ti = NULL;
78 char path[MAXPATHLEN];
79
80#ifdef DEBUG
81 printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
82 "savename=\"%s\")\n", t, t->pathname, realname,
83 (savename ? savename : "[NULL]"));
84#endif
85
86 if (lstat(realname, &s) != 0)
87 {
88#ifdef DEBUG
89 perror("lstat()");
90#endif
91 return -1;
92 }
93
94 /* set header block */
95#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050096 puts("tar_append_file(): setting header block...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -050097#endif
98 memset(&(t->th_buf), 0, sizeof(struct tar_header));
99 th_set_from_stat(t, &s);
100
101 /* set the header path */
102#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500103 puts("tar_append_file(): setting header path...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500104#endif
105 th_set_path(t, (savename ? savename : realname));
106
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200107 /* get selinux context */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500108 if (t->options & TAR_STORE_SELINUX)
109 {
110 if (t->th_buf.selinux_context != NULL)
111 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200112 free(t->th_buf.selinux_context);
113 t->th_buf.selinux_context = NULL;
114 }
115
116 security_context_t selinux_context = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500117 if (lgetfilecon(realname, &selinux_context) >= 0)
118 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200119 t->th_buf.selinux_context = strdup(selinux_context);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500120 printf(" ==> set selinux context: %s\n", selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200121 freecon(selinux_context);
122 }
123 else
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500124 {
125#ifdef DEBUG
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200126 perror("Failed to get selinux context");
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500127#endif
128 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200129 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500130
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600131#ifdef HAVE_EXT4_CRYPT
132 if (TH_ISDIR(t) && t->options & TAR_STORE_EXT4_POL)
133 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500134 if (t->th_buf.eep != NULL)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600135 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500136 free(t->th_buf.eep);
137 t->th_buf.eep = NULL;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600138 }
139
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500140 t->th_buf.eep = (struct ext4_encryption_policy*)malloc(sizeof(struct ext4_encryption_policy));
141 if (!t->th_buf.eep) {
142 printf("malloc ext4_encryption_policy\n");
143 return -1;
144 }
145 if (e4crypt_policy_get_struct(realname, t->th_buf.eep))
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600146 {
147 char tar_policy[EXT4_KEY_DESCRIPTOR_SIZE];
148 memset(tar_policy, 0, sizeof(tar_policy));
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500149 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
150 policy_to_hex(t->th_buf.eep->master_key_descriptor, policy_hex);
151 if (lookup_ref_key(t->th_buf.eep->master_key_descriptor, &tar_policy[0])) {
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600152 printf("found policy '%s' - '%s' - '%s'\n", realname, tar_policy, policy_hex);
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500153 memcpy(t->th_buf.eep->master_key_descriptor, tar_policy, EXT4_KEY_DESCRIPTOR_SIZE);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600154 } else {
155 printf("failed to lookup tar policy for '%s' - '%s'\n", realname, policy_hex);
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500156 free(t->th_buf.eep);
157 t->th_buf.eep = NULL;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600158 return -1;
159 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500160 }
161 else
162 {
163 // no policy found, but this is not an error as not all dirs will have a policy
164 free(t->th_buf.eep);
165 t->th_buf.eep = NULL;
166 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600167 }
168#endif
169
Ethan Yonker71187742017-01-13 13:30:10 -0600170 /* get posix file capabilities */
171 if (TH_ISREG(t) && t->options & TAR_STORE_POSIX_CAP)
172 {
173 if (t->th_buf.has_cap_data)
174 {
175 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
176 t->th_buf.has_cap_data = 0;
177 }
178
179 if (getxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data)) >= 0)
180 {
181 t->th_buf.has_cap_data = 1;
182#if 1 //def DEBUG
183 print_caps(&t->th_buf.cap_data);
184#endif
185 }
186 }
187
Ethan Yonker8d039f72017-02-03 14:26:15 -0600188 /* get android user.default xattr */
189 if (TH_ISDIR(t) && t->options & TAR_STORE_ANDROID_USER_XATTR)
190 {
191 if (getxattr(realname, "user.default", NULL, 0) >= 0)
192 {
193 t->th_buf.has_user_default = 1;
194#if 1 //def DEBUG
195 printf("storing xattr user.default\n");
196#endif
197 }
198 if (getxattr(realname, "user.inode_cache", NULL, 0) >= 0)
199 {
200 t->th_buf.has_user_cache = 1;
201#if 1 //def DEBUG
202 printf("storing xattr user.inode_cache\n");
203#endif
204 }
205 if (getxattr(realname, "user.inode_code_cache", NULL, 0) >= 0)
206 {
207 t->th_buf.has_user_code_cache = 1;
208#if 1 //def DEBUG
209 printf("storing xattr user.inode_code_cache\n");
210#endif
211 }
212 }
213
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500214 /* check if it's a hardlink */
215#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500216 puts("tar_append_file(): checking inode cache for hardlink...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500217#endif
218 libtar_hashptr_reset(&hp);
219 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
220 (libtar_matchfunc_t)dev_match) != 0)
221 td = (tar_dev_t *)libtar_hashptr_data(&hp);
222 else
223 {
224#ifdef DEBUG
225 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
226 major(s.st_dev), minor(s.st_dev));
227#endif
228 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
229 td->td_dev = s.st_dev;
230 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
231 if (td->td_h == NULL)
232 return -1;
233 if (libtar_hash_add(t->h, td) == -1)
234 return -1;
235 }
236 libtar_hashptr_reset(&hp);
237 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
238 (libtar_matchfunc_t)ino_match) != 0)
239 {
240 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
241#ifdef DEBUG
242 printf(" tar_append_file(): encoding hard link \"%s\" "
243 "to \"%s\"...\n", realname, ti->ti_name);
244#endif
245 t->th_buf.typeflag = LNKTYPE;
246 th_set_link(t, ti->ti_name);
247 }
248 else
249 {
250#ifdef DEBUG
251 printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
252 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
253 s.st_ino, realname);
254#endif
255 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
256 if (ti == NULL)
257 return -1;
258 ti->ti_ino = s.st_ino;
259 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
260 savename ? savename : realname);
261 libtar_hash_add(td->td_h, ti);
262 }
263
264 /* check if it's a symlink */
265 if (TH_ISSYM(t))
266 {
267 i = readlink(realname, path, sizeof(path));
268 if (i == -1)
269 return -1;
270 if (i >= MAXPATHLEN)
271 i = MAXPATHLEN - 1;
272 path[i] = '\0';
273#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500274 printf("tar_append_file(): encoding symlink \"%s\" -> "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500275 "\"%s\"...\n", realname, path);
276#endif
277 th_set_link(t, path);
278 }
279
280 /* print file info */
281 if (t->options & TAR_VERBOSE)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500282 printf("%s\n", th_get_pathname(t));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500283
284#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500285 puts("tar_append_file(): writing header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500286#endif
287 /* write header */
288 if (th_write(t) != 0)
289 {
290#ifdef DEBUG
291 printf("t->fd = %d\n", t->fd);
292#endif
293 return -1;
294 }
295#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500296 puts("tar_append_file(): back from th_write()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500297#endif
298
299 /* if it's a regular file, write the contents as well */
300 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
301 return -1;
302
303 return 0;
304}
305
306
307/* write EOF indicator */
308int
309tar_append_eof(TAR *t)
310{
311 int i, j;
312 char block[T_BLOCKSIZE];
313
314 memset(&block, 0, T_BLOCKSIZE);
315 for (j = 0; j < 2; j++)
316 {
317 i = tar_block_write(t, &block);
318 if (i != T_BLOCKSIZE)
319 {
320 if (i != -1)
321 errno = EINVAL;
322 return -1;
323 }
324 }
325
326 return 0;
327}
328
329
330/* add file contents to a tarchive */
331int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500332tar_append_regfile(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500333{
334 char block[T_BLOCKSIZE];
335 int filefd;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500336 int64_t i, size;
337 ssize_t j;
338 int rv = -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500339
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500340#if defined(O_BINARY)
341 filefd = open(realname, O_RDONLY|O_BINARY);
342#else
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500343 filefd = open(realname, O_RDONLY);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500344#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500345 if (filefd == -1)
346 {
347#ifdef DEBUG
348 perror("open()");
349#endif
350 return -1;
351 }
352
353 size = th_get_size(t);
354 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
355 {
356 j = read(filefd, &block, T_BLOCKSIZE);
357 if (j != T_BLOCKSIZE)
358 {
359 if (j != -1)
360 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500361 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500362 }
363 if (tar_block_write(t, &block) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500364 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500365 }
366
367 if (i > 0)
368 {
369 j = read(filefd, &block, i);
370 if (j == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500371 goto fail;
372 memset(&(block[i]), 0, T_BLOCKSIZE - i);
373 if (tar_block_write(t, &block) == -1)
374 goto fail;
375 }
376
377 /* success! */
378 rv = 0;
379fail:
380 close(filefd);
381
382 return rv;
383}
384
385
386/* add file contents to a tarchive */
387int
388tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
389 uid_t uid, gid_t gid, void *buf, size_t len)
390{
391 struct stat st;
392
393 memset(&st, 0, sizeof(st));
394 st.st_mode = S_IFREG | mode;
395 st.st_uid = uid;
396 st.st_gid = gid;
397 st.st_mtime = time(NULL);
398 st.st_size = len;
399
400 th_set_from_stat(t, &st);
401 th_set_path(t, savename);
402
403 /* write header */
404 if (th_write(t) != 0)
405 {
406#ifdef DEBUG
407 fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %d\n", t->fd);
408#endif
409 return -1;
410 }
411
412 return tar_append_buffer(t, buf, len);
413}
414
415int
416tar_append_buffer(TAR *t, void *buf, size_t len)
417{
418 char block[T_BLOCKSIZE];
Ethan Yonker58f21322018-08-24 11:17:36 -0500419 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500420 size_t size = len;
421
422 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
423 {
424 if (tar_block_write(t, buf) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500425 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500426 buf = (char *)buf + T_BLOCKSIZE;
427 }
428
429 if (i > 0)
430 {
431 memcpy(block, buf, i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500432 memset(&(block[i]), 0, T_BLOCKSIZE - i);
433 if (tar_block_write(t, &block) == -1)
434 return -1;
435 }
436
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500437 return 0;
438}
439