1 /* $Source: /u/mark/src/pax/RCS/link.c,v $ 2 * 3 * $Revision: 1.2 $ 4 * 5 * link.c - functions for handling multiple file links 6 * 7 * DESCRIPTION 8 * 9 * These function manage the link chains which are used to keep track 10 * of outstanding links during archive reading and writing. 11 * 12 * AUTHOR 13 * 14 * Mark H. Colburn, NAPS International (mark@jhereg.mn.org) 15 * 16 * Sponsored by The USENIX Association for public distribution. 17 * 18 * Copyright (c) 1989 Mark H. Colburn. 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms are permitted 22 * provided that the above copyright notice is duplicated in all such 23 * forms and that any documentation, advertising materials, and other 24 * materials related to such distribution and use acknowledge that the 25 * software was developed * by Mark H. Colburn and sponsored by The 26 * USENIX Association. 27 * 28 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 29 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 31 * 32 * $Log: link.c,v $ 33 * Revision 1.2 89/02/12 10:04:38 mark 34 * 1.2 release fixes 35 * 36 * Revision 1.1 88/12/23 18:02:12 mark 37 * Initial revision 38 * 39 */ 40 41 #ifndef lint 42 static char *ident = "$Id: link.c,v 1.2 89/02/12 10:04:38 mark Exp $"; 43 static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n"; 44 #endif /* ! lint */ 45 46 47 /* Headers */ 48 49 #include "pax.h" 50 51 52 /* Defines */ 53 54 /* 55 * Address link information base. 56 */ 57 #define LINKHASH(ino) (linkbase + (ino) % NEL(linkbase)) 58 59 /* 60 * Number of array elements. 61 */ 62 #define NEL(a) (sizeof(a) / sizeof(*(a))) 63 64 65 66 /* Internal Identifiers */ 67 68 static Link *linkbase[256]; /* Unresolved link information */ 69 70 71 /* linkfrom - find a file to link from 72 * 73 * DESCRIPTION 74 * 75 * Linkfrom searches the link chain to see if there is a file in the 76 * link chain which has the same inode number as the file specified 77 * by the stat block pointed at by asb. If a file is found, the 78 * name is returned to the caller, otherwise a NULL is returned. 79 * 80 * PARAMETERS 81 * 82 * char *name - name of the file which we are attempting 83 * to find a link for 84 * Stat *asb - stat structure of file to find a link to 85 * 86 * RETURNS 87 * 88 * Returns a pointer to a link structure, or NULL if unsuccessful. 89 * 90 */ 91 92 #ifdef __STDC__ 93 94 Link *linkfrom(char *name, Stat *asb) 95 96 #else 97 98 Link *linkfrom(name, asb) 99 char *name; 100 Stat *asb; 101 102 #endif 103 { 104 Link *linkp; 105 Link *linknext; 106 Path *path; 107 Path *pathnext; 108 Link **abase; 109 110 for (linkp = *(abase = LINKHASH(asb->sb_ino)); linkp; linkp = linknext) { 111 if (linkp->l_nlink == 0) { 112 if (linkp->l_name) { 113 free((char *) linkp->l_name); 114 } 115 if (linknext = linkp->l_forw) { 116 linknext->l_back = linkp->l_back; 117 } 118 if (linkp->l_back) { 119 linkp->l_back->l_forw = linkp->l_forw; 120 } 121 free((char *) linkp); 122 *abase = (Link *)NULL; 123 } else if (linkp->l_ino == asb->sb_ino && linkp->l_dev == asb->sb_dev) { 124 /* 125 * check to see if a file with the name "name" exists in the 126 * chain of files which we have for this particular link 127 */ 128 for (path = linkp->l_path; path; path = pathnext) { 129 if (strcmp(path->p_name, name) == 0) { 130 --linkp->l_nlink; 131 if (path->p_name) { 132 free(path->p_name); 133 } 134 if (pathnext = path->p_forw) { 135 pathnext->p_back = path->p_back; 136 } 137 if (path->p_back) { 138 path->p_back->p_forw = pathnext; 139 } 140 if (linkp->l_path == path) { 141 linkp->l_path = pathnext; 142 } 143 free(path); 144 return (linkp); 145 } 146 pathnext = path->p_forw; 147 } 148 return((Link *)NULL); 149 } else { 150 linknext = linkp->l_forw; 151 } 152 } 153 return ((Link *)NULL); 154 } 155 156 157 158 /* islink - determine whether a given file really a link 159 * 160 * DESCRIPTION 161 * 162 * Islink searches the link chain to see if there is a file in the 163 * link chain which has the same inode number as the file specified 164 * by the stat block pointed at by asb. If a file is found, a 165 * non-zero value is returned to the caller, otherwise a 0 is 166 * returned. 167 * 168 * PARAMETERS 169 * 170 * char *name - name of file to check to see if it is link. 171 * Stat *asb - stat structure of file to find a link to 172 * 173 * RETURNS 174 * 175 * Returns a pointer to a link structure, or NULL if unsuccessful. 176 * 177 */ 178 179 #ifdef __STDC__ 180 181 Link *islink(char *name, Stat *asb) 182 183 #else 184 185 Link *islink(name, asb) 186 char *name; 187 Stat *asb; 188 189 #endif 190 { 191 Link *linkp; 192 Link *linknext; 193 194 for (linkp = *(LINKHASH(asb->sb_ino)); linkp; linkp = linknext) { 195 if (linkp->l_ino == asb->sb_ino && linkp->l_dev == asb->sb_dev) { 196 if (strcmp(name, linkp->l_name) == 0) { 197 return ((Link *)NULL); 198 } 199 return (linkp); 200 } else { 201 linknext = linkp->l_forw; 202 } 203 } 204 return ((Link *)NULL); 205 } 206 207 208 /* linkto - remember a file with outstanding links 209 * 210 * DESCRIPTION 211 * 212 * Linkto adds the specified file to the link chain. Any subsequent 213 * calls to linkfrom which have the same inode will match the file 214 * just entered. If not enough space is available to make the link 215 * then the item is not added to the link chain, and a NULL is 216 * returned to the calling function. 217 * 218 * PARAMETERS 219 * 220 * char *name - name of file to remember 221 * Stat *asb - pointer to stat structure of file to remember 222 * 223 * RETURNS 224 * 225 * Returns a pointer to the associated link structure, or NULL when 226 * linking is not possible. 227 * 228 */ 229 230 #ifdef __STDC__ 231 232 Link *linkto(char *name, Stat *asb) 233 234 #else 235 236 Link *linkto(name, asb) 237 char *name; 238 Stat *asb; 239 240 #endif 241 { 242 Link *linkp; 243 Link *linknext; 244 Path *path; 245 Link **abase; 246 247 for (linkp = *(LINKHASH(asb->sb_ino)); linkp; linkp = linknext) { 248 if (linkp->l_ino == asb->sb_ino && linkp->l_dev == asb->sb_dev) { 249 if ((path = (Path *) mem_get(sizeof(Path))) == (Path *)NULL || 250 (path->p_name = mem_str(name)) == (char *)NULL) { 251 return((Link *)NULL); 252 } 253 if (path->p_forw = linkp->l_path) { 254 if (linkp->l_path->p_forw) { 255 linkp->l_path->p_forw->p_back = path; 256 } 257 } else { 258 linkp->l_path = path; 259 } 260 path->p_back = (Path *)NULL; 261 return(linkp); 262 } else { 263 linknext = linkp->l_forw; 264 } 265 } 266 /* 267 * This is a brand new link, for which there is no other information 268 */ 269 270 if ((asb->sb_mode & S_IFMT) == S_IFDIR 271 || (linkp = (Link *) mem_get(sizeof(Link))) == (Link *)NULL 272 || (linkp->l_name = mem_str(name)) == (char *)NULL) { 273 return ((Link *)NULL); 274 } 275 linkp->l_dev = asb->sb_dev; 276 linkp->l_ino = asb->sb_ino; 277 linkp->l_nlink = asb->sb_nlink - 1; 278 linkp->l_size = asb->sb_size; 279 linkp->l_path = (Path *)NULL; 280 if (linkp->l_forw = *(abase = LINKHASH(asb->sb_ino))) { 281 linkp->l_forw->l_back = linkp; 282 } else { 283 *abase = linkp; 284 } 285 linkp->l_back = (Link *)NULL; 286 return (linkp); 287 } 288 289 290 /* linkleft - complain about files with unseen links 291 * 292 * DESCRIPTION 293 * 294 * Linksleft scans through the link chain to see if there were any 295 * files which have outstanding links that were not processed by the 296 * archive. For each file in the link chain for which there was not 297 * a file, and error message is printed. 298 */ 299 300 #ifdef __STDC__ 301 302 void linkleft(void) 303 304 #else 305 306 void linkleft() 307 308 #endif 309 { 310 Link *lp; 311 Link **base; 312 313 for (base = linkbase; base < linkbase + NEL(linkbase); ++base) { 314 for (lp = *base; lp; lp = lp->l_forw) { 315 if (lp->l_nlink) { 316 warn(lp->l_path->p_name, "Unseen link(s)"); 317 } 318 } 319 } 320 } 321