diff options
Diffstat (limited to 'genisoimage/apple.c')
-rw-r--r-- | genisoimage/apple.c | 2688 |
1 files changed, 2688 insertions, 0 deletions
diff --git a/genisoimage/apple.c b/genisoimage/apple.c new file mode 100644 index 0000000..3939504 --- /dev/null +++ b/genisoimage/apple.c @@ -0,0 +1,2688 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)apple.c 1.19 04/03/02 joerg, Copyright 1997, 1998, 1999, 2000 James Pearson */ +/* + * Copyright (c) 1997, 1998, 1999, 2000 James Pearson + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Unix-HFS file interface including maping file extensions to TYPE/CREATOR + * + * Adapted from mkhfs routines for mkhybrid + * + * James Pearson 1/5/97 + * Bug fix JCP 4/12/97 + * Updated for 1.12 and added more Unix HFS filetypes. JCP 21/1/98 + * Tidy up to use Finfo and Dinfo for all formats where + * possible JCP 25/4/2000 + * + * Things still to de done: + * + * Check file size = finder + rsrc [+ data] is needed + */ + +#ifdef APPLE_HYB + +#include <mconfig.h> +#include "genisoimage.h" +#include <errno.h> +#include <fctldefs.h> +#include <utypes.h> +#include <ctype.h> +#include <netinet/in.h> +#include "apple.h" +#include <schily.h> + +#ifdef USE_MAGIC +#include <magic.h> +magic_t magic_state = NULL; +#ifndef MAGIC_ERROR +/* workaround for older ´API */ +#define MAGIC_ERROR 0 +#endif +#endif /* USE_MAGIC */ + +/* tidy up genisoimage definition ... */ +typedef struct directory_entry dir_ent; + +/* routines for getting HFS names and info */ +#ifndef HAVE_STRCASECMP +static int strcasecmp(const char *s1, const char *s2); +#endif +static int get_none_dir(char *, char *, dir_ent *, int); +static int get_none_info(char *, char *, dir_ent *, int); +static int get_cap_dir(char *, char *, dir_ent *, int); +static int get_cap_info(char *, char *, dir_ent *, int); +static int get_es_dir(char *, char *, dir_ent *, int); +static int get_es_info(char *, char *, dir_ent *, int); +static int get_dbl_dir(char *, char *, dir_ent *, int); +static int get_dbl_info(char *, char *, dir_ent *, int); +static int get_mb_info(char *, char *, dir_ent *, int); +static int get_sgl_info(char *, char *, dir_ent *, int); +static int get_fe_dir(char *, char *, dir_ent *, int); +static int get_fe_info(char *, char *, dir_ent *, int); +static int get_sgi_dir(char *, char *, dir_ent *, int); +static int get_sgi_info(char *, char *, dir_ent *, int); +static int get_sfm_info(char *, char *, dir_ent *, int); + +#ifdef IS_MACOS_X +static int get_xhfs_dir(char *, char *, dir_ent *, int); +static int get_xhfs_info(char *, char *, dir_ent *, int); +#else +#define get_xhfs_dir get_none_dir +#define get_xhfs_info get_none_info +#endif /* IS_MACOS_X */ + +static void set_ct(hfsdirent *, char *, char *); +static void set_Dinfo(byte *, hfsdirent *); +static void set_Finfo(byte *, hfsdirent *); +static void cstrncpy(char *, char *, int); +static unsigned char dehex(char); +static unsigned char hex2char(char *); +static void hstrncpy(unsigned char *, char *, int); +static int read_info_file(char *, void *, int); + +/*static unsigned short calc_mb_crc __PR((unsigned char *, long, unsigned short));*/ +static struct hfs_info *get_hfs_fe_info(struct hfs_info *, char *); +static struct hfs_info *get_hfs_sgi_info(struct hfs_info *, char *); +static struct hfs_info *match_key(struct hfs_info *, char *); + +static int get_hfs_itype(char *, char *, char *); +static void map_ext(char *, char **, char **, short *, char *); + +static afpmap **map; /* list of mappings */ +static afpmap *defmap; /* the default mapping */ +static int last_ent; /* previous mapped entry */ +static int map_num; /* number of mappings */ +static int mlen; /* min extension length */ +static char tmp[PATH_MAX]; /* tmp working buffer */ +static int hfs_num; /* number of file types */ +static char p_buf[PATH_MAX]; /* info working buffer */ +static FILE *p_fp = NULL; /* probe File pointer */ +static int p_num = 0; /* probe bytes read */ +static unsigned int hselect; /* type of HFS file selected */ + +struct hfs_type { /* Types of various HFS Unix files */ + int type; /* type of file */ + int flags; /* special flags */ + char *info; /* finderinfo name */ + char *rsrc; /* resource fork name */ + int (*get_info)(char *, char *, dir_ent *, int); /* finderinfo */ + /* function */ + int (*get_dir)(char *, char *, dir_ent *, int); /* directory */ + /* name */ + /* function */ + char *desc; /* description */ +}; + +/* Above filled in */ +static struct hfs_type hfs_types[] = { + {TYPE_NONE, INSERT, "", "", get_none_info, get_none_dir, "None"}, + {TYPE_CAP, INSERT, ".finderinfo/", ".resource/", + get_cap_info, get_cap_dir, "CAP"}, + {TYPE_NETA, INSERT, ".AppleDouble/", ".AppleDouble/", + get_dbl_info, get_dbl_dir, "Netatalk"}, + {TYPE_DBL, INSERT, "%", "%", get_dbl_info, get_dbl_dir, "AppleDouble"}, + {TYPE_ESH, INSERT, ".rsrc/", ".rsrc/", + get_es_info, get_es_dir, "EtherShare/UShare"}, + {TYPE_FEU, NOPEND, "FINDER.DAT", "RESOURCE.FRK/", + get_fe_info, get_fe_dir, "Exchange"}, + {TYPE_FEL, NOPEND, "finder.dat", "resource.frk/", + get_fe_info, get_fe_dir, "Exchange"}, + {TYPE_SGI, NOPEND, ".HSancillary", ".HSResource/", + get_sgi_info, get_sgi_dir, "XINET/SGI"}, + {TYPE_MBIN, PROBE, "", "", get_mb_info, get_none_dir, "MacBinary"}, + {TYPE_SGL, PROBE, "", "", get_sgl_info, get_none_dir, "AppleSingle"}, + {TYPE_DAVE, INSERT, "resource.frk/", "resource.frk/", + get_dbl_info, get_dbl_dir, "DAVE"}, + {TYPE_SFM, APPEND | NORSRC, ":Afp_AfpInfo", ":Afp_Resource", + get_sfm_info, get_none_dir, "SFM"}, + {TYPE_XDBL, INSERT, "._", "._", get_dbl_info, get_dbl_dir, + "MacOS X AppleDouble"}, + {TYPE_XHFS, APPEND | NOINFO, "/rsrc", "/rsrc", get_xhfs_info, get_xhfs_dir, + "MacOS X HFS"} +}; + +/* used by get_magic_match() return */ +static char tmp_type[CT_SIZE + 1], + tmp_creator[CT_SIZE + 1]; + +#ifdef __used__ +/* + * An array useful for CRC calculations that use 0x1021 as the "seed" + * taken from mcvert.c modified by Jim Van Verth. + */ + +static unsigned short mb_magic[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +#endif /* __used__ */ + +#ifndef HAVE_STRCASECMP +static int +strcasecmp(const char *s1, const char *s2) +{ + while (tolower(*s1) == tolower(*s2)) { + if (*s1 == 0) + return (0); + s1++; + s2++; + } + return (tolower(*s1) - tolower(*s2)); +} +#endif + +/* + * set_ct: set CREATOR and TYPE in hfs_ent + * + * CREATOR and TYPE are padded with spaces if not CT_SIZE long + */ + +static void +set_ct(hfsdirent *hfs_ent, char *c, char *t) +{ + memset(hfs_ent->u.file.type, ' ', CT_SIZE); + memset(hfs_ent->u.file.creator, ' ', CT_SIZE); + + strncpy(hfs_ent->u.file.type, t, MIN(CT_SIZE, strlen(t))); + strncpy(hfs_ent->u.file.creator, c, MIN(CT_SIZE, strlen(c))); + + hfs_ent->u.file.type[CT_SIZE] = '\0'; + hfs_ent->u.file.creator[CT_SIZE] = '\0'; +} + +/* + * cstrncopy: Cap Unix name to HFS name + * + * ':' is replaced by '%' and string is terminated with '\0' + */ +static void +cstrncpy(char *t, char *f, int c) +{ + while (c-- && *f) { + switch (*f) { + case ':': + *t = '%'; + break; + default: + *t = *f; + break; + } + t++; + f++; + } + + *t = '\0'; +} + +/* + * dehex() + * + * Given a hexadecimal digit in ASCII, return the integer representation. + * + * Taken from linux/fs/hfs/trans.c by Paul H. Hargrove + */ +static unsigned char +dehex(char c) +{ + if ((c >= '0') && (c <= '9')) { + return (c - '0'); + } + if ((c >= 'a') && (c <= 'f')) { + return (c - 'a' + 10); + } + if ((c >= 'A') && (c <= 'F')) { + return (c - 'A' + 10); + } +/* return (0xff); */ + return (0); +} + +static unsigned char +hex2char(char *s) +{ + unsigned char i1; + unsigned char i2; + unsigned char o; + + if (strlen(++s) < 2) + return (0); + + i1 = (unsigned char) s[0]; + i2 = (unsigned char) s[1]; + + if (!isxdigit(i1) || !isxdigit(i2)) + return (0); + + o = (dehex(i1) << 4) & 0xf0; + o |= (dehex(i2) & 0xf); + + return (o); +} + + +/* + * hstrncpy: Unix name to HFS name with special character + * translation. + * + * "%xx" or ":xx" is assumed to be a "special" character and + * replaced by character code given by the hex characters "xx" + * + * if "xx" is not a hex number, then it is left alone - except + * that ":" is replaced by "%" + * + */ +static void +hstrncpy(unsigned char *t, char *f, int c) +{ + unsigned char o; + + while (c-- && *f) { + switch (*f) { + case ':': + case '%': + if ((o = hex2char(f)) == 0) { + *t = conv_charset('%', in_nls, hfs_onls); + } else { + *t = o; + f += 2; + } + break; + default: + *t = conv_charset(*f, in_nls, hfs_onls); + break; + } + t++; + f++; + } + + *t = '\0'; +} + +/* + * basename: find just the filename with any directory component + */ +/* + not used at the moment ... +static char +basename(a) + char *a; +{ + char *b; + + if ((b = strchr(a, '/'))) + return (++b); + else + return (a); +} +*/ + +/* + * set_Dinfo: set directory info + */ +static void +set_Dinfo(byte *ptr, hfsdirent *ent) +{ + Dinfo *dinfo = (Dinfo *)ptr; + + /* finder flags */ + ent->fdflags = d_getw((unsigned char *) dinfo->frFlags); + + if (icon_pos) { + ent->u.dir.rect.top = + d_getw((unsigned char *) dinfo->frRect[0]); + ent->u.dir.rect.left = + d_getw((unsigned char *) dinfo->frRect[1]); + ent->u.dir.rect.bottom = + d_getw((unsigned char *) dinfo->frRect[2]); + ent->u.dir.rect.right = + d_getw((unsigned char *) dinfo->frRect[3]); + + ent->fdlocation.v = + d_getw((unsigned char *) dinfo->frLocation[0]); + ent->fdlocation.h = + d_getw((unsigned char *) dinfo->frLocation[1]); + + ent->u.dir.view = + d_getw((unsigned char *) dinfo->frView); + + ent->u.dir.frscroll.v = + d_getw((unsigned char *) dinfo->frScroll[0]); + ent->u.dir.frscroll.h = + d_getw((unsigned char *) dinfo->frScroll[1]); + + } else { + /* + * clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? + */ + ent->fdflags &= 0xfeff; + } +} + +/* + * set_Finfo: set file info + */ +static void +set_Finfo(byte *ptr, hfsdirent *ent) +{ + Finfo *finfo = (Finfo *)ptr; + + /* type and creator from finder info */ + set_ct(ent, finfo->fdCreator, finfo->fdType); + + /* finder flags */ + ent->fdflags = d_getw((unsigned char *) finfo->fdFlags); + + if (icon_pos) { + ent->fdlocation.v = + d_getw((unsigned char *) finfo->fdLocation[0]); + ent->fdlocation.h = + d_getw((unsigned char *) finfo->fdLocation[1]); + } else { + /* + * clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? + */ + ent->fdflags &= 0xfeff; + } +} + +/* + * get_none_dir: ordinary Unix directory + */ +static int +get_none_dir(char *hname, char *dname, dir_ent *s_entry, int ret) +{ + /* just copy the given name */ + hstrncpy((unsigned char *) (s_entry->hfs_ent->name), + dname, HFS_MAX_FLEN); + + return (ret); +} + +/* + * get_none_info: ordinary Unix file - try to map extension + */ +static int +get_none_info(char *hname, char *dname, dir_ent *s_entry, int ret) +{ + char *t, + *c; + hfsdirent *hfs_ent = s_entry->hfs_ent; + + map_ext(dname, &t, &c, &s_entry->hfs_ent->fdflags, s_entry->whole_name); + + /* just copy the given name */ + hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN); + + set_ct(hfs_ent, c, t); + + return (ret); +} + +/* + * read_info_file: open and read a finderinfo file for an HFS file + * or directory + */ +static int +read_info_file(char *name, /* finderinfo filename */ + void *info, /* info buffer */ + int len /* length of above */) +{ + FILE *fp; + int num; + + /* clear out any old finderinfo stuf */ + memset(info, 0, len); + + if ((fp = fopen(name, "rb")) == NULL) + return (-1); + + /* read and ignore if the file is short - checked later */ + num = fread(info, 1, len, fp); + + fclose(fp); + + return (num); +} + +/* + * get_cap_dir: get the CAP name for a directory + */ +static int +get_cap_dir(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + FileInfo info; /* finderinfo struct */ + int num = -1; /* bytes read */ + hfsdirent *hfs_ent = s_entry->hfs_ent; + + num = read_info_file(hname, &info, sizeof (FileInfo)); + + /* check finder info is OK */ + if (num > 0 && + info.fi_magic1 == FI_MAGIC1 && + info.fi_magic == FI_MAGIC && + info.fi_bitmap & FI_BM_MACINTOSHFILENAME) { + /* use the finderinfo name if it exists */ + cstrncpy((char *) (hfs_ent->name), + (char *) (info.fi_macfilename), HFS_MAX_FLEN); + + set_Dinfo(info.finderinfo, hfs_ent); + + return (ret); + } else { + /* otherwise give it it's Unix name */ + hstrncpy((unsigned char *) (s_entry->hfs_ent->name), + dname, HFS_MAX_FLEN); + return (TYPE_NONE); + } +} + +/* +** get_cap_info: get CAP finderinfo for a file +*/ +static int +get_cap_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + FileInfo info; /* finderinfo struct */ + int num = -1; /* bytes read */ + hfsdirent *hfs_ent = s_entry->hfs_ent; + + num = read_info_file(hname, &info, sizeof (info)); + + /* check finder info is OK */ + if (num > 0 && + info.fi_magic1 == FI_MAGIC1 && + info.fi_magic == FI_MAGIC) { + + if (info.fi_bitmap & FI_BM_MACINTOSHFILENAME) { + /* use the finderinfo name if it exists */ + cstrncpy((char *) (hfs_ent->name), + (char *) (info.fi_macfilename), HFS_MAX_FLEN); + } else { + /* use Unix name */ + hstrncpy((unsigned char *) (hfs_ent->name), dname, + HFS_MAX_FLEN); + } + + set_Finfo(info.finderinfo, hfs_ent); +#ifdef USE_MAC_DATES + /* + * set created/modified dates - these date should have already + * been set from the Unix data fork dates. The finderinfo dates + * are in Mac format - but we have to convert them back to Unix + * for the time being + */ + if ((info.fi_datemagic & FI_CDATE)) { + /* use libhfs routines to get correct byte order */ + hfs_ent->crdate = d_toutime(d_getl(info.fi_ctime)); + } + if (info.fi_datemagic & FI_MDATE) { + hfs_ent->mddate = d_toutime(d_getl(info.fi_mtime)); + } +#endif /* USE_MAC_DATES */ + } else { + /* failed to open/read finderinfo - so try afpfile mapping */ + if (verbose > 2) { + fprintf(stderr, + "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } + ret = get_none_info(hname, dname, s_entry, TYPE_NONE); + } + + return (ret); +} + +/* + * get_es_dir: get EtherShare/UShare finderinfo for a directory + * + * based on code from Jens-Uwe Mager (jum@helios.de) and Phil Sylvester + * <psylvstr@interaccess.com> + */ +static int +get_es_dir(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + es_FileInfo *einfo; /* EtherShare info struct */ + us_FileInfo *uinfo; /* UShare info struct */ + char info[ES_INFO_SIZE]; /* finderinfo buffer */ + int num = -1; /* bytes read */ + hfsdirent *hfs_ent = s_entry->hfs_ent; + + /* + * the EtherShare and UShare file layout is the same, but they store + * finderinfo differently + */ + einfo = (es_FileInfo *) info; + uinfo = (us_FileInfo *) info; + + num = read_info_file(hname, info, sizeof (info)); + + /* check finder info for EtherShare finderinfo */ + if (num >= (int)sizeof (es_FileInfo) && + d_getl(einfo->magic) == ES_MAGIC && + d_getw(einfo->version) == ES_VERSION) { + + set_Dinfo(einfo->finderinfo, hfs_ent); + + } else if (num >= (int)sizeof (us_FileInfo)) { + /* + * UShare has no magic number, so we assume that this is a valid + * info/resource file ... + */ + + set_Dinfo(uinfo->finderinfo, hfs_ent); + + } else { + /* failed to open/read finderinfo - so try afpfile mapping */ + if (verbose > 2) { + fprintf(stderr, + "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } + ret = get_none_dir(hname, dname, s_entry, TYPE_NONE); + return (ret); + } + + /* set name */ + hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN); + + return (ret); +} + +/* + * get_es_info: get EtherShare/UShare finderinfo for a file + * + * based on code from Jens-Uwe Mager (jum@helios.de) and Phil Sylvester + * <psylvstr@interaccess.com> + */ +static int +get_es_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + es_FileInfo *einfo; /* EtherShare info struct */ + us_FileInfo *uinfo; /* UShare info struct */ + char info[ES_INFO_SIZE]; /* finderinfo buffer */ + int num = -1; /* bytes read */ + hfsdirent *hfs_ent = s_entry->hfs_ent; + dir_ent *s_entry1; + + /* + * the EtherShare and UShare file layout is the same, but they store + * finderinfo differently + */ + einfo = (es_FileInfo *) info; + uinfo = (us_FileInfo *) info; + + num = read_info_file(hname, info, sizeof (info)); + + /* check finder info for EtherShare finderinfo */ + if (num >= (int)sizeof (es_FileInfo) && + d_getl(einfo->magic) == ES_MAGIC && + d_getw(einfo->version) == ES_VERSION) { + + set_Finfo(einfo->finderinfo, hfs_ent); + + /* + * set create date - modified date set from the Unix + * data fork date + */ + + hfs_ent->crdate = d_getl(einfo->createTime); + + } else if (num >= (int)sizeof (us_FileInfo)) { + /* + * UShare has no magic number, so we assume that this is a valid + * info/resource file ... + */ + + set_Finfo(uinfo->finderinfo, hfs_ent); + + /* set create and modified date - if they exist */ + if (uinfo->ctime) + hfs_ent->crdate = + d_getl(uinfo->ctime); + + if (uinfo->mtime) + hfs_ent->mddate = + d_getl(uinfo->mtime); + } else { + /* failed to open/read finderinfo - so try afpfile mapping */ + if (verbose > 2) { + fprintf(stderr, + "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } + ret = get_none_info(hname, dname, s_entry, TYPE_NONE); + return (ret); + } + + /* this should exist ... */ + if ((s_entry1 = s_entry->assoc) == NULL) + perr("TYPE_ESH error - shouldn't happen!"); + + /* set name */ + hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN); + + /* real rsrc file starts ES_INFO_SIZE bytes into the file */ + if (s_entry1->size <= ES_INFO_SIZE) { + s_entry1->size = 0; + hfs_ent->u.file.rsize = 0; + } else { + s_entry1->size -= ES_INFO_SIZE; + hfs_ent->u.file.rsize = s_entry1->size; + s_entry1->hfs_off = ES_INFO_SIZE; + } + + set_733((char *) s_entry1->isorec.size, s_entry1->size); + + return (ret); +} + +/* + * calc_crc() -- + * Compute the MacBinary II-style CRC for the data pointed to by p, with the + * crc seeded to seed. + * + * Modified by Jim Van Verth to use the magic array for efficiency. + */ +#ifdef __used__ +static unsigned short +calc_mb_crc(unsigned char *p, long len, unsigned short seed) +{ + unsigned short hold; /* crc computed so far */ + long i; /* index into data */ + + hold = seed; /* start with seed */ + for (i = 0; i < len; i++, p++) { + hold ^= (*p << 8); + hold = (hold << 8) ^ mb_magic[(unsigned char) (hold >> 8)]; + } + + return (hold); +}/* calc_mb_crc() */ + +#endif /* __used__ */ + +static int +get_mb_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + mb_info *info; /* finderinfo struct */ + char *c; + char *t; + hfsdirent *hfs_ent; + dir_ent *s_entry1; + int i; + +#ifdef TEST_CODE + unsigned short crc_file, + crc_calc; + +#endif + + info = (mb_info *) p_buf; + + /* + * routine called twice for each file - first to check that it is a + * valid MacBinary file, second to fill in the HFS info. p_buf holds + * the required raw data and it *should* remain the same between the + * two calls + */ + if (s_entry == 0) { + /* + * test that the CRC is OK - not set for MacBinary I files (and + * incorrect in some MacBinary II files!). If this fails, then + * perform some other checks + */ + +#ifdef TEST_CODE + /* leave this out for the time being ... */ + if (p_num >= MB_SIZE && info->version == 0 && info->zero1 == 0) { + crc_calc = calc_mb_crc((unsigned char *) info, 124, 0); + crc_file = d_getw(info->crc); +#ifdef DEBUG + fprintf(stderr, "%s: file %d, calc %d\n", hname, + crc_file, crc_calc); +#endif /* DEBUG */ + if (crc_file == crc_calc) + return (ret); + } +#endif /* TEST_CODE */ + + /* + * check some of the fields for a valid MacBinary file not + * zero1 and zero2 SHOULD be zero - but some files incorrect + */ + +/* if (p_num < MB_SIZE || info->nlen > 63 || info->zero2 || */ + if (p_num < MB_SIZE || info->zero1 || + info->zero2 || info->nlen > 63 || + info->version || info->nlen == 0 || *info->name == 0) + return (TYPE_NONE); + + /* check that the filename is OKish */ + for (i = 0; i < (int)info->nlen; i++) + if (info->name[i] == 0) + return (TYPE_NONE); + + /* check CREATOR and TYPE are valid */ + for (i = 0; i < 4; i++) + if (info->type[i] == 0 || info->auth[i] == 0) + return (TYPE_NONE); + } else { + /* we have a vaild MacBinary file, so fill in the bits */ + + /* this should exist ... */ + if ((s_entry1 = s_entry->assoc) == NULL) + perr("TYPE_MBIN error - shouldn't happen!"); + + hfs_ent = s_entry->hfs_ent; + + /* type and creator from finder info */ + t = (char *) (info->type); + c = (char *) (info->auth); + + set_ct(hfs_ent, c, t); + + /* finder flags */ + hfs_ent->fdflags = ((info->flags << 8) & 0xff00) | info->flags2; + + if (icon_pos) { + hfs_ent->fdlocation.v = + d_getw((unsigned char *) info->icon_vert); + hfs_ent->fdlocation.h = + d_getw((unsigned char *) info->icon_horiz); + } else { + /* + * clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? + */ + hfs_ent->fdflags &= 0xfeff; + } + + /* + * set created/modified dates - these date should have already + * been set from the Unix data fork dates. The finderinfo dates + * are in Mac format - but we have to convert them back to Unix + * for the time being + */ + hfs_ent->crdate = d_toutime(d_getl(info->cdate)); + hfs_ent->mddate = d_toutime(d_getl(info->mdate)); + + /* set name */ + hstrncpy((unsigned char *) (hfs_ent->name), + (char *) (info->name), MIN(HFS_MAX_FLEN, info->nlen)); + + /* set correct fork sizes */ + hfs_ent->u.file.dsize = d_getl(info->dflen); + hfs_ent->u.file.rsize = d_getl(info->rflen); + + /* update directory entries for data fork */ + s_entry->size = hfs_ent->u.file.dsize; + s_entry->hfs_off = MB_SIZE; + set_733((char *) s_entry->isorec.size, s_entry->size); + + /* + * real rsrc file starts after data fork (must be a multiple of + * MB_SIZE) + */ + s_entry1->size = hfs_ent->u.file.rsize; + s_entry1->hfs_off = MB_SIZE + ROUND_UP(hfs_ent->u.file.dsize, MB_SIZE); + set_733((char *) s_entry1->isorec.size, s_entry1->size); + } + + return (ret); +} + +/* + * get_dbl_dir: get Apple double finderinfo for a directory + * + * Based on code from cvt2cap.c (c) May 1988, Paul Campbell + */ +static int +get_dbl_dir(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + FileInfo info; /* finderinfo struct */ + a_hdr *hp; + a_entry *ep; + int num = -1; /* bytes read */ + int nentries; + FILE *fp; + hfsdirent *hfs_ent = s_entry->hfs_ent; + char name[64]; + int i; + int fail = 0; + int len = 0; + + hp = (a_hdr *) p_buf; + memset(hp, 0, A_HDR_SIZE); + + memset(name, 0, sizeof (name)); + + /* open and read the info/rsrc file (it's the same file) */ + if ((fp = fopen(hname, "rb")) != NULL) + num = fread(hp, 1, A_HDR_SIZE, fp); + + /* + * check finder info is OK - some Netatalk files don't have magic + * or version set - ignore if it's a netatalk file + */ + if (num == A_HDR_SIZE && ((ret == TYPE_NETA) || + (d_getl(hp->magic) == APPLE_DOUBLE && + (d_getl(hp->version) == A_VERSION1 || + d_getl(hp->version) == A_VERSION2)))) { + + /* read TOC of the AppleDouble file */ + nentries = (int) d_getw(hp->nentries); + if (fread(hp->entries, A_ENTRY_SIZE, nentries, fp) < 1) { + fail = 1; + nentries = 0; + } + /* extract what is needed */ + for (i = 0, ep = hp->entries; i < nentries; i++, ep++) { + switch ((int)d_getl(ep->id)) { + case ID_FINDER: + /* get the finder info */ + fseek(fp, (off_t)d_getl(ep->offset), SEEK_SET); + if (fread(&info, d_getl(ep->length), 1, fp) < 1) { + fail = 1; + } + break; + case ID_NAME: + /* get Mac file name */ + fseek(fp, (off_t)d_getl(ep->offset), SEEK_SET); + if (fread(name, d_getl(ep->length), 1, fp) < 1) + *name = '\0'; + len = d_getl(ep->length); + break; + default: + break; + } + } + + fclose(fp); + + /* skip this if we had a problem */ + if (!fail) { + + set_Dinfo(info.finderinfo, hfs_ent); + + /* use stored name if it exists */ + if (*name) { + /* + * In some cases the name is stored in the + * Pascal string format - first char is the + * length, the rest is the actual string. + * The following *should* be OK + */ + if (len == 32 && (int) name[0] < 32) { + cstrncpy(hfs_ent->name, &name[1], + MIN(name[0], HFS_MAX_FLEN)); + } else { + cstrncpy(hfs_ent->name, name, + HFS_MAX_FLEN); + } + } else { + hstrncpy((unsigned char *) (hfs_ent->name), + dname, HFS_MAX_FLEN); + } + } + } else { + /* failed to open/read finderinfo */ + fail = 1; + if (fp) + fclose(fp); + } + + if (fail) { + /* problem with the file - try mapping/magic */ + if (verbose > 2) { + fprintf(stderr, + "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } + ret = get_none_dir(hname, dname, s_entry, TYPE_NONE); + } + return (ret); +} + +/* + * Depending on the version, AppleDouble/Single stores dates + * relative to 1st Jan 1904 (v1) or 1st Jan 2000 (v2) + * + * The d_toutime() function uses 1st Jan 1904 to convert to + * Unix time (1st Jan 1970). + * + * The d_dtoutime() function uses 1st Jan 2000 to convert to + * Unix time (1st Jan 1970). + * + * However, NetaTalk files seem to do their own thing - older + * Netatalk files don't have a magic number of version and + * store dates in ID=7 (don't know how). Newer Netatalk files + * claim to be version 1, but store dates in ID=7 as if they + * were version 2 files. + */ + +/* + * get_dbl_info: get Apple double finderinfo for a file + * + * Based on code from cvt2cap.c (c) May 1988, Paul Campbell + */ +static int +get_dbl_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + FileInfo info; /* finderinfo struct */ + a_hdr *hp; + a_entry *ep; + int num = -1; /* bytes read */ + int nentries; + FILE *fp; + hfsdirent *hfs_ent = s_entry->hfs_ent; + dir_ent *s_entry1; + char name[64]; + int i; + int fail = 0; + int len = 0; + unsigned char dates[A_DATE]; + int ver = 0, dlen; + + hp = (a_hdr *) p_buf; + memset(hp, 0, A_HDR_SIZE); + + memset(name, 0, sizeof (name)); + memset(dates, 0, sizeof (dates)); + + /* get the rsrc file info - should exist ... */ + if ((s_entry1 = s_entry->assoc) == NULL) + perr("TYPE_DBL error - shouldn't happen!"); + + /* open and read the info/rsrc file (it's the same file) */ + if ((fp = fopen(hname, "rb")) != NULL) + num = fread(hp, 1, A_HDR_SIZE, fp); + + /* + * check finder info is OK - some Netatalk files don't have magic + * or version set - ignore if it's a netatalk file + */ + + ver = d_getl(hp->version); + if (num == A_HDR_SIZE && ((ret == TYPE_NETA) || + (d_getl(hp->magic) == APPLE_DOUBLE && + (ver == A_VERSION1 || ver == A_VERSION2)))) { + + /* read TOC of the AppleDouble file */ + nentries = (int) d_getw(hp->nentries); + if (fread(hp->entries, A_ENTRY_SIZE, nentries, fp) < 1) { + fail = 1; + nentries = 0; + } + /* extract what is needed */ + for (i = 0, ep = hp->entries; i < nentries; i++, ep++) { + switch ((int)d_getl(ep->id)) { + case ID_FINDER: + /* get the finder info */ + fseek(fp, (off_t)d_getl(ep->offset), SEEK_SET); + if (fread(&info, d_getl(ep->length), 1, fp) < 1) { + fail = 1; + } + break; + case ID_RESOURCE: + /* set the offset and correct rsrc fork size */ + s_entry1->size = d_getl(ep->length); + hfs_ent->u.file.rsize = s_entry1->size; + /* offset to start of real rsrc fork */ + s_entry1->hfs_off = d_getl(ep->offset); + set_733((char *) s_entry1->isorec.size, + s_entry1->size); + break; + case ID_NAME: + /* get Mac file name */ + fseek(fp, (off_t)d_getl(ep->offset), SEEK_SET); + if (fread(name, d_getl(ep->length), 1, fp) < 1) + *name = '\0'; + len = d_getl(ep->length); + break; + case ID_FILEI: + /* Workround for NetaTalk files ... */ + if (ret == TYPE_NETA && ver == A_VERSION1) + ver = A_VERSION2; + /* fall through */ + case ID_FILEDATESI: + /* get file info */ + fseek(fp, d_getl(ep->offset), 0); + dlen = MIN(d_getl(ep->length), A_DATE); + if (fread(dates, dlen, 1, fp) < 1) { + fail = 1; + } else { + /* get the correct Unix time */ + switch (ver) { + + case (A_VERSION1): + hfs_ent->crdate = + d_toutime(d_getl(dates)); + hfs_ent->mddate = + d_toutime(d_getl(dates+4)); + break; + case (A_VERSION2): + hfs_ent->crdate = + d_dtoutime(d_getl(dates)); + hfs_ent->mddate = + d_dtoutime(d_getl(dates+4)); + break; + default: + /* Use Unix dates */ + break; + } + } + break; + default: + break; + } + } + + fclose(fp); + + /* skip this if we had a problem */ + if (!fail) { + set_Finfo(info.finderinfo, hfs_ent); + + /* use stored name if it exists */ + if (*name) { + /* + * In some cases the name is stored in the + * Pascal string format - first char is the + * length, the rest is the actual string. + * The following *should* be OK + */ + if (len == 32 && (int) name[0] < 32) { + cstrncpy(hfs_ent->name, &name[1], + MIN(name[0], HFS_MAX_FLEN)); + } else { + cstrncpy(hfs_ent->name, name, + HFS_MAX_FLEN); + } + } else { + hstrncpy((unsigned char *) (hfs_ent->name), + dname, HFS_MAX_FLEN); + } + } + } else { + /* failed to open/read finderinfo */ + fail = 1; + if (fp) + fclose(fp); + } + + if (fail) { + /* problem with the file - try mapping/magic */ + if (verbose > 2) { + fprintf(stderr, + "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } + ret = get_none_info(hname, dname, s_entry, TYPE_NONE); + } + return (ret); +} + +/* + * get_sgl_info: get Apple single finderinfo for a file + * + * Based on code from cvt2cap.c (c) May 1988, Paul Campbell + */ +static int +get_sgl_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + FileInfo *info = 0; /* finderinfo struct */ + a_hdr *hp; + static a_entry *entries; + a_entry *ep; + int nentries; + hfsdirent *hfs_ent; + dir_ent *s_entry1; + char name[64]; + int i; + int len = 0; + unsigned char *dates; + int ver = 0; + + /* + * routine called twice for each file + * - first to check that it is a valid + * AppleSingle file, second to fill in the HFS info. + * p_buf holds the required + * raw data and it *should* remain the same between the two calls + */ + hp = (a_hdr *) p_buf; + + if (s_entry == 0) { + if (p_num < A_HDR_SIZE || + d_getl(hp->magic) != APPLE_SINGLE || + (d_getl(hp->version) != A_VERSION1 && + d_getl(hp->version) != A_VERSION2)) + return (TYPE_NONE); + + /* check we have TOC for the AppleSingle file */ + nentries = (int) d_getw(hp->nentries); + if (p_num < (int)(A_HDR_SIZE + nentries * A_ENTRY_SIZE)) + return (TYPE_NONE); + + /* save the TOC */ + entries = (a_entry *) e_malloc(nentries * A_ENTRY_SIZE); + + memcpy(entries, (p_buf + A_HDR_SIZE), nentries * A_ENTRY_SIZE); + } else { + /* have a vaild AppleSingle File */ + memset(name, 0, sizeof (name)); + + /* get the rsrc file info - should exist ... */ + if ((s_entry1 = s_entry->assoc) == NULL) + perr("TYPE_SGL error - shouldn't happen!"); + + hfs_ent = s_entry->hfs_ent; + + nentries = (int) d_getw(hp->nentries); + ver = d_getl(hp->version); + + /* extract what is needed */ + for (i = 0, ep = entries; i < nentries; i++, ep++) { + switch ((int)d_getl(ep->id)) { + case ID_FINDER: + /* get the finder info */ + info = (FileInfo *) (p_buf + d_getl(ep->offset)); + break; + case ID_DATA: + /* set the offset and correct data fork size */ + hfs_ent->u.file.dsize = s_entry->size = + d_getl(ep->length); + /* offset to start of real data fork */ + s_entry->hfs_off = d_getl(ep->offset); + set_733((char *) s_entry->isorec.size, + s_entry->size); + break; + case ID_RESOURCE: + /* set the offset and correct rsrc fork size */ + hfs_ent->u.file.rsize = s_entry1->size = + d_getl(ep->length); + /* offset to start of real rsrc fork */ + s_entry1->hfs_off = d_getl(ep->offset); + set_733((char *) s_entry1->isorec.size, + s_entry1->size); + break; + case ID_NAME: + /* get Mac file name */ + strncpy(name, (p_buf + d_getl(ep->offset)), + d_getl(ep->length)); + len = d_getl(ep->length); + break; + case ID_FILEI: + /* get file info - ignore at the moment*/ + break; + case ID_FILEDATESI: + /* get file info */ + dates = (unsigned char *)p_buf + d_getl(ep->offset); + /* get the correct Unix time */ + if (ver == A_VERSION1) { + hfs_ent->crdate = + d_toutime(d_getl(dates)); + hfs_ent->mddate = + d_toutime(d_getl(dates+4)); + } else { + hfs_ent->crdate = + d_dtoutime(d_getl(dates)); + hfs_ent->mddate = + d_dtoutime(d_getl(dates+4)); + } + break; + default: + break; + } + } + + free(entries); + + if (info == NULL) { + /* + * failed to open/read finderinfo + * - so try afpfile mapping + */ + if (verbose > 2) { + fprintf(stderr, + "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, + hfs_types[ret].desc); + } + ret = get_none_info(hname, dname, s_entry, TYPE_NONE); + return (ret); + } + + set_Finfo(info->finderinfo, hfs_ent); + + /* use stored name if it exists */ + if (*name) { + /* + * In some cases the name is stored in the Pascal string + * format - first char is the length, the rest is the + * actual string. The following *should* be OK + */ + if (len == 32 && (int) name[0] < 32) { + cstrncpy(hfs_ent->name, &name[1], MIN(name[0], + HFS_MAX_FLEN)); + } else { + cstrncpy(hfs_ent->name, name, HFS_MAX_FLEN); + } + } else { + hstrncpy((unsigned char *) (hfs_ent->name), dname, + HFS_MAX_FLEN); + } + } + + return (ret); +} + +/* + * get_hfs_fe_info: read in the whole finderinfo for a PC Exchange + * directory - saves on reading this many times for each file. + * + * Based of information provided by Mark Weinstein <mrwesq@earthlink.net> + * + * Note: the FINDER.DAT file layout depends on the FAT cluster size + * therefore, files should only be read directly from the FAT media + * + * Only tested with PC Exchange v2.1 - don't know if it will work + * with v2.2 and above. + */ +static struct hfs_info * +get_hfs_fe_info(struct hfs_info *hfs_info, char *name) +{ + FILE *fp; + int fe_num, + fe_pad; + fe_info info; + int c = 0; + struct hfs_info *hfs_info1 = NULL; + char keyname[12]; + char *s, + *e, + *k; + int i; + + if ((fp = fopen(name, "rb")) == NULL) + return (NULL); + + /* + * no longer attempt to find out FAT cluster + * - rely on command line parameter + */ + if (afe_size <= 0) + return (NULL); + + fe_num = afe_size / FE_SIZE; + fe_pad = afe_size % FE_SIZE; + + while (fread(&info, 1, FE_SIZE, fp) != 0) { + + /* the Mac name may be NULL - so ignore this entry */ + if (info.nlen != 0) { + + hfs_info1 = + (struct hfs_info *)e_malloc(sizeof (struct hfs_info)); + /* add this entry to the list */ + hfs_info1->next = hfs_info; + hfs_info = hfs_info1; + + /* + * get the bits we need + * - ignore [cm]time for the moment + */ + cstrncpy(hfs_info->name, (char *) (info.name), + info.nlen); + + memcpy(hfs_info->finderinfo, info.finderinfo, INFOLEN); + + s = (char *) (info.sname); + e = (char *) (info.ext); + k = keyname; + + /* + * short (Unix) name is stored in PC format, + * so needs to be mangled a bit + */ + + /* name part */ + for (i = 0; i < 8; i++, s++, k++) { + if (*s == ' ') + break; + else + *k = *s; + } + + /* extension - if it exists */ + if (strncmp((const char *) (info.ext), " ", 3)) { + *k = '.'; + k++; + for (i = 0; i < 3; i++, e++, k++) { + if (*e == ' ') + break; + else + *k = *e; + } + } + *k = '\0'; + + hfs_info1->keyname = strdup(keyname); + } + /* + * each record is FE_SIZE long, and there are FE_NUM + * per each "cluster size", so we may need to skip the padding + */ + if (++c == fe_num) { + c = 0; + fseek(fp, (off_t)fe_pad, SEEK_CUR); + } + } + fclose(fp); + + return (hfs_info); +} + +/* + * get_hfs_sgi_info: read in the whole finderinfo for a SGI (XINET) + * directory - saves on reading this many times for each + * file. + */ +static struct hfs_info * +get_hfs_sgi_info(struct hfs_info *hfs_info, char *name) +{ + FILE *fp; + sgi_info info; + struct hfs_info *hfs_info1 = NULL; + + if ((fp = fopen(name, "rb")) == NULL) + return (NULL); + + while (fread(&info, 1, SGI_SIZE, fp) != 0) { + + hfs_info1 = (struct hfs_info *)e_malloc(sizeof (struct hfs_info)); + /* add this entry to the list */ + hfs_info1->next = hfs_info; + hfs_info = hfs_info1; + + /* get the bits we need - ignore [cm]time for the moment */ + cstrncpy(hfs_info->name, (char *)info.name, HFS_MAX_FLEN); + + memcpy(hfs_info->finderinfo, info.finderinfo, INFOLEN); + + /* use the HFS name as the key */ + hfs_info1->keyname = hfs_info->name; + + } + fclose(fp); + + return (hfs_info); +} + +/* + * del_hfs_info: delete the info list and recover memory + */ +void +del_hfs_info(struct hfs_info *hfs_info) +{ + struct hfs_info *hfs_info1; + + while (hfs_info) { + hfs_info1 = hfs_info; + hfs_info = hfs_info->next; + + /* key may be the same as the HFS name - so don't free it */ + *hfs_info1->name = '\0'; + if (*hfs_info1->keyname) + free(hfs_info1->keyname); + free(hfs_info1); + } +} + +/* + * match_key: find the correct hfs_ent using the Unix filename + * as the key + */ +static struct hfs_info * +match_key(struct hfs_info *hfs_info, char *key) +{ + while (hfs_info) { + if (strcasecmp(key, hfs_info->keyname) == 0) + return (hfs_info); + hfs_info = hfs_info->next; + } + + return (NULL); +} + +/* + * get_fe_dir: get PC Exchange directory name + * + * base on probing with od ... + */ +static int +get_fe_dir(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + struct hfs_info *hfs_info; + hfsdirent *hfs_ent = s_entry->hfs_ent; + + /* cached finderinfo stored with parent directory */ + hfs_info = s_entry->filedir->hfs_info; + + /* if we have no cache, then make one and store it */ + if (hfs_info == NULL) { + if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL) + ret = TYPE_NONE; + else + s_entry->filedir->hfs_info = hfs_info; + } + if (ret != TYPE_NONE) { + /* see if we can find the details of this file */ + if ((hfs_info = match_key(hfs_info, dname)) != NULL) { + strcpy(hfs_ent->name, hfs_info->name); + + set_Dinfo(hfs_info->finderinfo, hfs_ent); + + return (ret); + } + } + /* can't find the entry, so use the Unix name */ + hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN); + + return (TYPE_NONE); +} + +/* + * get_fe_info: get PC Exchange file details. + * + * base on probing with od and details from Mark Weinstein + * <mrwesq@earthlink.net> + */ +static int +get_fe_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + struct hfs_info *hfs_info; + hfsdirent *hfs_ent = s_entry->hfs_ent; + + /* cached finderinfo stored with parent directory */ + hfs_info = s_entry->filedir->hfs_info; + + /* if we have no cache, then make one and store it */ + if (hfs_info == NULL) { + if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL) + ret = TYPE_NONE; + else + s_entry->filedir->hfs_info = hfs_info; + } + if (ret != TYPE_NONE) { + char *dn = dname; + +#ifdef _WIN32_TEST + /* + * may have a problem here - v2.2 has long filenames, + * but we need to key on the short filename, + * so we need do go a bit of win32 stuff + * ... + */ + char sname[1024]; + char lname[1024]; + + cygwin32_conv_to_full_win32_path(s_entry->whole_name, lname); + + if (GetShortPathName(lname, sname, sizeof (sname))) { + if (dn = strrchr(sname, '\\')) + dn++; + else + dn = sname; + } +#endif /* _WIN32 */ + + /* see if we can find the details of this file */ + if ((hfs_info = match_key(hfs_info, dn)) != NULL) { + + strcpy(hfs_ent->name, hfs_info->name); + + set_Finfo(hfs_info->finderinfo, hfs_ent); + + return (ret); + } + } + /* no entry found - use extension mapping */ + if (verbose > 2) { + fprintf(stderr, "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } + ret = get_none_info(hname, dname, s_entry, TYPE_NONE); + + return (TYPE_NONE); +} + +/* + * get_sgi_dir: get SGI (XINET) HFS directory name + * + * base on probing with od ... + */ +static int +get_sgi_dir(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + struct hfs_info *hfs_info; + hfsdirent *hfs_ent = s_entry->hfs_ent; + + /* cached finderinfo stored with parent directory */ + hfs_info = s_entry->filedir->hfs_info; + + /* if we haven't got a cache, then make one */ + if (hfs_info == NULL) { + if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL) + ret = TYPE_NONE; + else + s_entry->filedir->hfs_info = hfs_info; + } + /* find the matching entry in the cache */ + if (ret != TYPE_NONE) { + /* key is (hopefully) the real Mac name */ + cstrncpy(tmp, dname, strlen(dname)); + if ((hfs_info = match_key(hfs_info, tmp)) != NULL) { + strcpy(hfs_ent->name, hfs_info->name); + + set_Dinfo(hfs_info->finderinfo, hfs_ent); + + return (ret); + } + } + /* no entry found - use Unix name */ + hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN); + + return (TYPE_NONE); +} + +/* + * get_sgi_info: get SGI (XINET) HFS finder info + * + * base on probing with od ... + */ +static int +get_sgi_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + struct hfs_info *hfs_info; + hfsdirent *hfs_ent = s_entry->hfs_ent; + + /* cached finderinfo stored with parent directory */ + hfs_info = s_entry->filedir->hfs_info; + + /* if we haven't got a cache, then make one */ + if (hfs_info == NULL) { + if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL) + ret = TYPE_NONE; + else + s_entry->filedir->hfs_info = hfs_info; + } + if (ret != TYPE_NONE) { + /* + * tmp is the same as hname here, but we don't need hname + * anymore in this function ... see if we can find the + * details of this file using the Unix name as the key + */ + cstrncpy(tmp, dname, strlen(dname)); + if ((hfs_info = match_key(hfs_info, tmp)) != NULL) { + + strcpy(hfs_ent->name, hfs_info->name); + + set_Finfo(hfs_info->finderinfo, hfs_ent); + + return (ret); + } + } + /* no entry found, so try file extension */ + if (verbose > 2) { + fprintf(stderr, "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } + ret = get_none_info(hname, dname, s_entry, TYPE_NONE); + + return (TYPE_NONE); +} + +/* + * get_sfm_info: get SFM finderinfo for a file + */ + +static byte sfm_magic[4] = {0x41, 0x46, 0x50, 0x00}; +static byte sfm_version[4] = {0x00, 0x00, 0x01, 0x00}; + +static int +get_sfm_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + sfm_info info; /* finderinfo struct */ + int num = -1; /* bytes read */ + hfsdirent *hfs_ent = s_entry->hfs_ent; + + num = read_info_file(hname, &info, sizeof (info)); + + /* check finder info is OK */ + if (num == sizeof (info) && + !memcmp((char *)info.afpi_Signature, (char *)sfm_magic, 4) && + !memcmp((char *)info.afpi_Version, (char *)sfm_version, 4)) { + /* use Unix name */ + hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN); + + set_Finfo(info.finderinfo, hfs_ent); + + } else { + /* failed to open/read finderinfo - so try afpfile mapping */ + if (verbose > 2) { + fprintf(stderr, + "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } + ret = get_none_info(hname, dname, s_entry, TYPE_NONE); + } + + return (ret); +} + +#ifdef IS_MACOS_X +/* + * get_xhfs_dir: get MacOS X HFS finderinfo for a directory + * + * Code ideas from 'hfstar' by Marcel Weiher marcel@metaobject.com + * and another GNU hfstar by Torres Vedras paulotex@yahoo.com + * + * Here we are dealing with actual HFS files - not some encoding + * we have to use a system call to get the finderinfo + * + * The file name here is the pseudo name for the resource fork + */ +static int +get_xhfs_dir(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + int err; + hfsdirent *hfs_ent = s_entry->hfs_ent; + attrinfo ainfo; + struct attrlist attrs; + int i; + + memset(&attrs, 0, sizeof (attrs)); + + /* set flags we need to get info from getattrlist() */ + attrs.bitmapcount = ATTR_BIT_MAP_COUNT; + attrs.commonattr = ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | + ATTR_CMN_FNDRINFO; + + /* get the info */ + err = getattrlist(hname, &attrs, &ainfo, sizeof (ainfo), 0); + + if (err == 0) { + /* + * If the Finfo is blank then we assume it's not a + * 'true' HFS directory ... + */ + err = 1; + for (i = 0; i < sizeof (ainfo.info); i++) { + if (ainfo.info[i] != 0) { + err = 0; + break; + } + } + } + + /* check finder info is OK */ + if (err == 0) { + + hstrncpy((unsigned char *) (s_entry->hfs_ent->name), + dname, HFS_MAX_FLEN); + + set_Dinfo(ainfo.info, hfs_ent); + + return (ret); + } else { + /* otherwise give it it's Unix name */ + hstrncpy((unsigned char *) (s_entry->hfs_ent->name), + dname, HFS_MAX_FLEN); + return (TYPE_NONE); + } +} + +/* + * get_xhfs_info: get MacOS X HFS finderinfo for a file + * + * Code ideas from 'hfstar' by Marcel Weiher marcel@metaobject.com, + * another GNU hfstar by Torres Vedras paulotex@yahoo.com and + * hfspax by Howard Oakley howard@quercus.demon.co.uk + * + * Here we are dealing with actual HFS files - not some encoding + * we have to use a system call to get the finderinfo + * + * The file name here is the pseudo name for the resource fork + */ +static int +get_xhfs_info(char *hname, /* whole path */ + char *dname, /* this dir name */ + dir_ent *s_entry, /* directory entry */ + int ret) +{ + int err; + hfsdirent *hfs_ent = s_entry->hfs_ent; + attrinfo ainfo; + struct attrlist attrs; + int i; + int size; + + memset(&attrs, 0, sizeof (attrs)); + + /* set flags we need to get info from getattrlist() */ + attrs.bitmapcount = ATTR_BIT_MAP_COUNT; + attrs.commonattr = ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | + ATTR_CMN_FNDRINFO; + + /* get the info */ + err = getattrlist(hname, &attrs, &ainfo, sizeof (ainfo), 0); + + /* check finder info is OK */ + if (err == 0) { + + /* + * If the Finfo is blank and the resource file is empty, + * then we assume it's not a 'true' HFS file ... + * There will be not associated file if the resource fork + * is empty + */ + + if (s_entry->assoc == NULL) { + err = 1; + for (i = 0; i < sizeof (ainfo.info); i++) { + if (ainfo.info[i] != 0) { + err = 0; + break; + } + } + } + + if (err == 0) { + + /* use Unix name */ + hstrncpy((unsigned char *) (hfs_ent->name), dname, + HFS_MAX_FLEN); + + set_Finfo(ainfo.info, hfs_ent); + + /* + * dates have already been set - but we will + * set them here as well from the HFS info + * shouldn't need to check for byte order, as + * the source is HFS ... but we will just in case + */ + hfs_ent->crdate = d_getl((byte *)&ainfo.ctime.tv_sec); + + hfs_ent->mddate = d_getl((byte *)&ainfo.mtime.tv_sec); + } + + } + + if (err) { + /* not a 'true' HFS file - so try afpfile mapping */ +#if 0 + /* + * don't print a warning as we will get lots on HFS + * file systems ... + */ + if (verbose > 2) { + fprintf(stderr, + "warning: %s doesn't appear to be a %s file\n", + s_entry->whole_name, hfs_types[ret].desc); + } +#endif + ret = get_none_info(hname, dname, s_entry, TYPE_NONE); + } + + return (ret); +} +#endif /* IS_MACOS_X */ + +/* + * get_hfs_itype: get the type of HFS info for a file + */ +static int +get_hfs_itype(char *wname, char *dname, char *htmp) +{ + int wlen, + i; + int no_type = TYPE_NONE; + + wlen = strlen(wname) - strlen(dname); + + /* search through the known types looking for matches */ + for (i = 1; i < hfs_num; i++) { + /* skip the ones that we don't care about */ + if ((hfs_types[i].flags & PROBE) || + *(hfs_types[i].info) == TYPE_NONE) { + continue; + } + + strcpy(htmp, wname); + + /* + * special case - if the info file doesn't exist + * for a requested type, then remember the type - + * we don't return here, as we _may_ find another type + * so we save the type here in case - we will have + * problems if more than one of this type ever exists ... + */ + if (hfs_types[i].flags & NOINFO) { + no_type = i; + } else { + + /* append or insert finderinfo filename part */ + if (hfs_types[i].flags & APPEND) + strcat(htmp, hfs_types[i].info); + else + sprintf(htmp + wlen, "%s%s", hfs_types[i].info, + (hfs_types[i].flags & NOPEND) ? "" : dname); + + /* hack time ... Netatalk is a special case ... */ + if (i == TYPE_NETA) { + strcpy(htmp, wname); + strcat(htmp, "/.AppleDouble/.Parent"); + } + + if (!access(htmp, R_OK)) + return (hfs_types[i].type); + } + } + + return (no_type); +} + +/* + * set_root_info: set the root folder hfs_ent from given file + */ +void +set_root_info(char *name) +{ + dir_ent *s_entry; + hfsdirent *hfs_ent; + int i; + + s_entry = root->self; + + hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent)); + memset(hfs_ent, 0, sizeof (hfsdirent)); + + /* make sure root has a valid hfs_ent */ + s_entry->hfs_ent = root->hfs_ent = hfs_ent; + + /* search for correct type of root info data */ + for (i = 1; i < hfs_num; i++) { + if ((hfs_types[i].flags & PROBE) || + (hfs_types[i].get_info == get_none_info)) + continue; + + if ((*(hfs_types[i].get_dir))(name, "", s_entry, i) == i) + return; + } +} + + +/* + * get_hfs_dir: set the HFS directory name + */ +int +get_hfs_dir(char *wname, char *dname, dir_ent *s_entry) +{ + int type; + + /* get the HFS file type from the info file (if it exists) */ + type = get_hfs_itype(wname, dname, tmp); + + /* try to get the required info */ + type = (*(hfs_types[type].get_dir)) (tmp, dname, s_entry, type); + + return (type); +} + +/* + * get_hfs_info: set the HFS info for a file + */ +int +get_hfs_info(char *wname, char *dname, dir_ent *s_entry) +{ + int type, + wlen, + i; + + wlen = strlen(wname) - strlen(dname); + + /* we may already know the type of Unix/HFS file - so process */ + if (s_entry->hfs_type != TYPE_NONE) { + + type = s_entry->hfs_type; + + strcpy(tmp, wname); + + /* append or insert finderinfo filename part */ + if (hfs_types[type].flags & APPEND) + strcat(tmp, hfs_types[type].info); + else + sprintf(tmp + wlen, "%s%s", hfs_types[type].info, + (hfs_types[type].flags & NOPEND) ? "" : dname); + + type = (*(hfs_types[type].get_info))(tmp, dname, s_entry, type); + + /* if everything is as expected, then return */ + if (s_entry->hfs_type == type) + return (type); + } + /* we don't know what type we have so, find out */ + for (i = 1; i < hfs_num; i++) { + if ((hfs_types[i].flags & PROBE) || + *(hfs_types[i].info) == TYPE_NONE) { + continue; + } + + strcpy(tmp, wname); + + /* append or insert finderinfo filename part */ + if (hfs_types[i].flags & APPEND) { + strcat(tmp, hfs_types[i].info); + } else { + sprintf(tmp + wlen, "%s%s", hfs_types[i].info, + (hfs_types[i].flags & NOPEND) ? "" : dname); + } + + /* if the file exists - and not a type we've already tried */ + if (!access(tmp, R_OK) && i != s_entry->hfs_type) { + type = (*(hfs_types[i].get_info))(tmp, dname, + s_entry, i); + s_entry->hfs_type = type; + return (type); + } + } + + /* nothing found, so just a Unix file */ + type = (*(hfs_types[TYPE_NONE].get_info))(wname, dname, + s_entry, TYPE_NONE); + + return (type); +} + +/* + * get_hfs_rname: set the name of the Unix rsrc file for a file + * + * For the time being we ignore the 'NOINFO' flag - the only case + * at the moment is for MacOS X HFS files - for files the resource + * fork exists - so testing the "filename/rsrc" pseudo file as + * the 'info' filename is OK ... + */ +int +get_hfs_rname(char *wname, char *dname, char *rname) +{ + int wlen, + type, + i; + int p_fd = -1; + + wlen = strlen(wname) - strlen(dname); + + /* try to find what sort of Unix HFS file type we have */ + for (i = 1; i < hfs_num; i++) { + /* skip if don't want to probe the files - (default) */ + if (hfs_types[i].flags & PROBE) + continue; + + strcpy(rname, wname); + + /* if we have a different info file, the find out it's type */ + if (*(hfs_types[i].rsrc) && *(hfs_types[i].info)) { + /* first test the Info file */ + + /* append or insert finderinfo filename part */ + if (hfs_types[i].flags & APPEND) { + strcat(rname, hfs_types[i].info); + } else { + sprintf(rname + wlen, "%s%s", hfs_types[i].info, + (hfs_types[i].flags & NOPEND) ? + "" : dname); + } + + /* if it exists, then check the Rsrc file */ + if (!access(rname, R_OK)) { + if (hfs_types[i].flags & APPEND) { + sprintf(rname + wlen, "%s%s", dname, + hfs_types[i].rsrc); + } else { + sprintf(rname + wlen, "%s%s", + hfs_types[i].rsrc, dname); + } + + /* + * for some types, a rsrc fork may not exist, + * so just return the current type + * in these cases + */ + if (hfs_types[i].flags & NORSRC || + !access(rname, R_OK)) + return (hfs_types[i].type); + } + } else { + /* + * if we are probing, + * then have a look at the contents to find type + */ + if (p_fd < 0) { + /* open file, if not already open */ + if ((p_fd = open(wname, + O_RDONLY | O_BINARY)) < 0) { + /* can't open it, then give up */ + return (TYPE_NONE); + } else { + if ((p_num = read(p_fd, p_buf, + sizeof (p_buf))) <= 0) { + /* + * can't read, or zero length + * - give up + */ + close(p_fd); + return (TYPE_NONE); + } + /* get file pointer and close file */ + p_fp = fdopen(p_fd, "rb"); + close(p_fd); + if (p_fp == NULL) + return (TYPE_NONE); + } + } + /* + * call routine to do the work + * - use the given dname as this + * is the name we may use on the CD + */ + type = (*(hfs_types[i].get_info)) (rname, dname, 0, i); + if (type != 0) { + fclose(p_fp); + return (type); + } + if (p_fp) { + /* + * close file + * - just use contents of buffer next time + */ + fclose(p_fp); + p_fp = NULL; + } + } + } + + return (0); +} + +/* + * hfs_exclude: file/directory names that hold finder/resource + * information that we want to exclude from the tree. + * These files/directories are processed later ... + */ +int +hfs_exclude(char *d_name) +{ + /* we don't exclude "." and ".." */ + if (strcmp(d_name, ".") == 0) + return (0); + if (strcmp(d_name, "..") == 0) + return (0); + + /* do not add the following to our list of dir entries */ + if (DO_CAP & hselect) { + /* CAP */ + if (strcmp(d_name, ".finderinfo") == 0) + return (1); + if (strcmp(d_name, ".resource") == 0) + return (1); + if (strcmp(d_name, ".ADeskTop") == 0) + return (1); + if (strcmp(d_name, ".IDeskTop") == 0) + return (1); + if (strcmp(d_name, "Network Trash Folder") == 0) + return (1); + /* + * special case when HFS volume is mounted using Linux's hfs_fs + * Brad Midgley <brad@pht.com> + */ + if (strcmp(d_name, ".rootinfo") == 0) + return (1); + } + if (DO_ESH & hselect) { + /* Helios EtherShare files */ + if (strcmp(d_name, ".rsrc") == 0) + return (1); + if (strcmp(d_name, ".Desktop") == 0) + return (1); + if (strcmp(d_name, ".DeskServer") == 0) + return (1); + if (strcmp(d_name, ".Label") == 0) + return (1); + } + if (DO_DBL & hselect) { + /* Apple Double */ + /* + * special case when HFS volume is mounted using Linux's hfs_fs + */ + if (strcmp(d_name, "%RootInfo") == 0) + return (1); + /* + * have to be careful here - a filename starting with '%' + * may be vaild if the next two letters are a hex character - + * unfortunately '%' 'digit' 'digit' may be a valid resource + * file name ... + */ + if (*d_name == '%') + if (hex2char(d_name) == 0) + return (1); + } + if (DO_NETA & hselect) { + if (strcmp(d_name, ".AppleDouble") == 0) + return (1); + if (strcmp(d_name, ".AppleDesktop") == 0) + return (1); + } + if ((DO_FEU & hselect) || (DO_FEL & hselect)) { + /* PC Exchange */ + if (strcmp(d_name, "RESOURCE.FRK") == 0) + return (1); + if (strcmp(d_name, "FINDER.DAT") == 0) + return (1); + if (strcmp(d_name, "DESKTOP") == 0) + return (1); + if (strcmp(d_name, "FILEID.DAT") == 0) + return (1); + if (strcmp(d_name, "resource.frk") == 0) + return (1); + if (strcmp(d_name, "finder.dat") == 0) + return (1); + if (strcmp(d_name, "desktop") == 0) + return (1); + if (strcmp(d_name, "fileid.dat") == 0) + return (1); + } + if (DO_SGI & hselect) { + /* SGI */ + if (strcmp(d_name, ".HSResource") == 0) + return (1); + if (strcmp(d_name, ".HSancillary") == 0) + return (1); + } + if (DO_DAVE & hselect) { + /* DAVE */ + if (strcmp(d_name, "resource.frk") == 0) + return (1); + if (strcmp(d_name, "DesktopFolderDB") == 0) + return (1); + } +#ifndef _WIN32 + /* + * NTFS streams are not "seen" as files, + * so WinNT will not see these files - + * so ignore - used for testing under Unix + */ + if (DO_SFM & hselect) { + /* SFM */ + char *dn = strrchr(d_name, ':'); + + if (dn) { + if (strcmp(dn, ":Afp_Resource") == 0) + return (1); + if (strcmp(dn, ":Comments") == 0) + return (1); + if (strcmp(dn, ":Afp_AfpInfo") == 0) + return (1); + } + } +#endif /* _WIN32 */ + + if (DO_XDBL & hselect) { + /* XDB */ + if (strncmp(d_name, "._", 2) == 0) + return (1); + } + + return (0); +} + +/* + * print_hfs_info: print info about the HFS files. + * + */ +void +print_hfs_info(dir_ent *s_entry) +{ + fprintf(stderr, "Name: %s\n", s_entry->whole_name); + fprintf(stderr, "\tFile type: %s\n", hfs_types[s_entry->hfs_type].desc); + fprintf(stderr, "\tHFS Name: %s\n", s_entry->hfs_ent->name); + fprintf(stderr, "\tISO Name: %s\n", s_entry->isorec.name); + fprintf(stderr, "\tCREATOR: %s\n", s_entry->hfs_ent->u.file.creator); + fprintf(stderr, "\tTYPE: %s\n", s_entry->hfs_ent->u.file.type); +} + + +/* + * hfs_init: sets up the mapping list from the afpfile as well + * the default mapping (with or without) an afpfile + */ +void +hfs_init(char *name, Ushort fdflags, Uint hfs_select) +{ + FILE *fp; /* File pointer */ + int count = NUMMAP; /* max number of entries */ + char buf[PATH_MAX]; /* working buffer */ + afpmap *amap; /* mapping entry */ + char *c, + *t, + *e; + int i; + + /* setup number of Unix/HFS filetype - we may wish to not bother */ + if (hfs_select) { + hfs_num = sizeof (hfs_types) / sizeof (struct hfs_type); + + /* + * code below needs to be tidied up + * - most can be made redundant + */ + for (i = 0; i < hfs_num; i++) + hfs_types[i].flags &= ~1; /* 0xfffffffe */ + + for (i = 1; i < hfs_num; i++) + if (!((1 << i) & hfs_select)) + hfs_types[i].flags |= PROBE; + + hselect = hfs_select; + } else + hfs_num = hselect = 0; + +#ifdef DEBUG + for (i = 0; i < hfs_num; i++) + fprintf(stderr, "type = %d flags = %d\n", + i, hfs_types[i].flags); +#endif /* DEBUG */ + + /* min length set to max to start with */ + mlen = PATH_MAX; + +#ifdef USE_MAGIC + /* initialise magic state */ + if (magic_filename) { + magic_state = magic_open(MAGIC_ERROR); + if (magic_state == NULL) + perr("failed to initialise libmagic"); + if (magic_load(magic_state, magic_filename) == -1) { + fprintf(stderr, "failed to open magic file: %s\n", + magic_error(magic_state)); + exit(1); + } + } +#endif /* USE_MAGIC */ + + /* set defaults */ + map_num = last_ent = 0; + + /* allocate memory for the default entry */ + defmap = (afpmap *) e_malloc(sizeof (afpmap)); + + /* set default values */ + defmap->extn = DEFMATCH; + + /* make sure creator and type are 4 chars long */ + strcpy(defmap->type, BLANK); + strcpy(defmap->creator, BLANK); + + e = deftype; + t = defmap->type; + + while (*e && (e - deftype) < CT_SIZE) + *t++ = *e++; + + e = defcreator; + c = defmap->creator; + + while (*e && (e - defcreator) < CT_SIZE) + *c++ = *e++; + + /* length is not important here */ + defmap->elen = 0; + + /* no flags */ + defmap->fdflags = fdflags; + + /* no afpfile - no mappings */ + if (*name == '\0') { + map = NULL; + return; + } + if ((fp = fopen(name, "r")) == NULL) + perr("unable to open mapping file"); + + map = (afpmap **) e_malloc(NUMMAP * sizeof (afpmap *)); + + /* read afpfile line by line */ + while (fgets(buf, PATH_MAX, fp) != NULL) { + /* ignore any comment lines */ + c = tmp; + *c = '\0'; + if (sscanf(buf, "%1s", c) == EOF || *c == '#') + continue; + + /* increase list size if needed */ + if (map_num == count) { + count += NUMMAP; + map = (afpmap **)realloc(map, count * sizeof (afpmap *)); + if (map == NULL) + perr("not enough memory"); + } + /* allocate memory for this entry */ + amap = (afpmap *) e_malloc(sizeof (afpmap)); + + t = amap->type; + c = amap->creator; + + /* extract the info */ + if (sscanf(buf, "%s%*s%*1s%c%c%c%c%*1s%*1s%c%c%c%c%*1s", + tmp, c, c + 1, c + 2, c + 3, + t, t + 1, t + 2, t + 3) != 9) { + fprintf(stderr, + "error scanning afpfile %s - continuing", name); + free(amap); + continue; + } + /* copy the extension found */ + if ((amap->extn = (char *) strdup(tmp)) == NULL) + perr("not enough memory"); + + /* set end-of-string */ + *(t + 4) = *(c + 4) = '\0'; + + /* find the length of the extension */ + amap->elen = strlen(amap->extn); + + /* set flags */ + amap->fdflags = fdflags; + + /* see if we have the default creator/type */ + if (strcmp(amap->extn, DEFMATCH) == 0) { + /* get rid of the old default */ + free(defmap); + /* make this the default */ + defmap = amap; + continue; + } + /* update the smallest extension length */ + mlen = MIN(mlen, amap->elen); + + /* add entry to the list */ + map[map_num++] = amap; + + } + + /* free up some memory */ + if (map_num != count) { + map = (afpmap **) realloc(map, map_num * sizeof (afpmap *)); + if (map == NULL) + perr("not enough memory"); + } +} + +#ifdef USE_MAGIC +static int +try_map_magic(char *whole_name, char **type, /* set type */ + char **creator /* set creator */) +{ + const char * ret = magic_file(magic_state, whole_name); + +#ifdef DEBUG + fprintf(stderr, "magic_file(magic_state, \"%s\"): %s\n", + whole_name, ret ? ret : "NULL"); +#endif + /* + * check that we found a match; ignore results in the + * wrong format (probably due to libmagic's built-in rules) + */ + if (ret && strcspn(ret, " ") == CT_SIZE + && ret[CT_SIZE] == ' ' + && strcspn(ret + CT_SIZE + 1, " ") == CT_SIZE) { + memcpy(tmp_type, ret, CT_SIZE); + tmp_type[CT_SIZE] = 0; + memcpy(tmp_creator, ret + CT_SIZE + 1, CT_SIZE); + tmp_creator[CT_SIZE] = 0; +#ifdef DEBUG + fprintf(stderr, "tmp_type = \"%s\"; tmp_creator = \"%s\"\n", + tmp_type, tmp_creator); +#endif + *type = tmp_type; + *creator = tmp_creator; + return (1); + } + + return (0); +} +#endif /* USE_MAGIC */ + +/* + * map_ext: map a files extension with the list to get type/creator + */ +static void +map_ext(char *name, /* filename */ + char **type, /* set type */ + char **creator, /* set creator */ + short *fdflags, /* set finder flags */ + char *whole_name) +{ + int i; /* loop counter */ + int len; /* filename length */ + afpmap *amap; /* mapping entry */ + const char *ret; + + /* we don't take fdflags from the map or magic file */ + *fdflags = defmap->fdflags; + +#ifdef USE_MAGIC + /* + * if we have a magic file and we want to search it first, + * then try to get a match + */ + if (magic_state && hfs_last == MAP_LAST + && try_map_magic(whole_name, type, creator)) + return; +#endif /* USE_MAGIC */ + + len = strlen(name); + + /* have an afpfile and filename if long enough */ + if (map && len >= mlen) { + /* + * search through the list - we start where we left off + * last time in case this file is of the same type as the + * last one + */ + for (i = 0; i < map_num; i++) { + amap = map[last_ent]; + + /* compare the end of the filename */ +/* if (strcmp((name+len - amap->elen), amap->extn) == 0) { */ + if (strcasecmp((name+len - amap->elen), amap->extn) == 0) { + /* set the required info */ + *type = amap->type; + *creator = amap->creator; + *fdflags = amap->fdflags; + return; + } + /* + * move on to the next entry - wrapping round + * if neccessary + */ + last_ent++; + last_ent %= map_num; + } + } + /* + * if no matches are found, file name too short, or no afpfile, + * then take defaults + */ + *type = defmap->type; + *creator = defmap->creator; + +#ifdef USE_MAGIC + /* + * if we have a magic file and we haven't searched yet, + * then try to get a match + */ + if (magic_state && hfs_last == MAG_LAST) + try_map_magic(whole_name, type, creator); +#endif /* USE_MAGIC */ +} + +void +delete_rsrc_ent(dir_ent *s_entry) +{ + dir_ent *s_entry1 = s_entry->next; + + if (s_entry1 == NULL) + return; + + s_entry->next = s_entry1->next; + s_entry->assoc = NULL; + + free(s_entry1->name); + free(s_entry1->whole_name); + + free(s_entry1); +} + +void +clean_hfs() +{ + if (map) + free(map); + + if (defmap) + free(defmap); + +#ifdef USE_MAGIC + if (magic_state) { + magic_close(magic_state); + magic_state = NULL; + } +#endif /* USE_MAGIC */ +} + +#endif /* APPLE_HYB */ + +void +perr(char *a) +{ +#ifdef USE_LIBSCHILY + if (a) + comerr("%s\n", a); + else + comerr("<no error message given>\n"); +#else + if (a) + fprintf(stderr, "mkhybrid: %s\n", a); + perror("mkhybrid"); + exit(1); +#endif +} |