2998 lines
76 KiB
C
2998 lines
76 KiB
C
|
/* @(#)tree.c 1.137 16/12/13 joerg */
|
||
|
#include <schily/mconfig.h>
|
||
|
#ifndef lint
|
||
|
static UConst char sccsid[] =
|
||
|
"@(#)tree.c 1.137 16/12/13 joerg";
|
||
|
#endif
|
||
|
/*
|
||
|
* File tree.c - scan directory tree and build memory structures for iso9660
|
||
|
* filesystem
|
||
|
*
|
||
|
* Written by Eric Youngdale (1993).
|
||
|
*
|
||
|
* Copyright 1993 Yggdrasil Computing, Incorporated
|
||
|
* Copyright (c) 1999,2000-2016 J. Schilling
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||
|
* any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
*/
|
||
|
/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
|
||
|
|
||
|
/* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
|
||
|
|
||
|
/* DUPLICATES_ONCE Alex Kopylov cdrtools@bootcd.ru 19.06.2004 */
|
||
|
|
||
|
#include "mkisofs.h"
|
||
|
#include "rock.h"
|
||
|
#include "match.h"
|
||
|
#include <schily/time.h>
|
||
|
#include <schily/errno.h>
|
||
|
#include <schily/fcntl.h>
|
||
|
#include <schily/device.h>
|
||
|
#include <schily/schily.h>
|
||
|
|
||
|
#ifdef UDF
|
||
|
#include "udf.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef VMS
|
||
|
#include <sys/file.h>
|
||
|
#include <vms/fabdef.h>
|
||
|
#include "vms.h"
|
||
|
#endif
|
||
|
|
||
|
LOCAL Uchar symlink_buff[PATH_MAX+1];
|
||
|
|
||
|
LOCAL char *filetype __PR((int t));
|
||
|
LOCAL char *rstr __PR((char *s1, char *s2));
|
||
|
LOCAL void stat_fix __PR((struct stat *st));
|
||
|
EXPORT int stat_filter __PR((char *path, struct stat *st));
|
||
|
EXPORT int lstat_filter __PR((char *path, struct stat *st));
|
||
|
LOCAL int sort_n_finish __PR((struct directory *this_dir));
|
||
|
LOCAL void generate_reloc_directory __PR((void));
|
||
|
EXPORT void attach_dot_entries __PR((struct directory *dirnode,
|
||
|
struct stat *this_stat,
|
||
|
struct stat *parent_stat));
|
||
|
EXPORT char *find_rr_attribute __PR((unsigned char *pnt, int len,
|
||
|
char *attr_type));
|
||
|
EXPORT void finish_cl_pl_entries __PR((void));
|
||
|
LOCAL void dir_nesting_warn __PR((struct directory *this_dir,
|
||
|
char *path, int contflag));
|
||
|
EXPORT int scan_directory_tree __PR((struct directory *this_dir,
|
||
|
char *path,
|
||
|
struct directory_entry *de));
|
||
|
LOCAL struct directory_entry *
|
||
|
dup_relocated_dir __PR((struct directory *this_dir,
|
||
|
struct directory_entry *s_entry,
|
||
|
char *whole_path,
|
||
|
char *short_name,
|
||
|
struct stat *statp));
|
||
|
EXPORT int insert_file_entry __PR((struct directory *this_dir,
|
||
|
char *whole_path,
|
||
|
char *short_name,
|
||
|
struct stat *statp, int have_rsrc));
|
||
|
EXPORT struct directory_entry *
|
||
|
dup_directory_entry __PR((struct directory_entry *s_entry));
|
||
|
EXPORT void generate_iso9660_directories __PR((struct directory *node,
|
||
|
FILE *outfile));
|
||
|
|
||
|
LOCAL void set_de_path __PR((struct directory *parent,
|
||
|
struct directory *this));
|
||
|
|
||
|
EXPORT struct directory *
|
||
|
find_or_create_directory __PR((struct directory *parent,
|
||
|
char *path,
|
||
|
struct directory_entry *de,
|
||
|
int flag));
|
||
|
LOCAL void delete_directory __PR((struct directory *parent,
|
||
|
struct directory *child));
|
||
|
EXPORT int sort_tree __PR((struct directory *node));
|
||
|
EXPORT void dump_tree __PR((struct directory *node));
|
||
|
EXPORT struct directory_entry *
|
||
|
search_tree_file __PR((struct directory *node,
|
||
|
char *filename));
|
||
|
EXPORT void init_fstatbuf __PR((void));
|
||
|
|
||
|
extern int verbose;
|
||
|
struct stat fstatbuf; /* We use this for the artificial */
|
||
|
/* entries we create */
|
||
|
struct stat root_statbuf; /* Stat buffer for root directory */
|
||
|
struct directory *reloc_dir;
|
||
|
|
||
|
LOCAL char *
|
||
|
filetype(t)
|
||
|
int t;
|
||
|
{
|
||
|
static char unkn[32];
|
||
|
|
||
|
if (S_ISFIFO(t)) /* 1 */
|
||
|
return ("fifo");
|
||
|
if (S_ISCHR(t)) /* 2 */
|
||
|
return ("chr");
|
||
|
if (S_ISMPC(t)) /* 3 */
|
||
|
return ("multiplexed chr");
|
||
|
if (S_ISDIR(t)) /* 4 */
|
||
|
return ("dir");
|
||
|
if (S_ISNAM(t)) /* 5 */
|
||
|
return ("named file");
|
||
|
if (S_ISBLK(t)) /* 6 */
|
||
|
return ("blk");
|
||
|
if (S_ISMPB(t)) /* 7 */
|
||
|
return ("multiplexed blk");
|
||
|
if (S_ISREG(t)) /* 8 */
|
||
|
return ("regular file");
|
||
|
if (S_ISCTG(t)) /* 9 */
|
||
|
return ("contiguous file");
|
||
|
if (S_ISLNK(t)) /* 10 */
|
||
|
return ("symlink");
|
||
|
if (S_ISSHAD(t)) /* 11 */
|
||
|
return ("Solaris shadow inode");
|
||
|
if (S_ISSOCK(t)) /* 12 */
|
||
|
return ("socket");
|
||
|
if (S_ISDOOR(t)) /* 13 */
|
||
|
return ("door");
|
||
|
if (S_ISWHT(t)) /* 14 */
|
||
|
return ("whiteout");
|
||
|
if (S_ISEVC(t)) /* 15 */
|
||
|
return ("event count");
|
||
|
|
||
|
/*
|
||
|
* Needs to be last in case somebody makes this
|
||
|
* a supported file type.
|
||
|
*/
|
||
|
if ((t & S_IFMT) == 0) /* 0 (unallocated) */
|
||
|
return ("unallocated");
|
||
|
|
||
|
sprintf(unkn, "octal '%o'", t & S_IFMT);
|
||
|
return (unkn);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check if s1 ends in strings s2
|
||
|
*/
|
||
|
LOCAL char *
|
||
|
rstr(s1, s2)
|
||
|
char *s1;
|
||
|
char *s2;
|
||
|
{
|
||
|
int l1;
|
||
|
int l2;
|
||
|
|
||
|
l1 = strlen(s1);
|
||
|
l2 = strlen(s2);
|
||
|
if (l2 > l1)
|
||
|
return ((char *)NULL);
|
||
|
|
||
|
if (strcmp(&s1[l1 - l2], s2) == 0)
|
||
|
return (&s1[l1 - l2]);
|
||
|
return ((char *)NULL);
|
||
|
}
|
||
|
|
||
|
LOCAL void
|
||
|
stat_fix(st)
|
||
|
struct stat *st;
|
||
|
{
|
||
|
int adjust_modes = 0;
|
||
|
|
||
|
if (S_ISREG(st->st_mode))
|
||
|
adjust_modes = rationalize_filemode;
|
||
|
else if (S_ISDIR(st->st_mode))
|
||
|
adjust_modes = rationalize_dirmode;
|
||
|
else
|
||
|
adjust_modes = (rationalize_filemode || rationalize_dirmode);
|
||
|
|
||
|
/*
|
||
|
* If rationalizing, override the uid and gid, since the
|
||
|
* originals will only be useful on the author's system.
|
||
|
*/
|
||
|
if (rationalize_uid)
|
||
|
st->st_uid = uid_to_use;
|
||
|
if (rationalize_gid)
|
||
|
st->st_gid = gid_to_use;
|
||
|
|
||
|
if (adjust_modes) {
|
||
|
|
||
|
if (S_ISREG(st->st_mode) && (filemode_to_use != 0)) {
|
||
|
st->st_mode = filemode_to_use | S_IFREG;
|
||
|
} else if (S_ISDIR(st->st_mode) && (dirmode_to_use != 0)) {
|
||
|
st->st_mode = dirmode_to_use | S_IFDIR;
|
||
|
} else {
|
||
|
/*
|
||
|
* Make sure the file modes make sense. Turn
|
||
|
* on all read bits. Turn on all exec/search
|
||
|
* bits if any exec/search bit is set. Turn
|
||
|
* off all write bits, and all special mode
|
||
|
* bits (on a r/o fs lock bits are useless,
|
||
|
* and with uid+gid 0 don't want set-id bits,
|
||
|
* either).
|
||
|
*/
|
||
|
|
||
|
st->st_mode |= 0444;
|
||
|
#if !defined(_WIN32) && !defined(__DJGPP__) /* make all file "executable" */
|
||
|
if (st->st_mode & 0111)
|
||
|
#endif
|
||
|
st->st_mode |= 0111;
|
||
|
st->st_mode &= ~07222;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EXPORT int
|
||
|
stat_filter(path, st)
|
||
|
char *path;
|
||
|
struct stat *st;
|
||
|
{
|
||
|
int result = stat(path, st);
|
||
|
|
||
|
if (result >= 0 && rationalize)
|
||
|
stat_fix(st);
|
||
|
return (result);
|
||
|
}
|
||
|
|
||
|
EXPORT int
|
||
|
lstat_filter(path, st)
|
||
|
char *path;
|
||
|
struct stat *st;
|
||
|
{
|
||
|
int result = lstat(path, st);
|
||
|
|
||
|
if (result >= 0 && rationalize)
|
||
|
stat_fix(st);
|
||
|
return (result);
|
||
|
}
|
||
|
|
||
|
LOCAL int
|
||
|
sort_n_finish(this_dir)
|
||
|
struct directory *this_dir;
|
||
|
{
|
||
|
struct directory_entry *s_entry;
|
||
|
struct directory_entry *s_entry1;
|
||
|
struct directory_entry *table;
|
||
|
int count;
|
||
|
int d1;
|
||
|
int d2;
|
||
|
int d3;
|
||
|
register int new_reclen;
|
||
|
char *c;
|
||
|
int status = 0;
|
||
|
int tablesize = 0;
|
||
|
char newname[MAX_ISONAME+1];
|
||
|
char rootname[MAX_ISONAME+1];
|
||
|
char extname[MAX_ISONAME+1];
|
||
|
|
||
|
/*
|
||
|
* Here we can take the opportunity to toss duplicate entries from the
|
||
|
* directory.
|
||
|
*/
|
||
|
/* ignore if it's hidden */
|
||
|
if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
|
||
|
return (0);
|
||
|
}
|
||
|
table = NULL;
|
||
|
|
||
|
init_fstatbuf();
|
||
|
|
||
|
/*
|
||
|
* If we had artificially created this directory, then we might be
|
||
|
* missing the required '.' entries. Create these now if we need
|
||
|
* them.
|
||
|
*/
|
||
|
if ((this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) !=
|
||
|
(DIR_HAS_DOT | DIR_HAS_DOTDOT)) {
|
||
|
attach_dot_entries(this_dir, NULL, NULL);
|
||
|
}
|
||
|
flush_file_hash();
|
||
|
s_entry = this_dir->contents;
|
||
|
while (s_entry) {
|
||
|
#ifdef USE_LARGEFILES
|
||
|
/*
|
||
|
* Skip all but the last extent from a multi extent file,
|
||
|
* we like them all have the same name.
|
||
|
*/
|
||
|
if ((s_entry->de_flags & MULTI_EXTENT) &&
|
||
|
(s_entry->isorec.flags[0] & ISO_MULTIEXTENT)) {
|
||
|
s_entry = s_entry->next;
|
||
|
continue;
|
||
|
}
|
||
|
#endif
|
||
|
/* ignore if it's hidden */
|
||
|
if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
|
||
|
s_entry = s_entry->next;
|
||
|
continue;
|
||
|
}
|
||
|
/*
|
||
|
* First assume no conflict, and handle this case
|
||
|
*/
|
||
|
if (!(s_entry1 = find_file_hash(s_entry->isorec.name))) {
|
||
|
add_file_hash(s_entry);
|
||
|
s_entry = s_entry->next;
|
||
|
continue;
|
||
|
}
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* if the pair are associated, then skip (as they have the
|
||
|
* same name!)
|
||
|
*/
|
||
|
if (apple_both && s_entry1->assoc &&
|
||
|
s_entry1->assoc == s_entry) {
|
||
|
s_entry = s_entry->next;
|
||
|
continue;
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
if (s_entry1 == s_entry) {
|
||
|
comerrno(EX_BAD,
|
||
|
_("Fatal goof, file '%s' already in hash table.\n"),
|
||
|
s_entry->isorec.name);
|
||
|
}
|
||
|
/*
|
||
|
* OK, handle the conflicts. Try substitute names until we
|
||
|
* come up with a winner
|
||
|
*/
|
||
|
strlcpy(rootname, s_entry->isorec.name, sizeof (rootname));
|
||
|
/*
|
||
|
* Strip off the non-significant part of the name so that we
|
||
|
* are left with a sensible root filename. If we don't find
|
||
|
* a '.', then try a ';'.
|
||
|
*/
|
||
|
c = strchr(rootname, '.');
|
||
|
/*
|
||
|
* In case we ever allow more than on dot, only modify the
|
||
|
* section past the last dot if the file name starts with a
|
||
|
* dot.
|
||
|
*/
|
||
|
if (c != NULL && c == rootname && c != strrchr(rootname, '.')) {
|
||
|
c = strrchr(rootname, '.');
|
||
|
}
|
||
|
extname[0] = '\0'; /* In case we have no ext. */
|
||
|
if (c) {
|
||
|
strlcpy(extname, c, sizeof (extname));
|
||
|
*c = 0; /* Cut off complete ext. */
|
||
|
} else {
|
||
|
/*
|
||
|
* Could not find any '.'.
|
||
|
*/
|
||
|
c = strchr(rootname, ';');
|
||
|
if (c) {
|
||
|
*c = 0; /* Cut off version number */
|
||
|
}
|
||
|
}
|
||
|
c = strchr(extname, ';');
|
||
|
if (c) {
|
||
|
*c = 0; /* Cut off version number */
|
||
|
}
|
||
|
d1 = strlen(rootname);
|
||
|
if (full_iso9660_filenames || iso9660_level > 1) {
|
||
|
d2 = strlen(extname);
|
||
|
/*
|
||
|
* 31/37 chars minus the 3 characters we are
|
||
|
* appending below to create unique filenames.
|
||
|
*/
|
||
|
if ((d1 + d2) > (iso9660_namelen - 3))
|
||
|
rootname[iso9660_namelen - 3 - d2] = 0;
|
||
|
} else {
|
||
|
if (d1 > 5)
|
||
|
rootname[5] = 0;
|
||
|
}
|
||
|
new_reclen = strlen(rootname);
|
||
|
sprintf(newname, "%s000%s%s",
|
||
|
rootname,
|
||
|
extname,
|
||
|
((s_entry->isorec.flags[0] & ISO_DIRECTORY) ||
|
||
|
omit_version_number ? "" : ";1"));
|
||
|
|
||
|
for (d1 = 0; d1 < 36; d1++) {
|
||
|
for (d2 = 0; d2 < 36; d2++) {
|
||
|
for (d3 = 0; d3 < 36; d3++) {
|
||
|
newname[new_reclen + 0] =
|
||
|
(d1 <= 9 ? '0' + d1 : 'A' + d1 - 10);
|
||
|
newname[new_reclen + 1] =
|
||
|
(d2 <= 9 ? '0' + d2 : 'A' + d2 - 10);
|
||
|
newname[new_reclen + 2] =
|
||
|
(d3 <= 9 ? '0' + d3 : 'A' + d3 - 10);
|
||
|
if (debug)
|
||
|
error(_("NEW name '%s'\n"), newname);
|
||
|
|
||
|
#ifdef VMS
|
||
|
/* Sigh. VAXCRTL seems to be broken here */
|
||
|
{
|
||
|
int ijk = 0;
|
||
|
|
||
|
while (newname[ijk]) {
|
||
|
if (newname[ijk] == ' ')
|
||
|
newname[ijk] = '0';
|
||
|
ijk++;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (!find_file_hash(newname))
|
||
|
goto got_valid_name;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If we fell off the bottom here, we were in real trouble.
|
||
|
*/
|
||
|
comerrno(EX_BAD,
|
||
|
_("Unable to generate unique name for file %s\n"),
|
||
|
s_entry->name);
|
||
|
|
||
|
got_valid_name:
|
||
|
/*
|
||
|
* OK, now we have a good replacement name. Now decide which
|
||
|
* one of these two beasts should get the name changed
|
||
|
*/
|
||
|
if (s_entry->priority < s_entry1->priority) {
|
||
|
if (verbose > 0) {
|
||
|
fprintf(stderr, _("Using %s for %s%s%s (%s)\n"),
|
||
|
newname,
|
||
|
this_dir->whole_name, SPATH_SEPARATOR,
|
||
|
s_entry->name, s_entry1->name);
|
||
|
}
|
||
|
|
||
|
s_entry->isorec.name_len[0] = strlen(newname);
|
||
|
new_reclen = offsetof(struct iso_directory_record,
|
||
|
name[0]) +
|
||
|
strlen(newname);
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
if (new_reclen & 1)
|
||
|
new_reclen++; /* Pad to an even byte */
|
||
|
new_reclen += s_entry->rr_attr_size;
|
||
|
}
|
||
|
if (new_reclen & 1)
|
||
|
new_reclen++; /* Pad to an even byte */
|
||
|
s_entry->isorec.length[0] = new_reclen;
|
||
|
strcpy(s_entry->isorec.name, newname);
|
||
|
#ifdef USE_LARGEFILES
|
||
|
if (s_entry->de_flags & MULTI_EXTENT) {
|
||
|
struct directory_entry *s_e;
|
||
|
|
||
|
/*
|
||
|
* Copy over the new name to all other entries
|
||
|
*/
|
||
|
for (s_e = s_entry->mxroot;
|
||
|
s_e && s_e->mxroot == s_entry->mxroot;
|
||
|
s_e = s_e->next) {
|
||
|
s_e->isorec.length[0] = new_reclen;
|
||
|
s_e->isorec.name_len[0] = s_entry->isorec.name_len[0];
|
||
|
strcpy(s_e->isorec.name, newname);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* Has resource fork - needs new name
|
||
|
*/
|
||
|
if (apple_both && s_entry->assoc) {
|
||
|
struct directory_entry *s_entry2 =
|
||
|
s_entry->assoc;
|
||
|
|
||
|
/*
|
||
|
* resource fork name *should* be the same as
|
||
|
* the data fork
|
||
|
*/
|
||
|
s_entry2->isorec.name_len[0] =
|
||
|
s_entry->isorec.name_len[0];
|
||
|
strcpy(s_entry2->isorec.name,
|
||
|
s_entry->isorec.name);
|
||
|
s_entry2->isorec.length[0] = new_reclen;
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
} else {
|
||
|
delete_file_hash(s_entry1);
|
||
|
if (verbose > 0) {
|
||
|
fprintf(stderr, _("Using %s for %s%s%s (%s)\n"),
|
||
|
newname,
|
||
|
this_dir->whole_name, SPATH_SEPARATOR,
|
||
|
s_entry1->name, s_entry->name);
|
||
|
}
|
||
|
s_entry1->isorec.name_len[0] = strlen(newname);
|
||
|
new_reclen = offsetof(struct iso_directory_record,
|
||
|
name[0]) +
|
||
|
strlen(newname);
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
if (new_reclen & 1)
|
||
|
new_reclen++; /* Pad to an even byte */
|
||
|
new_reclen += s_entry1->rr_attr_size;
|
||
|
}
|
||
|
if (new_reclen & 1)
|
||
|
new_reclen++; /* Pad to an even byte */
|
||
|
s_entry1->isorec.length[0] = new_reclen;
|
||
|
strcpy(s_entry1->isorec.name, newname);
|
||
|
#ifdef USE_LARGEFILES
|
||
|
if (s_entry1->de_flags & MULTI_EXTENT) {
|
||
|
struct directory_entry *s_e;
|
||
|
|
||
|
/*
|
||
|
* Copy over the new name to all other entries
|
||
|
*/
|
||
|
for (s_e = s_entry1->mxroot;
|
||
|
s_e && s_e->mxroot == s_entry1->mxroot;
|
||
|
s_e = s_e->next) {
|
||
|
s_e->isorec.length[0] = new_reclen;
|
||
|
s_e->isorec.name_len[0] = s_entry1->isorec.name_len[0];
|
||
|
strcpy(s_e->isorec.name, newname);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
add_file_hash(s_entry1);
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* Has resource fork - needs new name
|
||
|
*/
|
||
|
if (apple_both && s_entry1->assoc) {
|
||
|
struct directory_entry *s_entry2 =
|
||
|
s_entry1->assoc;
|
||
|
|
||
|
/*
|
||
|
* resource fork name *should* be the same as
|
||
|
* the data fork
|
||
|
*/
|
||
|
s_entry2->isorec.name_len[0] =
|
||
|
s_entry1->isorec.name_len[0];
|
||
|
strcpy(s_entry2->isorec.name,
|
||
|
s_entry1->isorec.name);
|
||
|
s_entry2->isorec.length[0] = new_reclen;
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
}
|
||
|
add_file_hash(s_entry);
|
||
|
s_entry = s_entry->next;
|
||
|
}
|
||
|
|
||
|
if (generate_tables &&
|
||
|
!find_file_hash(trans_tbl) &&
|
||
|
(reloc_dir != this_dir) &&
|
||
|
(this_dir->extent == 0)) {
|
||
|
/*
|
||
|
* First we need to figure out how big this table is
|
||
|
*/
|
||
|
for (s_entry = this_dir->contents; s_entry;
|
||
|
s_entry = s_entry->next) {
|
||
|
if (strcmp(s_entry->name, ".") == 0 ||
|
||
|
strcmp(s_entry->name, "..") == 0)
|
||
|
continue;
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* Skip table entry for the resource fork
|
||
|
*/
|
||
|
if (apple_both &&
|
||
|
(s_entry->isorec.flags[0] & ISO_ASSOCIATED))
|
||
|
continue;
|
||
|
#endif /* APPLE_HYB */
|
||
|
if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
|
||
|
continue;
|
||
|
if (s_entry->table) {
|
||
|
/*
|
||
|
* Max namelen, a space before and a space
|
||
|
* after the iso filename.
|
||
|
*/
|
||
|
tablesize += MAX_ISONAME + 2 +
|
||
|
strlen(s_entry->table);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (tablesize > 0) {
|
||
|
table = (struct directory_entry *)
|
||
|
e_malloc(sizeof (struct directory_entry));
|
||
|
memset(table, 0, sizeof (struct directory_entry));
|
||
|
table->table = NULL;
|
||
|
table->next = this_dir->contents;
|
||
|
this_dir->contents = table;
|
||
|
|
||
|
table->filedir = root;
|
||
|
table->isorec.flags[0] = ISO_FILE;
|
||
|
table->priority = 32768;
|
||
|
iso9660_date(table->isorec.date, fstatbuf.st_mtime);
|
||
|
table->inode = TABLE_INODE;
|
||
|
table->dev = UNCACHED_DEVICE;
|
||
|
set_723(table->isorec.volume_sequence_number,
|
||
|
volume_sequence_number);
|
||
|
set_733((char *)table->isorec.size, tablesize);
|
||
|
table->size = tablesize;
|
||
|
table->filedir = this_dir;
|
||
|
if (jhide_trans_tbl)
|
||
|
table->de_flags |= INHIBIT_JOLIET_ENTRY;
|
||
|
/*
|
||
|
* Always hide transtable from UDF tree.
|
||
|
*/
|
||
|
table->de_flags |= INHIBIT_UDF_ENTRY;
|
||
|
/* table->name = e_strdup("<translation table>");*/
|
||
|
table->name = e_strdup(trans_tbl);
|
||
|
/*
|
||
|
* We use sprintf() to create the strings, for this reason
|
||
|
* we need to add one byte for the null character at the
|
||
|
* end of the string even though we don't use it.
|
||
|
*/
|
||
|
table->table = (char *)e_malloc(ISO_ROUND_UP(tablesize)+1);
|
||
|
memset(table->table, 0, ISO_ROUND_UP(tablesize)+1);
|
||
|
iso9660_file_length(trans_tbl, table, 0);
|
||
|
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
fstatbuf.st_mode = 0444 | S_IFREG;
|
||
|
fstatbuf.st_nlink = 1;
|
||
|
generate_xa_rr_attributes("",
|
||
|
trans_tbl, table,
|
||
|
&fstatbuf, &fstatbuf, 0);
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* We have now chosen the 8.3 names and we should now know the length
|
||
|
* of every entry in the directory.
|
||
|
*/
|
||
|
for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) {
|
||
|
/* skip if it's hidden */
|
||
|
if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
|
||
|
continue;
|
||
|
}
|
||
|
new_reclen = strlen(s_entry->isorec.name);
|
||
|
|
||
|
/*
|
||
|
* First update the path table sizes for directories.
|
||
|
*/
|
||
|
if (s_entry->isorec.flags[0] & ISO_DIRECTORY) {
|
||
|
if (strcmp(s_entry->name, ".") != 0 &&
|
||
|
strcmp(s_entry->name, "..") != 0) {
|
||
|
path_table_size += new_reclen +
|
||
|
offsetof(struct iso_path_table,
|
||
|
name[0]);
|
||
|
if (new_reclen & 1)
|
||
|
path_table_size++;
|
||
|
} else {
|
||
|
new_reclen = 1;
|
||
|
if (this_dir == root && strlen(s_entry->name)
|
||
|
== 1) {
|
||
|
path_table_size += new_reclen +
|
||
|
offsetof(struct iso_path_table,
|
||
|
name[0]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (path_table_size & 1)
|
||
|
path_table_size++; /* For odd lengths we pad */
|
||
|
s_entry->isorec.name_len[0] = new_reclen;
|
||
|
|
||
|
new_reclen += offsetof(struct iso_directory_record, name[0]);
|
||
|
|
||
|
if (new_reclen & 1)
|
||
|
new_reclen++;
|
||
|
|
||
|
new_reclen += s_entry->rr_attr_size;
|
||
|
|
||
|
if (new_reclen & 1)
|
||
|
new_reclen++;
|
||
|
|
||
|
if (new_reclen > 0xff) {
|
||
|
comerrno(EX_BAD,
|
||
|
_("Fatal error - RR overflow (reclen %d) for file %s\n"),
|
||
|
new_reclen,
|
||
|
s_entry->name);
|
||
|
}
|
||
|
s_entry->isorec.length[0] = new_reclen;
|
||
|
}
|
||
|
|
||
|
status = sort_directory(&this_dir->contents, (reloc_dir == this_dir));
|
||
|
if (status > 0) {
|
||
|
errmsgno(EX_BAD, _("Unable to sort directory %s\n"),
|
||
|
this_dir->whole_name);
|
||
|
errmsgno(EX_BAD,
|
||
|
_("If there was more than one directory type argument to mkisofs\n"));
|
||
|
comerrno(EX_BAD,
|
||
|
_("use -graft-points to create different target directory names.\n"));
|
||
|
}
|
||
|
/*
|
||
|
* If we are filling out a TRANS.TBL, generate the entries that will
|
||
|
* go in the thing.
|
||
|
*/
|
||
|
if (table) {
|
||
|
count = 0;
|
||
|
for (s_entry = this_dir->contents; s_entry;
|
||
|
s_entry = s_entry->next) {
|
||
|
if (s_entry == table)
|
||
|
continue;
|
||
|
if (!s_entry->table)
|
||
|
continue;
|
||
|
if (strcmp(s_entry->name, ".") == 0 ||
|
||
|
strcmp(s_entry->name, "..") == 0)
|
||
|
continue;
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* Skip table entry for the resource fork
|
||
|
*/
|
||
|
if (apple_both &&
|
||
|
(s_entry->isorec.flags[0] & ISO_ASSOCIATED))
|
||
|
continue;
|
||
|
#endif /* APPLE_HYB */
|
||
|
if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
|
||
|
continue;
|
||
|
/*
|
||
|
* Warning: we cannot use the return value of sprintf
|
||
|
* because old BSD based sprintf() implementations
|
||
|
* will return a pointer to the result instead of a
|
||
|
* count.
|
||
|
* Old mkiofs introduced a space after the iso
|
||
|
* filename to make parsing TRANS.TBL easier.
|
||
|
*/
|
||
|
sprintf(table->table + count, "%c %-*s%s",
|
||
|
s_entry->table[0],
|
||
|
MAX_ISONAME + 1,
|
||
|
s_entry->isorec.name, s_entry->table + 1);
|
||
|
count += strlen(table->table + count);
|
||
|
free(s_entry->table);
|
||
|
/*
|
||
|
* for a memory file, set s_entry->table to the
|
||
|
* correct data - which is stored in
|
||
|
* s_entry->whole_name
|
||
|
*/
|
||
|
if (s_entry->de_flags & MEMORY_FILE) {
|
||
|
s_entry->table = s_entry->whole_name;
|
||
|
s_entry->whole_name = NULL;
|
||
|
} else {
|
||
|
s_entry->table = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (count != tablesize) {
|
||
|
comerrno(EX_BAD,
|
||
|
_("Translation table size mismatch %d %d\n"),
|
||
|
count, tablesize);
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Now go through the directory and figure out how large this one will
|
||
|
* be. Do not split a directory entry across a sector boundary
|
||
|
*/
|
||
|
s_entry = this_dir->contents;
|
||
|
this_dir->ce_bytes = 0;
|
||
|
while (s_entry) {
|
||
|
/* skip if it's hidden */
|
||
|
if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
|
||
|
s_entry = s_entry->next;
|
||
|
continue;
|
||
|
}
|
||
|
new_reclen = s_entry->isorec.length[0];
|
||
|
if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen
|
||
|
>= SECTOR_SIZE)
|
||
|
|
||
|
this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) &
|
||
|
~(SECTOR_SIZE - 1);
|
||
|
this_dir->size += new_reclen;
|
||
|
|
||
|
/*
|
||
|
* See if continuation entries were used on disc
|
||
|
*/
|
||
|
if (use_RockRidge &&
|
||
|
s_entry->rr_attr_size != s_entry->total_rr_attr_size) {
|
||
|
unsigned char *pnt;
|
||
|
int len;
|
||
|
int nbytes;
|
||
|
|
||
|
pnt = s_entry->rr_attributes;
|
||
|
len = s_entry->total_rr_attr_size;
|
||
|
pnt = parse_xa(pnt, &len, 0);
|
||
|
/* pnt = parse_xa(pnt, &len, s_entry);*/
|
||
|
|
||
|
/*
|
||
|
* We make sure that each continuation entry record is
|
||
|
* not split across sectors, but each file could in
|
||
|
* theory have more than one CE, so we scan through
|
||
|
* and figure out what we need.
|
||
|
*/
|
||
|
while (len > 3) {
|
||
|
if (pnt[0] == 'C' && pnt[1] == 'E') {
|
||
|
nbytes = get_733((char *)pnt + 20);
|
||
|
|
||
|
if ((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >=
|
||
|
SECTOR_SIZE)
|
||
|
this_dir->ce_bytes =
|
||
|
ISO_ROUND_UP(this_dir->ce_bytes);
|
||
|
/*
|
||
|
* Now store the block in the
|
||
|
* ce buffer
|
||
|
*/
|
||
|
this_dir->ce_bytes += nbytes;
|
||
|
if (this_dir->ce_bytes & 1)
|
||
|
this_dir->ce_bytes++;
|
||
|
}
|
||
|
len -= pnt[2];
|
||
|
pnt += pnt[2];
|
||
|
}
|
||
|
}
|
||
|
s_entry = s_entry->next;
|
||
|
}
|
||
|
return (status);
|
||
|
}
|
||
|
|
||
|
LOCAL void
|
||
|
generate_reloc_directory()
|
||
|
{
|
||
|
time_t current_time;
|
||
|
struct directory_entry *s_entry;
|
||
|
|
||
|
/*
|
||
|
* Create an entry for our internal tree
|
||
|
*/
|
||
|
time(¤t_time);
|
||
|
reloc_dir = (struct directory *)
|
||
|
e_malloc(sizeof (struct directory));
|
||
|
memset(reloc_dir, 0, sizeof (struct directory));
|
||
|
reloc_dir->parent = root;
|
||
|
reloc_dir->next = root->subdir;
|
||
|
root->subdir = reloc_dir;
|
||
|
reloc_dir->depth = 1;
|
||
|
if (hide_rr_moved) {
|
||
|
reloc_dir->whole_name = e_strdup("./.rr_moved");
|
||
|
reloc_dir->de_name = e_strdup(".rr_moved");
|
||
|
} else {
|
||
|
reloc_dir->whole_name = e_strdup("./rr_moved");
|
||
|
reloc_dir->de_name = e_strdup("rr_moved");
|
||
|
}
|
||
|
reloc_dir->de_path = reloc_dir->de_name;
|
||
|
reloc_dir->extent = 0;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Now create an actual directory entry
|
||
|
*/
|
||
|
s_entry = (struct directory_entry *)
|
||
|
e_malloc(sizeof (struct directory_entry));
|
||
|
memset(s_entry, 0, sizeof (struct directory_entry));
|
||
|
s_entry->next = root->contents;
|
||
|
reloc_dir->self = s_entry;
|
||
|
|
||
|
/*
|
||
|
* The rr_moved entry will not appear in the Joliet nor the UDF tree.
|
||
|
*/
|
||
|
reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
|
||
|
s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
|
||
|
|
||
|
reloc_dir->dir_flags |= INHIBIT_UDF_ENTRY;
|
||
|
s_entry->de_flags |= INHIBIT_UDF_ENTRY;
|
||
|
|
||
|
root->contents = s_entry;
|
||
|
root->contents->name = e_strdup(reloc_dir->de_name);
|
||
|
root->contents->filedir = root;
|
||
|
root->contents->isorec.flags[0] = ISO_DIRECTORY;
|
||
|
root->contents->priority = 32768;
|
||
|
iso9660_date(root->contents->isorec.date, current_time);
|
||
|
root->contents->inode = UNCACHED_INODE;
|
||
|
root->contents->dev = UNCACHED_DEVICE;
|
||
|
set_723(root->contents->isorec.volume_sequence_number,
|
||
|
volume_sequence_number);
|
||
|
iso9660_file_length(reloc_dir->de_name, root->contents, 1);
|
||
|
|
||
|
init_fstatbuf();
|
||
|
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
fstatbuf.st_mode = 0555 | S_IFDIR;
|
||
|
fstatbuf.st_nlink = 2;
|
||
|
generate_xa_rr_attributes("",
|
||
|
hide_rr_moved ? ".rr_moved" : "rr_moved",
|
||
|
s_entry, &fstatbuf, &fstatbuf, NEED_RE);
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Now create the . and .. entries in rr_moved
|
||
|
* Now create an actual directory entry
|
||
|
*/
|
||
|
if (root_statbuf.st_nlink == 0)
|
||
|
root_statbuf = fstatbuf;
|
||
|
attach_dot_entries(reloc_dir, NULL, &root_statbuf);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: attach_dot_entries
|
||
|
*
|
||
|
* Purpose: Create . and .. entries for a new directory.
|
||
|
*
|
||
|
* Notes: Only used for artificial directories that
|
||
|
* we are creating.
|
||
|
*/
|
||
|
EXPORT void
|
||
|
attach_dot_entries(dirnode, this_stat, parent_stat)
|
||
|
struct directory *dirnode;
|
||
|
struct stat *this_stat;
|
||
|
struct stat *parent_stat;
|
||
|
{
|
||
|
struct directory_entry *s_entry;
|
||
|
struct directory_entry *orig_contents;
|
||
|
int deep_flag = 0;
|
||
|
|
||
|
init_fstatbuf();
|
||
|
fstatbuf.st_mode = new_dir_mode | S_IFDIR;
|
||
|
fstatbuf.st_nlink = 2;
|
||
|
if (parent_stat == NULL)
|
||
|
parent_stat = &fstatbuf;
|
||
|
if (this_stat == NULL)
|
||
|
this_stat = &fstatbuf;
|
||
|
|
||
|
orig_contents = dirnode->contents;
|
||
|
|
||
|
if ((dirnode->dir_flags & DIR_HAS_DOTDOT) == 0) {
|
||
|
if (dirnode->parent &&
|
||
|
dirnode->parent == reloc_dir) {
|
||
|
deep_flag = NEED_PL;
|
||
|
}
|
||
|
s_entry = (struct directory_entry *)
|
||
|
e_malloc(sizeof (struct directory_entry));
|
||
|
memcpy(s_entry, dirnode->self,
|
||
|
sizeof (struct directory_entry));
|
||
|
#ifdef APPLE_HYB
|
||
|
if (dirnode->self->hfs_ent) {
|
||
|
s_entry->hfs_ent = (hfsdirent *)
|
||
|
e_malloc(sizeof (hfsdirent));
|
||
|
memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
|
||
|
sizeof (hfsdirent));
|
||
|
}
|
||
|
#endif
|
||
|
s_entry->name = e_strdup("..");
|
||
|
s_entry->whole_name = NULL;
|
||
|
s_entry->isorec.name_len[0] = 1;
|
||
|
s_entry->isorec.flags[0] = ISO_DIRECTORY;
|
||
|
iso9660_file_length("..", s_entry, 1);
|
||
|
iso9660_date(s_entry->isorec.date, parent_stat->st_mtime);
|
||
|
set_723(s_entry->isorec.volume_sequence_number,
|
||
|
volume_sequence_number);
|
||
|
set_733(s_entry->isorec.size, SECTOR_SIZE);
|
||
|
memset(s_entry->isorec.extent, 0, 8);
|
||
|
s_entry->filedir = dirnode->parent;
|
||
|
|
||
|
dirnode->contents = s_entry;
|
||
|
dirnode->contents->next = orig_contents;
|
||
|
orig_contents = s_entry;
|
||
|
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
generate_xa_rr_attributes("",
|
||
|
"..", s_entry,
|
||
|
parent_stat,
|
||
|
parent_stat, deep_flag);
|
||
|
}
|
||
|
dirnode->dir_flags |= DIR_HAS_DOTDOT;
|
||
|
}
|
||
|
deep_flag = 0;
|
||
|
if ((dirnode->dir_flags & DIR_HAS_DOT) == 0) {
|
||
|
s_entry = (struct directory_entry *)
|
||
|
e_malloc(sizeof (struct directory_entry));
|
||
|
memcpy(s_entry, dirnode->self,
|
||
|
sizeof (struct directory_entry));
|
||
|
#ifdef APPLE_HYB
|
||
|
if (dirnode->self->hfs_ent) {
|
||
|
s_entry->hfs_ent = (hfsdirent *)
|
||
|
e_malloc(sizeof (hfsdirent));
|
||
|
memcpy(s_entry->hfs_ent, dirnode->self->hfs_ent,
|
||
|
sizeof (hfsdirent));
|
||
|
}
|
||
|
#endif
|
||
|
s_entry->name = e_strdup(".");
|
||
|
s_entry->whole_name = NULL;
|
||
|
s_entry->isorec.name_len[0] = 1;
|
||
|
s_entry->isorec.flags[0] = ISO_DIRECTORY;
|
||
|
iso9660_file_length(".", s_entry, 1);
|
||
|
iso9660_date(s_entry->isorec.date, this_stat->st_mtime);
|
||
|
set_723(s_entry->isorec.volume_sequence_number,
|
||
|
volume_sequence_number);
|
||
|
set_733(s_entry->isorec.size, SECTOR_SIZE);
|
||
|
memset(s_entry->isorec.extent, 0, 8);
|
||
|
s_entry->filedir = dirnode;
|
||
|
|
||
|
dirnode->contents = s_entry;
|
||
|
dirnode->contents->next = orig_contents;
|
||
|
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
if (dirnode == root) {
|
||
|
deep_flag |= NEED_CE | NEED_SP; /* For extension record */
|
||
|
}
|
||
|
generate_xa_rr_attributes("",
|
||
|
".", s_entry,
|
||
|
this_stat, this_stat, deep_flag);
|
||
|
}
|
||
|
dirnode->dir_flags |= DIR_HAS_DOT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EXPORT char *
|
||
|
find_rr_attribute(pnt, len, attr_type)
|
||
|
unsigned char *pnt;
|
||
|
int len;
|
||
|
char *attr_type;
|
||
|
{
|
||
|
pnt = parse_xa(pnt, &len, 0);
|
||
|
while (len >= 4) {
|
||
|
if (pnt[3] != 1 && pnt[3] != 2) {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("**BAD RRVERSION (%d) in '%c%c' field (%2.2X %2.2X).\n"),
|
||
|
pnt[3], pnt[0], pnt[1], pnt[0], pnt[1]);
|
||
|
}
|
||
|
if (pnt[2] < 4) {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("**BAD RRLEN (%d) in '%2.2s' field %2.2X %2.2X.\n"),
|
||
|
pnt[2], pnt, pnt[0], pnt[1]);
|
||
|
return (NULL);
|
||
|
}
|
||
|
if (strncmp((char *)pnt, attr_type, 2) == 0)
|
||
|
return ((char *)pnt);
|
||
|
else if (strncmp((char *)pnt, "ST", 2) == 0)
|
||
|
return (NULL);
|
||
|
len -= pnt[2];
|
||
|
pnt += pnt[2];
|
||
|
}
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
EXPORT void
|
||
|
finish_cl_pl_entries()
|
||
|
{
|
||
|
struct directory_entry *s_entry;
|
||
|
struct directory_entry *s_entry1;
|
||
|
struct directory *d_entry;
|
||
|
|
||
|
/*
|
||
|
* If the reloc_dir is hidden (empty), then return
|
||
|
*/
|
||
|
if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY)
|
||
|
return;
|
||
|
|
||
|
s_entry = reloc_dir->contents;
|
||
|
s_entry = s_entry->next->next; /* Skip past . and .. */
|
||
|
for (; s_entry; s_entry = s_entry->next) {
|
||
|
/* skip if it's hidden */
|
||
|
if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) {
|
||
|
continue;
|
||
|
}
|
||
|
d_entry = reloc_dir->subdir;
|
||
|
while (d_entry) {
|
||
|
if (d_entry->self == s_entry)
|
||
|
break;
|
||
|
d_entry = d_entry->next;
|
||
|
};
|
||
|
if (!d_entry) {
|
||
|
comerrno(EX_BAD,
|
||
|
_("Unable to locate directory parent\n"));
|
||
|
};
|
||
|
|
||
|
if (s_entry->filedir != NULL && s_entry->parent_rec != NULL) {
|
||
|
char *rr_attr;
|
||
|
|
||
|
/*
|
||
|
* First fix the PL pointer in the directory in the
|
||
|
* rr_reloc dir
|
||
|
*/
|
||
|
s_entry1 = d_entry->contents->next;
|
||
|
|
||
|
/* set_733((char *) s_entry1->rr_attributes +*/
|
||
|
/* s_entry1->total_rr_attr_size - 8,*/
|
||
|
/* s_entry->filedir->extent); */
|
||
|
/*
|
||
|
* The line above won't work when entry was read from
|
||
|
* the previous session, because if total_rr_attr_size
|
||
|
* was odd when recording previous session, now we have
|
||
|
* total_rr_attr_size off by 1 due to padding.
|
||
|
*
|
||
|
* So, just search for the attributes by name
|
||
|
*/
|
||
|
rr_attr = find_rr_attribute(s_entry1->rr_attributes,
|
||
|
s_entry1->total_rr_attr_size, "PL");
|
||
|
if (rr_attr != NULL)
|
||
|
set_733(rr_attr + 4, s_entry->filedir->extent);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Now fix the CL pointer
|
||
|
*/
|
||
|
s_entry1 = s_entry->parent_rec;
|
||
|
|
||
|
/* set_733((char *) s_entry1->rr_attributes +*/
|
||
|
/* s_entry1->total_rr_attr_size - 8, d_entry->extent); */
|
||
|
rr_attr = find_rr_attribute(s_entry1->rr_attributes,
|
||
|
s_entry1->total_rr_attr_size, "CL");
|
||
|
if (rr_attr != NULL)
|
||
|
set_733(rr_attr + 4, d_entry->extent);
|
||
|
}
|
||
|
s_entry->filedir = reloc_dir; /* Now we can fix this */
|
||
|
}
|
||
|
/*
|
||
|
* We would need to modify the NLINK terms in the assorted root
|
||
|
* directory records to account for the presence of the RR_MOVED
|
||
|
* directory. We do not do this here because we do it later when
|
||
|
* we correct the link count for all direstories in the tree.
|
||
|
*/
|
||
|
|
||
|
|
||
|
finish_cl_pl_for_prev_session();
|
||
|
}
|
||
|
|
||
|
LOCAL void
|
||
|
dir_nesting_warn(this_dir, path, contflag)
|
||
|
struct directory *this_dir;
|
||
|
char *path;
|
||
|
int contflag;
|
||
|
{
|
||
|
static BOOL did_hint = FALSE;
|
||
|
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Directories too deep for '%s' (%d) max is %d%s.\n"),
|
||
|
path, this_dir->depth, RR_relocation_depth,
|
||
|
contflag?_("; ignored - continuing"):"");
|
||
|
if (!did_hint) {
|
||
|
did_hint = TRUE;
|
||
|
errmsgno(EX_BAD, _("To include the complete directory tree,\n"));
|
||
|
errmsgno(EX_BAD, _("use Rock Ridge extensions via -R or -r,\n"));
|
||
|
errmsgno(EX_BAD, _("or allow deep ISO9660 directory nesting via -D.\n"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: scan_directory_tree
|
||
|
*
|
||
|
* Purpose: Walk through a directory on the local machine
|
||
|
* filter those things we don't want to include
|
||
|
* and build our representation of a dir.
|
||
|
*
|
||
|
* Notes:
|
||
|
*/
|
||
|
EXPORT int
|
||
|
scan_directory_tree(this_dir, path, de)
|
||
|
struct directory *this_dir;
|
||
|
char *path;
|
||
|
struct directory_entry *de;
|
||
|
{
|
||
|
DIR *current_dir;
|
||
|
char whole_path[2*PATH_MAX]; /* Avoid stat buffer overflow */
|
||
|
struct dirent *d_entry;
|
||
|
int dflag;
|
||
|
extern BOOL nodesc;
|
||
|
|
||
|
if (nodesc)
|
||
|
return (1);
|
||
|
|
||
|
if (verbose > 1) {
|
||
|
fprintf(stderr, _("Scanning %s\n"), path);
|
||
|
}
|
||
|
/*#define check_needed*/
|
||
|
#ifdef check_needed
|
||
|
/*
|
||
|
* Trying to use this to avoid directory loops from hard links
|
||
|
* or followed symlinks does not work. It would prevent us from
|
||
|
* implementing merge directories.
|
||
|
*/
|
||
|
if (this_dir->dir_flags & DIR_WAS_SCANNED) {
|
||
|
fprintf(stderr, _("Already scanned directory %s\n"), path);
|
||
|
return (1); /* It's a directory */
|
||
|
}
|
||
|
#endif
|
||
|
this_dir->dir_flags |= DIR_WAS_SCANNED;
|
||
|
|
||
|
errno = 0; /* Paranoia */
|
||
|
current_dir = opendir(path);
|
||
|
d_entry = NULL;
|
||
|
|
||
|
/*
|
||
|
* Apparently NFS sometimes allows you to open the directory, but then
|
||
|
* refuses to allow you to read the contents. Allow for this
|
||
|
*/
|
||
|
if (current_dir) {
|
||
|
errno = 0;
|
||
|
d_entry = readdir(current_dir);
|
||
|
}
|
||
|
|
||
|
if (!current_dir || (!d_entry && errno != 0)) {
|
||
|
int ret = 1;
|
||
|
|
||
|
errmsg(_("Unable to open directory %s\n"), path);
|
||
|
|
||
|
if (errno == ENOTDIR) {
|
||
|
/*
|
||
|
* Mark as not a directory
|
||
|
*/
|
||
|
de->isorec.flags[0] &= ~ISO_DIRECTORY;
|
||
|
ret = 0;
|
||
|
}
|
||
|
if (current_dir)
|
||
|
closedir(current_dir);
|
||
|
return (ret);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Set up the struct for the current directory, and insert it into
|
||
|
* the tree
|
||
|
*/
|
||
|
#ifdef VMS
|
||
|
vms_path_fixup(path);
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* if entry for this sub-directory is hidden, then hide this directory
|
||
|
*/
|
||
|
if (de->de_flags & INHIBIT_ISO9660_ENTRY)
|
||
|
this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY;
|
||
|
|
||
|
if (de->de_flags & INHIBIT_JOLIET_ENTRY)
|
||
|
this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY;
|
||
|
|
||
|
#ifdef SORTING
|
||
|
/*
|
||
|
* set any sort weighting from it's own directory entry - if a
|
||
|
* directory is given a weighting, then all the contents will use
|
||
|
* this as the default weighting
|
||
|
*/
|
||
|
this_dir->sort = de->sort;
|
||
|
#endif /* SORTING */
|
||
|
|
||
|
/*
|
||
|
* Now we scan the directory itself, and look at what is inside of it.
|
||
|
*/
|
||
|
whole_path[0] = '\0';
|
||
|
dflag = -2;
|
||
|
while (1 == 1) {
|
||
|
char *d_name;
|
||
|
|
||
|
if (dflag < 0) {
|
||
|
/*
|
||
|
* Some filesystems do not deliver "." and ".." at all,
|
||
|
* others (on Linux) deliver them in the wrong order.
|
||
|
* Make sure we add "." and ".." before all other
|
||
|
* entries.
|
||
|
*/
|
||
|
if (dflag < -1)
|
||
|
d_name = ".";
|
||
|
else
|
||
|
d_name = "..";
|
||
|
dflag++;
|
||
|
} else {
|
||
|
/*
|
||
|
* The first time through, skip this, since we already
|
||
|
* asked for the first entry when we opened the
|
||
|
* directory.
|
||
|
*/
|
||
|
if (dflag > 0) {
|
||
|
d_entry = readdir(current_dir);
|
||
|
} else {
|
||
|
dflag++;
|
||
|
}
|
||
|
if (!d_entry)
|
||
|
break;
|
||
|
d_name = d_entry->d_name;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* OK, got a valid entry
|
||
|
*
|
||
|
* If we do not want all files, then pitch the backups.
|
||
|
*/
|
||
|
if (!all_files) {
|
||
|
if (strchr(d_name, '~') ||
|
||
|
strchr(d_name, '#') ||
|
||
|
rstr(d_name, ".bak")) {
|
||
|
if (verbose > 0) {
|
||
|
fprintf(stderr,
|
||
|
_("Ignoring file %s\n"),
|
||
|
d_name);
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
#ifdef APPLE_HYB
|
||
|
if (apple_both) {
|
||
|
/*
|
||
|
* exclude certain HFS type files/directories for the
|
||
|
* time being
|
||
|
*/
|
||
|
if (hfs_exclude(d_name))
|
||
|
continue;
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
if (strlen(path) + strlen(d_name) + 2 > sizeof (whole_path)) {
|
||
|
errmsgno(EX_BAD, _("Path name %s/%s too long.\n"),
|
||
|
path, d_name);
|
||
|
comerrno(EX_BAD, _("Overflow of stat buffer\n"));
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Generate the complete ASCII path for this file
|
||
|
*/
|
||
|
strlcpy(whole_path, path, sizeof (whole_path));
|
||
|
#ifndef VMS
|
||
|
if (whole_path[strlen(whole_path) - 1] != '/')
|
||
|
strcat(whole_path, "/");
|
||
|
#endif
|
||
|
strcat(whole_path, d_name);
|
||
|
|
||
|
/*
|
||
|
* Should we exclude this file ?
|
||
|
* Do no check "." and ".."
|
||
|
*/
|
||
|
if (!(d_name[0] == '.' && (d_name[1] == '\0' ||
|
||
|
(d_name[1] == '.' && d_name[2] == '\0'))) &&
|
||
|
(matches(d_name) || matches(whole_path))) {
|
||
|
if (verbose > 1) {
|
||
|
fprintf(stderr,
|
||
|
_("Excluded by match: %s\n"), whole_path);
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
if (generate_tables &&
|
||
|
strcmp(d_name, trans_tbl) == 0) {
|
||
|
/*
|
||
|
* Ignore this entry. We are going to be generating
|
||
|
* new versions of these files, and we need to ignore
|
||
|
* any originals that we might have found.
|
||
|
*/
|
||
|
if (verbose > 1) {
|
||
|
fprintf(stderr, _("Excluded: %s\n"), whole_path);
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
/*
|
||
|
* If we already have a '.' or a '..' entry, then don't insert
|
||
|
* new ones.
|
||
|
*/
|
||
|
if (strcmp(d_name, ".") == 0 &&
|
||
|
this_dir->dir_flags & DIR_HAS_DOT) {
|
||
|
continue;
|
||
|
}
|
||
|
if (strcmp(d_name, "..") == 0 &&
|
||
|
this_dir->dir_flags & DIR_HAS_DOTDOT) {
|
||
|
continue;
|
||
|
}
|
||
|
#if 0
|
||
|
if (verbose > 1)
|
||
|
fprintf(stderr, "%s\n", whole_path);
|
||
|
#endif
|
||
|
/*
|
||
|
* This actually adds the entry to the directory in question.
|
||
|
*/
|
||
|
insert_file_entry(this_dir, whole_path, d_name, NULL, 0);
|
||
|
}
|
||
|
closedir(current_dir);
|
||
|
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* if we cached the HFS info stuff for this directory, then delete it
|
||
|
*/
|
||
|
if (this_dir->hfs_info) {
|
||
|
del_hfs_info(this_dir->hfs_info);
|
||
|
this_dir->hfs_info = 0;
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
LOCAL struct directory_entry *
|
||
|
dup_relocated_dir(this_dir, s_entry, whole_path, short_name, statp)
|
||
|
struct directory *this_dir;
|
||
|
struct directory_entry *s_entry;
|
||
|
char *whole_path;
|
||
|
char *short_name;
|
||
|
struct stat *statp;
|
||
|
{
|
||
|
struct directory_entry *s_entry1;
|
||
|
|
||
|
if (!reloc_dir)
|
||
|
generate_reloc_directory();
|
||
|
init_fstatbuf();
|
||
|
|
||
|
/*
|
||
|
* Replicate the entry for this directory. The old one will
|
||
|
* stay where it is, and it will be neutered so that it no
|
||
|
* longer looks like a directory. The new one will look like
|
||
|
* a directory, and it will be put in the reloc_dir.
|
||
|
*/
|
||
|
s_entry1 = (struct directory_entry *)
|
||
|
e_malloc(sizeof (struct directory_entry));
|
||
|
memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
|
||
|
s_entry1->table = NULL;
|
||
|
s_entry1->name = e_strdup(short_name);
|
||
|
s_entry1->whole_name = e_strdup(whole_path);
|
||
|
s_entry1->next = reloc_dir->contents;
|
||
|
reloc_dir->contents = s_entry1;
|
||
|
s_entry1->priority = 32768;
|
||
|
s_entry1->parent_rec = this_dir->contents;
|
||
|
set_723(s_entry1->isorec.volume_sequence_number,
|
||
|
volume_sequence_number);
|
||
|
s_entry1->filedir = this_dir;
|
||
|
iso9660_date(s_entry1->isorec.date, fstatbuf.st_mtime);
|
||
|
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
generate_xa_rr_attributes(whole_path,
|
||
|
short_name, s_entry1,
|
||
|
statp, statp, NEED_RE);
|
||
|
}
|
||
|
|
||
|
statp->st_size = (off_t)0;
|
||
|
statp->st_mode &= 0777;
|
||
|
set_733((char *)s_entry->isorec.size, 0);
|
||
|
s_entry->size = 0;
|
||
|
s_entry->isorec.flags[0] = ISO_FILE;
|
||
|
s_entry->inode = UNCACHED_INODE;
|
||
|
s_entry->dev = UNCACHED_DEVICE;
|
||
|
s_entry->de_flags |= RELOCATED_DIRECTORY;
|
||
|
|
||
|
return (s_entry1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Function: insert_file_entry
|
||
|
*
|
||
|
* Purpose: Insert one entry into our directory node.
|
||
|
*
|
||
|
* Note:
|
||
|
* This function inserts a single entry into the directory. It
|
||
|
* is assumed that all filtering and decision making regarding what
|
||
|
* we want to include has already been made, so the purpose of this
|
||
|
* is to insert one entry (file, link, dir, etc), into this directory.
|
||
|
* Note that if the entry is a dir (or if we are following links,
|
||
|
* and the thing it points to is a dir), then we will scan those
|
||
|
* trees before we return.
|
||
|
*/
|
||
|
EXPORT int
|
||
|
insert_file_entry(this_dir, whole_path, short_name, statp, have_rsrc)
|
||
|
struct directory *this_dir;
|
||
|
char *whole_path;
|
||
|
char *short_name;
|
||
|
struct stat *statp;
|
||
|
int have_rsrc;
|
||
|
{
|
||
|
struct stat statbuf,
|
||
|
lstatbuf;
|
||
|
struct directory_entry *s_entry,
|
||
|
*s_entry1;
|
||
|
int lstatus;
|
||
|
int status;
|
||
|
int deep_flag;
|
||
|
#ifdef USE_NO_SCANDIR
|
||
|
int no_scandir = 0;
|
||
|
#endif
|
||
|
|
||
|
#ifdef APPLE_HYB
|
||
|
int x_hfs = 0;
|
||
|
int htype = TYPE_NONE;
|
||
|
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
if (statp) {
|
||
|
status = lstatus = 0;
|
||
|
lstatbuf = *statp;
|
||
|
if (S_ISLNK(lstatbuf.st_mode)) {
|
||
|
status = stat_filter(short_name, &statbuf);
|
||
|
} else {
|
||
|
statbuf = *statp;
|
||
|
}
|
||
|
} else {
|
||
|
status = stat_filter(whole_path, &statbuf);
|
||
|
|
||
|
lstatus = lstat_filter(whole_path, &lstatbuf);
|
||
|
}
|
||
|
|
||
|
if ((status == -1) && (lstatus == -1)) {
|
||
|
/*
|
||
|
* This means that the file doesn't exist, or isn't accessible.
|
||
|
* Sometimes this is because of NFS permissions problems.
|
||
|
*/
|
||
|
errmsg(_("Non-existent or inaccessible: %s\n"), whole_path);
|
||
|
return (0);
|
||
|
}
|
||
|
if (S_ISDIR(statbuf.st_mode) &&
|
||
|
(this_dir->depth > RR_relocation_depth) && !use_RockRidge &&
|
||
|
strcmp(short_name, ".") != 0 && strcmp(short_name, "..") != 0) {
|
||
|
dir_nesting_warn(this_dir, whole_path, TRUE);
|
||
|
return (0);
|
||
|
}
|
||
|
if (this_dir == root && strcmp(short_name, ".") == 0)
|
||
|
root_statbuf = statbuf; /* Save this for later on */
|
||
|
|
||
|
/*
|
||
|
* We do this to make sure that the root entries are consistent
|
||
|
*/
|
||
|
if (this_dir == root && strcmp(short_name, "..") == 0) {
|
||
|
statbuf = root_statbuf;
|
||
|
lstatbuf = root_statbuf;
|
||
|
}
|
||
|
if (S_ISLNK(lstatbuf.st_mode)) {
|
||
|
/*
|
||
|
* Here we decide how to handle the symbolic links. Here we
|
||
|
* handle the general case - if we are not following links or
|
||
|
* there is an error, then we must change something. If RR
|
||
|
* is in use, it is easy, we let RR describe the file. If
|
||
|
* not, then we punt the file.
|
||
|
*/
|
||
|
if ((status || !follow_links)) {
|
||
|
#ifdef UDF
|
||
|
if (use_RockRidge || use_udf) {
|
||
|
#else
|
||
|
if (use_RockRidge) {
|
||
|
#endif
|
||
|
status = 0;
|
||
|
STAT_INODE(statbuf) = UNCACHED_INODE;
|
||
|
statbuf.st_dev = UNCACHED_DEVICE;
|
||
|
#ifdef UDF
|
||
|
if (create_udfsymlinks) {
|
||
|
char symlinkcontents[2048];
|
||
|
off_t size = sizeof (symlinkcontents);
|
||
|
|
||
|
if (udf_get_symlinkcontents(whole_path,
|
||
|
symlinkcontents, &size) == -1) {
|
||
|
statbuf.st_size = (off_t)0;
|
||
|
statbuf.st_mode =
|
||
|
(statbuf.st_mode & ~S_IFMT) | S_IFREG;
|
||
|
} else {
|
||
|
statbuf.st_size = size;
|
||
|
statbuf.st_mode = lstatbuf.st_mode;
|
||
|
}
|
||
|
} else {
|
||
|
#endif
|
||
|
statbuf.st_size = (off_t)0;
|
||
|
statbuf.st_mode =
|
||
|
(statbuf.st_mode & ~S_IFMT) | S_IFREG;
|
||
|
#ifdef UDF
|
||
|
}
|
||
|
#endif
|
||
|
} else {
|
||
|
if (follow_links) {
|
||
|
/* XXX errno may be wrong! */
|
||
|
errmsg(_("Unable to stat file %s - ignoring and continuing.\n"),
|
||
|
whole_path);
|
||
|
} else {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Symlink %s ignored - continuing.\n"),
|
||
|
whole_path);
|
||
|
return (0); /* Non Rock Ridge discs */
|
||
|
/* - ignore all symlinks */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Here we handle a different kind of case. Here we have a
|
||
|
* symlink, but we want to follow symlinks. If we run across
|
||
|
* a directory loop, then we need to pretend that we are not
|
||
|
* following symlinks for this file. If this is the first
|
||
|
* time we have seen this, then make this seem as if there was
|
||
|
* no symlink there in the first place
|
||
|
*/
|
||
|
if (follow_links &&
|
||
|
S_ISDIR(statbuf.st_mode)) {
|
||
|
if (strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
if (find_directory_hash(statbuf.st_dev,
|
||
|
STAT_INODE(statbuf))) {
|
||
|
if (!use_RockRidge) {
|
||
|
fprintf(stderr,
|
||
|
_("Already cached directory seen (%s)\n"),
|
||
|
whole_path);
|
||
|
return (0);
|
||
|
}
|
||
|
lstatbuf = statbuf;
|
||
|
/*
|
||
|
* XXX when this line was active,
|
||
|
* XXX mkisofs did not include all
|
||
|
* XXX files if it was called with '-f'
|
||
|
* XXX (follow symlinks).
|
||
|
* XXX Now scan_directory_tree()
|
||
|
* XXX checks if the directory has
|
||
|
* XXX already been scanned via the
|
||
|
* XXX DIR_WAS_SCANNED flag.
|
||
|
*/
|
||
|
/* no_scandir = 1;*/
|
||
|
} else {
|
||
|
lstatbuf = statbuf;
|
||
|
add_directory_hash(statbuf.st_dev,
|
||
|
STAT_INODE(statbuf));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* For non-directories, we just copy the stat information over
|
||
|
* so we correctly include this file.
|
||
|
*/
|
||
|
if (follow_links &&
|
||
|
!S_ISDIR(statbuf.st_mode)) {
|
||
|
lstatbuf = statbuf;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Add directories to the cache so that we don't waste space even if
|
||
|
* we are supposed to be following symlinks.
|
||
|
*/
|
||
|
if (follow_links &&
|
||
|
strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0 &&
|
||
|
S_ISDIR(statbuf.st_mode)) {
|
||
|
add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
|
||
|
}
|
||
|
#ifdef VMS
|
||
|
if (!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX &&
|
||
|
statbuf.st_fab_rfm != FAB$C_STMLF)) {
|
||
|
fprintf(stderr,
|
||
|
_("Warning - file %s has an unsupported VMS record format (%d)\n"),
|
||
|
whole_path, statbuf.st_fab_rfm);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (S_ISREG(lstatbuf.st_mode) &&
|
||
|
((statp != NULL && (status = access(short_name, R_OK))) ||
|
||
|
(statp == NULL && (status = access(whole_path, R_OK))))) {
|
||
|
errmsg(_("File %s is not readable - ignoring\n"),
|
||
|
whole_path);
|
||
|
return (0);
|
||
|
}
|
||
|
#ifdef USE_LARGEFILES
|
||
|
if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= maxnonlarge) &&
|
||
|
!do_largefiles) {
|
||
|
#else
|
||
|
/*
|
||
|
* >= is required by the large file summit standard.
|
||
|
*/
|
||
|
if (S_ISREG(lstatbuf.st_mode) && (lstatbuf.st_size >= (off_t)0x7FFFFFFF)) {
|
||
|
#endif
|
||
|
#ifdef EOVERFLOW
|
||
|
errno = EOVERFLOW;
|
||
|
#else
|
||
|
errno = EFBIG;
|
||
|
#endif
|
||
|
errmsg(_("File %s is too large for current mkisofs settings (-iso-level 3 or more required) - ignoring\n"),
|
||
|
whole_path);
|
||
|
return (0);
|
||
|
}
|
||
|
/*
|
||
|
* Add this so that we can detect directory loops with hard links.
|
||
|
* If we are set up to follow symlinks, then we skip this checking.
|
||
|
*/
|
||
|
if (!follow_links &&
|
||
|
S_ISDIR(lstatbuf.st_mode) &&
|
||
|
strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
if (find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) {
|
||
|
/* comerrno(EX_BAD,*/
|
||
|
/* _("Directory loop - fatal goof (%s %lx %lu).\n"),*/
|
||
|
errmsgno(EX_BAD,
|
||
|
_("Warning: Directory loop (%s dev: %lx ino: %lu).\n"),
|
||
|
whole_path, (unsigned long) statbuf.st_dev,
|
||
|
(unsigned long) STAT_INODE(statbuf));
|
||
|
}
|
||
|
add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
|
||
|
}
|
||
|
if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) &&
|
||
|
!S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) &&
|
||
|
!S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) &&
|
||
|
!S_ISDIR(lstatbuf.st_mode)) {
|
||
|
fprintf(stderr,
|
||
|
_("Unknown file type (%s) %s - ignoring and continuing.\n"),
|
||
|
filetype((int)lstatbuf.st_mode), whole_path);
|
||
|
return (0);
|
||
|
}
|
||
|
/*
|
||
|
* Who knows what trash this is - ignore and continue
|
||
|
*/
|
||
|
if (status) {
|
||
|
errmsg(_("Unable to stat file %s - ignoring and continuing.\n"),
|
||
|
whole_path);
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
#if !defined(__MINGW32__) && !defined(_MSC_VER)
|
||
|
#define is_archive(st) ((st).st_dev == archive_dev && (st).st_ino == archive_ino)
|
||
|
if (archive_isreg && is_archive(statbuf)) {
|
||
|
errmsgno(EX_BAD,
|
||
|
_("'%s' is the archive. Not dumped.\n"), whole_path);
|
||
|
return (0);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Check to see if we have already seen this directory node. If so,
|
||
|
* then we don't create a new entry for it, but we do want to recurse
|
||
|
* beneath it and add any new files we do find.
|
||
|
*/
|
||
|
if (S_ISDIR(statbuf.st_mode)) {
|
||
|
int dflag;
|
||
|
|
||
|
for (s_entry = this_dir->contents; s_entry;
|
||
|
s_entry = s_entry->next) {
|
||
|
if (strcmp(s_entry->name, short_name) == 0) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (s_entry != NULL &&
|
||
|
strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
struct directory *child;
|
||
|
|
||
|
/*
|
||
|
* This should not create a new directory
|
||
|
*/
|
||
|
if ((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) {
|
||
|
for (s_entry = reloc_dir->contents; s_entry;
|
||
|
s_entry = s_entry->next) {
|
||
|
if (strcmp(s_entry->name, short_name)
|
||
|
== 0) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
child = find_or_create_directory(reloc_dir,
|
||
|
whole_path,
|
||
|
s_entry, 1);
|
||
|
} else {
|
||
|
child = find_or_create_directory(this_dir,
|
||
|
whole_path,
|
||
|
s_entry, 1);
|
||
|
/*
|
||
|
* If unable to scan directory, mark this as a
|
||
|
* non-directory
|
||
|
*/
|
||
|
}
|
||
|
/* if (no_scandir)*/
|
||
|
if (0)
|
||
|
dflag = 1;
|
||
|
else
|
||
|
dflag = scan_directory_tree(child,
|
||
|
whole_path, s_entry);
|
||
|
if (!dflag) {
|
||
|
lstatbuf.st_mode =
|
||
|
(lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* Should we exclude this HFS file ? - only works with -hfs
|
||
|
*/
|
||
|
if (!have_rsrc && apple_hyb && strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
if ((x_hfs = (hfs_matches(short_name) ||
|
||
|
hfs_matches(whole_path))) == 1) {
|
||
|
if (verbose > 1) {
|
||
|
fprintf(stderr, _("Hidden from HFS tree: %s\n"),
|
||
|
whole_path);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* check we are a file, using Apple extensions and have a .resource
|
||
|
* part and not excluded
|
||
|
*/
|
||
|
if (S_ISREG(lstatbuf.st_mode) && !have_rsrc && apple_both && !x_hfs) {
|
||
|
char rsrc_path[PATH_MAX]; /* rsrc fork filename */
|
||
|
|
||
|
/*
|
||
|
* Construct the resource full path
|
||
|
*/
|
||
|
htype = get_hfs_rname(whole_path, short_name, rsrc_path);
|
||
|
/*
|
||
|
* Check we can read the resouce fork
|
||
|
*/
|
||
|
if (htype) {
|
||
|
struct stat rstatbuf,
|
||
|
rlstatbuf;
|
||
|
|
||
|
/*
|
||
|
* Some further checks on the file
|
||
|
*/
|
||
|
status = stat_filter(rsrc_path, &rstatbuf);
|
||
|
|
||
|
lstatus = lstat_filter(rsrc_path, &rlstatbuf);
|
||
|
|
||
|
/* if (!status && !lstatus && S_ISREG(rlstatbuf.st_mode)*/
|
||
|
/* && rlstatbuf.st_size > (off_t)0) { */
|
||
|
if (!status && !lstatus && S_ISREG(rstatbuf.st_mode) &&
|
||
|
rstatbuf.st_size > (off_t)0) {
|
||
|
|
||
|
/*
|
||
|
* have a resource file - insert it into the
|
||
|
* current directory but flag that we have a
|
||
|
* resource fork
|
||
|
*/
|
||
|
insert_file_entry(this_dir, rsrc_path,
|
||
|
short_name, NULL, htype);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
s_entry = (struct directory_entry *)
|
||
|
e_malloc(sizeof (struct directory_entry));
|
||
|
/* memset the whole struct, not just the isorec.extent part JCP */
|
||
|
memset(s_entry, 0, sizeof (struct directory_entry));
|
||
|
s_entry->next = this_dir->contents;
|
||
|
/* memset(s_entry->isorec.extent, 0, 8); */
|
||
|
this_dir->contents = s_entry;
|
||
|
deep_flag = 0;
|
||
|
s_entry->table = NULL;
|
||
|
|
||
|
s_entry->name = e_strdup(short_name);
|
||
|
s_entry->whole_name = e_strdup(whole_path);
|
||
|
|
||
|
s_entry->de_flags = 0;
|
||
|
if (S_ISLNK(lstatbuf.st_mode))
|
||
|
s_entry->de_flags |= IS_SYMLINK;
|
||
|
#ifdef DUPLICATES_ONCE
|
||
|
s_entry->digest_fast = NULL;
|
||
|
s_entry->digest_full = NULL;
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* If the current directory is hidden, then hide all it's members
|
||
|
* otherwise check if this entry needs to be hidden as well
|
||
|
*/
|
||
|
if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) {
|
||
|
s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
|
||
|
} else if (strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
if (i_matches(short_name) || i_matches(whole_path)) {
|
||
|
if (verbose > 1) {
|
||
|
fprintf(stderr,
|
||
|
_("Hidden from ISO9660 tree: %s\n"),
|
||
|
whole_path);
|
||
|
}
|
||
|
s_entry->de_flags |= INHIBIT_ISO9660_ENTRY;
|
||
|
}
|
||
|
if (h_matches(short_name) || h_matches(whole_path)) {
|
||
|
if (verbose > 1) {
|
||
|
fprintf(stderr,
|
||
|
_("Hidden ISO9660 attribute: %s\n"),
|
||
|
whole_path);
|
||
|
}
|
||
|
s_entry->de_flags |= HIDDEN_FILE;
|
||
|
}
|
||
|
}
|
||
|
if (this_dir != reloc_dir &&
|
||
|
this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) {
|
||
|
s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
|
||
|
} else if (strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
if (j_matches(short_name) || j_matches(whole_path)) {
|
||
|
if (verbose > 1) {
|
||
|
fprintf(stderr,
|
||
|
_("Hidden from Joliet tree: %s\n"),
|
||
|
whole_path);
|
||
|
}
|
||
|
s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
|
||
|
}
|
||
|
}
|
||
|
if (this_dir != reloc_dir &&
|
||
|
this_dir->dir_flags & INHIBIT_UDF_ENTRY) {
|
||
|
s_entry->de_flags |= INHIBIT_UDF_ENTRY;
|
||
|
} else if (strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
if (u_matches(short_name) || u_matches(whole_path)) {
|
||
|
if (verbose > 1) {
|
||
|
fprintf(stderr,
|
||
|
_("Hidden from UDF tree: %s\n"),
|
||
|
whole_path);
|
||
|
}
|
||
|
s_entry->de_flags |= INHIBIT_UDF_ENTRY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef SORTING
|
||
|
/*
|
||
|
* Inherit any sort weight from parent directory
|
||
|
*/
|
||
|
s_entry->sort = this_dir->sort;
|
||
|
|
||
|
#ifdef DVD_AUD_VID
|
||
|
/*
|
||
|
* No use at all to do a sort if we don't make a dvd video/audio
|
||
|
*/
|
||
|
/*
|
||
|
* Assign special weights to VIDEO_TS and AUDIO_TS files.
|
||
|
* This can't be done with sort_matches for two reasons:
|
||
|
* first, we need to match against the destination (DVD)
|
||
|
* path rather than the source path, and second, there are
|
||
|
* about 2400 different file names to check, each needing
|
||
|
* a different priority, and adding that many patterns to
|
||
|
* sort_matches would slow things to a crawl.
|
||
|
*/
|
||
|
|
||
|
if (dvd_aud_vid_flag) {
|
||
|
s_entry->sort = assign_dvd_weights(s_entry->name, this_dir, s_entry->sort);
|
||
|
/*
|
||
|
* Turn on sorting if necessary, regardless of cmd-line options
|
||
|
*/
|
||
|
if ((s_entry->sort != this_dir->sort) && do_sort == 0)
|
||
|
do_sort++;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* See if this entry should have a new weighting
|
||
|
*/
|
||
|
if (do_sort && strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
s_entry->sort = sort_matches(whole_path, s_entry->sort);
|
||
|
}
|
||
|
#endif /* SORTING */
|
||
|
|
||
|
s_entry->filedir = this_dir;
|
||
|
s_entry->isorec.flags[0] = ISO_FILE;
|
||
|
if (s_entry->de_flags & HIDDEN_FILE)
|
||
|
s_entry->isorec.flags[0] |= ISO_EXISTENCE;
|
||
|
s_entry->isorec.ext_attr_length[0] = 0;
|
||
|
iso9660_date(s_entry->isorec.date, statbuf.st_mtime);
|
||
|
s_entry->isorec.file_unit_size[0] = 0;
|
||
|
s_entry->isorec.interleave[0] = 0;
|
||
|
|
||
|
#ifdef APPLE_HYB
|
||
|
if (apple_both && !x_hfs) {
|
||
|
s_entry->hfs_ent = NULL;
|
||
|
s_entry->assoc = NULL;
|
||
|
s_entry->hfs_off = (off_t)0;
|
||
|
s_entry->hfs_type = htype;
|
||
|
if (have_rsrc) {
|
||
|
/* associated (rsrc) file */
|
||
|
s_entry->isorec.flags[0] |= ISO_ASSOCIATED;
|
||
|
/* set the type of HFS file */
|
||
|
s_entry->hfs_type = have_rsrc;
|
||
|
/*
|
||
|
* don't want the rsrc file to be included in any
|
||
|
* Joliet/UDF tree
|
||
|
*/
|
||
|
s_entry->de_flags |= INHIBIT_JOLIET_ENTRY;
|
||
|
s_entry->de_flags |= INHIBIT_UDF_ENTRY;
|
||
|
} else if (s_entry->next) {
|
||
|
/*
|
||
|
* if previous entry is an associated file,
|
||
|
* then "link" it to this file i.e. we have a
|
||
|
* data/resource pair
|
||
|
*/
|
||
|
if (s_entry->next->isorec.flags[0] & ISO_ASSOCIATED) {
|
||
|
s_entry->assoc = s_entry->next;
|
||
|
/*
|
||
|
* share the same HFS parameters
|
||
|
*/
|
||
|
s_entry->hfs_ent = s_entry->next->hfs_ent;
|
||
|
s_entry->hfs_type = s_entry->next->hfs_type;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Allocate HFS entry if required
|
||
|
*/
|
||
|
if (apple_both && strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
if (!s_entry->hfs_ent) {
|
||
|
hfsdirent *hfs_ent;
|
||
|
|
||
|
hfs_ent =
|
||
|
(hfsdirent *) e_malloc(sizeof (hfsdirent));
|
||
|
|
||
|
/*
|
||
|
* Sill in the defaults
|
||
|
*/
|
||
|
memset(hfs_ent, 0, sizeof (hfsdirent));
|
||
|
|
||
|
s_entry->hfs_ent = hfs_ent;
|
||
|
}
|
||
|
/*
|
||
|
* the resource fork is processed first, but the
|
||
|
* data fork's time info is used in preference
|
||
|
* i.e. time info is set from the resource fork
|
||
|
* initially, then it is set from the data fork
|
||
|
*/
|
||
|
if (have_rsrc) {
|
||
|
/*
|
||
|
* Set rsrc size
|
||
|
*/
|
||
|
s_entry->hfs_ent->u.file.rsize = lstatbuf.st_size;
|
||
|
/*
|
||
|
* This will be overwritten - but might as
|
||
|
* well set it here ...
|
||
|
*/
|
||
|
s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
|
||
|
s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
|
||
|
} else {
|
||
|
/*
|
||
|
* Set data size
|
||
|
*/
|
||
|
s_entry->hfs_ent->u.file.dsize = lstatbuf.st_size;
|
||
|
s_entry->hfs_ent->crdate = lstatbuf.st_ctime;
|
||
|
s_entry->hfs_ent->mddate = lstatbuf.st_mtime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
if (strcmp(short_name, ".") == 0) {
|
||
|
this_dir->dir_flags |= DIR_HAS_DOT;
|
||
|
}
|
||
|
if (strcmp(short_name, "..") == 0) {
|
||
|
this_dir->dir_flags |= DIR_HAS_DOTDOT;
|
||
|
}
|
||
|
if (this_dir->parent &&
|
||
|
this_dir->parent == reloc_dir &&
|
||
|
strcmp(short_name, "..") == 0) {
|
||
|
s_entry->inode = UNCACHED_INODE;
|
||
|
s_entry->dev = UNCACHED_DEVICE;
|
||
|
deep_flag = NEED_PL;
|
||
|
} else
|
||
|
#ifdef APPLE_HYB
|
||
|
if (have_rsrc) {
|
||
|
/*
|
||
|
* don't want rsrc files to be cached
|
||
|
*/
|
||
|
s_entry->de_flags |= RESOURCE_FORK;
|
||
|
s_entry->inode = UNCACHED_INODE;
|
||
|
s_entry->dev = UNCACHED_DEVICE;
|
||
|
} else
|
||
|
#endif /* APPLE_HYB */
|
||
|
{
|
||
|
s_entry->inode = STAT_INODE(statbuf);
|
||
|
s_entry->dev = statbuf.st_dev;
|
||
|
}
|
||
|
set_723(s_entry->isorec.volume_sequence_number,
|
||
|
volume_sequence_number);
|
||
|
iso9660_file_length(short_name, s_entry, S_ISDIR(statbuf.st_mode));
|
||
|
s_entry->rr_attr_size = 0;
|
||
|
s_entry->total_rr_attr_size = 0;
|
||
|
s_entry->rr_attributes = NULL;
|
||
|
|
||
|
/*
|
||
|
* Directories are assigned sizes later on
|
||
|
*/
|
||
|
if (!S_ISDIR(statbuf.st_mode)) {
|
||
|
if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) ||
|
||
|
S_ISFIFO(lstatbuf.st_mode) ||
|
||
|
S_ISSOCK(lstatbuf.st_mode) ||
|
||
|
#ifdef UDF
|
||
|
(S_ISLNK(lstatbuf.st_mode) && !create_udfsymlinks)) {
|
||
|
#else
|
||
|
FALSE) {
|
||
|
#endif
|
||
|
s_entry->size = (off_t)0;
|
||
|
statbuf.st_size = (off_t)0;
|
||
|
} else {
|
||
|
s_entry->size = statbuf.st_size;
|
||
|
}
|
||
|
|
||
|
set_733((char *)s_entry->isorec.size, statbuf.st_size);
|
||
|
} else {
|
||
|
s_entry->isorec.flags[0] |= ISO_DIRECTORY;
|
||
|
}
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* If the directory is HFS excluded, then we don't have an hfs_ent
|
||
|
*/
|
||
|
if (apple_both && s_entry->hfs_ent &&
|
||
|
(s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
|
||
|
/*
|
||
|
* Get the Mac directory name
|
||
|
*/
|
||
|
get_hfs_dir(whole_path, short_name, s_entry);
|
||
|
|
||
|
/*
|
||
|
* If required, set ISO directory name from HFS name
|
||
|
*/
|
||
|
if (use_mac_name)
|
||
|
iso9660_file_length(s_entry->hfs_ent->name, s_entry, 1);
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
if (strcmp(short_name, ".") != 0 && strcmp(short_name, "..") != 0 &&
|
||
|
S_ISDIR(statbuf.st_mode) &&
|
||
|
this_dir->depth > RR_relocation_depth) {
|
||
|
struct directory *child;
|
||
|
|
||
|
/*
|
||
|
* Replicate the entry for this directory. The old one will
|
||
|
* stay where it is, and it will be neutered so that it no
|
||
|
* longer looks like a directory. The new one will look like
|
||
|
* a directory, and it will be put in the reloc_dir.
|
||
|
*/
|
||
|
s_entry1 = dup_relocated_dir(this_dir, s_entry,
|
||
|
whole_path, short_name, &statbuf);
|
||
|
|
||
|
/*
|
||
|
* We need to set this temporarily so that the parent to this
|
||
|
* is correctly determined.
|
||
|
*/
|
||
|
s_entry1->filedir = reloc_dir;
|
||
|
child = find_or_create_directory(reloc_dir, whole_path,
|
||
|
s_entry1, 0);
|
||
|
free(child->de_path); /* allocated in this case */
|
||
|
set_de_path(this_dir, child);
|
||
|
|
||
|
|
||
|
/* if (!no_scandir)*/
|
||
|
if (!0)
|
||
|
scan_directory_tree(child, whole_path, s_entry1);
|
||
|
s_entry1->filedir = this_dir;
|
||
|
deep_flag = NEED_CL;
|
||
|
}
|
||
|
if (generate_tables &&
|
||
|
strcmp(s_entry->name, ".") != 0 &&
|
||
|
strcmp(s_entry->name, "..") != 0) {
|
||
|
|
||
|
char buffer[SECTOR_SIZE];
|
||
|
int nchar;
|
||
|
|
||
|
switch (lstatbuf.st_mode & S_IFMT) {
|
||
|
case S_IFDIR:
|
||
|
sprintf(buffer, "D\t%s\n",
|
||
|
s_entry->name);
|
||
|
break;
|
||
|
|
||
|
/*
|
||
|
* extra for WIN32 - if it doesn't have the major/minor defined, then
|
||
|
* S_IFBLK and S_IFCHR type files are unlikely to exist anyway ...
|
||
|
* code similar to that in rock.c
|
||
|
*/
|
||
|
#if 0
|
||
|
/*
|
||
|
* Use the device handling code from <schily/device.h>
|
||
|
*/
|
||
|
#ifndef major
|
||
|
#define major(dev) (sizeof (dev_t) <= 2 ? ((dev) >> 8) : \
|
||
|
(sizeof (dev_t) <= 4 ? (((dev) >> 8) >> 8) : \
|
||
|
(((dev) >> 16) >> 16)))
|
||
|
#define minor(dev) (sizeof (dev_t) <= 2 ? (dev) & 0xff : \
|
||
|
(sizeof (dev_t) <= 4 ? (dev) & 0xffff : \
|
||
|
(dev) & 0xffffffff))
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef S_IFBLK
|
||
|
case S_IFBLK:
|
||
|
sprintf(buffer, "B\t%s\t%lu %lu\n",
|
||
|
s_entry->name,
|
||
|
(unsigned long) major(statbuf.st_rdev),
|
||
|
(unsigned long) minor(statbuf.st_rdev));
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef S_IFIFO
|
||
|
case S_IFIFO:
|
||
|
sprintf(buffer, "P\t%s\n",
|
||
|
s_entry->name);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef S_IFCHR
|
||
|
case S_IFCHR:
|
||
|
sprintf(buffer, "C\t%s\t%lu %lu\n",
|
||
|
s_entry->name,
|
||
|
(unsigned long) major(statbuf.st_rdev),
|
||
|
(unsigned long) minor(statbuf.st_rdev));
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef S_IFLNK
|
||
|
case S_IFLNK:
|
||
|
#ifdef HAVE_READLINK
|
||
|
nchar = readlink(statp?short_name:whole_path,
|
||
|
(char *)symlink_buff,
|
||
|
sizeof (symlink_buff)-1);
|
||
|
if (nchar < 0) {
|
||
|
errmsg(_("Cannot read link '%s'.\n"),
|
||
|
statp?short_name:whole_path);
|
||
|
}
|
||
|
#else
|
||
|
nchar = -1;
|
||
|
#endif
|
||
|
symlink_buff[nchar < 0 ? 0 : nchar] = 0;
|
||
|
sprintf(buffer, "L\t%s\t%s\n",
|
||
|
s_entry->name, symlink_buff);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef S_IFSOCK
|
||
|
case S_IFSOCK:
|
||
|
sprintf(buffer, "S\t%s\n",
|
||
|
s_entry->name);
|
||
|
break;
|
||
|
#endif
|
||
|
case S_IFREG:
|
||
|
default:
|
||
|
sprintf(buffer, "F\t%s\n",
|
||
|
s_entry->name);
|
||
|
break;
|
||
|
};
|
||
|
s_entry->table = e_strdup(buffer);
|
||
|
}
|
||
|
if (S_ISDIR(statbuf.st_mode)) {
|
||
|
int dflag;
|
||
|
|
||
|
if (strcmp(short_name, ".") != 0 &&
|
||
|
strcmp(short_name, "..") != 0) {
|
||
|
struct directory *child;
|
||
|
|
||
|
child = find_or_create_directory(this_dir, whole_path,
|
||
|
s_entry, 1);
|
||
|
#ifdef USE_NO_SCANDIR
|
||
|
if (no_scandir)
|
||
|
dflag = 1;
|
||
|
else
|
||
|
#endif
|
||
|
dflag = scan_directory_tree(child, whole_path,
|
||
|
s_entry);
|
||
|
|
||
|
if (!dflag) {
|
||
|
lstatbuf.st_mode =
|
||
|
(lstatbuf.st_mode & ~S_IFMT) | S_IFREG;
|
||
|
if (child->contents == NULL) {
|
||
|
delete_directory(this_dir, child);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* If unable to scan directory, mark this as a non-directory */
|
||
|
}
|
||
|
if (use_RockRidge && this_dir == root &&
|
||
|
strcmp(s_entry->name, ".") == 0) {
|
||
|
deep_flag |= NEED_CE | NEED_SP; /* For extension record */
|
||
|
}
|
||
|
/*
|
||
|
* Now figure out how much room this file will take in the directory
|
||
|
*/
|
||
|
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* Ff the file is HFS excluded, then we don't have an hfs_ent
|
||
|
*/
|
||
|
if (apple_both && !have_rsrc && s_entry->hfs_ent) {
|
||
|
if (S_ISREG(lstatbuf.st_mode)) { /* it's a regular file */
|
||
|
|
||
|
/*
|
||
|
* Fill in the rest of the HFS entry
|
||
|
*/
|
||
|
get_hfs_info(whole_path, short_name, s_entry);
|
||
|
|
||
|
/*
|
||
|
* If required, set ISO directory name from HFS name
|
||
|
*/
|
||
|
if (use_mac_name)
|
||
|
iso9660_file_length(s_entry->hfs_ent->name,
|
||
|
s_entry, 0);
|
||
|
|
||
|
/*
|
||
|
* Print details about the HFS file
|
||
|
*/
|
||
|
if (verbose > 2)
|
||
|
print_hfs_info(s_entry);
|
||
|
|
||
|
/*
|
||
|
* copy the new ISO9660 name to the rsrc fork
|
||
|
* - if it exists
|
||
|
*/
|
||
|
if (s_entry->assoc)
|
||
|
strcpy(s_entry->assoc->isorec.name,
|
||
|
s_entry->isorec.name);
|
||
|
|
||
|
/*
|
||
|
* we can't handle hard links in the hybrid case, so we
|
||
|
* "uncache" the file. The downside to this is that
|
||
|
* hard linked files are added to the output image
|
||
|
* more than once (we've already done this for rsrc
|
||
|
* files)
|
||
|
*/
|
||
|
if (apple_hyb && have_rsrc) {
|
||
|
s_entry->de_flags |= RESOURCE_FORK;
|
||
|
s_entry->inode = UNCACHED_INODE;
|
||
|
s_entry->dev = UNCACHED_DEVICE;
|
||
|
}
|
||
|
} else if (!(s_entry->isorec.flags[0] & ISO_DIRECTORY)) {
|
||
|
/* not a directory .. */
|
||
|
|
||
|
/*
|
||
|
* no mac equivalent, so ignore - have to be careful
|
||
|
* here, the hfs_ent may be also be for a relocated
|
||
|
* directory
|
||
|
*/
|
||
|
if (s_entry->hfs_ent &&
|
||
|
!(s_entry->de_flags & RELOCATED_DIRECTORY) &&
|
||
|
(s_entry->isorec.flags[0] & ISO_MULTIEXTENT) == 0) {
|
||
|
free(s_entry->hfs_ent);
|
||
|
}
|
||
|
s_entry->hfs_ent = NULL;
|
||
|
}
|
||
|
/*
|
||
|
* if the rsrc size is zero, then we don't need the entry, so
|
||
|
* we might as well delete it - this will only happen if we
|
||
|
* didn't know the rsrc size from the rsrc file size
|
||
|
*/
|
||
|
if (s_entry->assoc && s_entry->assoc->size == 0)
|
||
|
delete_rsrc_ent(s_entry);
|
||
|
}
|
||
|
if (apple_ext && s_entry->assoc) {
|
||
|
/*
|
||
|
* Need Apple extensions for the resource fork as well
|
||
|
*/
|
||
|
generate_xa_rr_attributes(whole_path,
|
||
|
short_name, s_entry->assoc,
|
||
|
&statbuf, &lstatbuf, deep_flag | (statp?DID_CHDIR:0));
|
||
|
}
|
||
|
/* leave out resource fork for the time being */
|
||
|
/*
|
||
|
* XXX This is most likely wrong and should just be:
|
||
|
* XXX if (use_XA || use_RockRidge) {
|
||
|
*/
|
||
|
/* if ((use_XA || use_RockRidge) && !have_rsrc) {*/
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
#else
|
||
|
if (use_XA || use_RockRidge) {
|
||
|
#endif /* APPLE_HYB */
|
||
|
generate_xa_rr_attributes(whole_path,
|
||
|
short_name, s_entry,
|
||
|
&statbuf, &lstatbuf, deep_flag | (statp?DID_CHDIR:0));
|
||
|
|
||
|
}
|
||
|
#ifdef UDF
|
||
|
/* set some info used for udf */
|
||
|
s_entry->mode = lstatbuf.st_mode;
|
||
|
s_entry->rdev = lstatbuf.st_rdev;
|
||
|
s_entry->uid = lstatbuf.st_uid;
|
||
|
s_entry->gid = lstatbuf.st_gid;
|
||
|
s_entry->atime.tv_sec = lstatbuf.st_atime;
|
||
|
s_entry->atime.tv_nsec = stat_ansecs(&lstatbuf);
|
||
|
s_entry->mtime.tv_sec = lstatbuf.st_mtime;
|
||
|
s_entry->mtime.tv_nsec = stat_mnsecs(&lstatbuf);
|
||
|
s_entry->ctime.tv_sec = lstatbuf.st_ctime;
|
||
|
s_entry->ctime.tv_nsec = stat_cnsecs(&lstatbuf);
|
||
|
#endif
|
||
|
|
||
|
#ifdef USE_LARGEFILES
|
||
|
#ifndef MAX_EXTENT
|
||
|
/*
|
||
|
* Allow to #define MAX_EXTENT from outside for debug purposes.
|
||
|
*/
|
||
|
#ifdef PROTOTYPES
|
||
|
#define LARGE_EXTENT ((off_t)0xFFFFF800UL)
|
||
|
#define MAX_EXTENT ((off_t)0xFFFFFFFEUL)
|
||
|
#else
|
||
|
#define LARGE_EXTENT ((off_t)0xFFFFF800L)
|
||
|
#define MAX_EXTENT ((off_t)0xFFFFFFFEL)
|
||
|
#endif
|
||
|
#else /* MAX_EXTENT */
|
||
|
#define LARGE_EXTENT MAX_EXTENT & ~(off_t)2047L
|
||
|
#endif /* !MAX_EXTENT */
|
||
|
/*
|
||
|
* Break up files greater than (4GB -2) into multiple extents.
|
||
|
* The original entry, with ->size untouched, remains for UDF.
|
||
|
* Each of the new file sections will get its own entry.
|
||
|
* The file sections are the only entries actually written out to the
|
||
|
* disk. The UDF entry will use "mxroot" to get the same start
|
||
|
* block as the first file section, and all the sections will end up
|
||
|
* in the ISO9660 directory in the correct order by "mxpart",
|
||
|
* which the directory sorting routine knows about.
|
||
|
*
|
||
|
* If we ever need to be able to find mxpart == 1 after sorting,
|
||
|
* we need to add another pointer to s_entry or to be very careful
|
||
|
* with the loops above where the ISO-9660 name is copied back to
|
||
|
* all multi-extent parts.
|
||
|
*/
|
||
|
if (s_entry->size > MAX_EXTENT) {
|
||
|
off_t size;
|
||
|
|
||
|
s_entry->de_flags |= MULTI_EXTENT;
|
||
|
s_entry->isorec.flags[0] |= ISO_MULTIEXTENT;
|
||
|
s_entry->mxroot = s_entry;
|
||
|
s_entry->mxpart = 0;
|
||
|
set_733((char *)s_entry->isorec.size, LARGE_EXTENT);
|
||
|
s_entry1 = dup_directory_entry(s_entry);
|
||
|
s_entry->next = s_entry1;
|
||
|
|
||
|
/*
|
||
|
* full size UDF version
|
||
|
*/
|
||
|
s_entry->de_flags |= INHIBIT_ISO9660_ENTRY|INHIBIT_JOLIET_ENTRY;
|
||
|
if (s_entry->size > (((off_t)190)*0x3FFFF800)) {
|
||
|
#ifndef EOVERFLOW
|
||
|
#define EOVERFLOW EFBIG
|
||
|
#endif
|
||
|
errmsgno(EOVERFLOW,
|
||
|
_("File %s is too large - hiding from UDF tree.\n"),
|
||
|
whole_path);
|
||
|
s_entry->de_flags |= INHIBIT_UDF_ENTRY;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Prepare the first file multi-extent section of the file.
|
||
|
*/
|
||
|
s_entry = s_entry1;
|
||
|
s_entry->de_flags |= INHIBIT_UDF_ENTRY;
|
||
|
size = s_entry->size;
|
||
|
s_entry->size = LARGE_EXTENT;
|
||
|
s_entry->mxpart++;
|
||
|
|
||
|
/*
|
||
|
* Additional extents, as needed
|
||
|
*/
|
||
|
while (size > MAX_EXTENT) {
|
||
|
s_entry1 = dup_directory_entry(s_entry);
|
||
|
s_entry->next = s_entry1;
|
||
|
|
||
|
s_entry = s_entry1;
|
||
|
s_entry->mxpart++;
|
||
|
size -= LARGE_EXTENT;
|
||
|
}
|
||
|
/*
|
||
|
* That was the last one.
|
||
|
*/
|
||
|
s_entry->isorec.flags[0] &= ~ISO_MULTIEXTENT;
|
||
|
s_entry->size = size;
|
||
|
set_733((char *)s_entry->isorec.size, (UInt32_t)s_entry->size);
|
||
|
}
|
||
|
#endif /* USE_LARGEFILES */
|
||
|
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
EXPORT struct directory_entry *
|
||
|
dup_directory_entry(s_entry)
|
||
|
struct directory_entry *s_entry;
|
||
|
{
|
||
|
struct directory_entry *s_entry1;
|
||
|
|
||
|
s_entry1 = (struct directory_entry *)
|
||
|
e_malloc(sizeof (struct directory_entry));
|
||
|
memcpy(s_entry1, s_entry, sizeof (struct directory_entry));
|
||
|
|
||
|
if (s_entry->rr_attributes) {
|
||
|
s_entry1->rr_attributes =
|
||
|
e_malloc(s_entry->total_rr_attr_size);
|
||
|
memcpy(s_entry1->rr_attributes, s_entry->rr_attributes,
|
||
|
s_entry->total_rr_attr_size);
|
||
|
}
|
||
|
if (s_entry->name)
|
||
|
s_entry1->name = e_strdup(s_entry->name);
|
||
|
if (s_entry->whole_name)
|
||
|
s_entry1->whole_name = e_strdup(s_entry->whole_name);
|
||
|
#ifdef APPLE_HYB
|
||
|
/*
|
||
|
* If we also duplicate s_entry->hfs_ent, we would need to change
|
||
|
* free_one_directory() and other calls to free(s_entry->hfs_ent) too.
|
||
|
*/
|
||
|
#endif
|
||
|
return (s_entry1);
|
||
|
}
|
||
|
|
||
|
EXPORT void
|
||
|
generate_iso9660_directories(node, outfile)
|
||
|
struct directory *node;
|
||
|
FILE *outfile;
|
||
|
{
|
||
|
struct directory *dpnt;
|
||
|
|
||
|
dpnt = node;
|
||
|
|
||
|
while (dpnt) {
|
||
|
if (dpnt->extent > session_start) {
|
||
|
generate_one_directory(dpnt, outfile);
|
||
|
}
|
||
|
if (dpnt->subdir)
|
||
|
generate_iso9660_directories(dpnt->subdir, outfile);
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* XXX This may need some work for the MVS port.
|
||
|
*/
|
||
|
LOCAL void
|
||
|
set_de_path(parent, this)
|
||
|
struct directory *parent;
|
||
|
struct directory *this;
|
||
|
{
|
||
|
char *p;
|
||
|
size_t len;
|
||
|
|
||
|
if (parent == NULL) { /* We are just creating root */
|
||
|
this->de_path = this->whole_name;
|
||
|
return;
|
||
|
} else if (parent == root) { /* full path == component */
|
||
|
this->de_path = this->de_name;
|
||
|
return;
|
||
|
}
|
||
|
len = strlen(parent->de_path)+1+strlen(this->de_name)+1;
|
||
|
p = e_malloc(len);
|
||
|
js_snprintf(p, len, "%s/%s", parent->de_path, this->de_name);
|
||
|
this->de_path = p;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: find_or_create_directory
|
||
|
*
|
||
|
* Purpose: Locate a directory entry in the tree, create if needed.
|
||
|
*
|
||
|
* Arguments: parent & de are never NULL at the same time.
|
||
|
*/
|
||
|
EXPORT struct directory *
|
||
|
find_or_create_directory(parent, path, de, flag)
|
||
|
struct directory *parent;
|
||
|
char *path;
|
||
|
struct directory_entry *de;
|
||
|
int flag;
|
||
|
{
|
||
|
struct directory *child = 0;
|
||
|
struct directory *dpnt;
|
||
|
struct directory_entry *orig_de;
|
||
|
struct directory *next_brother;
|
||
|
const char *cpnt;
|
||
|
const char *pnt;
|
||
|
int deep_flag = 0;
|
||
|
|
||
|
orig_de = de;
|
||
|
|
||
|
/*
|
||
|
* XXX It seems that the tree that has been read from the
|
||
|
* XXX previous session does not carry whole_name entries.
|
||
|
* XXX We provide a hack in multi.c:find_or_create_directory()
|
||
|
* XXX that should be removed when a reasonable method could
|
||
|
* XXX be found.
|
||
|
*/
|
||
|
if (path == NULL) {
|
||
|
error(_("Warning: missing whole name for: '%s'\n"), de->name);
|
||
|
path = de->name;
|
||
|
if (path == NULL)
|
||
|
comerrno(EX_BAD, _("Panic no node name.\n"));
|
||
|
}
|
||
|
pnt = strrchr(path, PATH_SEPARATOR);
|
||
|
if (pnt == NULL) {
|
||
|
pnt = path;
|
||
|
} else {
|
||
|
pnt++;
|
||
|
}
|
||
|
|
||
|
if (parent != NULL) {
|
||
|
|
||
|
dpnt = parent->subdir;
|
||
|
if (dpnt == NULL) {
|
||
|
struct directory_entry *s_entry;
|
||
|
|
||
|
for (s_entry = parent->contents; s_entry;
|
||
|
s_entry = s_entry->next) {
|
||
|
if ((strcmp(s_entry->name, pnt) == 0) &&
|
||
|
(s_entry->de_flags & RELOCATED_DIRECTORY)) {
|
||
|
return (find_or_create_directory(
|
||
|
reloc_dir, path, de,
|
||
|
flag));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (dpnt) {
|
||
|
/*
|
||
|
* Weird hack time - if there are two directories by
|
||
|
* the same name in the reloc_dir, they are not
|
||
|
* treated as the same thing unless the entire path
|
||
|
* matches completely.
|
||
|
*/
|
||
|
if (flag && strcmp(dpnt->de_name, pnt) == 0) {
|
||
|
|
||
|
/*
|
||
|
* XXX Remove test?
|
||
|
* XXX dpnt->de_path should always be != NULL
|
||
|
*/
|
||
|
if (dpnt->de_path != NULL &&
|
||
|
strcmp(dpnt->de_path, path) == 0)
|
||
|
return (dpnt);
|
||
|
|
||
|
if (parent != reloc_dir &&
|
||
|
strcmp(dpnt->de_name, pnt) == 0)
|
||
|
return (dpnt);
|
||
|
}
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* We don't know if we have a valid directory entry for this one yet.
|
||
|
* If not, we need to create one.
|
||
|
*/
|
||
|
if (de == NULL) {
|
||
|
de = (struct directory_entry *)
|
||
|
e_malloc(sizeof (struct directory_entry));
|
||
|
memset(de, 0, sizeof (struct directory_entry));
|
||
|
de->next = parent->contents;
|
||
|
parent->contents = de;
|
||
|
de->name = e_strdup(pnt);
|
||
|
de->whole_name = e_strdup(path);
|
||
|
de->filedir = parent;
|
||
|
de->isorec.flags[0] = ISO_DIRECTORY;
|
||
|
de->priority = 32768;
|
||
|
de->inode = UNCACHED_INODE;
|
||
|
de->dev = UNCACHED_DEVICE;
|
||
|
set_723(de->isorec.volume_sequence_number,
|
||
|
volume_sequence_number);
|
||
|
iso9660_file_length(pnt, de, 1);
|
||
|
|
||
|
init_fstatbuf();
|
||
|
#ifdef APPLE_HYB
|
||
|
if (apple_both) {
|
||
|
/*
|
||
|
* Give the directory an HFS entry
|
||
|
*/
|
||
|
hfsdirent *hfs_ent;
|
||
|
|
||
|
hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
|
||
|
|
||
|
/*
|
||
|
* Fill in the defaults
|
||
|
*/
|
||
|
memset(hfs_ent, 0, sizeof (hfsdirent));
|
||
|
hfs_ent->crdate = fstatbuf.st_ctime;
|
||
|
hfs_ent->mddate = fstatbuf.st_mtime;
|
||
|
|
||
|
de->hfs_ent = hfs_ent;
|
||
|
|
||
|
/*
|
||
|
* Get the Mac directory name
|
||
|
*/
|
||
|
get_hfs_dir((char *)path, (char *)pnt, de);
|
||
|
}
|
||
|
#endif /* APPLE_HYB */
|
||
|
}
|
||
|
/*
|
||
|
* If we don't have a directory for this one yet, then allocate it now,
|
||
|
* and patch it into the tree in the appropriate place.
|
||
|
*/
|
||
|
dpnt = (struct directory *)e_malloc(sizeof (struct directory));
|
||
|
memset(dpnt, 0, sizeof (struct directory));
|
||
|
dpnt->next = NULL;
|
||
|
dpnt->subdir = NULL;
|
||
|
dpnt->self = de;
|
||
|
dpnt->contents = NULL;
|
||
|
dpnt->whole_name = e_strdup(path);
|
||
|
cpnt = strrchr(path, PATH_SEPARATOR);
|
||
|
if (cpnt)
|
||
|
cpnt++;
|
||
|
else
|
||
|
cpnt = path;
|
||
|
dpnt->de_name = e_strdup(cpnt);
|
||
|
dpnt->de_path = NULL;
|
||
|
set_de_path(parent, dpnt);
|
||
|
dpnt->size = 0;
|
||
|
dpnt->extent = 0;
|
||
|
dpnt->jextent = 0;
|
||
|
dpnt->jsize = 0;
|
||
|
#ifdef APPLE_HYB
|
||
|
dpnt->hfs_ent = de->hfs_ent;
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
if (orig_de == NULL) {
|
||
|
struct stat xstatbuf;
|
||
|
int sts;
|
||
|
|
||
|
/*
|
||
|
* Now add a . and .. entry in the directory itself. This is a
|
||
|
* little tricky - if the real directory exists, we need to
|
||
|
* stat it first. Otherwise, we use the fictitious fstatbuf
|
||
|
* which points to the time at which mkisofs was started.
|
||
|
*/
|
||
|
if (parent == NULL || parent->whole_name[0] == '\0')
|
||
|
sts = -1;
|
||
|
else
|
||
|
sts = stat_filter(parent->whole_name, &xstatbuf);
|
||
|
if (debug && parent) {
|
||
|
error(_("stat parent->whole_name: '%s' -> %d.\n"),
|
||
|
parent->whole_name, sts);
|
||
|
}
|
||
|
if (sts == 0) {
|
||
|
attach_dot_entries(dpnt, NULL, &xstatbuf);
|
||
|
} else {
|
||
|
attach_dot_entries(dpnt, NULL, NULL);
|
||
|
}
|
||
|
}
|
||
|
if (!parent || parent == root) {
|
||
|
if (!root) {
|
||
|
root = dpnt; /* First time through for root */
|
||
|
/* directory only */
|
||
|
root->depth = 0;
|
||
|
root->parent = root;
|
||
|
} else {
|
||
|
dpnt->depth = 1;
|
||
|
if (!root->subdir) {
|
||
|
root->subdir = dpnt;
|
||
|
} else {
|
||
|
next_brother = root->subdir;
|
||
|
while (next_brother->next)
|
||
|
next_brother = next_brother->next;
|
||
|
next_brother->next = dpnt;
|
||
|
}
|
||
|
dpnt->parent = parent;
|
||
|
}
|
||
|
} else {
|
||
|
struct directory_entry *s_entry1;
|
||
|
|
||
|
/*
|
||
|
* Come through here for normal traversal of tree
|
||
|
*/
|
||
|
#ifdef DEBUG
|
||
|
fprintf(stderr, "%s(%d) ", path, dpnt->depth);
|
||
|
#endif
|
||
|
|
||
|
if (parent->depth > RR_relocation_depth && use_RockRidge) {
|
||
|
/*
|
||
|
* We come here in case that a graft-point needs to
|
||
|
* create a new relocated (deep) directory.
|
||
|
*
|
||
|
* Replicate the entry for this directory. The old one
|
||
|
* will stay where it is, and it will be neutered so
|
||
|
* that it no longer looks like a directory. The new
|
||
|
* one will look like a directory, and it will be put
|
||
|
* in the reloc_dir.
|
||
|
*/
|
||
|
s_entry1 = dup_relocated_dir(parent, de, path,
|
||
|
dpnt->de_name, &fstatbuf);
|
||
|
child = find_or_create_directory(reloc_dir, path,
|
||
|
s_entry1, 0);
|
||
|
free(child->de_path); /* allocated in this case */
|
||
|
set_de_path(parent, child);
|
||
|
|
||
|
deep_flag |= NEED_CL;
|
||
|
}
|
||
|
if (parent->depth > RR_relocation_depth && !use_RockRidge) {
|
||
|
dir_nesting_warn(parent, path, FALSE);
|
||
|
exit(EX_BAD);
|
||
|
}
|
||
|
dpnt->parent = parent;
|
||
|
dpnt->depth = parent->depth + 1;
|
||
|
|
||
|
if ((deep_flag & NEED_CL) == 0) {
|
||
|
/*
|
||
|
* Do not add this directory to the list of subdirs if
|
||
|
* this is a relocated directory.
|
||
|
*/
|
||
|
if (!parent->subdir) {
|
||
|
parent->subdir = dpnt;
|
||
|
} else {
|
||
|
next_brother = parent->subdir;
|
||
|
while (next_brother->next)
|
||
|
next_brother = next_brother->next;
|
||
|
next_brother->next = dpnt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* It doesn't exist for real, so we cannot add any
|
||
|
* XA or Rock Ridge attributes.
|
||
|
*/
|
||
|
if (orig_de == NULL || (parent == NULL && path[0] == '\0')) {
|
||
|
init_fstatbuf();
|
||
|
fstatbuf.st_mode = new_dir_mode | S_IFDIR;
|
||
|
fstatbuf.st_nlink = 2;
|
||
|
if ((use_XA || use_RockRidge) &&
|
||
|
!(parent == NULL && path[0] == '\0')) {
|
||
|
/*
|
||
|
* We cannot set up RR attrubutes for the real
|
||
|
* ISO-9660 root directory. This is why we
|
||
|
* check for parent == NULL && path[0] == '\0'.
|
||
|
*/
|
||
|
generate_xa_rr_attributes("",
|
||
|
(char *)pnt, de,
|
||
|
&fstatbuf,
|
||
|
&fstatbuf, deep_flag);
|
||
|
}
|
||
|
#ifdef UDF
|
||
|
/* set some info used for udf */
|
||
|
de->mode = fstatbuf.st_mode;
|
||
|
de->uid = fstatbuf.st_uid;
|
||
|
de->gid = fstatbuf.st_gid;
|
||
|
de->atime.tv_sec = fstatbuf.st_atime;
|
||
|
de->atime.tv_nsec = stat_ansecs(&fstatbuf);
|
||
|
de->mtime.tv_sec = fstatbuf.st_mtime;
|
||
|
de->mtime.tv_nsec = stat_mnsecs(&fstatbuf);
|
||
|
de->ctime.tv_sec = fstatbuf.st_ctime;
|
||
|
de->ctime.tv_nsec = stat_cnsecs(&fstatbuf);
|
||
|
#endif
|
||
|
iso9660_date(de->isorec.date, fstatbuf.st_mtime);
|
||
|
}
|
||
|
if (child)
|
||
|
return (child); /* Return reloaction target */
|
||
|
|
||
|
return (dpnt);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: delete_directory
|
||
|
*
|
||
|
* Purpose: Locate a directory entry in the tree, create if needed.
|
||
|
*
|
||
|
* Arguments:
|
||
|
*/
|
||
|
LOCAL void
|
||
|
delete_directory(parent, child)
|
||
|
struct directory *parent;
|
||
|
struct directory *child;
|
||
|
{
|
||
|
struct directory *tdir;
|
||
|
|
||
|
if (child == NULL)
|
||
|
return;
|
||
|
if (child->contents != NULL) {
|
||
|
comerrno(EX_BAD, _("Unable to delete non-empty directory\n"));
|
||
|
}
|
||
|
free(child->whole_name);
|
||
|
child->whole_name = NULL;
|
||
|
|
||
|
free(child->de_name);
|
||
|
child->de_name = NULL;
|
||
|
|
||
|
#ifdef APPLE_HYB
|
||
|
if (apple_both && child->hfs_ent)
|
||
|
free(child->hfs_ent);
|
||
|
#endif /* APPLE_HYB */
|
||
|
|
||
|
if (parent->subdir == child) {
|
||
|
parent->subdir = child->next;
|
||
|
} else {
|
||
|
for (tdir = parent->subdir; tdir != NULL && tdir->next != NULL;
|
||
|
tdir = tdir->next) {
|
||
|
if (tdir->next == child) {
|
||
|
tdir->next = child->next;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (tdir == NULL || tdir->next != child->next) {
|
||
|
comerrno(EX_BAD,
|
||
|
_("Unable to locate child directory in parent list\n"));
|
||
|
}
|
||
|
}
|
||
|
free(child);
|
||
|
}
|
||
|
|
||
|
EXPORT int
|
||
|
sort_tree(node)
|
||
|
struct directory *node;
|
||
|
{
|
||
|
struct directory *dpnt;
|
||
|
int ret = 0;
|
||
|
|
||
|
dpnt = node;
|
||
|
|
||
|
while (dpnt) {
|
||
|
ret = sort_n_finish(dpnt);
|
||
|
if (ret) {
|
||
|
break;
|
||
|
}
|
||
|
if (dpnt->subdir)
|
||
|
sort_tree(dpnt->subdir);
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
return (ret);
|
||
|
}
|
||
|
|
||
|
EXPORT void
|
||
|
dump_tree(node)
|
||
|
struct directory *node;
|
||
|
{
|
||
|
struct directory *dpnt;
|
||
|
|
||
|
dpnt = node;
|
||
|
|
||
|
while (dpnt) {
|
||
|
fprintf(stderr, "%4d %5d %s\n",
|
||
|
dpnt->extent, dpnt->size, dpnt->de_name);
|
||
|
if (dpnt->subdir)
|
||
|
dump_tree(dpnt->subdir);
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* something quick and dirty to locate a file given a path
|
||
|
* recursively walks down path in filename until it finds the
|
||
|
* directory entry for the desired file
|
||
|
*/
|
||
|
EXPORT struct directory_entry *
|
||
|
search_tree_file(node, filename)
|
||
|
struct directory *node;
|
||
|
char *filename;
|
||
|
{
|
||
|
struct directory_entry *depnt;
|
||
|
struct directory *dpnt;
|
||
|
char *p1;
|
||
|
char *rest;
|
||
|
char *subdir;
|
||
|
|
||
|
/*
|
||
|
* Strip off next directory name from filename:
|
||
|
*/
|
||
|
subdir = e_strdup(filename);
|
||
|
|
||
|
if ((p1 = strchr(subdir, '/')) == subdir) {
|
||
|
fprintf(stderr,
|
||
|
_("call to search_tree_file with an absolute path, stripping\n"));
|
||
|
fprintf(stderr,
|
||
|
_("initial path separator. Hope this was intended...\n"));
|
||
|
memmove(subdir, subdir + 1, strlen(subdir) - 1);
|
||
|
p1 = strchr(subdir, '/');
|
||
|
}
|
||
|
/*
|
||
|
* Do we need to find a subdirectory?
|
||
|
*/
|
||
|
if (p1) {
|
||
|
*p1 = '\0';
|
||
|
|
||
|
#ifdef DEBUG_TORITO
|
||
|
fprintf(stderr, _("Looking for subdir called %s\n"), p1);
|
||
|
#endif
|
||
|
|
||
|
rest = p1 + 1;
|
||
|
|
||
|
#ifdef DEBUG_TORITO
|
||
|
fprintf(stderr, _("Remainder of path name is now %s\n"), rest);
|
||
|
#endif
|
||
|
|
||
|
dpnt = node->subdir;
|
||
|
while (dpnt) {
|
||
|
#ifdef DEBUG_TORITO
|
||
|
fprintf(stderr,
|
||
|
"%4d %5d %s\n", dpnt->extent, dpnt->size,
|
||
|
dpnt->de_name);
|
||
|
#endif
|
||
|
if (strcmp(subdir, dpnt->de_name) == 0) {
|
||
|
#ifdef DEBUG_TORITO
|
||
|
fprintf(stderr,
|
||
|
_("Calling next level with filename = %s\n"), rest);
|
||
|
#endif
|
||
|
return (search_tree_file(dpnt, rest));
|
||
|
}
|
||
|
dpnt = dpnt->next;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If we got here means we couldn't find the subdir.
|
||
|
*/
|
||
|
return (NULL);
|
||
|
} else {
|
||
|
/*
|
||
|
* Look for a normal file now
|
||
|
*/
|
||
|
depnt = node->contents;
|
||
|
while (depnt) {
|
||
|
#ifdef DEBUG_TORITO
|
||
|
fprintf(stderr, "%4d %5d %s\n", depnt->isorec.extent,
|
||
|
depnt->size, depnt->name);
|
||
|
#endif
|
||
|
if (strcmp(filename, depnt->name) == 0) {
|
||
|
#ifdef DEBUG_TORITO
|
||
|
fprintf(stderr, _("Found our file %s"), filename);
|
||
|
#endif
|
||
|
return (depnt);
|
||
|
}
|
||
|
depnt = depnt->next;
|
||
|
}
|
||
|
/*
|
||
|
* If we got here means we couldn't find the subdir.
|
||
|
*/
|
||
|
return (NULL);
|
||
|
}
|
||
|
#ifdef ERIC_FUN
|
||
|
fprintf(stderr, _("We cant get here in search_tree_file :-/ \n"));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
EXPORT void
|
||
|
init_fstatbuf()
|
||
|
{
|
||
|
struct timeval current_time;
|
||
|
|
||
|
if (fstatbuf.st_ctime == 0) {
|
||
|
gettimeofday(¤t_time, NULL);
|
||
|
if (rationalize_uid)
|
||
|
fstatbuf.st_uid = uid_to_use;
|
||
|
else
|
||
|
fstatbuf.st_uid = getuid();
|
||
|
if (rationalize_gid)
|
||
|
fstatbuf.st_gid = gid_to_use;
|
||
|
else
|
||
|
fstatbuf.st_gid = getgid();
|
||
|
|
||
|
current_time.tv_usec *= 1000;
|
||
|
fstatbuf.st_ctime = current_time.tv_sec;
|
||
|
stat_set_ansecs(&fstatbuf, current_time.tv_usec);
|
||
|
fstatbuf.st_mtime = current_time.tv_sec;
|
||
|
stat_set_mnsecs(&fstatbuf, current_time.tv_usec);
|
||
|
fstatbuf.st_atime = current_time.tv_sec;
|
||
|
stat_set_cnsecs(&fstatbuf, current_time.tv_usec);
|
||
|
}
|
||
|
}
|