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