blob: 1831990be055c454709e32339077142a45417de4 [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>
16#include <errno.h>
17#include <fcntl.h>
18#include <sys/param.h>
19#include <sys/types.h>
20
21#ifdef STDC_HEADERS
22# include <stdlib.h>
23# include <string.h>
24#endif
25
26#ifdef HAVE_UNISTD_H
27# include <unistd.h>
28#endif
29
Ethan Yonker50381972014-02-11 11:44:06 -060030#ifdef HAVE_SELINUX
31#include "selinux/selinux.h"
32#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050033
34struct tar_dev
35{
36 dev_t td_dev;
37 libtar_hash_t *td_h;
38};
39typedef struct tar_dev tar_dev_t;
40
41struct tar_ino
42{
43 ino_t ti_ino;
44 char ti_name[MAXPATHLEN];
45};
46typedef struct tar_ino tar_ino_t;
47
48
49/* free memory associated with a tar_dev_t */
50void
51tar_dev_free(tar_dev_t *tdp)
52{
53 libtar_hash_free(tdp->td_h, free);
54 free(tdp);
55}
56
57
58/* appends a file to the tar archive */
59int
60tar_append_file(TAR *t, char *realname, char *savename)
61{
62 struct stat s;
63 int i;
64 libtar_hashptr_t hp;
65 tar_dev_t *td = NULL;
66 tar_ino_t *ti = NULL;
67 char path[MAXPATHLEN];
68
69#ifdef DEBUG
70 printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
71 "savename=\"%s\")\n", t, t->pathname, realname,
72 (savename ? savename : "[NULL]"));
73#endif
74
75 if (lstat(realname, &s) != 0)
76 {
77#ifdef DEBUG
78 perror("lstat()");
79#endif
80 return -1;
81 }
82
83 /* set header block */
84#ifdef DEBUG
85 puts(" tar_append_file(): setting header block...");
86#endif
87 memset(&(t->th_buf), 0, sizeof(struct tar_header));
88 th_set_from_stat(t, &s);
89
90 /* set the header path */
91#ifdef DEBUG
92 puts(" tar_append_file(): setting header path...");
93#endif
94 th_set_path(t, (savename ? savename : realname));
95
Vojtech Bocek25fd68d2013-08-27 03:10:10 +020096#ifdef HAVE_SELINUX
97 /* get selinux context */
bigbiff bigbiffc49d7062013-10-11 20:28:00 -040098 if(t->options & TAR_STORE_SELINUX) {
99 if(t->th_buf.selinux_context != NULL) {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200100 free(t->th_buf.selinux_context);
101 t->th_buf.selinux_context = NULL;
102 }
103
104 security_context_t selinux_context = NULL;
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400105 if (lgetfilecon(realname, &selinux_context) >= 0) {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200106 t->th_buf.selinux_context = strdup(selinux_context);
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400107 printf("setting selinux context: %s\n", selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200108 freecon(selinux_context);
109 }
110 else
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200111 perror("Failed to get selinux context");
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200112 }
113#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500114 /* check if it's a hardlink */
115#ifdef DEBUG
116 puts(" tar_append_file(): checking inode cache for hardlink...");
117#endif
118 libtar_hashptr_reset(&hp);
119 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
120 (libtar_matchfunc_t)dev_match) != 0)
121 td = (tar_dev_t *)libtar_hashptr_data(&hp);
122 else
123 {
124#ifdef DEBUG
125 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
126 major(s.st_dev), minor(s.st_dev));
127#endif
128 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
129 td->td_dev = s.st_dev;
130 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
131 if (td->td_h == NULL)
132 return -1;
133 if (libtar_hash_add(t->h, td) == -1)
134 return -1;
135 }
136 libtar_hashptr_reset(&hp);
137 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
138 (libtar_matchfunc_t)ino_match) != 0)
139 {
140 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
141#ifdef DEBUG
142 printf(" tar_append_file(): encoding hard link \"%s\" "
143 "to \"%s\"...\n", realname, ti->ti_name);
144#endif
145 t->th_buf.typeflag = LNKTYPE;
146 th_set_link(t, ti->ti_name);
147 }
148 else
149 {
150#ifdef DEBUG
151 printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
152 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
153 s.st_ino, realname);
154#endif
155 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
156 if (ti == NULL)
157 return -1;
158 ti->ti_ino = s.st_ino;
159 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
160 savename ? savename : realname);
161 libtar_hash_add(td->td_h, ti);
162 }
163
164 /* check if it's a symlink */
165 if (TH_ISSYM(t))
166 {
167 i = readlink(realname, path, sizeof(path));
168 if (i == -1)
169 return -1;
170 if (i >= MAXPATHLEN)
171 i = MAXPATHLEN - 1;
172 path[i] = '\0';
173#ifdef DEBUG
174 printf(" tar_append_file(): encoding symlink \"%s\" -> "
175 "\"%s\"...\n", realname, path);
176#endif
177 th_set_link(t, path);
178 }
179
180 /* print file info */
181 if (t->options & TAR_VERBOSE)
182 th_print_long_ls(t);
183
184#ifdef DEBUG
185 puts(" tar_append_file(): writing header");
186#endif
187 /* write header */
188 if (th_write(t) != 0)
189 {
190#ifdef DEBUG
191 printf("t->fd = %d\n", t->fd);
192#endif
193 return -1;
194 }
195#ifdef DEBUG
196 puts(" tar_append_file(): back from th_write()");
197#endif
198
199 /* if it's a regular file, write the contents as well */
200 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
201 return -1;
202
203 return 0;
204}
205
206
207/* write EOF indicator */
208int
209tar_append_eof(TAR *t)
210{
211 int i, j;
212 char block[T_BLOCKSIZE];
213
214 memset(&block, 0, T_BLOCKSIZE);
215 for (j = 0; j < 2; j++)
216 {
217 i = tar_block_write(t, &block);
218 if (i != T_BLOCKSIZE)
219 {
220 if (i != -1)
221 errno = EINVAL;
222 return -1;
223 }
224 }
225
226 return 0;
227}
228
229
230/* add file contents to a tarchive */
231int
232tar_append_regfile(TAR *t, char *realname)
233{
234 char block[T_BLOCKSIZE];
235 int filefd;
Vojtech Bocek78ab0c52015-03-20 15:34:45 +0100236 int j;
237 size_t size, i;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500238
239 filefd = open(realname, O_RDONLY);
240 if (filefd == -1)
241 {
242#ifdef DEBUG
243 perror("open()");
244#endif
245 return -1;
246 }
247
248 size = th_get_size(t);
249 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
250 {
251 j = read(filefd, &block, T_BLOCKSIZE);
252 if (j != T_BLOCKSIZE)
253 {
254 if (j != -1)
255 errno = EINVAL;
256 return -1;
257 }
258 if (tar_block_write(t, &block) == -1)
259 return -1;
260 }
261
262 if (i > 0)
263 {
264 j = read(filefd, &block, i);
265 if (j == -1)
266 return -1;
267 memset(&(block[i]), 0, T_BLOCKSIZE - i);
268 if (tar_block_write(t, &block) == -1)
269 return -1;
270 }
271
272 close(filefd);
273
274 return 0;
275}
276
277