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(¤t_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(¤t_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