1 /* @(#)files.c 1.20 18/09/17 joerg */
2 #ifndef lint
3 static char sccsid[] =
4 "@(#)files.c 1.20 18/09/17 joerg";
5
6 #endif
7 /*
8 * File files.c - Handle ADD_FILES related stuff.
9 *
10 * Written by Eric Youngdale (1993).
11 *
12 * Copyright 1993 Yggdrasil Computing, Incorporated
13 * Copyright (c) 1999-2018 J. Schilling
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2, or (at your option)
18 * any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29
30 /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
31
32 #include <schily/mconfig.h>
33 #include "mkisofs.h"
34 #include <schily/errno.h>
35 #include <schily/schily.h>
36 #include <schily/ctype.h>
37
38 #ifdef ADD_FILES
39
40 void add_one_file __PR((char *addpath, char *path));
41 void add_file_list __PR((int argc, char **argv, int ind));
42 void add_file __PR((char *filename));
43 char *look_up_addition __PR((char **newpath, char *path,
44 struct dirent **de));
45 void nuke_duplicates __PR((char *path, struct dirent **de));
46 struct dirent *readdir_add_files __PR((char **pathp, char *path, DIR *dir));
47
48 struct file_adds {
49 char *name;
50 struct file_adds *child;
51 struct file_adds *next;
52 int add_count;
53 int used;
54 union diru {
55 /*
56 * XXX Struct dirent is not guaranteed to be any size on a POSIX
57 * XXX compliant system.
58 * XXX We need to allocate enough space here, to allow the hacky
59 * XXX code in tree.c made by Ross Biro biro@yggdrasil.com
60 * XXX to work on operating systems other than Linux :-(
61 * XXX Changes made by Joerg Schilling
62 * XXX joerg@schily.net
63 * XXX to prevent core dumps on Solaris.
64 * XXX Space allocated:
65 * XXX 1024 bytes == NAME_MAX
66 * XXX + 2 bytes for directory record length
67 * XXX + 2*8 bytes for inode number & offset (64 for future exp)
68 */
69 struct dirent de;
70 char dspace[NAME_MAX + 2 + 2 * 8];
71 } du;
72 struct {
73 char *path;
74 char *name;
75 } *adds;
76 };
77 extern struct file_adds *root_file_adds;
78
79 /*
80 * FIXME(eric) - the file adding code really doesn't work very well
81 * at all. We should differentiate between adding directories, and adding
82 * single files, as adding a full directory affects how we should be
83 * searching for things. Ideally what we should do is make two passes
84 * through the local filesystem - one to figure out what trees we need
85 * to scan (and merge in any additions at that point), and the second to
86 * actually fill out each structure with the appropriate contents.
87 */
88
89 struct file_adds *root_file_adds = NULL;
90
91 void
add_one_file(addpath,path)92 add_one_file(addpath, path)
93 char *addpath;
94 char *path;
95 {
96 char *cp;
97 char *name;
98 struct file_adds *f;
99 struct file_adds *tmp;
100
101 f = root_file_adds;
102 tmp = NULL;
103
104 name = strrchr(addpath, PATH_SEPARATOR);
105 if (name == NULL) {
106 name = addpath;
107 } else {
108 name++;
109 }
110
111 cp = strtok(addpath, SPATH_SEPARATOR);
112
113 while (cp != NULL && strcmp(name, cp)) {
114 if (f == NULL) {
115 root_file_adds = e_malloc(sizeof (*root_file_adds));
116 f = root_file_adds;
117 f->name = NULL;
118 f->child = NULL;
119 f->next = NULL;
120 f->add_count = 0;
121 f->adds = NULL;
122 f->used = 0;
123 }
124 if (f->child) {
125 for (tmp = f->child; tmp->next != NULL;
126 tmp = tmp->next) {
127 if (strcmp(tmp->name, cp) == 0) {
128 f = tmp;
129 goto next;
130 }
131 }
132 if (strcmp(tmp->name, cp) == 0) {
133 f = tmp;
134 goto next;
135 }
136 /* add a new node. */
137 tmp->next = e_malloc(sizeof (*tmp->next));
138 f = tmp->next;
139 f->name = e_strdup(cp);
140 f->child = NULL;
141 f->next = NULL;
142 f->add_count = 0;
143 f->adds = NULL;
144 f->used = 0;
145 } else {
146 /* no children. */
147 f->child = e_malloc(sizeof (*f->child));
148 f = f->child;
149 f->name = e_strdup(cp);
150 f->child = NULL;
151 f->next = NULL;
152 f->add_count = 0;
153 f->adds = NULL;
154 f->used = 0;
155
156 }
157 next:
158 cp = strtok(NULL, SPATH_SEPARATOR);
159 }
160 /* Now f if non-null points to where we should add things */
161 if (f == NULL) {
162 root_file_adds = e_malloc(sizeof (*root_file_adds));
163 f = root_file_adds;
164 f->name = NULL;
165 f->child = NULL;
166 f->next = NULL;
167 f->add_count = 0;
168 f->adds = NULL;
169 }
170 /* Now f really points to where we should add this name. */
171 f->add_count++;
172 f->adds = realloc(f->adds, sizeof (*f->adds) * f->add_count);
173 f->adds[f->add_count - 1].path = e_strdup(path);
174 f->adds[f->add_count - 1].name = e_strdup(name);
175 }
176
177 /*
178 * Function: add_file_list
179 *
180 * Purpose: Register an add-in file.
181 *
182 * Arguments:
183 */
184 void
add_file_list(argc,argv,ind)185 add_file_list(argc, argv, ind)
186 int argc;
187 char **argv;
188 int ind;
189 {
190 char *ptr;
191 char *dup_arg;
192
193 while (ind < argc) {
194 dup_arg = e_strdup(argv[ind]);
195 ptr = strchr(dup_arg, '=');
196 if (ptr == NULL) {
197 free(dup_arg);
198 return;
199 }
200 *ptr = 0;
201 ptr++;
202 add_one_file(dup_arg, ptr);
203 free(dup_arg);
204 ind++;
205 }
206 }
207
208 void
add_file(filename)209 add_file(filename)
210 char *filename;
211 {
212 char buff[PATH_MAX];
213 FILE *f;
214 char *ptr;
215 char *p2;
216 int count = 0;
217
218 if (strcmp(filename, "-") == 0) {
219 f = stdin;
220 } else {
221 f = fopen(filename, "r");
222 if (f == NULL) {
223 comerr(_("Cannot open '%s'.\n"), filename);
224 }
225 }
226 while (fgets(buff, sizeof (buff), f)) {
227 count++;
228 ptr = buff;
229 while (isspace(*ptr))
230 ptr++;
231 if (*ptr == 0)
232 continue;
233 if (*ptr == '#')
234 continue;
235
236 if (ptr[strlen(ptr) - 1] == '\n')
237 ptr[strlen(ptr) - 1] = 0;
238 p2 = strchr(ptr, '=');
239 if (p2 == NULL) {
240 comerrno(EX_BAD, _("Error in file '%s' line %d: %s\n"),
241 filename, count, buff);
242 }
243 *p2 = 0;
244 p2++;
245 add_one_file(ptr, p2);
246 }
247 if (f != stdin)
248 fclose(f);
249 }
250
251 /* This function looks up additions. */
252 char *
look_up_addition(newpath,path,de)253 look_up_addition(newpath, path, de)
254 char **newpath;
255 char *path;
256 struct dirent **de;
257 {
258 char *dup_path;
259 char *cp;
260 struct file_adds *f;
261 struct file_adds *tmp = NULL;
262
263 f = root_file_adds;
264 if (!f)
265 return (NULL);
266
267 /* I don't trust strtok */
268 dup_path = e_strdup(path);
269
270 cp = strtok(dup_path, SPATH_SEPARATOR);
271 while (cp != NULL) {
272 for (tmp = f->child; tmp != NULL; tmp = tmp->next) {
273 if (strcmp(tmp->name, cp) == 0)
274 break;
275 }
276 if (tmp == NULL) {
277 /* no match */
278 free(dup_path);
279 return (NULL);
280 }
281 f = tmp;
282 cp = strtok(NULL, SPATH_SEPARATOR);
283 }
284 free(dup_path);
285
286 /* If nothing, then return. */
287 if (tmp == NULL) {
288 /* no match */
289 return (NULL);
290 }
291 /* looks like we found something. */
292 if (tmp->used >= tmp->add_count)
293 return (NULL);
294
295 *newpath = tmp->adds[tmp->used].path;
296 tmp->used++;
297 *de = &(tmp->du.de);
298 return (tmp->adds[tmp->used - 1].name);
299
300 }
301
302 /* This function looks up additions. */
303 void
nuke_duplicates(path,de)304 nuke_duplicates(path, de)
305 char *path;
306 struct dirent **de;
307 {
308 char *dup_path;
309 char *cp;
310 struct file_adds *f;
311 struct file_adds *tmp;
312
313 f = root_file_adds;
314 if (!f)
315 return;
316
317 /* I don't trust strtok */
318 dup_path = e_strdup(path);
319
320 cp = strtok(dup_path, SPATH_SEPARATOR);
321 while (cp != NULL) {
322 for (tmp = f->child; tmp != NULL; tmp = tmp->next) {
323 if (strcmp(tmp->name, cp) == 0)
324 break;
325 }
326 if (tmp == NULL) {
327 /* no match */
328 free(dup_path);
329 return;
330 }
331 f = tmp;
332 cp = strtok(NULL, SPATH_SEPARATOR);
333 }
334 free(dup_path);
335
336 #if 0
337 /* looks like we found something. */
338 if (tmp->used >= tmp->add_count)
339 return;
340
341 *newpath = tmp->adds[tmp->used].path;
342 tmp->used++;
343 *de = &(tmp->du.de);
344 return (tmp->adds[tmp->used - 1].name);
345 #endif
346 }
347
348 /*
349 * This function lets us add files from outside the standard file tree.
350 * It is useful if we want to duplicate a cd, but add/replace things.
351 * We should note that the real path will be used for exclusions.
352 */
353
354 struct dirent *
readdir_add_files(pathp,path,dir)355 readdir_add_files(pathp, path, dir)
356 char **pathp;
357 char *path;
358 DIR *dir;
359 {
360 struct dirent *de;
361
362 char *addpath;
363 char *name;
364
365 de = readdir(dir);
366 if (de) {
367 nuke_duplicates(path, &de);
368 return (de);
369 }
370 name = look_up_addition(&addpath, path, &de);
371
372 if (!name) {
373 return (NULL);
374 }
375 *pathp = addpath;
376
377 /*
378 * Now we must create the directory entry.
379 * fortuneately only the name seems to matter.
380 */
381 /* de->d_ino = -1; de->d_off = 0; de->d_reclen = strlen (name); */
382 strncpy(de->d_name, name, NAME_MAX);
383 de->d_name[NAME_MAX] = 0;
384 nuke_duplicates(path, &de);
385 return (de);
386
387 }
388
389 #else
390 struct dirent *
readdir_add_files(pathp,path,dir)391 readdir_add_files(pathp, path, dir)
392 char **pathp;
393 char *path;
394 DIR *dir;
395 {
396 return (readdir(dir));
397 }
398
399 #endif
400