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