ENH: make this work for older versions of OSX
[cmake.git] / Utilities / cmtar / append.c
blob38e829451d63cfb5c6baab3f25232167cde8678e
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 <libtarint/internal.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #if defined(_WIN32) && !defined(__CYGWIN__)
19 # include <libtar/compat.h>
20 #else
21 # include <sys/param.h>
22 #endif
23 #include <libtar/compat.h>
24 #include <sys/types.h>
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 # include <string.h>
29 #endif
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
35 #ifdef HAVE_IO_H
36 # include <io.h>
37 #endif
39 struct tar_dev
41 dev_t td_dev;
42 libtar_hash_t *td_h;
44 typedef struct tar_dev tar_dev_t;
46 struct tar_ino
48 ino_t ti_ino;
49 char ti_name[TAR_MAXPATHLEN];
51 typedef struct tar_ino tar_ino_t;
54 /* free memory associated with a tar_dev_t */
55 void
56 tar_dev_free(tar_dev_t *tdp)
58 libtar_hash_free(tdp->td_h, free);
59 free(tdp);
63 /* appends a file to the tar archive */
64 int
65 tar_append_file(TAR *t, char *realname, char *savename)
67 struct stat s;
68 libtar_hashptr_t hp;
69 tar_dev_t *td;
70 tar_ino_t *ti;
71 #if !defined(_WIN32) || defined(__CYGWIN__)
72 int i;
73 #else
74 size_t plen;
75 #endif
76 char path[TAR_MAXPATHLEN];
78 #ifdef DEBUG
79 printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
80 "savename=\"%s\")\n", t, t->pathname, realname,
81 (savename ? savename : "[NULL]"));
82 #endif
84 #if defined(_WIN32) && !defined(__CYGWIN__)
85 strncpy(path, realname, sizeof(path)-1);
86 path[sizeof(path)-1] = 0;
87 plen = strlen(path);
88 if (path[plen-1] == '/' )
90 path[plen-1] = 0;
92 if (stat(path, &s) != 0)
93 #else
94 if (lstat(realname, &s) != 0)
95 #endif
97 #ifdef DEBUG
98 perror("lstat()");
99 #endif
100 return -1;
103 /* set header block */
104 #ifdef DEBUG
105 puts(" tar_append_file(): setting header block...");
106 #endif
107 memset(&(t->th_buf), 0, sizeof(struct tar_header));
108 th_set_from_stat(t, &s);
110 /* set the header path */
111 #ifdef DEBUG
112 puts(" tar_append_file(): setting header path...");
113 #endif
114 th_set_path(t, (savename ? savename : realname));
116 /* check if it's a hardlink */
117 #ifdef DEBUG
118 puts(" tar_append_file(): checking inode cache for hardlink...");
119 #endif
120 libtar_hashptr_reset(&hp);
121 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
122 (libtar_matchfunc_t)dev_match) != 0)
123 td = (tar_dev_t *)libtar_hashptr_data(&hp);
124 else
126 #ifdef DEBUG
127 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
128 major(s.st_dev), minor(s.st_dev));
129 #endif
130 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
131 td->td_dev = s.st_dev;
132 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
133 if (td->td_h == NULL)
134 return -1;
135 if (libtar_hash_add(t->h, td) == -1)
136 return -1;
138 libtar_hashptr_reset(&hp);
139 #if !defined(_WIN32) || defined(__CYGWIN__)
140 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
141 (libtar_matchfunc_t)ino_match) != 0)
143 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
144 #ifdef DEBUG
145 printf(" tar_append_file(): encoding hard link \"%s\" "
146 "to \"%s\"...\n", realname, ti->ti_name);
147 #endif
148 t->th_buf.typeflag = LNKTYPE;
149 th_set_link(t, ti->ti_name);
151 else
152 #endif
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);
168 #if !defined(_WIN32) || defined(__CYGWIN__)
169 /* check if it's a symlink */
170 if (TH_ISSYM(t))
172 #if defined(_WIN32) && !defined(__CYGWIN__)
173 i = -1;
174 #else
175 i = readlink(realname, path, sizeof(path));
176 #endif
177 if (i == -1)
178 return -1;
179 if (i >= TAR_MAXPATHLEN)
180 i = TAR_MAXPATHLEN - 1;
181 path[i] = '\0';
182 #ifdef DEBUG
183 printf(" tar_append_file(): encoding symlink \"%s\" -> "
184 "\"%s\"...\n", realname, path);
185 #endif
186 th_set_link(t, path);
188 #endif
190 /* print file info */
191 if (t->options & TAR_VERBOSE)
192 th_print_long_ls(t);
194 #ifdef DEBUG
195 puts(" tar_append_file(): writing header");
196 #endif
197 /* write header */
198 if (th_write(t) != 0)
200 #ifdef DEBUG
201 printf("t->fd = %d\n", t->fd);
202 #endif
203 return -1;
205 #ifdef DEBUG
206 puts(" tar_append_file(): back from th_write()");
207 #endif
209 /* if it's a regular file, write the contents as well */
210 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
211 return -1;
213 return 0;
217 /* write EOF indicator */
219 tar_append_eof(TAR *t)
221 ssize_t i, j;
222 char block[T_BLOCKSIZE];
224 memset(&block, 0, T_BLOCKSIZE);
225 for (j = 0; j < 2; j++)
227 i = tar_block_write(t, &block);
228 if (i != T_BLOCKSIZE)
230 if (i != -1)
231 errno = EINVAL;
232 return -1;
236 return 0;
240 /* add file contents to a tarchive */
242 tar_append_regfile(TAR *t, char *realname)
244 char block[T_BLOCKSIZE];
245 int filefd;
246 ssize_t i, j;
247 size_t size;
249 #if defined( _WIN32 ) || defined(__CYGWIN__)
250 filefd = open(realname, O_RDONLY | O_BINARY);
251 #else
252 filefd = open(realname, O_RDONLY);
253 #endif
254 if (filefd == -1)
256 #ifdef DEBUG
257 perror("open()");
258 #endif
259 return -1;
262 size = th_get_size(t);
263 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
265 j = read(filefd, &block, T_BLOCKSIZE);
266 if (j != T_BLOCKSIZE)
268 if (j != -1)
270 fprintf(stderr, "Unexpected size of read data: %d <> %d for file: %s\n",
271 (int)j, T_BLOCKSIZE, realname);
272 errno = EINVAL;
274 return -1;
276 if (tar_block_write(t, &block) == -1)
277 return -1;
280 if (i > 0)
282 j = (size_t)read(filefd, &block, (unsigned int)i);
283 if (j == -1)
284 return -1;
285 memset(&(block[i]), 0, T_BLOCKSIZE - i);
286 if (tar_block_write(t, &block) == -1)
287 return -1;
290 close(filefd);
292 return 0;