blob: 3a8bfc69014e563045beb5d6dd0bf92f5b9f6b95 [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 */
95 if(t->options & TAR_STORE_SELINUX)
96 {
97 if(t->th_buf.selinux_context != NULL)
98 {
99 free(t->th_buf.selinux_context);
100 t->th_buf.selinux_context = NULL;
101 }
102
103 security_context_t selinux_context = NULL;
104 if(getfilecon(realname, &selinux_context) >= 0)
105 {
106 t->th_buf.selinux_context = strdup(selinux_context);
107 freecon(selinux_context);
108 }
109 else
110 {
111#ifdef DEBUG
112 perror("Failed to get selinux context");
113#endif
114 }
115 }
116#endif
117
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500118 /* check if it's a hardlink */
119#ifdef DEBUG
120 puts(" tar_append_file(): checking inode cache for hardlink...");
121#endif
122 libtar_hashptr_reset(&hp);
123 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
124 (libtar_matchfunc_t)dev_match) != 0)
125 td = (tar_dev_t *)libtar_hashptr_data(&hp);
126 else
127 {
128#ifdef DEBUG
129 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
130 major(s.st_dev), minor(s.st_dev));
131#endif
132 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
133 td->td_dev = s.st_dev;
134 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
135 if (td->td_h == NULL)
136 return -1;
137 if (libtar_hash_add(t->h, td) == -1)
138 return -1;
139 }
140 libtar_hashptr_reset(&hp);
141 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
142 (libtar_matchfunc_t)ino_match) != 0)
143 {
144 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
145#ifdef DEBUG
146 printf(" tar_append_file(): encoding hard link \"%s\" "
147 "to \"%s\"...\n", realname, ti->ti_name);
148#endif
149 t->th_buf.typeflag = LNKTYPE;
150 th_set_link(t, ti->ti_name);
151 }
152 else
153 {
154#ifdef DEBUG
155 printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
156 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
157 s.st_ino, realname);
158#endif
159 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
160 if (ti == NULL)
161 return -1;
162 ti->ti_ino = s.st_ino;
163 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
164 savename ? savename : realname);
165 libtar_hash_add(td->td_h, ti);
166 }
167
168 /* check if it's a symlink */
169 if (TH_ISSYM(t))
170 {
171 i = readlink(realname, path, sizeof(path));
172 if (i == -1)
173 return -1;
174 if (i >= MAXPATHLEN)
175 i = MAXPATHLEN - 1;
176 path[i] = '\0';
177#ifdef DEBUG
178 printf(" tar_append_file(): encoding symlink \"%s\" -> "
179 "\"%s\"...\n", realname, path);
180#endif
181 th_set_link(t, path);
182 }
183
184 /* print file info */
185 if (t->options & TAR_VERBOSE)
186 th_print_long_ls(t);
187
188#ifdef DEBUG
189 puts(" tar_append_file(): writing header");
190#endif
191 /* write header */
192 if (th_write(t) != 0)
193 {
194#ifdef DEBUG
195 printf("t->fd = %d\n", t->fd);
196#endif
197 return -1;
198 }
199#ifdef DEBUG
200 puts(" tar_append_file(): back from th_write()");
201#endif
202
203 /* if it's a regular file, write the contents as well */
204 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
205 return -1;
206
207 return 0;
208}
209
210
211/* write EOF indicator */
212int
213tar_append_eof(TAR *t)
214{
215 int i, j;
216 char block[T_BLOCKSIZE];
217
218 memset(&block, 0, T_BLOCKSIZE);
219 for (j = 0; j < 2; j++)
220 {
221 i = tar_block_write(t, &block);
222 if (i != T_BLOCKSIZE)
223 {
224 if (i != -1)
225 errno = EINVAL;
226 return -1;
227 }
228 }
229
230 return 0;
231}
232
233
234/* add file contents to a tarchive */
235int
236tar_append_regfile(TAR *t, char *realname)
237{
238 char block[T_BLOCKSIZE];
239 int filefd;
240 int i, j;
241 size_t size;
242
243 filefd = open(realname, O_RDONLY);
244 if (filefd == -1)
245 {
246#ifdef DEBUG
247 perror("open()");
248#endif
249 return -1;
250 }
251
252 size = th_get_size(t);
253 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
254 {
255 j = read(filefd, &block, T_BLOCKSIZE);
256 if (j != T_BLOCKSIZE)
257 {
258 if (j != -1)
259 errno = EINVAL;
260 return -1;
261 }
262 if (tar_block_write(t, &block) == -1)
263 return -1;
264 }
265
266 if (i > 0)
267 {
268 j = read(filefd, &block, i);
269 if (j == -1)
270 return -1;
271 memset(&(block[i]), 0, T_BLOCKSIZE - i);
272 if (tar_block_write(t, &block) == -1)
273 return -1;
274 }
275
276 close(filefd);
277
278 return 0;
279}
280
281