xref: /plan9/sys/src/ape/cmd/pax/link.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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 
linkfrom(char * name,Stat * asb)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 
islink(char * name,Stat * asb)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 
linkto(char * name,Stat * asb)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 
linkleft(void)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