cdrtools/mkisofs/apple.c

3082 lines
75 KiB
C
Raw Permalink Normal View History

2025-06-15 04:19:58 +08:00
/* @(#)apple.c 1.46 16/10/10 joerg, Copyright 1997, 1998, 1999, 2000 James Pearson, Copyright 2000-2016 J. Schilling */
#include <schily/mconfig.h>
#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 <schily/errno.h>
#include <schily/fcntl.h>
#include <schily/utypes.h>
#include <schily/ctype.h>
#include <schily/in.h>
#include <schily/schily.h>
#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
* <psylvstr@interaccess.com>
*/
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
* <psylvstr@interaccess.com>
*/
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 <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.
*/
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
* <mrwesq@earthlink.net>
*/
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 <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);
}
/*
* is_pathcomponent: Check if <compare> is a path component of
* <path>. 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 <brad@pht.com>
*/
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(_("<no error message given>\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 */