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