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