blob: e922233781bdc9b076ceed670141f44a798bd70c [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>
bigbiff7ba75002020-04-11 20:47:09 -040027#include <linux/fs.h>
Ethan Yonker71187742017-01-13 13:30:10 -060028#include <linux/xattr.h>
29
bigbiff bigbiff9c754052013-01-09 09:09:08 -050030#ifdef STDC_HEADERS
bigbiff7ba75002020-04-11 20:47:09 -040031#include <stdlib.h>
32#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050033#endif
34
35#ifdef HAVE_UNISTD_H
bigbiff7ba75002020-04-11 20:47:09 -040036#include <unistd.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050037#endif
38
Matt Mower87413642017-01-17 21:14:46 -060039#include <selinux/selinux.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050040
bigbiff7ba75002020-04-11 20:47:09 -040041#ifdef USE_FSCRYPT
42#include "fscrypt_policy.h"
43#endif
44
Ethan Yonker8d039f72017-02-03 14:26:15 -060045#include "android_utils.h"
Ethan Yonker79f88bd2016-12-09 14:52:12 -060046
bigbiffa957f072021-03-07 18:20:29 -050047#ifdef TW_LIBTAR_DEBUG
48#define DEBUG 1
49#endif
50
bigbiff bigbiff9c754052013-01-09 09:09:08 -050051struct tar_dev
52{
53 dev_t td_dev;
54 libtar_hash_t *td_h;
55};
56typedef struct tar_dev tar_dev_t;
57
58struct tar_ino
59{
60 ino_t ti_ino;
61 char ti_name[MAXPATHLEN];
62};
63typedef struct tar_ino tar_ino_t;
64
65
66/* free memory associated with a tar_dev_t */
67void
68tar_dev_free(tar_dev_t *tdp)
69{
70 libtar_hash_free(tdp->td_h, free);
71 free(tdp);
72}
73
74
75/* appends a file to the tar archive */
76int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050077tar_append_file(TAR *t, const char *realname, const char *savename)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050078{
79 struct stat s;
80 int i;
81 libtar_hashptr_t hp;
82 tar_dev_t *td = NULL;
83 tar_ino_t *ti = NULL;
84 char path[MAXPATHLEN];
bigbiffc9a28c22023-04-11 19:55:06 -040085 int filefd;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050086
87#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +010088 LOG("==> tar_append_file(TAR=0x%p (\"%s\"), realname=\"%s\", "
bigbiffa957f072021-03-07 18:20:29 -050089 "savename=\"%s\")\n", (void*) t, t->pathname, realname,
bigbiff bigbiff9c754052013-01-09 09:09:08 -050090 (savename ? savename : "[NULL]"));
91#endif
92
93 if (lstat(realname, &s) != 0)
94 {
95#ifdef DEBUG
96 perror("lstat()");
97#endif
98 return -1;
99 }
100
101 /* set header block */
102#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100103 LOG("tar_append_file(): setting header block...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500104#endif
105 memset(&(t->th_buf), 0, sizeof(struct tar_header));
106 th_set_from_stat(t, &s);
107
108 /* set the header path */
109#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100110 LOG("tar_append_file(): setting header path...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500111#endif
112 th_set_path(t, (savename ? savename : realname));
113
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200114 /* get selinux context */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500115 if (t->options & TAR_STORE_SELINUX)
116 {
117 if (t->th_buf.selinux_context != NULL)
118 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200119 free(t->th_buf.selinux_context);
120 t->th_buf.selinux_context = NULL;
121 }
122
bigbiff7df87472022-09-24 16:45:03 -0400123 char* selinux_context = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500124 if (lgetfilecon(realname, &selinux_context) >= 0)
125 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200126 t->th_buf.selinux_context = strdup(selinux_context);
Mohd Faraz15247642023-01-16 16:16:21 +0100127 LOG(" ==> set selinux context: %s\n", selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200128 freecon(selinux_context);
129 }
130 else
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500131 {
132#ifdef DEBUG
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200133 perror("Failed to get selinux context");
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500134#endif
135 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200136 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500137
bigbiff7ba75002020-04-11 20:47:09 -0400138#ifdef USE_FSCRYPT
139 if (TH_ISDIR(t) && t->options & TAR_STORE_FSCRYPT_POL)
140 {
141 if (t->th_buf.fep != NULL)
142 {
143 free(t->th_buf.fep);
144 t->th_buf.fep = NULL;
145 }
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100146 t->th_buf.fep = (fscrypt_policy *)malloc(sizeof(fscrypt_policy));
bigbiff7ba75002020-04-11 20:47:09 -0400147 if (!t->th_buf.fep) {
Mohd Faraz15247642023-01-16 16:16:21 +0100148 LOG("malloc fs_encryption_policy\n");
bigbiff7ba75002020-04-11 20:47:09 -0400149 return -1;
150 }
151
152 if (fscrypt_policy_get_struct(realname, t->th_buf.fep)) {
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100153 uint8_t size, hex_size, *descriptor;
154 size = get_policy_size(t->th_buf.fep, false);
155 hex_size = get_policy_size(t->th_buf.fep, true);
156 descriptor = get_policy_descriptor(t->th_buf.fep);
157 char user_ce[4], user_de[4], system_de[4];
158 sprintf(user_ce,"%u%s", t->th_buf.fep->version, USER_CE_FSCRYPT_POLICY);
159 sprintf(user_de,"%u%s", t->th_buf.fep->version, USER_DE_FSCRYPT_POLICY);
160 sprintf(system_de,"%u%s", t->th_buf.fep->version, SYSTEM_DE_FSCRYPT_POLICY);
161#ifdef DEBUG
162 LOG("version: %u\n", t->th_buf.fep->version);
bigbiff2e344ab2021-05-07 10:41:55 -0400163#endif
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100164 uint8_t tar_policy[size];
165 char policy_hex[hex_size];
bigbiff2e344ab2021-05-07 10:41:55 -0400166 memset(tar_policy, 0, sizeof(tar_policy));
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100167 bytes_to_hex(descriptor, size, policy_hex);
bigbiffa957f072021-03-07 18:20:29 -0500168 if (lookup_ref_key(t->th_buf.fep, &tar_policy[0])) {
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100169 if (strncmp((char *) tar_policy, user_ce, sizeof(user_ce) - 1) == 0
170 || strncmp((char *) tar_policy, user_de, sizeof(user_de) - 1) == 0
171 || strncmp((char *) tar_policy, system_de, sizeof(system_de)) == 0) {
172 memcpy(descriptor, tar_policy, size);
173 LOG("found fscrypt policy '%s' - '%s' - '%s'\n", realname, descriptor, policy_hex);
bigbiffa957f072021-03-07 18:20:29 -0500174 } else {
Mohd Faraz15247642023-01-16 16:16:21 +0100175 LOG("failed to match fscrypt tar policy for '%s' - '%s'\n", realname, policy_hex);
bigbiffa957f072021-03-07 18:20:29 -0500176 free(t->th_buf.fep);
177 t->th_buf.fep = NULL;
178 }
bigbiff7ba75002020-04-11 20:47:09 -0400179 } else {
Mohd Faraz15247642023-01-16 16:16:21 +0100180 LOG("failed to lookup fscrypt tar policy for '%s' - '%s'\n", realname, policy_hex);
bigbiff7ba75002020-04-11 20:47:09 -0400181 free(t->th_buf.fep);
182 t->th_buf.fep = NULL;
bigbiff7ba75002020-04-11 20:47:09 -0400183 }
184 }
185 else {
186 // no policy found, but this is not an error as not all dirs will have a policy
187 free(t->th_buf.fep);
188 t->th_buf.fep = NULL;
189 }
190 }
191#endif
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600192
Ethan Yonker71187742017-01-13 13:30:10 -0600193 /* get posix file capabilities */
194 if (TH_ISREG(t) && t->options & TAR_STORE_POSIX_CAP)
195 {
196 if (t->th_buf.has_cap_data)
197 {
198 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
199 t->th_buf.has_cap_data = 0;
200 }
201
202 if (getxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data)) >= 0)
203 {
204 t->th_buf.has_cap_data = 1;
205#if 1 //def DEBUG
206 print_caps(&t->th_buf.cap_data);
207#endif
208 }
209 }
210
Ethan Yonker8d039f72017-02-03 14:26:15 -0600211 /* get android user.default xattr */
212 if (TH_ISDIR(t) && t->options & TAR_STORE_ANDROID_USER_XATTR)
213 {
214 if (getxattr(realname, "user.default", NULL, 0) >= 0)
215 {
216 t->th_buf.has_user_default = 1;
217#if 1 //def DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100218 LOG("storing xattr user.default\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600219#endif
220 }
221 if (getxattr(realname, "user.inode_cache", NULL, 0) >= 0)
222 {
223 t->th_buf.has_user_cache = 1;
224#if 1 //def DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100225 LOG("storing xattr user.inode_cache\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600226#endif
227 }
228 if (getxattr(realname, "user.inode_code_cache", NULL, 0) >= 0)
229 {
230 t->th_buf.has_user_code_cache = 1;
231#if 1 //def DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100232 LOG("storing xattr user.inode_code_cache\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600233#endif
234 }
235 }
236
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500237 /* check if it's a hardlink */
238#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100239 LOG("tar_append_file(): checking inode cache for hardlink...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500240#endif
241 libtar_hashptr_reset(&hp);
242 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
243 (libtar_matchfunc_t)dev_match) != 0)
244 td = (tar_dev_t *)libtar_hashptr_data(&hp);
245 else
246 {
247#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100248 LOG("+++ adding hash for device (0x%x, 0x%x)...\n",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500249 major(s.st_dev), minor(s.st_dev));
250#endif
251 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
252 td->td_dev = s.st_dev;
253 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
254 if (td->td_h == NULL)
255 return -1;
256 if (libtar_hash_add(t->h, td) == -1)
257 return -1;
258 }
259 libtar_hashptr_reset(&hp);
260 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
261 (libtar_matchfunc_t)ino_match) != 0)
262 {
263 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
264#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100265 LOG(" tar_append_file(): encoding hard link \"%s\" "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500266 "to \"%s\"...\n", realname, ti->ti_name);
267#endif
268 t->th_buf.typeflag = LNKTYPE;
269 th_set_link(t, ti->ti_name);
270 }
271 else
272 {
273#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100274 LOG("+++ adding entry: device (0x%d,0x%x), inode %lu"
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500275 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
bigbiffa957f072021-03-07 18:20:29 -0500276 (unsigned long) s.st_ino, realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500277#endif
278 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
279 if (ti == NULL)
280 return -1;
281 ti->ti_ino = s.st_ino;
282 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
283 savename ? savename : realname);
284 libtar_hash_add(td->td_h, ti);
285 }
286
287 /* check if it's a symlink */
288 if (TH_ISSYM(t))
289 {
290 i = readlink(realname, path, sizeof(path));
291 if (i == -1)
292 return -1;
293 if (i >= MAXPATHLEN)
294 i = MAXPATHLEN - 1;
295 path[i] = '\0';
296#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100297 LOG("tar_append_file(): encoding symlink \"%s\" -> "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500298 "\"%s\"...\n", realname, path);
299#endif
300 th_set_link(t, path);
301 }
302
303 /* print file info */
304 if (t->options & TAR_VERBOSE)
Mohd Faraz15247642023-01-16 16:16:21 +0100305 LOG("%s\n", th_get_pathname(t));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500306
bigbiffc9a28c22023-04-11 19:55:06 -0400307#if defined(O_BINARY)
308 filefd = open(realname, O_RDONLY|O_BINARY);
309#else
310 filefd = open(realname, O_RDONLY);
311#endif
312 if (filefd == -1)
313 {
314 if (errno == ENOKEY) {
315 LOG("Required key not available, skipping file\n");
316 close(filefd);
317 return 0;
318 }
319 }
320 close(filefd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500321#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100322 LOG("tar_append_file(): writing header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500323#endif
324 /* write header */
325 if (th_write(t) != 0)
326 {
327#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100328 LOG("t->fd = %ld\n", t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500329#endif
330 return -1;
331 }
332#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100333 LOG("tar_append_file(): back from th_write()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500334#endif
335
336 /* if it's a regular file, write the contents as well */
337 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
338 return -1;
339
340 return 0;
341}
342
343
344/* write EOF indicator */
345int
346tar_append_eof(TAR *t)
347{
348 int i, j;
349 char block[T_BLOCKSIZE];
350
351 memset(&block, 0, T_BLOCKSIZE);
352 for (j = 0; j < 2; j++)
353 {
354 i = tar_block_write(t, &block);
355 if (i != T_BLOCKSIZE)
356 {
357 if (i != -1)
358 errno = EINVAL;
359 return -1;
360 }
361 }
362
363 return 0;
364}
365
366
367/* add file contents to a tarchive */
368int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500369tar_append_regfile(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500370{
371 char block[T_BLOCKSIZE];
372 int filefd;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500373 int64_t i, size;
374 ssize_t j;
375 int rv = -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500376
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500377#if defined(O_BINARY)
378 filefd = open(realname, O_RDONLY|O_BINARY);
379#else
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500380 filefd = open(realname, O_RDONLY);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500381#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500382 if (filefd == -1)
383 {
384#ifdef DEBUG
385 perror("open()");
386#endif
387 return -1;
388 }
389
390 size = th_get_size(t);
391 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
392 {
393 j = read(filefd, &block, T_BLOCKSIZE);
394 if (j != T_BLOCKSIZE)
395 {
396 if (j != -1)
397 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500398 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500399 }
400 if (tar_block_write(t, &block) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500401 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500402 }
403
404 if (i > 0)
405 {
406 j = read(filefd, &block, i);
407 if (j == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500408 goto fail;
409 memset(&(block[i]), 0, T_BLOCKSIZE - i);
410 if (tar_block_write(t, &block) == -1)
411 goto fail;
412 }
413
414 /* success! */
415 rv = 0;
416fail:
417 close(filefd);
418
419 return rv;
420}
421
422
423/* add file contents to a tarchive */
424int
425tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
426 uid_t uid, gid_t gid, void *buf, size_t len)
427{
428 struct stat st;
429
430 memset(&st, 0, sizeof(st));
431 st.st_mode = S_IFREG | mode;
432 st.st_uid = uid;
433 st.st_gid = gid;
434 st.st_mtime = time(NULL);
435 st.st_size = len;
436
437 th_set_from_stat(t, &st);
438 th_set_path(t, savename);
439
440 /* write header */
441 if (th_write(t) != 0)
442 {
443#ifdef DEBUG
bigbiffa957f072021-03-07 18:20:29 -0500444 fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %ld\n", t->fd);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500445#endif
446 return -1;
447 }
448
449 return tar_append_buffer(t, buf, len);
450}
451
452int
453tar_append_buffer(TAR *t, void *buf, size_t len)
454{
455 char block[T_BLOCKSIZE];
Ethan Yonker58f21322018-08-24 11:17:36 -0500456 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500457 size_t size = len;
458
459 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
460 {
461 if (tar_block_write(t, buf) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500462 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500463 buf = (char *)buf + T_BLOCKSIZE;
464 }
465
466 if (i > 0)
467 {
468 memcpy(block, buf, i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500469 memset(&(block[i]), 0, T_BLOCKSIZE - i);
470 if (tar_block_write(t, &block) == -1)
471 return -1;
472 }
473
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500474 return 0;
475}
476