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