1 /* @(#)append.c	1.33 18/06/21 Copyright 1992, 2001-2018 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)append.c	1.33 18/06/21 Copyright 1992, 2001-2018 J. Schilling";
6 #endif
7 /*
8  *	Routines used to append files to an existing
9  *	tape archive
10  *
11  *	Copyright (c) 1992, 2001-2018 J. Schilling
12  */
13 /*
14  * The contents of this file are subject to the terms of the
15  * Common Development and Distribution License, Version 1.0 only
16  * (the "License").  You may not use this file except in compliance
17  * with the License.
18  *
19  * See the file CDDL.Schily.txt in this distribution for details.
20  * A copy of the CDDL is also available via the Internet at
21  * http://www.opensource.org/licenses/cddl1.txt
22  *
23  * When distributing Covered Code, include this CDDL HEADER in each
24  * file and include the License file CDDL.Schily.txt from this distribution.
25  */
26 
27 #include <schily/stdio.h>
28 #include <schily/unistd.h>
29 #include <schily/standard.h>
30 #include "star.h"
31 #define	GT_COMERR		/* #define comerr gtcomerr */
32 #define	GT_ERROR		/* #define error gterror   */
33 #include <schily/schily.h>
34 #include "starsubs.h"
35 
36 extern	FILE	*vpr;
37 
38 extern	BOOL	debug;
39 extern	BOOL	cflag;
40 extern	BOOL	uflag;
41 extern	BOOL	rflag;
42 
43 /*
44  * XXX We should try to share the hash code with lhash.c
45  */
46 static struct h_elem {
47 	struct h_elem *h_next;
48 	time_t		h_time;
49 	long		h_nsec;
50 	short		h_len;
51 	char		h_flags;
52 	char		h_data[1];			/* Variable size. */
53 } **h_tab;
54 
55 #define	HF_NSEC		0x01				/* have nsecs	*/
56 
57 static	unsigned	h_size;
58 LOCAL	int		cachesize;
59 
60 EXPORT	void	skipall		__PR((void));
61 LOCAL	void	hash_new	__PR((size_t size));
62 LOCAL	struct h_elem *uhash_lookup	__PR((FINFO *info));
63 LOCAL	void	hash_add	__PR((FINFO *info));
64 EXPORT	BOOL	update_newer	__PR((FINFO *info));
65 LOCAL	int	hashval		__PR((Uchar *str, Uint maxsize));
66 
67 EXPORT void
68 skipall()
69 {
70 		FINFO	finfo;
71 		TCB	tb;
72 	register TCB 	*ptb = &tb;
73 
74 	if (uflag)
75 		hash_new(100);
76 
77 	fillbytes((char *)&finfo, sizeof (finfo), '\0');
78 
79 	if (init_pspace(PS_STDERR, &finfo.f_pname) < 0)
80 		return;
81 	if (init_pspace(PS_STDERR, &finfo.f_plname) < 0)
82 		return;
83 
84 	finfo.f_tcb = ptb;
85 	for (;;) {
86 		if (get_tcb(ptb) == EOF)
87 			break;
88 
89 		finfo.f_name = finfo.f_pname.ps_path;
90 		finfo.f_lname = finfo.f_plname.ps_path;
91 		if (tcb_to_info(ptb, &finfo) == EOF)
92 			break;
93 
94 		if (debug)
95 			fprintf(vpr, "R %s\n", finfo.f_name);
96 		if (uflag)
97 			hash_add(&finfo);
98 
99 		void_file(&finfo);
100 	}
101 	if (debug)
102 		error("used %d bytes for update cache.\n", cachesize);
103 }
104 
105 #include <schily/string.h>
106 
107 LOCAL void
108 hash_new(size)
109 	size_t	size;
110 {
111 	register	int	i;
112 
113 	h_size = size;
114 	h_tab = (struct h_elem **)___malloc(size * sizeof (struct h_elem *), "new hash");
115 	for (i = 0; i < size; i++) h_tab[i] = 0;
116 
117 	cachesize += size * sizeof (struct h_elem *);
118 }
119 
120 LOCAL struct h_elem *
121 uhash_lookup(info)
122 	FINFO	*info;
123 {
124 	register char		*name = info->f_name;
125 	register struct h_elem *hp;
126 	register int		hv;
127 		BOOL		slash = FALSE;
128 
129 	if (info->f_namelen == 0)
130 		info->f_namelen = strlen(info->f_name);
131 
132 	if (is_dir(info) && info->f_name[info->f_namelen-1] == '/') {
133 		info->f_name[--info->f_namelen] = '\0';
134 		slash = TRUE;
135 	}
136 
137 	hv = hashval((unsigned char *)name, h_size);
138 	for (hp = h_tab[hv]; hp; hp = hp->h_next) {
139 		if (info->f_namelen == hp->h_len && *name == *hp->h_data) {
140 			if (streql(name, hp->h_data)) {
141 				if (slash)
142 					info->f_name[info->f_namelen++] = '/';
143 				return (hp);
144 			}
145 		}
146 	}
147 	if (slash)
148 		info->f_name[info->f_namelen++] = '/';
149 	return (0);
150 }
151 
152 LOCAL void
153 hash_add(info)
154 	FINFO	*info;
155 {
156 	register	int	len;
157 	register struct h_elem	*hp;
158 	register	int	hv;
159 			BOOL	slash = FALSE;
160 
161 	if (info->f_namelen == 0)
162 		info->f_namelen = strlen(info->f_name);
163 
164 	if (is_dir(info) && info->f_name[info->f_namelen-1] == '/') {
165 		info->f_name[--info->f_namelen] = '\0';
166 		slash = TRUE;
167 	}
168 	if ((hp = uhash_lookup(info)) != 0) {
169 		if (hp->h_time < info->f_mtime) {
170 			hp->h_time = info->f_mtime;
171 			hp->h_nsec = info->f_mnsec;
172 		} else if (hp->h_time == info->f_mtime) {
173 			/*
174 			 * If the current archive entry holds extended
175 			 * time imformation, honor it.
176 			 * Since this function is only called with data from
177 			 * the archive, it is sufficient to check the XF_MTIME
178 			 * flag.
179 			 */
180 			if (info->f_xflags & XF_MTIME)
181 				hp->h_flags |= HF_NSEC;
182 			else
183 				hp->h_flags &= ~HF_NSEC;
184 
185 			if ((hp->h_flags & HF_NSEC) &&
186 			    (hp->h_nsec < info->f_mnsec))
187 				hp->h_nsec = info->f_mnsec;
188 		}
189 		if (slash)
190 			info->f_name[info->f_namelen++] = '/';
191 		return;
192 	}
193 
194 	len = info->f_namelen;
195 	hp = ___malloc((size_t)len + sizeof (struct h_elem), "add hash");
196 	cachesize += len + sizeof (struct h_elem);
197 	strcpy(hp->h_data, info->f_name);
198 	hp->h_time = info->f_mtime;
199 	hp->h_nsec = info->f_mnsec;
200 	hp->h_len = len;
201 	hp->h_flags = 0;
202 	if (info->f_xflags & XF_MTIME)
203 		hp->h_flags |= HF_NSEC;
204 	hv = hashval((unsigned char *)info->f_name, h_size);
205 	hp->h_next = h_tab[hv];
206 	h_tab[hv] = hp;
207 	if (slash)
208 		info->f_name[info->f_namelen++] = '/';
209 }
210 
211 EXPORT BOOL
212 update_newer(info)
213 	FINFO	*info;
214 {
215 	register struct h_elem *hp;
216 
217 	/*
218 	 * Since this function is only called with FINFO data from the
219 	 * filesystem, it is sufficient to check F_NSECS.
220 	 */
221 	if ((hp = uhash_lookup(info)) != 0) {
222 		if (info->f_mtime > hp->h_time)
223 			return (TRUE);
224 		if ((hp->h_flags & HF_NSEC) && (info->f_flags & F_NSECS) &&
225 		    info->f_mtime == hp->h_time && info->f_mnsec > hp->h_nsec)
226 			return (TRUE);
227 		return (FALSE);
228 	}
229 	return (TRUE);
230 }
231 
232 LOCAL int
233 hashval(str, maxsize)
234 	register Uchar *str;
235 		Uint	maxsize;
236 {
237 	register int	sum = 0;
238 	register int	i;
239 	register int	c;
240 
241 	for (i = 0; (c = *str++) != '\0'; i++)
242 		sum ^= (c << (i&7));
243 	return (sum % maxsize);
244 }
245