/* @(#)apple.c 1.46 16/10/10 joerg, Copyright 1997, 1998, 1999, 2000 James Pearson, Copyright 2000-2016 J. Schilling */ #include #ifndef lint static UConst char sccsid[] = "@(#)apple.c 1.46 16/10/10 joerg, Copyright 1997, 1998, 1999, 2000 James Pearson, Copyright 2000-2016 J. Schilling"; #endif /* * Copyright (c) 1997, 1998, 1999, 2000 James Pearson * Copyright (c) 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; 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 */ #include "mkisofs.h" #include #include #include #include #include #include #ifdef APPLE_HYB #include "apple.h" /* tidy up mkisofs definition ... */ typedef struct directory_entry dir_ent; /* routines for getting HFS names and info */ EXPORT void del_hfs_info __PR((struct hfs_info *hfs_info)); EXPORT void set_root_info __PR((char *name)); EXPORT int get_hfs_dir __PR((char *wname, char *dname, dir_ent *s_entry)); EXPORT int get_hfs_info __PR((char *wname, char *dname, dir_ent *s_entry)); EXPORT int get_hfs_rname __PR((char *wname, char *dname, char *rname)); EXPORT int hfs_exclude __PR((char *d_name)); EXPORT int hfs_excludepath __PR((char *path)); EXPORT void print_hfs_info __PR((dir_ent *s_entry)); EXPORT int file_is_resource __PR((char *fname, int hfstype)); EXPORT void hfs_init __PR((char *name, Ushort fdflags, Uint hfs_select)); EXPORT void delete_rsrc_ent __PR((dir_ent *s_entry)); EXPORT void clean_hfs __PR((void)); EXPORT void perr __PR((char *a)); #ifndef HAVE_STRCASECMP LOCAL int strcasecmp __PR((const char *s1, const char *s2)); #endif LOCAL int get_none_dir __PR((char *, char *, dir_ent *, int)); LOCAL int get_none_info __PR((char *, char *, dir_ent *, int)); LOCAL int get_cap_dir __PR((char *, char *, dir_ent *, int)); LOCAL int get_cap_info __PR((char *, char *, dir_ent *, int)); LOCAL int get_es_dir __PR((char *, char *, dir_ent *, int)); LOCAL int get_es_info __PR((char *, char *, dir_ent *, int)); LOCAL int get_dbl_dir __PR((char *, char *, dir_ent *, int)); LOCAL int get_dbl_info __PR((char *, char *, dir_ent *, int)); LOCAL int get_mb_info __PR((char *, char *, dir_ent *, int)); LOCAL int get_sgl_info __PR((char *, char *, dir_ent *, int)); LOCAL int get_fe_dir __PR((char *, char *, dir_ent *, int)); LOCAL int get_fe_info __PR((char *, char *, dir_ent *, int)); LOCAL int get_sgi_dir __PR((char *, char *, dir_ent *, int)); LOCAL int get_sgi_info __PR((char *, char *, dir_ent *, int)); LOCAL int get_sfm_info __PR((char *, char *, dir_ent *, int)); #ifdef IS_MACOS_X LOCAL int get_xhfs_dir __PR((char *, char *, dir_ent *, int)); LOCAL int get_xhfs_info __PR((char *, char *, dir_ent *, int)); #else #define get_xhfs_dir get_none_dir #define get_xhfs_info get_none_info #endif /* IS_MACOS_X */ #define OSX_RES_FORK_SUFFIX "/..namedfork/rsrc" LOCAL int is_pathcomponent __PR((char *, char *)); LOCAL void set_ct __PR((hfsdirent *, char *, char *)); LOCAL void set_Dinfo __PR((byte *, hfsdirent *)); LOCAL void set_Finfo __PR((byte *, hfsdirent *)); LOCAL void cstrncpy __PR((char *, char *, int)); LOCAL unsigned char dehex __PR((char)); LOCAL unsigned char hex2char __PR((char *)); LOCAL void hstrncpy __PR((unsigned char *, char *, size_t)); LOCAL int read_info_file __PR((char *, void *, int)); /*LOCAL unsigned short calc_mb_crc __PR((unsigned char *, long, unsigned short));*/ LOCAL struct hfs_info *get_hfs_fe_info __PR((struct hfs_info *, char *)); LOCAL struct hfs_info *get_hfs_sgi_info __PR((struct hfs_info *, char *)); LOCAL struct hfs_info *match_key __PR((struct hfs_info *, char *)); LOCAL int get_hfs_itype __PR((char *, char *, char *)); LOCAL void map_ext __PR((char *, char **, char **, short *, char *)); LOCAL afpmap **map; /* list of mappings */ LOCAL afpmap *defmap; /* the default mapping */ LOCAL int last_ent; /* previous mapped entry */ LOCAL int map_num; /* number of mappings */ LOCAL int mlen; /* min extension length */ LOCAL char tmp[PATH_MAX]; /* tmp working buffer */ LOCAL int hfs_num; /* number of file types */ LOCAL char p_buf[PATH_MAX]; /* info working buffer */ LOCAL FILE *p_fp = NULL; /* probe File pointer */ LOCAL int p_num = 0; /* probe bytes read */ LOCAL 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) __PR((char *, char *, dir_ent *, int)); /* finderinfo */ /* function */ int (*get_dir) __PR((char *, char *, dir_ent *, int)); /* directory */ /* name */ /* function */ char *desc; /* description */ }; /* Above filled in */ LOCAL 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"}, #ifdef __needed__ /* * Causes syslog error since Mac OS X 10.4 */ {TYPE_XHFS, APPEND | NOINFO, "/rsrc", "/rsrc", get_xhfs_info, get_xhfs_dir, "MacOS X HFS"} #endif {TYPE_XHFS, APPEND | NOINFO, OSX_RES_FORK_SUFFIX, OSX_RES_FORK_SUFFIX, get_xhfs_info, get_xhfs_dir, "MacOS X HFS"}, }; /* used by get_magic_match() return */ LOCAL char tmp_type[CT_SIZE + 1]; LOCAL char 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. */ LOCAL 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 LOCAL int strcasecmp(s1, s2) 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 */ LOCAL void set_ct(hfs_ent, c, t) 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' */ LOCAL void cstrncpy(t, f, c) 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 */ #ifdef PROTOTYPES LOCAL unsigned char dehex(char c) #else LOCAL unsigned char dehex(c) char c; #endif { 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); } LOCAL unsigned char hex2char(s) 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 "%" * */ LOCAL void hstrncpy(t, f, tlen) unsigned char *t; char *f; size_t tlen; /* The to-length */ { unsigned char o; size_t slen = strlen(f); while (tlen > 0 && *f) { size_t ofl = slen; size_t otl = tlen; switch (*f) { case ':': case '%': if ((o = hex2char(f)) == 0) { goto def; } else { *t++ = o; tlen--; f += 3; slen -= 3; continue; } def: default: conv_charset(t, &tlen, (unsigned char *)f, &slen, in_nls, hfs_onls); break; } t += otl - tlen; f += ofl - slen; } *t = '\0'; } /* * basename: find just the filename with any directory component */ #ifdef __needed__ /* * not used at the moment ... */ LOCAL char basename(a) char *a; { char *b; if ((b = strchr(a, '/'))) return (++b); else return (a); } #endif /* * set_Dinfo: set directory info */ LOCAL void set_Dinfo(ptr, ent) 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 */ LOCAL void set_Finfo(ptr, ent) 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 */ LOCAL int get_none_dir(hname, dname, s_entry, ret) 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 */ LOCAL int get_none_info(hname, dname, s_entry, ret) 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 */ LOCAL int read_info_file(name, info, len) 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 */ LOCAL int get_cap_dir(hname, dname, s_entry, ret) 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 */ LOCAL int get_cap_info(hname, dname, s_entry, ret) 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 * */ LOCAL int get_es_dir(hname, dname, s_entry, ret) 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 * */ LOCAL int get_es_info(hname, dname, s_entry, ret) 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 (d_getl(uinfo->ctime)) hfs_ent->crdate = d_getl(uinfo->ctime); if (d_getl(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__ #ifdef PROTOTYPES LOCAL unsigned short calc_mb_crc(unsigned char *p, long len, unsigned short seed) #else LOCAL unsigned short calc_mb_crc(p, len, seed) unsigned char *p; long len; unsigned short seed; #endif { 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__ */ LOCAL int get_mb_info(hname, dname, s_entry, ret) 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 */ LOCAL int get_dbl_dir(hname, dname, s_entry, ret) 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); fp = NULL; /* 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 */ LOCAL int get_dbl_info(hname, dname, s_entry, ret) 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); fp = NULL; /* 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 */ LOCAL int get_sgl_info(hname, dname, s_entry, ret) 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 * * 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. */ LOCAL struct hfs_info * get_hfs_fe_info(hfs_info, name) 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; /* * 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; if ((fp = fopen(name, "rb")) == NULL) return (NULL); 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 = e_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. */ LOCAL struct hfs_info * get_hfs_sgi_info(hfs_info, name) 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 */ EXPORT void del_hfs_info(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 */ LOCAL struct hfs_info * match_key(hfs_info, 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 ... */ LOCAL int get_fe_dir(hname, dname, s_entry, ret) 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 * */ LOCAL int get_fe_info(hname, dname, s_entry, ret) 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 ... */ LOCAL int get_sgi_dir(hname, dname, s_entry, ret) 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 ... */ LOCAL int get_sgi_info(hname, dname, s_entry, ret) 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 */ LOCAL byte sfm_magic[4] = {0x41, 0x46, 0x50, 0x00}; LOCAL byte sfm_version[4] = {0x00, 0x00, 0x01, 0x00}; LOCAL int get_sfm_info(hname, dname, s_entry, ret) 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 * * Notes from HELIOS: we will not use the pseudo name here, * otherwise we will get the info for the resource file * instead of info for the data file. */ LOCAL int get_xhfs_dir(hname, dname, s_entry, ret) 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)); memset(&ainfo, 0, sizeof (ainfo)); /* 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; attrs.commonattr |= ATTR_CMN_OBJID; /* Helios add */ /* 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; } } err = 0; /* HELIOS: don't do any afpfile mapping */ } /* 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 * * Notes from HELIOS: we will not use the pseudo name here, * otherwise we will get the info for the resource file * instead of info for the data file. */ LOCAL int get_xhfs_info(hname, dname, s_entry, ret) 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; char tmphname[2048]; /* XXX is this sufficient with -find? */ strlcpy(tmphname, hname, sizeof (tmphname)); /* * delete the /..namedfork/rsrc */ tmphname[strlen(tmphname) - strlen(OSX_RES_FORK_SUFFIX)] = 0; memset(&attrs, 0, sizeof (attrs)); memset(&ainfo, 0, sizeof (ainfo)); /* 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; attrs.commonattr |= ATTR_CMN_OBJID; /* Helios add */ attrs.fileattr = ATTR_FILE_RSRCLENGTH; /* get the info */ err = getattrlist(tmphname, &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; } } } err = 0; /* HELIOS: don't do any afpfile mapping */ 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(tmphname, dname, s_entry, TYPE_NONE); } return (ret); } #endif /* IS_MACOS_X */ /* * get_hfs_itype: get the type of HFS info for a file */ LOCAL int get_hfs_itype(wname, dname, htmp) 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 */ EXPORT void set_root_info(name) 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 */ EXPORT int get_hfs_dir(wname, dname, s_entry) 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 */ EXPORT int get_hfs_info(wname, dname, s_entry) 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 ... */ EXPORT int get_hfs_rname(wname, dname, 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 file */ p_fp = fdopen(p_fd, "rb"); if (p_fp == NULL) { close(p_fd); 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 ... */ EXPORT int hfs_exclude(d_name) 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 */ 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); } /* * is_pathcomponent: Check if is a path component of * . Return 1 if yes and 0 otherwise. */ LOCAL int is_pathcomponent(path, compare) char *path; char *compare; { char *p, *q; char *r = path; while ((p = strstr(r, compare)) != NULL) { q = p + strlen(compare); if ((*q == 0 || *q == '/') && (p == r || *(p - 1) == '/')) return (1); r = q; } return (0); } /* * hfs_excludepath: file/directory names that hold finder/resource * information that we want to exclude from the tree. * These files/directories are processed later ... */ EXPORT int hfs_excludepath(path) char *path; { /* do not add the following to our list of dir entries */ if (DO_CAP & hselect) { /* CAP */ if (is_pathcomponent(path, ".finderinfo")) return (1); if (is_pathcomponent(path, ".resource")) return (1); if (is_pathcomponent(path, ".ADeskTop")) return (1); if (is_pathcomponent(path, ".IDeskTop")) return (1); if (is_pathcomponent(path, "Network Trash Folder")) return (1); /* * special case when HFS volume is mounted using Linux's hfs_fs * Brad Midgley */ if (is_pathcomponent(path, ".rootinfo")) return (1); } if ((DO_ESH & hselect)) { /* Helios EtherShare files */ if (is_pathcomponent(path, ".rsrc")) return (1); if (is_pathcomponent(path, ".Desktop")) return (1); if (is_pathcomponent(path, ".DeskServer")) return (1); if (is_pathcomponent(path, ".Label")) return (1); } if (DO_DBL & hselect) { /* Apple Double */ /* * special case when HFS volume is mounted using Linux's hfs_fs */ if (is_pathcomponent(path, "%RootInfo")) 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 ... */ /* todo!! */ if (*path == '%') if (hex2char(path) == 0) return (1); } if (DO_NETA & hselect) { if (is_pathcomponent(path, ".AppleDouble")) return (1); if (is_pathcomponent(path, ".AppleDesktop")) return (1); } if ((DO_FEU & hselect) || (DO_FEL & hselect)) { /* PC Exchange */ if (is_pathcomponent(path, "RESOURCE.FRK")) return (1); if (is_pathcomponent(path, "FINDER.DAT")) return (1); if (is_pathcomponent(path, "DESKTOP")) return (1); if (is_pathcomponent(path, "FILEID.DAT")) return (1); if (is_pathcomponent(path, "resource.frk")) return (1); if (is_pathcomponent(path, "finder.dat")) return (1); if (is_pathcomponent(path, "desktop")) return (1); if (is_pathcomponent(path, "fileid.dat")) return (1); } if (DO_SGI & hselect) { /* SGI */ if (is_pathcomponent(path, ".HSResource")) return (1); if (is_pathcomponent(path, ".HSancillary")) return (1); } if (DO_DAVE & hselect) { /* DAVE */ if (is_pathcomponent(path, "resource.frk")) return (1); if (is_pathcomponent(path, "DesktopFolderDB")) 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 */ /* todo!! */ if (DO_SFM & hselect) { /* SFM */ if (is_pathcomponent(path, ":Afp_Resource")) return (1); if (is_pathcomponent(path, ":Comments")) return (1); if (is_pathcomponent(path, ":Afp_AfpInfo")) return (1); } #endif /* _WIN32 */ if (DO_XDBL & hselect) { char *p; char *r = path; char *compare = "._"; /* XDB */ while ((p = strstr(r, compare)) != NULL) { if (p == r) { if (*(p + strlen(compare)) != 0) { return (1); } } else if (*(p - 1) == '/' && *(p + strlen(compare)) != 0) { return (1); } r += strlen(compare); } } return (0); } /* * print_hfs_info: print info about the HFS files. * */ EXPORT void print_hfs_info(s_entry) 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); fprintf(stderr, _("\tFlags: %d\n"), s_entry->hfs_ent->fdflags); fprintf(stderr, _("\tISO-Size: %ld\n"), (long)get_733(s_entry->isorec.size)); fprintf(stderr, _("\tSize: %llu\n"), (Llong)s_entry->size); fprintf(stderr, _("\tExtent: %ld\n"), (long)get_733(s_entry->isorec.extent)); if (s_entry->assoc) { fprintf(stderr, _("\tResource Name: %s\n"), s_entry->assoc->whole_name); fprintf(stderr, _("\t\tISO-Size: %ld\n"), (long)get_733(s_entry->assoc->isorec.size)); fprintf(stderr, _("\t\tSize: %llu\n"), (Llong)s_entry->assoc->size); fprintf(stderr, _("\t\tExtent: %ld\n"), (long)get_733(s_entry->assoc->isorec.extent)); } } /* test if passed file is a resource file */ EXPORT int file_is_resource(fname, hfstype) char *fname; int hfstype; { char compare[2048]; switch (hfstype) { case TYPE_NONE: case TYPE_MBIN: case TYPE_SGL: break; case TYPE_XHFS: strlcpy(compare, hfs_types[hfstype].rsrc, sizeof (compare)); if (strlen(fname) > strlen(compare)) { if (strcmp(&fname[strlen(fname) - strlen(compare)], compare) == 0) { return (1); } } break; case TYPE_DAVE: case TYPE_SGI: case TYPE_FEL: case TYPE_FEU: case TYPE_ESH: case TYPE_NETA: case TYPE_CAP: strcpy(compare, "/"); strcat(compare, hfs_types[hfstype].rsrc); if (strstr(fname, compare) != NULL) { return (1); } break; case TYPE_XDBL: case TYPE_SFM: case TYPE_DBL: strcpy(compare, "/"); strcat(compare, hfs_types[hfstype].rsrc); if (strstr(fname, compare) != NULL) { return (1); } break; default: break; } return (0); } /* * hfs_init: sets up the mapping list from the afpfile as well * the default mapping (with or without) an afpfile */ #ifdef PROTOTYPES EXPORT void hfs_init(char *name, Ushort fdflags, Uint hfs_select) #else EXPORT void hfs_init(name, fdflags, hfs_select) char *name; /* afpfile name */ Ushort fdflags; /* default finder flags */ Uint hfs_select; /* select certain mac files */ #endif { 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; /* initialise magic file */ if (magic_file && init_magic(magic_file) != 0) comerr("Unable to open magic file '%s'.\n", magic_file); /* 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) comerr("Unable to open mapping file '%s'.\n", name); 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 for mapping file"); } /* 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\n"), name); free(amap); continue; } /* copy the extension found */ amap->extn = e_strdup(tmp); /* 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; } fclose(fp); /* free up some memory */ if (map_num != count) { map = (afpmap **) realloc(map, map_num * sizeof (afpmap *)); if (map == NULL) perr("not enough memory for mapping file"); } } /* * map_ext: map a files extension with the list to get type/creator */ LOCAL void map_ext(name, type, creator, fdflags, whole_name) 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 */ char *ret; /* we don't take fdflags from the map or magic file */ *fdflags = defmap->fdflags; /* * if we have a magic file and we want to search it first, * then try to get a match */ if (magic_file && hfs_last == MAP_LAST) { ret = get_magic_match(whole_name); if (ret) { if (sscanf(ret, "%4s%4s", tmp_creator, tmp_type) == 2) { *type = tmp_type; *creator = tmp_creator; return; } } } 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; /* * if we have a magic file and we haven't searched yet, * then try to get a match */ if (magic_file && hfs_last == MAG_LAST) { ret = get_magic_match(whole_name); if (ret) { if (sscanf(ret, "%4s%4s", tmp_creator, tmp_type) == 2) { *type = tmp_type; *creator = tmp_creator; } } } } EXPORT void delete_rsrc_ent(s_entry) 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); } EXPORT void clean_hfs() { if (map) free(map); if (defmap) free(defmap); if (magic_file) clean_magic(); } /* * We are in hope that errno is set up by libhfs_iso if there * is no system error code. */ EXPORT void perr(a) char *a; { if (a) comerr("%s\n", _(a)); else comerr(_("\n")); } #endif /* APPLE_HYB */ #ifndef APPLE_HFS_HYB /* * Convert 2 bytes in big-endian format into local host format */ EXPORT short d_getw(p) Uchar *p; { return ((short)((p[0] << 8) | p[1])); } /* * Convert 4 bytes in big-endian format into local host format */ EXPORT long d_getl(p) Uchar *p; { return ((long)((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])); } /* * Apple v1 strores dates beginnign with 1st Jan 1904 * Apple v2 strores dates beginnign with 1st Jan 2000 */ #define V2TDIFF 946684800L /* 30 years (1970 .. 2000) */ #define V1TDIFF 2082844800L /* 66 years (1904 .. 1970) */ #define TZNONE 0x0F0F0F0F /* no valid time */ LOCAL unsigned long tzdiff = TZNONE; /* * Calculate the timezone difference between local time and UTC */ LOCAL void inittzdiff() { time_t now; struct tm tm; struct tm *lmp; struct tm *gmp; time(&now); lmp = localtime(&now); gmp = gmtime(&now); tzdiff = 0; if (lmp && gmp) { tm = *gmp; tm.tm_isdst = lmp->tm_isdst; tzdiff = now - mktime(&tm); } } /* * Convert Macintosh time to UNIX time */ EXPORT unsigned long d_toutime(secs) unsigned long secs; { time_t utime = secs; if (tzdiff == TZNONE) inittzdiff(); return (utime - V1TDIFF - tzdiff); } /* * Convert Apple Double v2 time to UNIX time */ EXPORT unsigned long d_dtoutime(secs) long secs; { time_t utime = secs; if (tzdiff == TZNONE) inittzdiff(); return (utime + V2TDIFF - tzdiff); } #endif /* !APPLE_HFS_HYB */