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