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