Added stdlib.h for malloc() in lib/decode.c
[libtar.git] / lib / append.c
blobff5853215edd63aef6af9a13a4e59dfddaf3de34
1 /*
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
13 #include <internal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <sys/param.h>
21 #include <sys/types.h>
23 #ifdef STDC_HEADERS
24 # include <stdlib.h>
25 # include <string.h>
26 #endif
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
33 struct tar_dev
35 dev_t td_dev;
36 libtar_hash_t *td_h;
38 typedef struct tar_dev tar_dev_t;
40 struct tar_ino
42 ino_t ti_ino;
43 char ti_name[MAXPATHLEN];
45 typedef struct tar_ino tar_ino_t;
48 /* free memory associated with a tar_dev_t */
49 void
50 tar_dev_free(tar_dev_t *tdp)
52 libtar_hash_free(tdp->td_h, free);
53 free(tdp);
57 /* appends a file to the tar archive */
58 int
59 tar_append_file(TAR *t, const char *realname, const char *savename)
61 struct stat s;
62 int i;
63 libtar_hashptr_t hp;
64 tar_dev_t *td = NULL;
65 tar_ino_t *ti = NULL;
66 char path[MAXPATHLEN];
68 #ifdef DEBUG
69 printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
70 "savename=\"%s\")\n", t, t->pathname, realname,
71 (savename ? savename : "[NULL]"));
72 #endif
74 if (lstat(realname, &s) != 0)
76 #ifdef DEBUG
77 perror("lstat()");
78 #endif
79 return -1;
82 /* set header block */
83 #ifdef DEBUG
84 puts(" tar_append_file(): setting header block...");
85 #endif
86 memset(&(t->th_buf), 0, sizeof(struct tar_header));
87 th_set_from_stat(t, &s);
89 /* set the header path */
90 #ifdef DEBUG
91 puts(" tar_append_file(): setting header path...");
92 #endif
93 th_set_path(t, (savename ? savename : realname));
95 /* check if it's a hardlink */
96 #ifdef DEBUG
97 puts(" tar_append_file(): checking inode cache for hardlink...");
98 #endif
99 libtar_hashptr_reset(&hp);
100 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
101 (libtar_matchfunc_t)dev_match) != 0)
102 td = (tar_dev_t *)libtar_hashptr_data(&hp);
103 else
105 #ifdef DEBUG
106 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
107 major(s.st_dev), minor(s.st_dev));
108 #endif
109 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
110 td->td_dev = s.st_dev;
111 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
112 if (td->td_h == NULL)
113 return -1;
114 if (libtar_hash_add(t->h, td) == -1)
115 return -1;
117 libtar_hashptr_reset(&hp);
118 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
119 (libtar_matchfunc_t)ino_match) != 0)
121 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
122 #ifdef DEBUG
123 printf(" tar_append_file(): encoding hard link \"%s\" "
124 "to \"%s\"...\n", realname, ti->ti_name);
125 #endif
126 t->th_buf.typeflag = LNKTYPE;
127 th_set_link(t, ti->ti_name);
129 else
131 #ifdef DEBUG
132 printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
133 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
134 s.st_ino, realname);
135 #endif
136 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
137 if (ti == NULL)
138 return -1;
139 ti->ti_ino = s.st_ino;
140 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
141 savename ? savename : realname);
142 libtar_hash_add(td->td_h, ti);
145 /* check if it's a symlink */
146 if (TH_ISSYM(t))
148 i = readlink(realname, path, sizeof(path));
149 if (i == -1)
150 return -1;
151 if (i >= MAXPATHLEN)
152 i = MAXPATHLEN - 1;
153 path[i] = '\0';
154 #ifdef DEBUG
155 printf(" tar_append_file(): encoding symlink \"%s\" -> "
156 "\"%s\"...\n", realname, path);
157 #endif
158 th_set_link(t, path);
161 /* print file info */
162 if (t->options & TAR_VERBOSE)
163 th_print_long_ls(t);
165 #ifdef DEBUG
166 puts(" tar_append_file(): writing header");
167 #endif
168 /* write header */
169 if (th_write(t) != 0)
171 #ifdef DEBUG
172 printf("t->fd = %d\n", t->fd);
173 #endif
174 return -1;
176 #ifdef DEBUG
177 puts(" tar_append_file(): back from th_write()");
178 #endif
180 /* if it's a regular file, write the contents as well */
181 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
182 return -1;
184 return 0;
188 /* write EOF indicator */
190 tar_append_eof(TAR *t)
192 int i, j;
193 char block[T_BLOCKSIZE];
195 memset(&block, 0, T_BLOCKSIZE);
196 for (j = 0; j < 2; j++)
198 i = tar_block_write(t, &block);
199 if (i != T_BLOCKSIZE)
201 if (i != -1)
202 errno = EINVAL;
203 return -1;
207 return 0;
211 /* add file contents to a tarchive */
213 tar_append_regfile(TAR *t, const char *realname)
215 char block[T_BLOCKSIZE];
216 int filefd;
217 int i, j;
218 size_t size;
219 int rv = -1;
221 filefd = open(realname, O_RDONLY);
222 if (filefd == -1)
224 #ifdef DEBUG
225 perror("open()");
226 #endif
227 return -1;
230 size = th_get_size(t);
231 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
233 j = read(filefd, &block, T_BLOCKSIZE);
234 if (j != T_BLOCKSIZE)
236 if (j != -1)
237 errno = EINVAL;
238 goto fail;
240 if (tar_block_write(t, &block) == -1)
241 goto fail;
244 if (i > 0)
246 j = read(filefd, &block, i);
247 if (j == -1)
248 goto fail;
249 memset(&(block[i]), 0, T_BLOCKSIZE - i);
250 if (tar_block_write(t, &block) == -1)
251 goto fail;
254 /* success! */
255 rv = 0;
256 fail:
257 close(filefd);
259 return rv;