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