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