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