1 /* @(#)tree.c	1.143 20/07/23 joerg */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)tree.c	1.143 20/07/23 joerg";
6 #endif
7 /*
8  * File tree.c - scan directory  tree and build memory structures for iso9660
9  * filesystem
10  *
11  * Written by Eric Youngdale (1993).
12  *
13  * Copyright 1993 Yggdrasil Computing, Incorporated
14  * Copyright (c) 1999,2000-2020 J. Schilling
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2, or (at your option)
19  * any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  */
30 /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
31 
32 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
33 
34 /* DUPLICATES_ONCE Alex Kopylov cdrtools@bootcd.ru 19.06.2004 */
35 
36 #include "mkisofs.h"
37 #include "rock.h"
38 #include "match.h"
39 #include <schily/time.h>
40 #include <schily/errno.h>
41 #include <schily/fcntl.h>
42 #include <schily/device.h>
43 #include <schily/schily.h>
44 
45 #ifdef UDF
46 #include "udf.h"
47 #endif
48 
49 #ifdef VMS
50 #include <sys/file.h>
51 #include <vms/fabdef.h>
52 #include "vms.h"
53 #endif
54 
55 LOCAL	Uchar	symlink_buff[PATH_MAX+1];
56 
57 LOCAL	char	*filetype		__PR((int t));
58 LOCAL	char	*rstr			__PR((char *s1, char *s2));
59 LOCAL	void	stat_fix		__PR((struct stat *st));
60 EXPORT	int	stat_filter		__PR((char *path, struct stat *st));
61 EXPORT	int	lstat_filter		__PR((char *path, struct stat *st));
62 LOCAL	int	sort_n_finish		__PR((struct directory *this_dir));
63 LOCAL	void	generate_reloc_directory __PR((void));
64 EXPORT	void	attach_dot_entries	__PR((struct directory *dirnode,
65 						struct stat *this_stat,
66 						struct stat *parent_stat));
67 EXPORT	char	*find_rr_attribute	__PR((unsigned char *pnt, int len,
68 						char *attr_type));
69 EXPORT	void	finish_cl_pl_entries	__PR((void));
70 LOCAL	void	dir_nesting_warn	__PR((struct directory *this_dir,
71 						char *path, int contflag));
72 EXPORT	int	scan_directory_tree	__PR((struct directory *this_dir,
73 						char *path,
74 						struct directory_entry *de));
75 LOCAL	struct directory_entry *
76 		dup_relocated_dir	__PR((struct directory *this_dir,
77 					    struct directory_entry *s_entry,
78 					    char *whole_path,
79 					    char *short_name,
80 					    struct stat *statp));
81 EXPORT	int	insert_file_entry	__PR((struct directory *this_dir,
82 						char *whole_path,
83 						char *short_name,
84 						struct stat *statp, int have_rsrc));
85 EXPORT	struct directory_entry *
86 		dup_directory_entry	__PR((struct directory_entry *s_entry));
87 EXPORT	void	generate_iso9660_directories __PR((struct directory *node,
88 						FILE *outfile));
89 
90 LOCAL	void	set_de_path		__PR((struct directory *parent,
91 						struct directory *this));
92 
93 EXPORT	struct directory *
94 		find_or_create_directory __PR((struct directory *parent,
95 						char *path,
96 						struct directory_entry *de,
97 						int flag));
98 LOCAL	void	delete_directory	__PR((struct directory *parent,
99 						struct directory *child));
100 EXPORT	int	sort_tree		__PR((struct directory *node));
101 EXPORT	void	dump_tree		__PR((struct directory *node));
102 EXPORT	struct directory_entry *
103 		search_tree_file	__PR((struct directory *node,
104 						char *filename));
105 EXPORT	void	init_fstatbuf		__PR((void));
106 
107 extern int	verbose;
108 struct stat	fstatbuf;		/* We use this for the artificial */
109 					/* entries we create		  */
110 struct stat	root_statbuf;		/* Stat buffer for root directory */
111 struct directory *reloc_dir;
112 
113 LOCAL char *
filetype(t)114 filetype(t)
115 	int	t;
116 {
117 	static	char	unkn[32];
118 
119 	if (S_ISFIFO(t))		/* 1 */
120 		return ("fifo");
121 	if (S_ISCHR(t))			/* 2 */
122 		return ("chr");
123 	if (S_ISMPC(t))			/* 3 */
124 		return ("multiplexed chr");
125 	if (S_ISDIR(t))			/* 4 */
126 		return ("dir");
127 	if (S_ISNAM(t))			/* 5 */
128 		return ("named file");
129 	if (S_ISBLK(t))			/* 6 */
130 		return ("blk");
131 	if (S_ISMPB(t))			/* 7 */
132 		return ("multiplexed blk");
133 	if (S_ISREG(t))			/* 8 */
134 		return ("regular file");
135 	if (S_ISCTG(t))			/* 9 */
136 		return ("contiguous file");
137 	if (S_ISLNK(t))			/* 10 */
138 		return ("symlink");
139 	if (S_ISSHAD(t))		/* 11 */
140 		return ("Solaris shadow inode");
141 	if (S_ISSOCK(t))		/* 12 */
142 		return ("socket");
143 	if (S_ISDOOR(t))		/* 13 */
144 		return ("door");
145 	if (S_ISWHT(t))			/* 14 */
146 		return ("whiteout");
147 	if (S_ISEVC(t))			/* 15 */
148 		return ("event count");
149 
150 	/*
151 	 * Needs to be last in case somebody makes this
152 	 * a supported file type.
153 	 */
154 	if ((t & S_IFMT) == 0)		/* 0 (unallocated) */
155 		return ("unallocated");
156 
157 	sprintf(unkn, "octal '%o'", t & S_IFMT);
158 	return (unkn);
159 }
160 
161 /*
162  * Check if s1 ends in strings s2
163  */
164 LOCAL char *
rstr(s1,s2)165 rstr(s1, s2)
166 	char	*s1;
167 	char	*s2;
168 {
169 	int	l1;
170 	int	l2;
171 
172 	l1 = strlen(s1);
173 	l2 = strlen(s2);
174 	if (l2 > l1)
175 		return ((char *)NULL);
176 
177 	if (strcmp(&s1[l1 - l2], s2) == 0)
178 		return (&s1[l1 - l2]);
179 	return ((char *)NULL);
180 }
181 
182 LOCAL void
stat_fix(st)183 stat_fix(st)
184 	struct stat	*st;
185 {
186 	int adjust_modes = 0;
187 
188 	if (S_ISREG(st->st_mode))
189 		adjust_modes = rationalize_filemode;
190 	else if (S_ISDIR(st->st_mode))
191 		adjust_modes = rationalize_dirmode;
192 	else
193 		adjust_modes = (rationalize_filemode || rationalize_dirmode);
194 
195 	/*
196 	 * If rationalizing, override the uid and gid, since the
197 	 * originals will only be useful on the author's system.
198 	 */
199 	if (rationalize_uid)
200 		st->st_uid = uid_to_use;
201 	if (rationalize_gid)
202 		st->st_gid = gid_to_use;
203 
204 	if (adjust_modes) {
205 
206 		if (S_ISREG(st->st_mode) && (filemode_to_use != 0)) {
207 			st->st_mode = filemode_to_use | S_IFREG;
208 		} else if (S_ISDIR(st->st_mode) && (dirmode_to_use != 0)) {
209 			st->st_mode = dirmode_to_use | S_IFDIR;
210 		} else {
211 			/*
212 			 * Make sure the file modes make sense.  Turn
213 			 * on all read bits.  Turn on all exec/search
214 			 * bits if any exec/search bit is set.  Turn
215 			 * off all write bits, and all special mode
216 			 * bits (on a r/o fs lock bits are useless,
217 			 * and with uid+gid 0 don't want set-id bits,
218 			 * either).
219 			 */
220 
221 			st->st_mode |= 0444;
222 #if !defined(_WIN32) && !defined(__DJGPP__)	/* make all file "executable" */
223 			if (st->st_mode & 0111)
224 #endif
225 				st->st_mode |= 0111;
226 			st->st_mode &= ~07222;
227 		}
228 	}
229 }
230 
231 EXPORT int
stat_filter(path,st)232 stat_filter(path, st)
233 	char		*path;
234 	struct stat	*st;
235 {
236 	int	result = stat(path, st);
237 
238 	if (result < 0)
239 		return (result);
240 
241 	if (rationalize)
242 		stat_fix(st);
243 
244 	if (noatime) {
245 		int	nsecs = stat_mnsecs(st);
246 
247 		st->st_atime = st->st_mtime;
248 		stat_set_ansecs(st, nsecs);
249 	}
250 	return (result);
251 }
252 
253 EXPORT int
lstat_filter(path,st)254 lstat_filter(path, st)
255 	char		*path;
256 	struct stat	*st;
257 {
258 	int	result = lstat(path, st);
259 
260 	if (result < 0)
261 		return (result);
262 
263 	if (rationalize)
264 		stat_fix(st);
265 
266 	if (noatime) {
267 		int	nsecs = stat_mnsecs(st);
268 
269 		st->st_atime = st->st_mtime;
270 		stat_set_ansecs(st, nsecs);
271 	}
272 
273 	return (result);
274 }
275 
276 LOCAL int
sort_n_finish(this_dir)277 sort_n_finish(this_dir)
278 	struct directory	*this_dir;
279 {
280 	struct directory_entry *s_entry;
281 	struct directory_entry *s_entry1;
282 	struct directory_entry *table;
283 	int		count;
284 	int		d1;
285 	int		d2;
286 	int		d3;
287 	register int	new_reclen;
288 	char		*c;
289 	int		status = 0;
290 	int		tablesize = 0;
291 	char		newname[MAX_ISONAME+1];
292 	char		rootname[MAX_ISONAME+1];
293 	char		extname[MAX_ISONAME+1];
294 
295 	/*
296 	 * Here we can take the opportunity to toss duplicate entries from the
297 	 * directory.
298 	 */
299 	/* ignore if it's hidden */
300 	if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
301 		return (0);
302 	}
303 	table = NULL;
304 
305 	init_fstatbuf();
306 
307 	/*
308 	 * If we had artificially created this directory, then we might be
309 	 * missing the required '.' entries.  Create these now if we need
310 	 * them.
311 	 */
312 	if ((this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) !=
313 		(DIR_HAS_DOT | DIR_HAS_DOTDOT)) {
314 		attach_dot_entries(this_dir, NULL, NULL);
315 	}
316 	flush_file_hash();
317 	s_entry = this_dir->contents;
318 	while (s_entry) {
319 #ifdef	USE_LARGEFILES
320 		/*
321 		 * Skip all but the last extent from a multi extent file,
322 		 * we like them all have the same name.
323 		 */
324 		if ((s_entry->de_flags & MULTI_EXTENT) &&
325 		    (s_entry->isorec.flags[0] & ISO_MULTIEXTENT)) {
326 			s_entry = s_entry->next;
327 			continue;
328 		}
329 #endif
330 		/* ignore if it's hidden */
331 		if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
332 			s_entry = s_entry->next;
333 			continue;
334 		}
335 		/*
336 		 * First assume no conflict, and handle this case
337 		 */
338 		if (!(s_entry1 = find_file_hash(s_entry->isorec.name))) {
339 			add_file_hash(s_entry);
340 			s_entry = s_entry->next;
341 			continue;
342 		}
343 #ifdef APPLE_HYB
344 		/*
345 		 * if the pair are associated, then skip (as they have the
346 		 * same name!)
347 		 */
348 		if (apple_both && s_entry1->assoc &&
349 						s_entry1->assoc == s_entry) {
350 			s_entry = s_entry->next;
351 			continue;
352 		}
353 #endif	/* APPLE_HYB */
354 
355 		if (s_entry1 == s_entry) {
356 			comerrno(EX_BAD,
357 			_("Fatal goof, file '%s' already in hash table.\n"),
358 			s_entry->isorec.name);
359 		}
360 		/*
361 		 * OK, handle the conflicts.  Try substitute names until we
362 		 * come up with a winner
363 		 */
364 		strlcpy(rootname, s_entry->isorec.name, sizeof (rootname));
365 		/*
366 		 * Strip off the non-significant part of the name so that we
367 		 * are left with a sensible root filename.  If we don't find
368 		 * a '.', then try a ';'.
369 		 */
370 		c = strchr(rootname, '.');
371 		/*
372 		 * In case we ever allow more than on dot, only modify the
373 		 * section past the last dot if the file name starts with a
374 		 * dot.
375 		 */
376 		if (c != NULL && c == rootname && c != strrchr(rootname, '.')) {
377 			c = strrchr(rootname, '.');
378 		}
379 		extname[0] = '\0';		/* In case we have no ext.  */
380 		if (c) {
381 			strlcpy(extname, c, sizeof (extname));
382 			*c = 0;			/* Cut off complete ext.    */
383 		} else {
384 			/*
385 			 * Could not find any '.'.
386 			 */
387 			c = strchr(rootname, ';');
388 			if (c) {
389 				*c = 0;		/* Cut off version number    */
390 			}
391 		}
392 		c = strchr(extname, ';');
393 		if (c) {
394 			*c = 0;			/* Cut off version number    */
395 		}
396 		d1 = strlen(rootname);
397 		if (full_iso9660_filenames || iso9660_level > 1) {
398 			d2 = strlen(extname);
399 			/*
400 			 * 31/37 chars minus the 3 characters we are
401 			 * appending below to create unique filenames.
402 			 */
403 			if ((d1 + d2) > (iso9660_namelen - 3))
404 				rootname[iso9660_namelen - 3 - d2] = 0;
405 		} else {
406 			if (d1 > 5)
407 				rootname[5] = 0;
408 		}
409 		new_reclen = strlen(rootname);
410 		sprintf(newname, "%s000%s%s",
411 				rootname,
412 				extname,
413 				((s_entry->isorec.flags[0] & ISO_DIRECTORY) ||
414 				omit_version_number ? "" : ";1"));
415 
416 		for (d1 = 0; d1 < 36; d1++) {
417 			for (d2 = 0; d2 < 36; d2++) {
418 				for (d3 = 0; d3 < 36; d3++) {
419 					newname[new_reclen + 0] =
420 					    (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10);
421 					newname[new_reclen + 1] =
422 					    (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10);
423 					newname[new_reclen + 2] =
424 					    (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10);
425 					if (debug)
426 						error(_("NEW name '%s'\n"), newname);
427 
428 #ifdef VMS
429 					/* Sigh.  VAXCRTL seems to be broken here */
430 					{
431 						int	ijk = 0;
432 
433 						while (newname[ijk]) {
434 							if (newname[ijk] == ' ')
435 								newname[ijk] = '0';
436 							ijk++;
437 						}
438 					}
439 #endif
440 
441 					if (!find_file_hash(newname))
442 						goto got_valid_name;
443 				}
444 			}
445 		}
446 
447 		/*
448 		 * If we fell off the bottom here, we were in real trouble.
449 		 */
450 		comerrno(EX_BAD,
451 			_("Unable to generate unique name for file %s\n"),
452 			s_entry->name);
453 
454 got_valid_name:
455 		/*
456 		 * OK, now we have a good replacement name.  Now decide which
457 		 * one of these two beasts should get the name changed
458 		 */
459 		if (s_entry->priority < s_entry1->priority) {
460 			if (verbose > 0) {
461 				fprintf(stderr, _("Using %s for  %s%s%s (%s)\n"),
462 					newname,
463 					this_dir->whole_name, SPATH_SEPARATOR,
464 					s_entry->name, s_entry1->name);
465 			}
466 
467 			s_entry->isorec.name_len[0] = strlen(newname);
468 			new_reclen = offsetof(struct iso_directory_record,
469 				name[0]) +
470 				strlen(newname);
471 			if (use_XA || use_RockRidge) {
472 				if (new_reclen & 1)
473 					new_reclen++; /* Pad to an even byte */
474 				new_reclen += s_entry->rr_attr_size;
475 			}
476 			if (new_reclen & 1)
477 				new_reclen++;	/* Pad to an even byte */
478 			s_entry->isorec.length[0] = new_reclen;
479 			strcpy(s_entry->isorec.name, newname);
480 #ifdef	USE_LARGEFILES
481 			if (s_entry->de_flags & MULTI_EXTENT) {
482 				struct directory_entry	*s_e;
483 
484 				/*
485 				 * Copy over the new name to all other entries
486 				 */
487 				for (s_e = s_entry->mxroot;
488 				    s_e && s_e->mxroot == s_entry->mxroot;
489 							s_e = s_e->next) {
490 					s_e->isorec.length[0] = new_reclen;
491 					s_e->isorec.name_len[0] = s_entry->isorec.name_len[0];
492 					strcpy(s_e->isorec.name, newname);
493 				}
494 			}
495 #endif
496 #ifdef APPLE_HYB
497 			/*
498 			 * Has resource fork - needs new name
499 			 */
500 			if (apple_both && s_entry->assoc) {
501 				struct directory_entry *s_entry2 =
502 								s_entry->assoc;
503 
504 				/*
505 				 * resource fork name *should* be the same as
506 				 * the data fork
507 				 */
508 				s_entry2->isorec.name_len[0] =
509 						s_entry->isorec.name_len[0];
510 				strcpy(s_entry2->isorec.name,
511 						s_entry->isorec.name);
512 				s_entry2->isorec.length[0] = new_reclen;
513 			}
514 #endif	/* APPLE_HYB */
515 		} else {
516 			delete_file_hash(s_entry1);
517 			if (verbose > 0) {
518 				fprintf(stderr, _("Using %s for  %s%s%s (%s)\n"),
519 					newname,
520 					this_dir->whole_name, SPATH_SEPARATOR,
521 					s_entry1->name, s_entry->name);
522 			}
523 			s_entry1->isorec.name_len[0] = strlen(newname);
524 			new_reclen = offsetof(struct iso_directory_record,
525 					name[0]) +
526 					strlen(newname);
527 			if (use_XA || use_RockRidge) {
528 				if (new_reclen & 1)
529 					new_reclen++; /* Pad to an even byte */
530 				new_reclen += s_entry1->rr_attr_size;
531 			}
532 			if (new_reclen & 1)
533 				new_reclen++;	/* Pad to an even byte */
534 			s_entry1->isorec.length[0] = new_reclen;
535 			strcpy(s_entry1->isorec.name, newname);
536 #ifdef	USE_LARGEFILES
537 			if (s_entry1->de_flags & MULTI_EXTENT) {
538 				struct directory_entry	*s_e;
539 
540 				/*
541 				 * Copy over the new name to all other entries
542 				 */
543 				for (s_e = s_entry1->mxroot;
544 				    s_e && s_e->mxroot == s_entry1->mxroot;
545 							s_e = s_e->next) {
546 					s_e->isorec.length[0] = new_reclen;
547 					s_e->isorec.name_len[0] = s_entry1->isorec.name_len[0];
548 					strcpy(s_e->isorec.name, newname);
549 				}
550 			}
551 #endif
552 			add_file_hash(s_entry1);
553 #ifdef APPLE_HYB
554 			/*
555 			 * Has resource fork - needs new name
556 			 */
557 			if (apple_both && s_entry1->assoc) {
558 				struct directory_entry *s_entry2 =
559 							s_entry1->assoc;
560 
561 				/*
562 				 * resource fork name *should* be the same as
563 				 * the data fork
564 				 */
565 				s_entry2->isorec.name_len[0] =
566 						s_entry1->isorec.name_len[0];
567 				strcpy(s_entry2->isorec.name,
568 							s_entry1->isorec.name);
569 				s_entry2->isorec.length[0] = new_reclen;
570 			}
571 #endif	/* APPLE_HYB */
572 		}
573 		add_file_hash(s_entry);
574 		s_entry = s_entry->next;
575 	}
576 
577 	if (generate_tables &&
578 	    !find_file_hash(trans_tbl) &&
579 	    (reloc_dir != this_dir) &&
580 	    (this_dir->extent == 0)) {
581 		/*
582 		 * First we need to figure out how big this table is
583 		 */
584 		for (s_entry = this_dir->contents; s_entry;
585 						s_entry = s_entry->next) {
586 			if (strcmp(s_entry->name, ".") == 0 ||
587 				strcmp(s_entry->name, "..") == 0)
588 				continue;
589 			if (s_entry->isorec.flags[0] & ISO_MULTIEXTENT)
590 				continue;
591 #ifdef APPLE_HYB
592 			/*
593 			 * Skip table entry for the resource fork
594 			 */
595 			if (apple_both &&
596 			    (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
597 				continue;
598 #endif	/* APPLE_HYB */
599 			if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
600 				continue;
601 			if (s_entry->table) {
602 				/*
603 				 * Max namelen, a space before and a space
604 				 * after the iso filename.
605 				 */
606 				tablesize += MAX_ISONAME + 2 +
607 						strlen(s_entry->table);
608 			}
609 		}
610 	}
611 	if (tablesize > 0) {
612 		table = (struct directory_entry *)
613 			e_malloc(sizeof (struct directory_entry));
614 		memset(table, 0, sizeof (struct directory_entry));
615 		table->table = NULL;
616 		table->next = this_dir->contents;
617 		this_dir->contents = table;
618 
619 		table->filedir = root;
620 		table->isorec.flags[0] = ISO_FILE;
621 		table->priority = 32768;
622 		iso9660_date(table->isorec.date, fstatbuf.st_mtime);
623 		table->inode = TABLE_INODE;
624 		table->dev = UNCACHED_DEVICE;
625 		set_723(table->isorec.volume_sequence_number,
626 						volume_sequence_number);
627 		set_733((char *)table->isorec.size, tablesize);
628 		table->size = tablesize;
629 		table->filedir = this_dir;
630 		if (jhide_trans_tbl)
631 			table->de_flags |= INHIBIT_JOLIET_ENTRY;
632 		/*
633 		 * Always hide transtable from UDF tree.
634 		 */
635 		table->de_flags |= INHIBIT_UDF_ENTRY;
636 /*		table->name = e_strdup("<translation table>");*/
637 		table->name = e_strdup(trans_tbl);
638 		/*
639 		 * We use sprintf() to create the strings, for this reason
640 		 * we need to add one byte for the null character at the
641 		 * end of the string even though we don't use it.
642 		 */
643 		table->table = (char *)e_malloc(ISO_ROUND_UP(tablesize)+1);
644 		memset(table->table, 0, ISO_ROUND_UP(tablesize)+1);
645 		iso9660_file_length(trans_tbl, table, 0);
646 
647 		if (use_XA || use_RockRidge) {
648 			fstatbuf.st_mode = 0444 | S_IFREG;
649 			fstatbuf.st_nlink = 1;
650 			generate_xa_rr_attributes("",
651 				trans_tbl, table,
652 				&fstatbuf, &fstatbuf, 0);
653 		}
654 	}
655 	/*
656 	 * We have now chosen the 8.3 names and we should now know the length
657 	 * of every entry in the directory.
658 	 */
659 	for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
660 		/* skip if it's hidden */
661 		if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
662 			continue;
663 		}
664 		new_reclen = strlen(s_entry->isorec.name);
665 
666 		/*
667 		 * First update the path table sizes for directories.
668 		 */
669 		if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
670 			if (strcmp(s_entry->name, ".") != 0 &&
671 					strcmp(s_entry->name, "..") != 0) {
672 				path_table_size += new_reclen +
673 						offsetof(struct iso_path_table,
674 						name[0]);
675 				if (new_reclen & 1)
676 					path_table_size++;
677 			} else {
678 				new_reclen = 1;
679 				if (this_dir == root && strlen(s_entry->name)
680 									== 1) {
681 					path_table_size += new_reclen +
682 						offsetof(struct iso_path_table,
683 						name[0]);
684 				}
685 			}
686 		}
687 		if (path_table_size & 1)
688 			path_table_size++;	/* For odd lengths we pad */
689 		s_entry->isorec.name_len[0] = new_reclen;
690 
691 		new_reclen += offsetof(struct iso_directory_record, name[0]);
692 
693 		if (new_reclen & 1)
694 			new_reclen++;
695 
696 		new_reclen += s_entry->rr_attr_size;
697 
698 		if (new_reclen & 1)
699 			new_reclen++;
700 
701 		if (new_reclen > 0xff) {
702 			comerrno(EX_BAD,
703 				_("Fatal error - RR overflow (reclen %d) for file %s\n"),
704 				new_reclen,
705 				s_entry->name);
706 		}
707 		s_entry->isorec.length[0] = new_reclen;
708 	}
709 
710 	status = sort_directory(&this_dir->contents, (reloc_dir == this_dir));
711 	if (status > 0) {
712 		errmsgno(EX_BAD, _("Unable to sort directory %s\n"),
713 			this_dir->whole_name);
714 		errmsgno(EX_BAD,
715 		_("If there was more than one directory type argument to mkisofs\n"));
716 		comerrno(EX_BAD,
717 		_("use -graft-points to create different target directory names.\n"));
718 	}
719 	/*
720 	 * If we are filling out a TRANS.TBL, generate the entries that will
721 	 * go in the thing.
722 	 */
723 	if (table) {
724 		count = 0;
725 		for (s_entry = this_dir->contents; s_entry;
726 						s_entry = s_entry->next) {
727 			if (s_entry == table)
728 				continue;
729 			if (!s_entry->table)
730 				continue;
731 			if (strcmp(s_entry->name, ".") == 0 ||
732 				strcmp(s_entry->name, "..") == 0)
733 				continue;
734 
735 			if (s_entry->isorec.flags[0] & ISO_MULTIEXTENT)
736 				continue;
737 #ifdef APPLE_HYB
738 			/*
739 			 * Skip table entry for the resource fork
740 			 */
741 			if (apple_both &&
742 			    (s_entry->isorec.flags[0] & ISO_ASSOCIATED))
743 				continue;
744 #endif	/* APPLE_HYB */
745 			if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
746 				continue;
747 			/*
748 			 * Warning: we cannot use the return value of sprintf
749 			 * because old BSD based sprintf() implementations
750 			 * will return a pointer to the result instead of a
751 			 * count.
752 			 * Old mkiofs introduced a space after the iso
753 			 * filename to make parsing TRANS.TBL easier.
754 			 */
755 			sprintf(table->table + count, "%c %-*s%s",
756 				s_entry->table[0],
757 				MAX_ISONAME + 1,
758 				s_entry->isorec.name, s_entry->table + 1);
759 			count += strlen(table->table + count);
760 			free(s_entry->table);
761 			/*
762 			 * for a memory file, set s_entry->table to the
763 			 * correct data - which is stored in
764 			 * s_entry->whole_name
765 			 */
766 			if (s_entry->de_flags & MEMORY_FILE) {
767 				s_entry->table = s_entry->whole_name;
768 				s_entry->whole_name = NULL;
769 			} else {
770 				s_entry->table = NULL;
771 			}
772 		}
773 
774 		if (count != tablesize) {
775 			comerrno(EX_BAD,
776 				_("Translation table size mismatch %d %d\n"),
777 				count, tablesize);
778 		}
779 	}
780 	/*
781 	 * Now go through the directory and figure out how large this one will
782 	 * be. Do not split a directory entry across a sector boundary
783 	 */
784 	s_entry = this_dir->contents;
785 	this_dir->ce_bytes = 0;
786 	while (s_entry) {
787 		/* skip if it's hidden */
788 		if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
789 			s_entry = s_entry->next;
790 			continue;
791 		}
792 		new_reclen = s_entry->isorec.length[0];
793 		if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen
794 								>= SECTOR_SIZE)
795 
796 			this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
797 				~(SECTOR_SIZE - 1);
798 		this_dir->size += new_reclen;
799 
800 		/*
801 		 * See if continuation entries were used on disc
802 		 */
803 		if (use_RockRidge &&
804 			s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
805 			unsigned char	*pnt;
806 			int		len;
807 			int		nbytes;
808 
809 			pnt = s_entry->rr_attributes;
810 			len = s_entry->total_rr_attr_size;
811 			pnt = parse_xa(pnt, &len, 0);
812 /*			pnt = parse_xa(pnt, &len, s_entry);*/
813 
814 			/*
815 			 * We make sure that each continuation entry record is
816 			 * not split across sectors, but each file could in
817 			 * theory have more than one CE, so we scan through
818 			 * and figure out what we need.
819 			 */
820 			while (len > 3) {
821 				if (pnt[0] == 'C' && pnt[1] == 'E') {
822 					nbytes = get_733((char *)pnt + 20);
823 
824 					if ((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
825 						SECTOR_SIZE)
826 						this_dir->ce_bytes =
827 							ISO_ROUND_UP(this_dir->ce_bytes);
828 					/*
829 					 * Now store the block in the
830 					 * ce buffer
831 					 */
832 					this_dir->ce_bytes += nbytes;
833 					if (this_dir->ce_bytes & 1)
834 						this_dir->ce_bytes++;
835 				}
836 				len -= pnt[2];
837 				pnt += pnt[2];
838 			}
839 		}
840 		s_entry = s_entry->next;
841 	}
842 	return (status);
843 }
844 
845 LOCAL void
generate_reloc_directory()846 generate_reloc_directory()
847 {
848 	time_t		current_time;
849 	struct directory_entry *s_entry;
850 extern	time_t		begun;
851 
852 	/*
853 	 * Create an  entry for our internal tree
854 	 */
855 	current_time = begun;
856 	reloc_dir = (struct directory *)
857 		e_malloc(sizeof (struct directory));
858 	memset(reloc_dir, 0, sizeof (struct directory));
859 	reloc_dir->parent = root;
860 	reloc_dir->next = root->subdir;
861 	root->subdir = reloc_dir;
862 	reloc_dir->depth = 1;
863 	if (hide_rr_moved) {
864 		reloc_dir->whole_name = e_strdup("./.rr_moved");
865 		reloc_dir->de_name = e_strdup(".rr_moved");
866 	} else {
867 		reloc_dir->whole_name = e_strdup("./rr_moved");
868 		reloc_dir->de_name = e_strdup("rr_moved");
869 	}
870 	reloc_dir->de_path = reloc_dir->de_name;
871 	reloc_dir->extent = 0;
872 
873 
874 	/*
875 	 * Now create an actual directory entry
876 	 */
877 	s_entry = (struct directory_entry *)
878 		e_malloc(sizeof (struct directory_entry));
879 	memset(s_entry, 0, sizeof (struct directory_entry));
880 	s_entry->next = root->contents;
881 	reloc_dir->self = s_entry;
882 
883 	/*
884 	 * The rr_moved entry will not appear in the Joliet nor the UDF tree.
885 	 */
886 	reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
887 	s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
888 
889 	reloc_dir->dir_flags |= INHIBIT_UDF_ENTRY;
890 	s_entry->de_flags |= INHIBIT_UDF_ENTRY;
891 
892 	root->contents = s_entry;
893 	root->contents->name = e_strdup(reloc_dir->de_name);
894 	root->contents->filedir = root;
895 	root->contents->isorec.flags[0] = ISO_DIRECTORY;
896 	root->contents->priority = 32768;
897 	iso9660_date(root->contents->isorec.date, current_time);
898 	root->contents->inode = UNCACHED_INODE;
899 	root->contents->dev = UNCACHED_DEVICE;
900 	set_723(root->contents->isorec.volume_sequence_number,
901 						volume_sequence_number);
902 	iso9660_file_length(reloc_dir->de_name, root->contents, 1);
903 
904 	init_fstatbuf();
905 
906 	if (use_XA || use_RockRidge) {
907 		fstatbuf.st_mode = 0555 | S_IFDIR;
908 		fstatbuf.st_nlink = 2;
909 		generate_xa_rr_attributes("",
910 			hide_rr_moved ? ".rr_moved" : "rr_moved",
911 			s_entry, &fstatbuf, &fstatbuf, NEED_RE);
912 	};
913 
914 	/*
915 	 * Now create the . and .. entries in rr_moved
916 	 * Now create an actual directory entry
917 	 */
918 	if (root_statbuf.st_nlink == 0)
919 		root_statbuf = fstatbuf;
920 	attach_dot_entries(reloc_dir, NULL, &root_statbuf);
921 }
922 
923 /*
924  * Function:		attach_dot_entries
925  *
926  * Purpose:		Create . and .. entries for a new directory.
927  *
928  * Notes:		Only used for artificial directories that
929  *			we are creating.
930  */
931 EXPORT void
attach_dot_entries(dirnode,this_stat,parent_stat)932 attach_dot_entries(dirnode, this_stat, parent_stat)
933 	struct directory	*dirnode;
934 	struct stat		*this_stat;
935 	struct stat		*parent_stat;
936 {
937 	struct directory_entry *s_entry;
938 	struct directory_entry *orig_contents;
939 	int		deep_flag = 0;
940 
941 	init_fstatbuf();
942 	fstatbuf.st_mode = new_dir_mode | S_IFDIR;
943 	fstatbuf.st_nlink = 2;
944 	if (parent_stat == NULL)
945 		parent_stat = &fstatbuf;
946 	if (this_stat == NULL)
947 		this_stat = &fstatbuf;
948 
949 	orig_contents = dirnode->contents;
950 
951 	if ((dirnode->dir_flags & DIR_HAS_DOTDOT) == 0) {
952 		if (dirnode->parent &&
953 		    dirnode->parent == reloc_dir) {
954 			deep_flag = NEED_PL;
955 		}
956 		s_entry = (struct directory_entry *)
957 			e_malloc(sizeof (struct directory_entry));
958 		memcpy(s_entry, dirnode->self,
959 			sizeof (struct directory_entry));
960 #ifdef	APPLE_HYB
961 		if (dirnode->self->hfs_ent) {
962 			s_entry->hfs_ent = (hfsdirent *)
963 				e_malloc(sizeof (hfsdirent));
964 			memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
965 				sizeof (hfsdirent));
966 		}
967 #endif
968 		s_entry->name = e_strdup("..");
969 		s_entry->whole_name = NULL;
970 		s_entry->isorec.name_len[0] = 1;
971 		s_entry->isorec.flags[0] = ISO_DIRECTORY;
972 		iso9660_file_length("..", s_entry, 1);
973 		iso9660_date(s_entry->isorec.date, parent_stat->st_mtime);
974 		set_723(s_entry->isorec.volume_sequence_number,
975 						volume_sequence_number);
976 		set_733(s_entry->isorec.size, SECTOR_SIZE);
977 		memset(s_entry->isorec.extent, 0, 8);
978 		s_entry->filedir = dirnode->parent;
979 
980 		dirnode->contents = s_entry;
981 		dirnode->contents->next = orig_contents;
982 		orig_contents = s_entry;
983 
984 		if (use_XA || use_RockRidge) {
985 			generate_xa_rr_attributes("",
986 				"..", s_entry,
987 				parent_stat,
988 				parent_stat, deep_flag);
989 		}
990 		dirnode->dir_flags |= DIR_HAS_DOTDOT;
991 	}
992 	deep_flag = 0;
993 	if ((dirnode->dir_flags & DIR_HAS_DOT) == 0) {
994 		s_entry = (struct directory_entry *)
995 			e_malloc(sizeof (struct directory_entry));
996 		memcpy(s_entry, dirnode->self,
997 			sizeof (struct directory_entry));
998 #ifdef	APPLE_HYB
999 		if (dirnode->self->hfs_ent) {
1000 			s_entry->hfs_ent = (hfsdirent *)
1001 				e_malloc(sizeof (hfsdirent));
1002 			memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
1003 				sizeof (hfsdirent));
1004 		}
1005 #endif
1006 		s_entry->name = e_strdup(".");
1007 		s_entry->whole_name = NULL;
1008 		s_entry->isorec.name_len[0] = 1;
1009 		s_entry->isorec.flags[0] = ISO_DIRECTORY;
1010 		iso9660_file_length(".", s_entry, 1);
1011 		iso9660_date(s_entry->isorec.date, this_stat->st_mtime);
1012 		set_723(s_entry->isorec.volume_sequence_number,
1013 						volume_sequence_number);
1014 		set_733(s_entry->isorec.size, SECTOR_SIZE);
1015 		memset(s_entry->isorec.extent, 0, 8);
1016 		s_entry->filedir = dirnode;
1017 
1018 		dirnode->contents = s_entry;
1019 		dirnode->contents->next = orig_contents;
1020 
1021 		if (use_XA || use_RockRidge) {
1022 			if (dirnode == root) {
1023 				deep_flag |= NEED_CE | NEED_SP;	/* For extension record */
1024 			}
1025 			generate_xa_rr_attributes("",
1026 				".", s_entry,
1027 				this_stat, this_stat, deep_flag);
1028 		}
1029 		dirnode->dir_flags |= DIR_HAS_DOT;
1030 	}
1031 }
1032 
1033 EXPORT char *
find_rr_attribute(pnt,len,attr_type)1034 find_rr_attribute(pnt, len, attr_type)
1035 	unsigned char	*pnt;
1036 	int		len;
1037 	char		*attr_type;
1038 {
1039 	pnt = parse_xa(pnt, &len, 0);
1040 	while (len >= 4) {
1041 		if (pnt[3] != 1 && pnt[3] != 2) {
1042 			errmsgno(EX_BAD,
1043 				_("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
1044 				pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
1045 		}
1046 		if (pnt[2] < 4) {
1047 			errmsgno(EX_BAD,
1048 				_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
1049 				pnt[2], pnt, pnt[0], pnt[1]);
1050 			return (NULL);
1051 		}
1052 		if (strncmp((char *)pnt, attr_type, 2) == 0)
1053 			return ((char *)pnt);
1054 		else if (strncmp((char *)pnt, "ST", 2) == 0)
1055 			return (NULL);
1056 		len -= pnt[2];
1057 		pnt += pnt[2];
1058 	}
1059 	return (NULL);
1060 }
1061 
1062 EXPORT void
finish_cl_pl_entries()1063 finish_cl_pl_entries()
1064 {
1065 	struct directory_entry	*s_entry;
1066 	struct directory_entry	*s_entry1;
1067 	struct directory	*d_entry;
1068 
1069 	/*
1070 	 * If the reloc_dir is hidden (empty), then return
1071 	 */
1072 	if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
1073 		return;
1074 
1075 	s_entry = reloc_dir->contents;
1076 	s_entry = s_entry->next->next;	/* Skip past . and .. */
1077 	for (; s_entry; s_entry = s_entry->next) {
1078 		/* skip if it's hidden */
1079 		if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
1080 			continue;
1081 		}
1082 		d_entry = reloc_dir->subdir;
1083 		while (d_entry) {
1084 			if (d_entry->self == s_entry)
1085 				break;
1086 			d_entry = d_entry->next;
1087 		};
1088 		if (!d_entry) {
1089 			comerrno(EX_BAD,
1090 					_("Unable to locate directory parent\n"));
1091 		};
1092 
1093 		if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
1094 			char	*rr_attr;
1095 
1096 			/*
1097 			 * First fix the PL pointer in the directory in the
1098 			 * rr_reloc dir
1099 			 */
1100 			s_entry1 = d_entry->contents->next;
1101 
1102 /*			set_733((char *) s_entry1->rr_attributes +*/
1103 /*				s_entry1->total_rr_attr_size - 8,*/
1104 /*				s_entry->filedir->extent); */
1105 			/*
1106 			 * The line above won't work when entry was read from
1107 			 * the previous session, because if total_rr_attr_size
1108 			 * was odd when recording previous session, now we have
1109 			 * total_rr_attr_size off by 1 due to padding.
1110 			 *
1111 			 * So, just search for the attributes by name
1112 			 */
1113 			rr_attr = find_rr_attribute(s_entry1->rr_attributes,
1114 				s_entry1->total_rr_attr_size, "PL");
1115 			if (rr_attr != NULL)
1116 				set_733(rr_attr + 4, s_entry->filedir->extent);
1117 
1118 
1119 			/*
1120 			 * Now fix the CL pointer
1121 			 */
1122 			s_entry1 = s_entry->parent_rec;
1123 
1124 /*			set_733((char *) s_entry1->rr_attributes +*/
1125 /*			s_entry1->total_rr_attr_size - 8, d_entry->extent); */
1126 			rr_attr = find_rr_attribute(s_entry1->rr_attributes,
1127 				s_entry1->total_rr_attr_size, "CL");
1128 			if (rr_attr != NULL)
1129 				set_733(rr_attr + 4, d_entry->extent);
1130 		}
1131 		s_entry->filedir = reloc_dir;	/* Now we can fix this */
1132 	}
1133 	/*
1134 	 * We would need to modify the NLINK terms in the assorted root
1135 	 * directory records to account for the presence of the RR_MOVED
1136 	 * directory. We do not do this here because we do it later when
1137 	 * we correct the link count for all direstories in the tree.
1138 	 */
1139 
1140 
1141 	finish_cl_pl_for_prev_session();
1142 }
1143 
1144 LOCAL void
dir_nesting_warn(this_dir,path,contflag)1145 dir_nesting_warn(this_dir, path, contflag)
1146 	struct directory	*this_dir;
1147 	char			*path;
1148 	int			contflag;
1149 {
1150 	static	BOOL	did_hint = FALSE;
1151 
1152 	errmsgno(EX_BAD,
1153 		_("Directories too deep for '%s' (%d) max is %d%s.\n"),
1154 		path, this_dir->depth, RR_relocation_depth,
1155 		contflag?_("; ignored - continuing"):"");
1156 	if (!did_hint) {
1157 		did_hint = TRUE;
1158 		errmsgno(EX_BAD, _("To include the complete directory tree,\n"));
1159 		errmsgno(EX_BAD, _("use Rock Ridge extensions via -R or -r,\n"));
1160 		errmsgno(EX_BAD, _("or allow deep ISO9660 directory nesting via -D.\n"));
1161 	}
1162 }
1163 
1164 /*
1165  * Function:		scan_directory_tree
1166  *
1167  * Purpose:		Walk through a directory on the local machine
1168  *			filter those things we don't want to include
1169  *			and build our representation of a dir.
1170  *
1171  * Notes:
1172  */
1173 EXPORT int
scan_directory_tree(this_dir,path,de)1174 scan_directory_tree(this_dir, path, de)
1175 	struct directory	*this_dir;
1176 	char			*path;
1177 	struct directory_entry	*de;
1178 {
1179 	DIR		*current_dir;
1180 	char		whole_path[2*PATH_MAX];	/* Avoid stat buffer overflow */
1181 	struct dirent	*d_entry;
1182 	int		dflag;
1183 extern	BOOL		nodesc;
1184 
1185 	if (nodesc)
1186 		return (1);
1187 
1188 	if (verbose > 1) {
1189 		fprintf(stderr, _("Scanning %s\n"), path);
1190 	}
1191 /*#define	check_needed*/
1192 #ifdef	check_needed
1193 	/*
1194 	 * Trying to use this to avoid directory loops from hard links
1195 	 * or followed symlinks does not work. It would prevent us from
1196 	 * implementing merge directories.
1197 	 */
1198 	if (this_dir->dir_flags & DIR_WAS_SCANNED) {
1199 		fprintf(stderr, _("Already scanned directory %s\n"), path);
1200 		return (1);	/* It's a directory */
1201 	}
1202 #endif
1203 	this_dir->dir_flags |= DIR_WAS_SCANNED;
1204 
1205 	errno = 0;	/* Paranoia */
1206 	current_dir = opendir(path);
1207 	d_entry = NULL;
1208 
1209 	/*
1210 	 * Apparently NFS sometimes allows you to open the directory, but then
1211 	 * refuses to allow you to read the contents.  Allow for this
1212 	 */
1213 	if (current_dir) {
1214 		errno = 0;
1215 		d_entry = readdir(current_dir);
1216 	}
1217 
1218 	if (!current_dir || (!d_entry && errno != 0)) {
1219 		int	ret = 1;
1220 
1221 		errmsg(_("Unable to open directory %s\n"), path);
1222 
1223 		if (errno == ENOTDIR) {
1224 			/*
1225 			 * Mark as not a directory
1226 			 */
1227 			de->isorec.flags[0] &= ~ISO_DIRECTORY;
1228 			ret = 0;
1229 		}
1230 		if (current_dir)
1231 			closedir(current_dir);
1232 		return (ret);
1233 	}
1234 
1235 	/*
1236 	 * Set up the struct for the current directory, and insert it into
1237 	 * the tree
1238 	 */
1239 #ifdef VMS
1240 	vms_path_fixup(path);
1241 #endif
1242 
1243 	/*
1244 	 * if entry for this sub-directory is hidden, then hide this directory
1245 	 */
1246 	if (de->de_flags & INHIBIT_ISO9660_ENTRY)
1247 		this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
1248 
1249 	if (de->de_flags & INHIBIT_JOLIET_ENTRY)
1250 		this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
1251 
1252 #ifdef SORTING
1253 	/*
1254 	 * set any sort weighting from it's own directory entry - if a
1255 	 * directory is given a weighting, then all the contents will use
1256 	 * this as the default weighting
1257 	 */
1258 	this_dir->sort = de->sort;
1259 #endif /* SORTING */
1260 
1261 	/*
1262 	 * Now we scan the directory itself, and look at what is inside of it.
1263 	 */
1264 	whole_path[0] = '\0';
1265 	dflag = -2;
1266 	while (1 == 1) {
1267 		char	*d_name;
1268 
1269 		if (dflag < 0) {
1270 			/*
1271 			 * Some filesystems do not deliver "." and ".." at all,
1272 			 * others (on Linux) deliver them in the wrong order.
1273 			 * Make sure we add "." and ".." before all other
1274 			 * entries.
1275 			 */
1276 			if (dflag < -1)
1277 				d_name = ".";
1278 			else
1279 				d_name = "..";
1280 			dflag++;
1281 		} else {
1282 			/*
1283 			 * The first time through, skip this, since we already
1284 			 * asked for the first entry when we opened the
1285 			 * directory.
1286 			 */
1287 			if (dflag > 0) {
1288 				d_entry = readdir(current_dir);
1289 			} else {
1290 				dflag++;
1291 			}
1292 			if (!d_entry)
1293 				break;
1294 			d_name = d_entry->d_name;
1295 		}
1296 
1297 		/*
1298 		 * OK, got a valid entry
1299 		 *
1300 		 * If we do not want all files, then pitch the backups.
1301 		 */
1302 		if (!all_files) {
1303 			if (strchr(d_name, '~') ||
1304 			    strchr(d_name, '#') ||
1305 			    rstr(d_name, ".bak")) {
1306 				if (verbose > 0) {
1307 					fprintf(stderr,
1308 						_("Ignoring file %s\n"),
1309 						d_name);
1310 				}
1311 				continue;
1312 			}
1313 		}
1314 #ifdef APPLE_HYB
1315 		if (apple_both) {
1316 			/*
1317 			 * exclude certain HFS type files/directories for the
1318 			 * time being
1319 			 */
1320 			if (hfs_exclude(d_name))
1321 				continue;
1322 		}
1323 #endif	/* APPLE_HYB */
1324 
1325 		if (strlen(path) + strlen(d_name) + 2 > sizeof (whole_path)) {
1326 			errmsgno(EX_BAD, _("Path name %s/%s too long.\n"),
1327 					path, d_name);
1328 			comerrno(EX_BAD, _("Overflow of stat buffer\n"));
1329 		};
1330 
1331 		/*
1332 		 * Generate the complete ASCII path for this file
1333 		 */
1334 		strlcpy(whole_path, path, sizeof (whole_path));
1335 #ifndef VMS
1336 		if (whole_path[strlen(whole_path) - 1] != '/')
1337 			strcat(whole_path, "/");
1338 #endif
1339 		strcat(whole_path, d_name);
1340 
1341 		/*
1342 		 * Should we exclude this file ?
1343 		 * Do no check "." and ".."
1344 		 */
1345 		if (!(d_name[0] == '.' && (d_name[1] == '\0' ||
1346 		    (d_name[1] == '.' && d_name[2] == '\0'))) &&
1347 		    (matches(d_name) || matches(whole_path))) {
1348 			if (verbose > 1) {
1349 				fprintf(stderr,
1350 					_("Excluded by match: %s\n"), whole_path);
1351 			}
1352 			continue;
1353 		}
1354 		if (generate_tables &&
1355 		    strcmp(d_name, trans_tbl) == 0) {
1356 			/*
1357 			 * Ignore this entry.  We are going to be generating
1358 			 * new versions of these files, and we need to ignore
1359 			 * any originals that we might have found.
1360 			 */
1361 			if (verbose > 1) {
1362 				fprintf(stderr, _("Excluded: %s\n"), whole_path);
1363 			}
1364 			continue;
1365 		}
1366 		/*
1367 		 * If we already have a '.' or a '..' entry, then don't insert
1368 		 * new ones.
1369 		 */
1370 		if (strcmp(d_name, ".") == 0 &&
1371 		    this_dir->dir_flags & DIR_HAS_DOT) {
1372 			continue;
1373 		}
1374 		if (strcmp(d_name, "..") == 0 &&
1375 		    this_dir->dir_flags & DIR_HAS_DOTDOT) {
1376 			continue;
1377 		}
1378 #if 0
1379 		if (verbose > 1)
1380 			fprintf(stderr, "%s\n", whole_path);
1381 #endif
1382 		/*
1383 		 * This actually adds the entry to the directory in question.
1384 		 */
1385 		insert_file_entry(this_dir, whole_path, d_name, NULL, 0);
1386 	}
1387 	closedir(current_dir);
1388 
1389 #ifdef APPLE_HYB
1390 	/*
1391 	 * if we cached the HFS info stuff for this directory, then delete it
1392 	 */
1393 	if (this_dir->hfs_info) {
1394 		del_hfs_info(this_dir->hfs_info);
1395 		this_dir->hfs_info = 0;
1396 	}
1397 #endif	/* APPLE_HYB */
1398 
1399 	return (1);
1400 }
1401 
1402 LOCAL struct directory_entry *
dup_relocated_dir(this_dir,s_entry,whole_path,short_name,statp)1403 dup_relocated_dir(this_dir, s_entry, whole_path, short_name, statp)
1404 	struct directory	*this_dir;
1405 	struct directory_entry	*s_entry;
1406 	char			*whole_path;
1407 	char			*short_name;
1408 	struct stat		*statp;
1409 {
1410 	struct directory_entry *s_entry1;
1411 
1412 	if (!reloc_dir)
1413 		generate_reloc_directory();
1414 	init_fstatbuf();
1415 
1416 	/*
1417 	 * Replicate the entry for this directory.  The old one will
1418 	 * stay where it is, and it will be neutered so that it no
1419 	 * longer looks like a directory. The new one will look like
1420 	 * a directory, and it will be put in the reloc_dir.
1421 	 */
1422 	s_entry1 = (struct directory_entry *)
1423 		e_malloc(sizeof (struct directory_entry));
1424 	memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
1425 	s_entry1->table = NULL;
1426 	s_entry1->name = e_strdup(short_name);
1427 	s_entry1->whole_name = e_strdup(whole_path);
1428 	s_entry1->next = reloc_dir->contents;
1429 	reloc_dir->contents = s_entry1;
1430 	s_entry1->priority = 32768;
1431 	s_entry1->parent_rec = this_dir->contents;
1432 	set_723(s_entry1->isorec.volume_sequence_number,
1433 						volume_sequence_number);
1434 	s_entry1->filedir = this_dir;
1435 	iso9660_date(s_entry1->isorec.date, fstatbuf.st_mtime);
1436 
1437 	if (use_XA || use_RockRidge) {
1438 		generate_xa_rr_attributes(whole_path,
1439 			short_name, s_entry1,
1440 			statp, statp, NEED_RE);
1441 	}
1442 #ifdef UDF
1443 	/* set some info used for udf */
1444 	s_entry1->mode = statp->st_mode;
1445 	s_entry1->uid =  statp->st_uid;
1446 	s_entry1->gid =  statp->st_gid;
1447 	s_entry1->atime.tv_sec = statp->st_atime;
1448 	s_entry1->atime.tv_nsec = stat_ansecs(statp);
1449 	s_entry1->mtime.tv_sec = statp->st_mtime;
1450 	s_entry1->mtime.tv_nsec = stat_mnsecs(statp);
1451 	s_entry1->ctime.tv_sec = statp->st_ctime;
1452 	s_entry1->ctime.tv_nsec = stat_cnsecs(statp);
1453 #endif
1454 
1455 	statp->st_size = (off_t)0;
1456 	statp->st_mode &= 0777;
1457 	set_733((char *)s_entry->isorec.size, 0);
1458 	s_entry->size = 0;
1459 	s_entry->isorec.flags[0] = ISO_FILE;
1460 	s_entry->inode = UNCACHED_INODE;
1461 	s_entry->dev = UNCACHED_DEVICE;
1462 	s_entry->de_flags |= RELOCATED_DIRECTORY;
1463 
1464 	return (s_entry1);
1465 }
1466 
1467 
1468 /*
1469  * Function:		insert_file_entry
1470  *
1471  * Purpose:		Insert one entry into our directory node.
1472  *
1473  * Note:
1474  * This function inserts a single entry into the directory.  It
1475  * is assumed that all filtering and decision making regarding what
1476  * we want to include has already been made, so the purpose of this
1477  * is to insert one entry (file, link, dir, etc), into this directory.
1478  * Note that if the entry is a dir (or if we are following links,
1479  * and the thing it points to is a dir), then we will scan those
1480  * trees before we return.
1481  */
1482 EXPORT int
insert_file_entry(this_dir,whole_path,short_name,statp,have_rsrc)1483 insert_file_entry(this_dir, whole_path, short_name, statp, have_rsrc)
1484 	struct directory	*this_dir;
1485 	char			*whole_path;
1486 	char			*short_name;
1487 	struct stat		*statp;
1488 	int			have_rsrc;
1489 {
1490 	struct stat	statbuf,
1491 			lstatbuf;
1492 	struct directory_entry *s_entry,
1493 			*s_entry1;
1494 	int		lstatus;
1495 	int		status;
1496 	int		deep_flag;
1497 #ifdef	USE_NO_SCANDIR
1498 	int		no_scandir = 0;
1499 #endif
1500 
1501 #ifdef APPLE_HYB
1502 	int		x_hfs = 0;
1503 	int		htype = TYPE_NONE;
1504 
1505 #endif	/* APPLE_HYB */
1506 
1507 	if (statp) {
1508 		status = lstatus = 0;
1509 		lstatbuf = *statp;
1510 		if (S_ISLNK(lstatbuf.st_mode)) {
1511 			status = stat_filter(short_name, &statbuf);
1512 		} else {
1513 			statbuf = *statp;
1514 		}
1515 	} else {
1516 		status = stat_filter(whole_path, &statbuf);
1517 
1518 		lstatus = lstat_filter(whole_path, &lstatbuf);
1519 	}
1520 
1521 	if ((status == -1) && (lstatus == -1)) {
1522 		/*
1523 		 * This means that the file doesn't exist, or isn't accessible.
1524 		 * Sometimes this is because of NFS permissions problems.
1525 		 */
1526 		errmsg(_("Non-existent or inaccessible: %s\n"), whole_path);
1527 		return (0);
1528 	}
1529 	if (S_ISDIR(statbuf.st_mode) &&
1530 	    (this_dir->depth > RR_relocation_depth) && !use_RockRidge &&
1531 	    strcmp(short_name, ".") != 0 && strcmp(short_name, "..") != 0) {
1532 		dir_nesting_warn(this_dir, whole_path, TRUE);
1533 		return (0);
1534 	}
1535 	if (this_dir == root && strcmp(short_name, ".") == 0)
1536 		root_statbuf = statbuf;	/* Save this for later on */
1537 
1538 	/*
1539 	 * We do this to make sure that the root entries are consistent
1540 	 */
1541 	if (this_dir == root && strcmp(short_name, "..") == 0) {
1542 		statbuf = root_statbuf;
1543 		lstatbuf = root_statbuf;
1544 	}
1545 	if (S_ISLNK(lstatbuf.st_mode)) {
1546 		/*
1547 		 * Here we decide how to handle the symbolic links.  Here we
1548 		 * handle the general case - if we are not following links or
1549 		 * there is an error, then we must change something.  If RR
1550 		 * is in use, it is easy, we let RR describe the file.  If
1551 		 * not, then we punt the file.
1552 		 */
1553 		if ((status || !follow_links)) {
1554 #ifdef UDF
1555 			if (use_RockRidge || use_udf) {
1556 #else
1557 			if (use_RockRidge) {
1558 #endif
1559 				status = 0;
1560 				STAT_INODE(statbuf) = UNCACHED_INODE;
1561 				statbuf.st_dev = UNCACHED_DEVICE;
1562 #ifdef UDF
1563 				if (create_udfsymlinks) {
1564 					char symlinkcontents[2048];
1565 					off_t size = sizeof (symlinkcontents);
1566 
1567 					if (udf_get_symlinkcontents(whole_path,
1568 					    symlinkcontents, &size) == -1) {
1569 						statbuf.st_size = (off_t)0;
1570 						statbuf.st_mode =
1571 							(statbuf.st_mode & ~S_IFMT) | S_IFREG;
1572 					} else {
1573 						statbuf.st_size = size;
1574 						statbuf.st_mode = lstatbuf.st_mode;
1575 					}
1576 				} else {
1577 #endif
1578 					statbuf.st_size = (off_t)0;
1579 					statbuf.st_mode =
1580 						(statbuf.st_mode & ~S_IFMT) | S_IFREG;
1581 #ifdef UDF
1582 				}
1583 #endif
1584 			} else {
1585 				if (follow_links) {
1586 					/* XXX errno may be wrong! */
1587 					errmsg(_("Unable to stat file %s - ignoring and continuing.\n"),
1588 						whole_path);
1589 				} else {
1590 					errmsgno(EX_BAD,
1591 						_("Symlink %s ignored - continuing.\n"),
1592 						whole_path);
1593 					return (0); /* Non Rock Ridge discs */
1594 						    /* - ignore all symlinks */
1595 				}
1596 			}
1597 		}
1598 		/*
1599 		 * Here we handle a different kind of case.  Here we have a
1600 		 * symlink, but we want to follow symlinks.  If we run across
1601 		 * a directory loop, then we need to pretend that we are not
1602 		 * following symlinks for this file.  If this is the first
1603 		 * time we have seen this, then make this seem as if there was
1604 		 * no symlink there in the first place
1605 		 */
1606 		if (follow_links &&
1607 		    S_ISDIR(statbuf.st_mode)) {
1608 			if (strcmp(short_name, ".") != 0 &&
1609 			    strcmp(short_name, "..") != 0) {
1610 				if (find_directory_hash(statbuf.st_dev,
1611 							STAT_INODE(statbuf))) {
1612 					if (!use_RockRidge) {
1613 						fprintf(stderr,
1614 						_("Already cached directory seen (%s)\n"),
1615 							whole_path);
1616 						return (0);
1617 					}
1618 					lstatbuf = statbuf;
1619 					/*
1620 					 * XXX when this line was active,
1621 					 * XXX mkisofs did not include all
1622 					 * XXX files if it was called with '-f'
1623 					 * XXX (follow symlinks).
1624 					 * XXX Now scan_directory_tree()
1625 					 * XXX checks if the directory has
1626 					 * XXX already been scanned via the
1627 					 * XXX DIR_WAS_SCANNED flag.
1628 					 */
1629 /*					no_scandir = 1;*/
1630 				} else {
1631 					lstatbuf = statbuf;
1632 					add_directory_hash(statbuf.st_dev,
1633 							STAT_INODE(statbuf));
1634 				}
1635 			}
1636 		}
1637 		/*
1638 		 * For non-directories, we just copy the stat information over
1639 		 * so we correctly include this file.
1640 		 */
1641 		if (follow_links &&
1642 		    !S_ISDIR(statbuf.st_mode)) {
1643 			lstatbuf = statbuf;
1644 		}
1645 	}
1646 	/*
1647 	 * Add directories to the cache so that we don't waste space even if
1648 	 * we are supposed to be following symlinks.
1649 	 */
1650 	if (follow_links &&
1651 	    strcmp(short_name, ".") != 0 &&
1652 	    strcmp(short_name, "..") != 0 &&
1653 	    S_ISDIR(statbuf.st_mode)) {
1654 		add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1655 	}
1656 #ifdef VMS
1657 	if (!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX &&
1658 			statbuf.st_fab_rfm != FAB$C_STMLF)) {
1659 		fprintf(stderr,
1660 		_("Warning - file %s has an unsupported VMS record format (%d)\n"),
1661 			whole_path, statbuf.st_fab_rfm);
1662 	}
1663 #endif
1664 
1665 	if (S_ISREG(lstatbuf.st_mode) &&
1666 	    ((statp != NULL && (status = access(short_name, R_OK))) ||
1667 	    (statp == NULL && (status = access(whole_path, R_OK))))) {
1668 		errmsg(_("File %s is not readable - ignoring\n"),
1669 			whole_path);
1670 		return (0);
1671 	}
1672 #ifdef	USE_LARGEFILES
1673 	if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= maxnonlarge) &&
1674 	    !do_largefiles) {
1675 #else
1676 	/*
1677 	 * >= is required by the large file summit standard.
1678 	 */
1679 	if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= (off_t)0x7FFFFFFF)) {
1680 #endif
1681 #ifdef	EOVERFLOW
1682 		errno = EOVERFLOW;
1683 #else
1684 		errno = EFBIG;
1685 #endif
1686 		errmsg(_("File %s is too large for current mkisofs settings (-iso-level 3 or more required) - ignoring\n"),
1687 			whole_path);
1688 		return (0);
1689 	}
1690 	/*
1691 	 * Add this so that we can detect directory loops with hard links.
1692 	 * If we are set up to follow symlinks, then we skip this checking.
1693 	 */
1694 	if (!follow_links &&
1695 	    S_ISDIR(lstatbuf.st_mode) &&
1696 	    strcmp(short_name, ".") != 0 &&
1697 	    strcmp(short_name, "..") != 0) {
1698 		if (find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
1699 /*			comerrno(EX_BAD,*/
1700 /*			_("Directory loop - fatal goof (%s %lx %lu).\n"),*/
1701 			errmsgno(EX_BAD,
1702 			_("Warning: Directory loop (%s dev: %lx ino: %lu).\n"),
1703 				whole_path, (unsigned long) statbuf.st_dev,
1704 				(unsigned long) STAT_INODE(statbuf));
1705 		}
1706 		add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
1707 	}
1708 	if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
1709 		!S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) &&
1710 		!S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
1711 		!S_ISDIR(lstatbuf.st_mode)) {
1712 		fprintf(stderr,
1713 		_("Unknown file type (%s) %s - ignoring and continuing.\n"),
1714 			filetype((int)lstatbuf.st_mode), whole_path);
1715 		return (0);
1716 	}
1717 	/*
1718 	 * Who knows what trash this is - ignore and continue
1719 	 */
1720 	if (status) {
1721 		errmsg(_("Unable to stat file %s - ignoring and continuing.\n"),
1722 			whole_path);
1723 		return (0);
1724 	}
1725 
1726 #if !defined(__MINGW32__) && !defined(_MSC_VER)
1727 #define	is_archive(st)	((st).st_dev == archive_dev && (st).st_ino == archive_ino)
1728 	if (archive_isreg && is_archive(statbuf)) {
1729 		errmsgno(EX_BAD,
1730 			_("'%s' is the archive. Not dumped.\n"), whole_path);
1731 		return (0);
1732 	}
1733 #endif
1734 
1735 	/*
1736 	 * Check to see if we have already seen this directory node. If so,
1737 	 * then we don't create a new entry for it, but we do want to recurse
1738 	 * beneath it and add any new files we do find.
1739 	 */
1740 	if (S_ISDIR(statbuf.st_mode)) {
1741 		int	dflag;
1742 
1743 		for (s_entry = this_dir->contents; s_entry;
1744 						s_entry = s_entry->next) {
1745 			if (strcmp(s_entry->name, short_name) == 0) {
1746 				break;
1747 			}
1748 		}
1749 		if (s_entry != NULL &&
1750 		    strcmp(short_name, ".") != 0 &&
1751 		    strcmp(short_name, "..") != 0) {
1752 			struct directory *child;
1753 
1754 			/*
1755 			 * This should not create a new directory
1756 			 */
1757 			if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
1758 				for (s_entry = reloc_dir->contents; s_entry;
1759 						s_entry = s_entry->next) {
1760 					if (strcmp(s_entry->name, short_name)
1761 									== 0) {
1762 						break;
1763 					}
1764 				}
1765 				child = find_or_create_directory(reloc_dir,
1766 					whole_path,
1767 					s_entry, 1);
1768 			} else {
1769 				child = find_or_create_directory(this_dir,
1770 					whole_path,
1771 					s_entry, 1);
1772 				/*
1773 				 * If unable to scan directory, mark this as a
1774 				 * non-directory
1775 				 */
1776 			}
1777 /*			if (no_scandir)*/
1778 			if (0)
1779 				dflag = 1;
1780 			else
1781 				dflag = scan_directory_tree(child,
1782 							whole_path, s_entry);
1783 			if (!dflag) {
1784 				lstatbuf.st_mode =
1785 					(lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
1786 			}
1787 			return (0);
1788 		}
1789 	}
1790 #ifdef APPLE_HYB
1791 	/*
1792 	 * Should we exclude this HFS file ? - only works with -hfs
1793 	 */
1794 	if (!have_rsrc && apple_hyb && strcmp(short_name, ".") != 0 &&
1795 					strcmp(short_name, "..") != 0) {
1796 		if ((x_hfs = (hfs_matches(short_name) ||
1797 					hfs_matches(whole_path))) == 1) {
1798 			if (verbose > 1) {
1799 				fprintf(stderr, _("Hidden from HFS tree: %s\n"),
1800 							whole_path);
1801 			}
1802 		}
1803 	}
1804 	/*
1805 	 * check we are a file, using Apple extensions and have a .resource
1806 	 * part and not excluded
1807 	 */
1808 	if (S_ISREG(lstatbuf.st_mode) && !have_rsrc && apple_both && !x_hfs) {
1809 		char	rsrc_path[PATH_MAX];	/* rsrc fork filename */
1810 
1811 		/*
1812 		 * Construct the resource full path
1813 		 */
1814 		htype = get_hfs_rname(whole_path, short_name, rsrc_path);
1815 		/*
1816 		 * Check we can read the resouce fork
1817 		 */
1818 		if (htype) {
1819 			struct stat	rstatbuf,
1820 					rlstatbuf;
1821 
1822 			/*
1823 			 * Some further checks on the file
1824 			 */
1825 			status = stat_filter(rsrc_path, &rstatbuf);
1826 
1827 			lstatus = lstat_filter(rsrc_path, &rlstatbuf);
1828 
1829 /*			if (!status && !lstatus && S_ISREG(rlstatbuf.st_mode)*/
1830 /*					&& rlstatbuf.st_size > (off_t)0) { */
1831 			if (!status && !lstatus && S_ISREG(rstatbuf.st_mode) &&
1832 					rstatbuf.st_size > (off_t)0) {
1833 
1834 				/*
1835 				 * have a resource file - insert it into the
1836 				 * current directory but flag that we have a
1837 				 * resource fork
1838 				 */
1839 				insert_file_entry(this_dir, rsrc_path,
1840 							short_name, NULL, htype);
1841 			}
1842 		}
1843 	}
1844 #endif	/* APPLE_HYB */
1845 
1846 	s_entry = (struct directory_entry *)
1847 		e_malloc(sizeof (struct directory_entry));
1848 	/* memset the whole struct, not just the isorec.extent part JCP */
1849 	memset(s_entry, 0, sizeof (struct directory_entry));
1850 	s_entry->next = this_dir->contents;
1851 /*	memset(s_entry->isorec.extent, 0, 8); */
1852 	this_dir->contents = s_entry;
1853 	deep_flag = 0;
1854 	s_entry->table = NULL;
1855 
1856 	s_entry->name = e_strdup(short_name);
1857 	s_entry->whole_name = e_strdup(whole_path);
1858 
1859 	s_entry->de_flags = 0;
1860 	if (S_ISLNK(lstatbuf.st_mode))
1861 		s_entry->de_flags |= IS_SYMLINK;
1862 #ifdef	DUPLICATES_ONCE
1863 	s_entry->digest_fast = NULL;
1864 	s_entry->digest_full = NULL;
1865 #endif
1866 
1867 	/*
1868 	 * If the current directory is hidden, then hide all it's members
1869 	 * otherwise check if this entry needs to be hidden as well
1870 	 */
1871 	if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
1872 		s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
1873 	} else if (strcmp(short_name, ".") != 0 &&
1874 		    strcmp(short_name, "..") != 0) {
1875 		if (i_matches(short_name) || i_matches(whole_path)) {
1876 			if (verbose > 1) {
1877 				fprintf(stderr,
1878 					_("Hidden from ISO9660 tree: %s\n"),
1879 					whole_path);
1880 			}
1881 			s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
1882 		}
1883 		if (h_matches(short_name) || h_matches(whole_path)) {
1884 			if (verbose > 1) {
1885 				fprintf(stderr,
1886 					_("Hidden ISO9660 attribute: %s\n"),
1887 					whole_path);
1888 			}
1889 			s_entry->de_flags |= HIDDEN_FILE;
1890 		}
1891 	}
1892 	if (this_dir != reloc_dir &&
1893 				this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
1894 		s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1895 	} else if (strcmp(short_name, ".") != 0 &&
1896 		    strcmp(short_name, "..") != 0) {
1897 		if (j_matches(short_name) || j_matches(whole_path)) {
1898 			if (verbose > 1) {
1899 				fprintf(stderr,
1900 					_("Hidden from Joliet tree: %s\n"),
1901 					whole_path);
1902 			}
1903 			s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1904 		}
1905 	}
1906 	if (this_dir != reloc_dir &&
1907 				this_dir->dir_flags & INHIBIT_UDF_ENTRY) {
1908 		s_entry->de_flags |= INHIBIT_UDF_ENTRY;
1909 	} else if (strcmp(short_name, ".") != 0 &&
1910 		    strcmp(short_name, "..") != 0) {
1911 		if (u_matches(short_name) || u_matches(whole_path)) {
1912 			if (verbose > 1) {
1913 				fprintf(stderr,
1914 					_("Hidden from UDF tree: %s\n"),
1915 					whole_path);
1916 			}
1917 			s_entry->de_flags |= INHIBIT_UDF_ENTRY;
1918 		}
1919 	}
1920 
1921 #ifdef SORTING
1922 	/*
1923 	 * Inherit any sort weight from parent directory
1924 	 */
1925 	s_entry->sort = this_dir->sort;
1926 
1927 #ifdef  DVD_AUD_VID
1928 	/*
1929 	 * No use at all to do a sort if we don't make a dvd video/audio
1930 	 */
1931 	/*
1932 	 * Assign special weights to VIDEO_TS and AUDIO_TS files.
1933 	 * This can't be done with sort_matches for two reasons:
1934 	 * first, we need to match against the destination (DVD)
1935 	 * path rather than the source path, and second, there are
1936 	 * about 2400 different file names to check, each needing
1937 	 * a different priority, and adding that many patterns to
1938 	 * sort_matches would slow things to a crawl.
1939 	 */
1940 
1941 	if (dvd_aud_vid_flag) {
1942 		s_entry->sort = assign_dvd_weights(s_entry->name, this_dir, s_entry->sort);
1943 		/*
1944 		 * Turn on sorting if necessary, regardless of cmd-line options
1945 		 */
1946 		if ((s_entry->sort != this_dir->sort) && do_sort == 0)
1947 			do_sort++;
1948 	}
1949 #endif
1950 
1951 	/*
1952 	 * See if this entry should have a new weighting
1953 	 */
1954 	if (do_sort && strcmp(short_name, ".") != 0 &&
1955 			strcmp(short_name, "..") != 0) {
1956 		s_entry->sort = sort_matches(whole_path, s_entry->sort);
1957 	}
1958 #endif /* SORTING */
1959 
1960 	s_entry->filedir = this_dir;
1961 	s_entry->isorec.flags[0] = ISO_FILE;
1962 	if (s_entry->de_flags & HIDDEN_FILE)
1963 		s_entry->isorec.flags[0] |= ISO_EXISTENCE;
1964 	s_entry->isorec.ext_attr_length[0] = 0;
1965 	iso9660_date(s_entry->isorec.date, statbuf.st_mtime);
1966 	s_entry->isorec.file_unit_size[0] = 0;
1967 	s_entry->isorec.interleave[0] = 0;
1968 
1969 #ifdef APPLE_HYB
1970 	if (apple_both && !x_hfs) {
1971 		s_entry->hfs_ent = NULL;
1972 		s_entry->assoc = NULL;
1973 		s_entry->hfs_off = (off_t)0;
1974 		s_entry->hfs_type = htype;
1975 		if (have_rsrc) {
1976 			/* associated (rsrc) file */
1977 			s_entry->isorec.flags[0] |= ISO_ASSOCIATED;
1978 			/* set the type of HFS file */
1979 			s_entry->hfs_type = have_rsrc;
1980 			/*
1981 			 * don't want the rsrc file to be included in any
1982 			 * Joliet/UDF tree
1983 			 */
1984 			s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
1985 			s_entry->de_flags |= INHIBIT_UDF_ENTRY;
1986 		} else if (s_entry->next) {
1987 			/*
1988 			 * if previous entry is an associated file,
1989 			 * then "link" it to this file i.e. we have a
1990 			 * data/resource pair
1991 			 */
1992 			if (s_entry->next->isorec.flags[0] & ISO_ASSOCIATED) {
1993 				s_entry->assoc = s_entry->next;
1994 				/*
1995 				 * share the same HFS parameters
1996 				 */
1997 				s_entry->hfs_ent = s_entry->next->hfs_ent;
1998 				s_entry->hfs_type = s_entry->next->hfs_type;
1999 			}
2000 		}
2001 		/*
2002 		 * Allocate HFS entry if required
2003 		 */
2004 		if (apple_both && strcmp(short_name, ".") != 0 &&
2005 					strcmp(short_name, "..") != 0) {
2006 			if (!s_entry->hfs_ent) {
2007 				hfsdirent	*hfs_ent;
2008 
2009 				hfs_ent =
2010 				(hfsdirent *) e_malloc(sizeof (hfsdirent));
2011 
2012 				/*
2013 				 * Sill in the defaults
2014 				 */
2015 				memset(hfs_ent, 0, sizeof (hfsdirent));
2016 
2017 				s_entry->hfs_ent = hfs_ent;
2018 			}
2019 			/*
2020 			 * the resource fork is processed first, but the
2021 			 * data fork's time info is used in preference
2022 			 * i.e. time info is set from the resource fork
2023 			 * initially, then it is set from the data fork
2024 			 */
2025 			if (have_rsrc) {
2026 				/*
2027 				 * Set rsrc size
2028 				 */
2029 				s_entry->hfs_ent->u.file.rsize = lstatbuf.st_size;
2030 				/*
2031 				 * This will be overwritten - but might as
2032 				 * well set it here ...
2033 				 */
2034 				s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
2035 				s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
2036 			} else {
2037 				/*
2038 				 * Set data size
2039 				 */
2040 				s_entry->hfs_ent->u.file.dsize = lstatbuf.st_size;
2041 				s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
2042 				s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
2043 			}
2044 		}
2045 	}
2046 #endif	/* APPLE_HYB */
2047 
2048 	if (strcmp(short_name, ".") == 0) {
2049 		this_dir->dir_flags |= DIR_HAS_DOT;
2050 	}
2051 	if (strcmp(short_name, "..") == 0) {
2052 		this_dir->dir_flags |= DIR_HAS_DOTDOT;
2053 	}
2054 	if (this_dir->parent &&
2055 	    this_dir->parent == reloc_dir &&
2056 	    strcmp(short_name, "..") == 0) {
2057 		s_entry->inode = UNCACHED_INODE;
2058 		s_entry->dev = UNCACHED_DEVICE;
2059 		deep_flag = NEED_PL;
2060 	} else
2061 #ifdef APPLE_HYB
2062 	if (have_rsrc) {
2063 		/*
2064 		 * don't want rsrc files to be cached
2065 		 */
2066 		s_entry->de_flags |= RESOURCE_FORK;
2067 		s_entry->inode = UNCACHED_INODE;
2068 		s_entry->dev = UNCACHED_DEVICE;
2069 	} else
2070 #endif	/* APPLE_HYB */
2071 	{
2072 		s_entry->inode = STAT_INODE(statbuf);
2073 		s_entry->dev = statbuf.st_dev;
2074 	}
2075 	set_723(s_entry->isorec.volume_sequence_number,
2076 						volume_sequence_number);
2077 	iso9660_file_length(short_name, s_entry, S_ISDIR(statbuf.st_mode));
2078 	s_entry->rr_attr_size = 0;
2079 	s_entry->total_rr_attr_size = 0;
2080 	s_entry->rr_attributes = NULL;
2081 
2082 	/*
2083 	 * Directories are assigned sizes later on
2084 	 */
2085 	if (!S_ISDIR(statbuf.st_mode)) {
2086 		if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) ||
2087 			S_ISFIFO(lstatbuf.st_mode) ||
2088 				S_ISSOCK(lstatbuf.st_mode) ||
2089 #ifdef	UDF
2090 				(S_ISLNK(lstatbuf.st_mode) && !create_udfsymlinks)) {
2091 #else
2092 				FALSE) {
2093 #endif
2094 			s_entry->size = (off_t)0;
2095 			statbuf.st_size = (off_t)0;
2096 		} else {
2097 			s_entry->size = statbuf.st_size;
2098 		}
2099 
2100 		set_733((char *)s_entry->isorec.size, statbuf.st_size);
2101 	} else {
2102 		s_entry->isorec.flags[0] |= ISO_DIRECTORY;
2103 	}
2104 #ifdef APPLE_HYB
2105 	/*
2106 	 * If the directory is HFS excluded, then we don't have an hfs_ent
2107 	 */
2108 	if (apple_both && s_entry->hfs_ent &&
2109 				(s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
2110 		/*
2111 		 * Get the Mac directory name
2112 		 */
2113 		get_hfs_dir(whole_path, short_name, s_entry);
2114 
2115 		/*
2116 		 * If required, set ISO directory name from HFS name
2117 		 */
2118 		if (use_mac_name)
2119 			iso9660_file_length(s_entry->hfs_ent->name, s_entry, 1);
2120 	}
2121 #endif	/* APPLE_HYB */
2122 
2123 	if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..") != 0 &&
2124 		S_ISDIR(statbuf.st_mode) &&
2125 				this_dir->depth > RR_relocation_depth) {
2126 		struct directory *child;
2127 
2128 		/*
2129 		 * Replicate the entry for this directory.  The old one will
2130 		 * stay where it is, and it will be neutered so that it no
2131 		 * longer looks like a directory. The new one will look like
2132 		 * a directory, and it will be put in the reloc_dir.
2133 		 */
2134 		s_entry1 = dup_relocated_dir(this_dir, s_entry,
2135 					whole_path, short_name, &statbuf);
2136 
2137 		/*
2138 		 * We need to set this temporarily so that the parent to this
2139 		 * is correctly determined.
2140 		 */
2141 		s_entry1->filedir = reloc_dir;
2142 		child = find_or_create_directory(reloc_dir, whole_path,
2143 			s_entry1, 0);
2144 		free(child->de_path);		/* allocated in this case */
2145 		set_de_path(this_dir, child);
2146 
2147 
2148 /*		if (!no_scandir)*/
2149 		if (!0)
2150 			scan_directory_tree(child, whole_path, s_entry1);
2151 		s_entry1->filedir = this_dir;
2152 		deep_flag = NEED_CL;
2153 	}
2154 	if (generate_tables &&
2155 	    strcmp(s_entry->name, ".") != 0 &&
2156 	    strcmp(s_entry->name, "..") != 0) {
2157 
2158 		char	buffer[SECTOR_SIZE];
2159 		int	nchar;
2160 
2161 		switch (lstatbuf.st_mode & S_IFMT) {
2162 		case S_IFDIR:
2163 			sprintf(buffer, "D\t%s\n",
2164 				s_entry->name);
2165 			break;
2166 
2167 /*
2168  * extra for WIN32 - if it doesn't have the major/minor defined, then
2169  * S_IFBLK and S_IFCHR type files are unlikely to exist anyway ...
2170  * code similar to that in rock.c
2171  */
2172 #if 0
2173 /*
2174  * Use the device handling code from <schily/device.h>
2175  */
2176 #ifndef major
2177 #define	major(dev) (sizeof (dev_t) <= 2 ? ((dev) >> 8) : \
2178 	(sizeof (dev_t) <= 4 ? (((dev) >> 8) >> 8) : \
2179 	(((dev) >> 16) >> 16)))
2180 #define	minor(dev) (sizeof (dev_t) <= 2 ? (dev) & 0xff : \
2181 	(sizeof (dev_t) <= 4 ? (dev) & 0xffff : \
2182 	(dev) & 0xffffffff))
2183 #endif
2184 #endif
2185 
2186 #ifdef S_IFBLK
2187 		case S_IFBLK:
2188 			sprintf(buffer, "B\t%s\t%lu %lu\n",
2189 				s_entry->name,
2190 				(unsigned long) major(statbuf.st_rdev),
2191 				(unsigned long) minor(statbuf.st_rdev));
2192 			break;
2193 #endif
2194 #ifdef S_IFIFO
2195 		case S_IFIFO:
2196 			sprintf(buffer, "P\t%s\n",
2197 				s_entry->name);
2198 			break;
2199 #endif
2200 #ifdef S_IFCHR
2201 		case S_IFCHR:
2202 			sprintf(buffer, "C\t%s\t%lu %lu\n",
2203 				s_entry->name,
2204 				(unsigned long) major(statbuf.st_rdev),
2205 				(unsigned long) minor(statbuf.st_rdev));
2206 			break;
2207 #endif
2208 #ifdef S_IFLNK
2209 		case S_IFLNK:
2210 #ifdef	HAVE_READLINK
2211 			nchar = readlink(statp?short_name:whole_path,
2212 				(char *)symlink_buff,
2213 				sizeof (symlink_buff)-1);
2214 			if (nchar < 0) {
2215 				errmsg(_("Cannot read link '%s'.\n"),
2216 					statp?short_name:whole_path);
2217 			}
2218 #else
2219 			nchar = -1;
2220 #endif
2221 			symlink_buff[nchar < 0 ? 0 : nchar] = 0;
2222 			sprintf(buffer, "L\t%s\t%s\n",
2223 				s_entry->name, symlink_buff);
2224 			break;
2225 #endif
2226 #ifdef S_IFSOCK
2227 		case S_IFSOCK:
2228 			sprintf(buffer, "S\t%s\n",
2229 				s_entry->name);
2230 			break;
2231 #endif
2232 		case S_IFREG:
2233 		default:
2234 			sprintf(buffer, "F\t%s\n",
2235 				s_entry->name);
2236 			break;
2237 		};
2238 		s_entry->table = e_strdup(buffer);
2239 	}
2240 	if (S_ISDIR(statbuf.st_mode)) {
2241 		int	dflag;
2242 
2243 		if (strcmp(short_name, ".") != 0 &&
2244 		    strcmp(short_name, "..") != 0) {
2245 			struct directory *child;
2246 
2247 			child = find_or_create_directory(this_dir, whole_path,
2248 				s_entry, 1);
2249 #ifdef	USE_NO_SCANDIR
2250 			if (no_scandir)
2251 				dflag = 1;
2252 			else
2253 #endif
2254 				dflag = scan_directory_tree(child, whole_path,
2255 								s_entry);
2256 
2257 			if (!dflag) {
2258 				lstatbuf.st_mode =
2259 					(lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
2260 				if (child->contents == NULL) {
2261 					delete_directory(this_dir, child);
2262 				}
2263 			}
2264 		}
2265 		/* If unable to scan directory, mark this as a non-directory */
2266 	}
2267 	if (use_RockRidge && this_dir == root &&
2268 	    strcmp(s_entry->name, ".") == 0) {
2269 		deep_flag |= NEED_CE | NEED_SP;	/* For extension record */
2270 	}
2271 	/*
2272 	 * Now figure out how much room this file will take in the directory
2273 	 */
2274 
2275 #ifdef APPLE_HYB
2276 	/*
2277 	 * Ff the file is HFS excluded, then we don't have an hfs_ent
2278 	 */
2279 	if (apple_both && !have_rsrc && s_entry->hfs_ent) {
2280 		if (S_ISREG(lstatbuf.st_mode)) { /* it's a regular file */
2281 
2282 			/*
2283 			 * Fill in the rest of the HFS entry
2284 			 */
2285 			get_hfs_info(whole_path, short_name, s_entry);
2286 
2287 			/*
2288 			 * If required, set ISO directory name from HFS name
2289 			 */
2290 			if (use_mac_name)
2291 				iso9660_file_length(s_entry->hfs_ent->name,
2292 								s_entry, 0);
2293 
2294 			/*
2295 			 * Print details about the HFS file
2296 			 */
2297 			if (verbose > 2)
2298 				print_hfs_info(s_entry);
2299 
2300 			/*
2301 			 * copy the new ISO9660 name to the rsrc fork
2302 			 * - if it exists
2303 			 */
2304 			if (s_entry->assoc)
2305 				strcpy(s_entry->assoc->isorec.name,
2306 							s_entry->isorec.name);
2307 
2308 			/*
2309 			 * we can't handle hard links in the hybrid case, so we
2310 			 * "uncache" the file. The downside to this is that
2311 			 * hard linked files are added to the output image
2312 			 * more than once (we've already done this for rsrc
2313 			 * files)
2314 			 */
2315 			if (apple_hyb && have_rsrc) {
2316 				s_entry->de_flags |= RESOURCE_FORK;
2317 				s_entry->inode = UNCACHED_INODE;
2318 				s_entry->dev = UNCACHED_DEVICE;
2319 			}
2320 		} else if (!(s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
2321 			/* not a directory .. */
2322 
2323 			/*
2324 			 * no mac equivalent, so ignore - have to be careful
2325 			 * here, the hfs_ent may be also be for a relocated
2326 			 * directory
2327 			 */
2328 			if (s_entry->hfs_ent &&
2329 			    !(s_entry->de_flags & RELOCATED_DIRECTORY) &&
2330 			    (s_entry->isorec.flags[0] & ISO_MULTIEXTENT) == 0) {
2331 				free(s_entry->hfs_ent);
2332 			}
2333 			s_entry->hfs_ent = NULL;
2334 		}
2335 		/*
2336 		 * if the rsrc size is zero, then we don't need the entry, so
2337 		 * we might as well delete it - this will only happen if we
2338 		 * didn't know the rsrc size from the rsrc file size
2339 		 */
2340 		if (s_entry->assoc && s_entry->assoc->size == 0)
2341 			delete_rsrc_ent(s_entry);
2342 	}
2343 	if (apple_ext && s_entry->assoc) {
2344 		/*
2345 		 * Need Apple extensions for the resource fork as well
2346 		 */
2347 		generate_xa_rr_attributes(whole_path,
2348 			short_name, s_entry->assoc,
2349 			&statbuf, &lstatbuf, deep_flag | (statp?DID_CHDIR:0));
2350 	}
2351 	/* leave out resource fork for the time being */
2352 	/*
2353 	 * XXX This is most likely wrong and should just be:
2354 	 * XXX if (use_XA || use_RockRidge) {
2355 	 */
2356 /*	if ((use_XA || use_RockRidge) && !have_rsrc) {*/
2357 	if (use_XA || use_RockRidge) {
2358 #else
2359 	if (use_XA || use_RockRidge) {
2360 #endif	/* APPLE_HYB */
2361 		generate_xa_rr_attributes(whole_path,
2362 			short_name, s_entry,
2363 			&statbuf, &lstatbuf, deep_flag | (statp?DID_CHDIR:0));
2364 
2365 	}
2366 #ifdef UDF
2367 	/* set some info used for udf */
2368 	s_entry->mode = lstatbuf.st_mode;
2369 	s_entry->rdev = lstatbuf.st_rdev;
2370 	s_entry->uid = lstatbuf.st_uid;
2371 	s_entry->gid = lstatbuf.st_gid;
2372 	s_entry->atime.tv_sec = lstatbuf.st_atime;
2373 	s_entry->atime.tv_nsec = stat_ansecs(&lstatbuf);
2374 	s_entry->mtime.tv_sec = lstatbuf.st_mtime;
2375 	s_entry->mtime.tv_nsec = stat_mnsecs(&lstatbuf);
2376 	s_entry->ctime.tv_sec = lstatbuf.st_ctime;
2377 	s_entry->ctime.tv_nsec = stat_cnsecs(&lstatbuf);
2378 #endif
2379 
2380 #ifdef	USE_LARGEFILES
2381 #ifndef	MAX_EXTENT
2382 	/*
2383 	 * Allow to #define MAX_EXTENT from outside for debug purposes.
2384 	 */
2385 #ifdef	PROTOTYPES
2386 #define	LARGE_EXTENT	((off_t)0xFFFFF800UL)
2387 #define	MAX_EXTENT	((off_t)0xFFFFFFFEUL)
2388 #else
2389 #define	LARGE_EXTENT	((off_t)0xFFFFF800L)
2390 #define	MAX_EXTENT	((off_t)0xFFFFFFFEL)
2391 #endif
2392 #else	/* MAX_EXTENT */
2393 #define	LARGE_EXTENT	MAX_EXTENT & ~(off_t)2047L
2394 #endif	/* !MAX_EXTENT */
2395 	/*
2396 	 * Break up files greater than (4GB -2) into multiple extents.
2397 	 * The original entry, with ->size untouched, remains for UDF.
2398 	 * Each of the new file sections will get its own entry.
2399 	 * The file sections are the only entries actually written out to the
2400 	 * disk. The UDF entry will use "mxroot" to get the same start
2401 	 * block as the first file section, and all the sections will end up
2402 	 * in the ISO9660 directory in the correct order by "mxpart",
2403 	 * which the directory sorting routine knows about.
2404 	 *
2405 	 * If we ever need to be able to find mxpart == 1 after sorting,
2406 	 * we need to add another pointer to s_entry or to be very careful
2407 	 * with the loops above where the ISO-9660 name is copied back to
2408 	 * all multi-extent parts.
2409 	 */
2410 	if (s_entry->size > MAX_EXTENT) {
2411 		off_t	size;
2412 
2413 		s_entry->de_flags |= MULTI_EXTENT;
2414 		s_entry->isorec.flags[0] |= ISO_MULTIEXTENT;
2415 		s_entry->mxroot = s_entry;
2416 		s_entry->mxpart = 0;
2417 		set_733((char *)s_entry->isorec.size, LARGE_EXTENT);
2418 		s_entry1 = dup_directory_entry(s_entry);
2419 		s_entry->next = s_entry1;
2420 
2421 		/*
2422 		 * full size UDF version
2423 		 */
2424 		s_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
2425 #ifdef	HAVE_LARGEFILES
2426 		if (s_entry->size > (((off_t)190)*(off_t)0x3FFFF800)) {
2427 #ifndef	EOVERFLOW
2428 #define	EOVERFLOW	EFBIG
2429 #endif
2430 			errmsgno(EOVERFLOW,
2431 			_("File %s is too large - hiding from UDF tree.\n"),
2432 							whole_path);
2433 			s_entry->de_flags |= INHIBIT_UDF_ENTRY;
2434 		}
2435 #endif
2436 
2437 		/*
2438 		 * Prepare the first file multi-extent section of the file.
2439 		 */
2440 		s_entry = s_entry1;
2441 		s_entry->de_flags |= INHIBIT_UDF_ENTRY;
2442 		size = s_entry->size;
2443 		s_entry->size = LARGE_EXTENT;
2444 		s_entry->mxpart++;
2445 
2446 		/*
2447 		 * Additional extents, as needed
2448 		 */
2449 		while (size > MAX_EXTENT) {
2450 			s_entry1 = dup_directory_entry(s_entry);
2451 			s_entry->next = s_entry1;
2452 
2453 			s_entry = s_entry1;
2454 			s_entry->mxpart++;
2455 			size -= LARGE_EXTENT;
2456 		}
2457 		/*
2458 		 * That was the last one.
2459 		 */
2460 		s_entry->isorec.flags[0] &= ~ISO_MULTIEXTENT;
2461 		s_entry->size = size;
2462 		set_733((char *)s_entry->isorec.size, (UInt32_t)s_entry->size);
2463 	}
2464 #endif /* USE_LARGEFILES */
2465 
2466 	return (1);
2467 }
2468 
2469 EXPORT struct directory_entry *
dup_directory_entry(s_entry)2470 dup_directory_entry(s_entry)
2471 	struct directory_entry	*s_entry;
2472 {
2473 	struct directory_entry	*s_entry1;
2474 
2475 	s_entry1 = (struct directory_entry *)
2476 		e_malloc(sizeof (struct directory_entry));
2477 	memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
2478 
2479 	if (s_entry->rr_attributes) {
2480 		s_entry1->rr_attributes =
2481 				e_malloc(s_entry->total_rr_attr_size);
2482 		memcpy(s_entry1->rr_attributes, s_entry->rr_attributes,
2483 					s_entry->total_rr_attr_size);
2484 	}
2485 	if (s_entry->name)
2486 		s_entry1->name = e_strdup(s_entry->name);
2487 	if (s_entry->whole_name)
2488 		s_entry1->whole_name = e_strdup(s_entry->whole_name);
2489 #ifdef	APPLE_HYB
2490 	/*
2491 	 * If we also duplicate s_entry->hfs_ent, we would need to change
2492 	 * free_one_directory() and other calls to free(s_entry->hfs_ent) too.
2493 	 */
2494 #endif
2495 	return (s_entry1);
2496 }
2497 
2498 EXPORT void
generate_iso9660_directories(node,outfile)2499 generate_iso9660_directories(node, outfile)
2500 	struct directory	*node;
2501 	FILE			*outfile;
2502 {
2503 	struct directory *dpnt;
2504 
2505 	dpnt = node;
2506 
2507 	while (dpnt) {
2508 		if (dpnt->extent > session_start) {
2509 			generate_one_directory(dpnt, outfile);
2510 		}
2511 		if (dpnt->subdir)
2512 			generate_iso9660_directories(dpnt->subdir, outfile);
2513 		dpnt = dpnt->next;
2514 	}
2515 }
2516 
2517 /*
2518  * XXX This may need some work for the MVS port.
2519  */
2520 LOCAL void
set_de_path(parent,this)2521 set_de_path(parent, this)
2522 	struct directory	*parent;
2523 	struct directory	*this;
2524 {
2525 	char	*p;
2526 	size_t	len;
2527 
2528 	if (parent == NULL) {			/* We are just creating root */
2529 		this->de_path = this->whole_name;
2530 		return;
2531 	} else if (parent == root) {		/* full path == component    */
2532 		this->de_path = this->de_name;
2533 		return;
2534 	}
2535 	len = strlen(parent->de_path)+1+strlen(this->de_name)+1;
2536 	p = e_malloc(len);
2537 	js_snprintf(p, len, "%s/%s", parent->de_path, this->de_name);
2538 	this->de_path = p;
2539 }
2540 
2541 /*
2542  * Function:	find_or_create_directory
2543  *
2544  * Purpose:	Locate a directory entry in the tree, create if needed.
2545  *
2546  * Arguments:	parent & de are never NULL at the same time.
2547  */
2548 EXPORT struct directory *
find_or_create_directory(parent,path,de,flag)2549 find_or_create_directory(parent, path, de, flag)
2550 	struct directory	*parent;
2551 	char			*path;
2552 	struct directory_entry	*de;
2553 	int			flag;
2554 {
2555 	struct directory *child = 0;
2556 	struct directory *dpnt;
2557 	struct directory_entry *orig_de;
2558 	struct directory *next_brother;
2559 	const char	*cpnt;
2560 	const char	*pnt;
2561 	int		deep_flag = 0;
2562 
2563 	orig_de = de;
2564 
2565 	/*
2566 	 * XXX It seems that the tree that has been read from the
2567 	 * XXX previous session does not carry whole_name entries.
2568 	 * XXX We provide a hack in multi.c:find_or_create_directory()
2569 	 * XXX that should be removed when a reasonable method could
2570 	 * XXX be found.
2571 	 */
2572 	if (path == NULL) {
2573 		error(_("Warning: missing whole name for: '%s'\n"), de->name);
2574 		path = de->name;
2575 		if (path == NULL)
2576 			comerrno(EX_BAD, _("Panic no node name.\n"));
2577 	}
2578 	pnt = strrchr(path, PATH_SEPARATOR);
2579 	if (pnt == NULL) {
2580 		pnt = path;
2581 	} else {
2582 		pnt++;
2583 	}
2584 
2585 	if (parent != NULL) {
2586 
2587 		dpnt = parent->subdir;
2588 		if (dpnt == NULL) {
2589 			struct directory_entry *s_entry;
2590 
2591 			for (s_entry = parent->contents; s_entry;
2592 						s_entry = s_entry->next) {
2593 				if ((strcmp(s_entry->name, pnt) == 0) &&
2594 				    (s_entry->de_flags & RELOCATED_DIRECTORY)) {
2595 					return (find_or_create_directory(
2596 							reloc_dir, path, de,
2597 									flag));
2598 				}
2599 			}
2600 		}
2601 
2602 		while (dpnt) {
2603 			/*
2604 			 * Weird hack time - if there are two directories by
2605 			 * the same name in the reloc_dir, they are not
2606 			 * treated as the same thing unless the entire path
2607 			 * matches completely.
2608 			 */
2609 			if (flag && strcmp(dpnt->de_name, pnt) == 0) {
2610 
2611 				/*
2612 				 * XXX Remove test?
2613 				 * XXX dpnt->de_path should always be != NULL
2614 				 */
2615 				if (dpnt->de_path != NULL &&
2616 				    strcmp(dpnt->de_path, path) == 0)
2617 					return (dpnt);
2618 
2619 				if (parent != reloc_dir &&
2620 				    strcmp(dpnt->de_name, pnt) == 0)
2621 					return (dpnt);
2622 			}
2623 			dpnt = dpnt->next;
2624 		}
2625 	}
2626 	/*
2627 	 * We don't know if we have a valid directory entry for this one yet.
2628 	 * If not, we need to create one.
2629 	 */
2630 	if (de == NULL) {
2631 		de = (struct directory_entry *)
2632 			e_malloc(sizeof (struct directory_entry));
2633 		memset(de, 0, sizeof (struct directory_entry));
2634 		de->next = parent->contents;
2635 		parent->contents = de;
2636 		de->name = e_strdup(pnt);
2637 		de->whole_name = e_strdup(path);
2638 		de->filedir = parent;
2639 		de->isorec.flags[0] = ISO_DIRECTORY;
2640 		de->priority = 32768;
2641 		de->inode = UNCACHED_INODE;
2642 		de->dev = UNCACHED_DEVICE;
2643 		set_723(de->isorec.volume_sequence_number,
2644 						volume_sequence_number);
2645 		iso9660_file_length(pnt, de, 1);
2646 
2647 		init_fstatbuf();
2648 #ifdef APPLE_HYB
2649 		if (apple_both) {
2650 			/*
2651 			 * Give the directory an HFS entry
2652 			 */
2653 			hfsdirent	*hfs_ent;
2654 
2655 			hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
2656 
2657 			/*
2658 			 * Fill in the defaults
2659 			 */
2660 			memset(hfs_ent, 0, sizeof (hfsdirent));
2661 			hfs_ent->crdate = fstatbuf.st_ctime;
2662 			hfs_ent->mddate = fstatbuf.st_mtime;
2663 
2664 			de->hfs_ent = hfs_ent;
2665 
2666 			/*
2667 			 * Get the Mac directory name
2668 			 */
2669 			get_hfs_dir((char *)path, (char *)pnt, de);
2670 		}
2671 #endif	/* APPLE_HYB */
2672 	}
2673 	/*
2674 	 * If we don't have a directory for this one yet, then allocate it now,
2675 	 * and patch it into the tree in the appropriate place.
2676 	 */
2677 	dpnt = (struct directory *)e_malloc(sizeof (struct directory));
2678 	memset(dpnt, 0, sizeof (struct directory));
2679 	dpnt->next = NULL;
2680 	dpnt->subdir = NULL;
2681 	dpnt->self = de;
2682 	dpnt->contents = NULL;
2683 	dpnt->whole_name = e_strdup(path);
2684 	cpnt = strrchr(path, PATH_SEPARATOR);
2685 	if (cpnt)
2686 		cpnt++;
2687 	else
2688 		cpnt = path;
2689 	dpnt->de_name = e_strdup(cpnt);
2690 	dpnt->de_path = NULL;
2691 	set_de_path(parent, dpnt);
2692 	dpnt->size = 0;
2693 	dpnt->extent = 0;
2694 	dpnt->jextent = 0;
2695 	dpnt->jsize = 0;
2696 #ifdef APPLE_HYB
2697 	dpnt->hfs_ent = de->hfs_ent;
2698 #endif	/* APPLE_HYB */
2699 
2700 	if (orig_de == NULL) {
2701 		struct stat	xstatbuf;
2702 		int		sts;
2703 
2704 		/*
2705 		 * Now add a . and .. entry in the directory itself. This is a
2706 		 * little tricky - if the real directory exists, we need to
2707 		 * stat it first. Otherwise, we use the fictitious fstatbuf
2708 		 * which points to the time at which mkisofs was started.
2709 		 */
2710 		if (parent == NULL || parent->whole_name[0] == '\0')
2711 			sts = -1;
2712 		else
2713 			sts = stat_filter(parent->whole_name, &xstatbuf);
2714 		if (debug && parent) {
2715 			error(_("stat parent->whole_name: '%s' -> %d.\n"),
2716 				parent->whole_name, sts);
2717 		}
2718 		if (sts == 0) {
2719 			attach_dot_entries(dpnt, NULL, &xstatbuf);
2720 		} else {
2721 			attach_dot_entries(dpnt, NULL, NULL);
2722 		}
2723 	}
2724 	if (!parent || parent == root) {
2725 		if (!root) {
2726 			root = dpnt;	/* First time through for root	*/
2727 					/* directory only		*/
2728 			root->depth = 0;
2729 			root->parent = root;
2730 		} else {
2731 			dpnt->depth = 1;
2732 			if (!root->subdir) {
2733 				root->subdir = dpnt;
2734 			} else {
2735 				next_brother = root->subdir;
2736 				while (next_brother->next)
2737 					next_brother = next_brother->next;
2738 				next_brother->next = dpnt;
2739 			}
2740 			dpnt->parent = parent;
2741 		}
2742 	} else {
2743 		struct directory_entry *s_entry1;
2744 
2745 		/*
2746 		 * Come through here for  normal traversal of  tree
2747 		 */
2748 #ifdef DEBUG
2749 		fprintf(stderr, "%s(%d) ", path, dpnt->depth);
2750 #endif
2751 
2752 		if (parent->depth > RR_relocation_depth && use_RockRidge) {
2753 			/*
2754 			 * We come here in case that a graft-point needs to
2755 			 * create a new relocated (deep) directory.
2756 			 *
2757 			 * Replicate the entry for this directory.  The old one
2758 			 * will stay where it is, and it will be neutered so
2759 			 * that it no longer looks like a directory. The new
2760 			 * one will look like a directory, and it will be put
2761 			 * in the reloc_dir.
2762 			 */
2763 			s_entry1 = dup_relocated_dir(parent, de, path,
2764 						dpnt->de_name, &fstatbuf);
2765 			child = find_or_create_directory(reloc_dir, path,
2766 								s_entry1, 0);
2767 			free(child->de_path);	/* allocated in this case */
2768 			set_de_path(parent, child);
2769 
2770 			deep_flag |= NEED_CL;
2771 		}
2772 		if (parent->depth > RR_relocation_depth && !use_RockRidge) {
2773 			dir_nesting_warn(parent, path, FALSE);
2774 			exit(EX_BAD);
2775 		}
2776 		dpnt->parent = parent;
2777 		dpnt->depth = parent->depth + 1;
2778 
2779 		if ((deep_flag & NEED_CL) == 0) {
2780 			/*
2781 			 * Do not add this directory to the list of subdirs if
2782 			 * this is a relocated directory.
2783 			 */
2784 			if (!parent->subdir) {
2785 				parent->subdir = dpnt;
2786 			} else {
2787 				next_brother = parent->subdir;
2788 				while (next_brother->next)
2789 					next_brother = next_brother->next;
2790 				next_brother->next = dpnt;
2791 			}
2792 		}
2793 	}
2794 	/*
2795 	 * It doesn't exist for real, so we cannot add any
2796 	 * XA or Rock Ridge attributes.
2797 	 */
2798 	if (orig_de == NULL || (parent == NULL && path[0] == '\0')) {
2799 		init_fstatbuf();
2800 		fstatbuf.st_mode = new_dir_mode | S_IFDIR;
2801 		fstatbuf.st_nlink = 2;
2802 		if ((use_XA || use_RockRidge) &&
2803 		    !(parent == NULL && path[0] == '\0')) {
2804 			/*
2805 			 * We cannot set up RR attrubutes for the real
2806 			 * ISO-9660 root directory. This is why we
2807 			 * check for parent == NULL && path[0] == '\0'.
2808 			 */
2809 			generate_xa_rr_attributes("",
2810 				(char *)pnt, de,
2811 				&fstatbuf,
2812 				&fstatbuf, deep_flag);
2813 		}
2814 #ifdef UDF
2815 		/* set some info used for udf */
2816 		de->mode = fstatbuf.st_mode;
2817 		de->uid =  fstatbuf.st_uid;
2818 		de->gid =  fstatbuf.st_gid;
2819 		de->atime.tv_sec = fstatbuf.st_atime;
2820 		de->atime.tv_nsec = stat_ansecs(&fstatbuf);
2821 		de->mtime.tv_sec = fstatbuf.st_mtime;
2822 		de->mtime.tv_nsec = stat_mnsecs(&fstatbuf);
2823 		de->ctime.tv_sec = fstatbuf.st_ctime;
2824 		de->ctime.tv_nsec = stat_cnsecs(&fstatbuf);
2825 #endif
2826 		iso9660_date(de->isorec.date, fstatbuf.st_mtime);
2827 	}
2828 	if (child)
2829 		return (child);	/* Return reloaction target */
2830 
2831 	return (dpnt);
2832 }
2833 
2834 /*
2835  * Function:	delete_directory
2836  *
2837  * Purpose:	Locate a directory entry in the tree, create if needed.
2838  *
2839  * Arguments:
2840  */
2841 LOCAL void
delete_directory(parent,child)2842 delete_directory(parent, child)
2843 	struct directory	*parent;
2844 	struct directory	*child;
2845 {
2846 	struct directory *tdir;
2847 
2848 	if (child == NULL)
2849 		return;
2850 	if (child->contents != NULL) {
2851 		comerrno(EX_BAD, _("Unable to delete non-empty directory\n"));
2852 	}
2853 	free(child->whole_name);
2854 	child->whole_name = NULL;
2855 
2856 	free(child->de_name);
2857 	child->de_name = NULL;
2858 
2859 #ifdef APPLE_HYB
2860 	if (apple_both && child->hfs_ent)
2861 		free(child->hfs_ent);
2862 #endif	/* APPLE_HYB */
2863 
2864 	if (parent->subdir == child) {
2865 		parent->subdir = child->next;
2866 	} else {
2867 		for (tdir = parent->subdir; tdir != NULL && tdir->next != NULL;
2868 							tdir = tdir->next) {
2869 			if (tdir->next == child) {
2870 				tdir->next = child->next;
2871 				break;
2872 			}
2873 		}
2874 		if (tdir == NULL || tdir->next != child->next) {
2875 			comerrno(EX_BAD,
2876 			_("Unable to locate child directory in parent list\n"));
2877 		}
2878 	}
2879 	free(child);
2880 }
2881 
2882 EXPORT int
sort_tree(node)2883 sort_tree(node)
2884 	struct directory	*node;
2885 {
2886 	struct directory *dpnt;
2887 	int		ret = 0;
2888 
2889 	dpnt = node;
2890 
2891 	while (dpnt) {
2892 		ret = sort_n_finish(dpnt);
2893 		if (ret) {
2894 			break;
2895 		}
2896 		if (dpnt->subdir)
2897 			sort_tree(dpnt->subdir);
2898 		dpnt = dpnt->next;
2899 	}
2900 	return (ret);
2901 }
2902 
2903 EXPORT void
dump_tree(node)2904 dump_tree(node)
2905 	struct directory *node;
2906 {
2907 	struct directory *dpnt;
2908 
2909 	dpnt = node;
2910 
2911 	while (dpnt) {
2912 		fprintf(stderr, "%4d %5d %s\n",
2913 				dpnt->extent, dpnt->size, dpnt->de_name);
2914 		if (dpnt->subdir)
2915 			dump_tree(dpnt->subdir);
2916 		dpnt = dpnt->next;
2917 	}
2918 }
2919 
2920 /*
2921  * something quick and dirty to locate a file given a path
2922  * recursively walks down path in filename until it finds the
2923  * directory entry for the desired file
2924  */
2925 EXPORT struct directory_entry *
search_tree_file(node,filename)2926 search_tree_file(node, filename)
2927 	struct directory *node;
2928 	char		*filename;
2929 {
2930 	struct directory_entry *depnt;
2931 	struct directory *dpnt;
2932 	char		*p1;
2933 	char		*rest;
2934 	char		*subdir;
2935 
2936 	/*
2937 	 * Strip off next directory name from filename:
2938 	 */
2939 	subdir = e_strdup(filename);
2940 
2941 	if ((p1 = strchr(subdir, '/')) == subdir) {
2942 		fprintf(stderr,
2943 		_("call to search_tree_file with an absolute path, stripping\n"));
2944 		fprintf(stderr,
2945 		_("initial path separator. Hope this was intended...\n"));
2946 		memmove(subdir, subdir + 1, strlen(subdir) - 1);
2947 		p1 = strchr(subdir, '/');
2948 	}
2949 	/*
2950 	 * Do we need to find a subdirectory?
2951 	 */
2952 	if (p1) {
2953 		*p1 = '\0';
2954 
2955 #ifdef DEBUG_TORITO
2956 		fprintf(stderr, _("Looking for subdir called %s\n"), p1);
2957 #endif
2958 
2959 		rest = p1 + 1;
2960 
2961 #ifdef DEBUG_TORITO
2962 		fprintf(stderr, _("Remainder of path name is now %s\n"), rest);
2963 #endif
2964 
2965 		dpnt = node->subdir;
2966 		while (dpnt) {
2967 #ifdef DEBUG_TORITO
2968 			fprintf(stderr,
2969 				"%4d %5d %s\n", dpnt->extent, dpnt->size,
2970 				dpnt->de_name);
2971 #endif
2972 			if (strcmp(subdir, dpnt->de_name) == 0) {
2973 #ifdef DEBUG_TORITO
2974 				fprintf(stderr,
2975 				_("Calling next level with filename = %s\n"), rest);
2976 #endif
2977 				return (search_tree_file(dpnt, rest));
2978 			}
2979 			dpnt = dpnt->next;
2980 		}
2981 
2982 		/*
2983 		 * If we got here means we couldn't find the subdir.
2984 		 */
2985 		return (NULL);
2986 	} else {
2987 		/*
2988 		 * Look for a normal file now
2989 		 */
2990 		depnt = node->contents;
2991 		while (depnt) {
2992 #ifdef DEBUG_TORITO
2993 			fprintf(stderr, "%4d %5d %s\n", depnt->isorec.extent,
2994 				depnt->size, depnt->name);
2995 #endif
2996 			if (strcmp(filename, depnt->name) == 0) {
2997 #ifdef DEBUG_TORITO
2998 				fprintf(stderr, _("Found our file %s"), filename);
2999 #endif
3000 				return (depnt);
3001 			}
3002 			depnt = depnt->next;
3003 		}
3004 		/*
3005 		 * If we got here means we couldn't find the subdir.
3006 		 */
3007 		return (NULL);
3008 	}
3009 #ifdef	ERIC_FUN
3010 	fprintf(stderr, _("We cant get here in search_tree_file :-/ \n"));
3011 #endif
3012 }
3013 
3014 EXPORT void
init_fstatbuf()3015 init_fstatbuf()
3016 {
3017 	struct timeval	current_time;
3018 extern	struct timeval	tv_begun;
3019 
3020 	if (fstatbuf.st_ctime == 0) {
3021 		current_time = tv_begun;
3022 		if (rationalize_uid)
3023 			fstatbuf.st_uid = uid_to_use;
3024 		else
3025 			fstatbuf.st_uid = getuid();
3026 		if (rationalize_gid)
3027 			fstatbuf.st_gid = gid_to_use;
3028 		else
3029 			fstatbuf.st_gid = getgid();
3030 
3031 		current_time.tv_usec *= 1000;
3032 		fstatbuf.st_ctime = current_time.tv_sec;
3033 		stat_set_ansecs(&fstatbuf, current_time.tv_usec);
3034 		fstatbuf.st_mtime = current_time.tv_sec;
3035 		stat_set_mnsecs(&fstatbuf, current_time.tv_usec);
3036 		fstatbuf.st_atime = current_time.tv_sec;
3037 		stat_set_cnsecs(&fstatbuf, current_time.tv_usec);
3038 	}
3039 }
3040