Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2 **	Unix-HFS file interface including maping file extensions to TYPE/CREATOR
      3 **
      4 **	Adapted from mkhfs routines for mkhybrid
      5 **
      6 **	James Pearson 1/5/97
      7 **	Bug fix JCP 4/12/97
      8 **	Updated for 1.12 and added more Unix HFS filetypes. JCP 21/1/98
      9 **
     10 **	Things still to de done:
     11 **
     12 **		Check SGI (XINET) structs
     13 **		Check file size = finder + rsrc [+ data] is needed
     14 **		AppleSingle/Double version 2?
     15 **		Clean up byte order swapping.
     16 */
     17 
     18 #ifdef APPLE_HYB
     19 
     20 #include <ctype.h>
     21 #include <errno.h>
     22 #include <unistd.h>
     23 #include <err.h>
     24 #include <fcntl.h>
     25 #include <config.h>
     26 #include <stdlib.h>
     27 #include <sys/types.h>
     28 #include <netinet/in.h>
     29 #include <apple.h>
     30 #include "apple_proto.h"
     31 #include <mkisofs.h>
     32 
     33 /* tidy up mkisofs definition ... */
     34 typedef struct directory_entry dir_ent;
     35 
     36 /* routines for getting HFS names and info */
     37 static int get_none_dir(char *, const char *, dir_ent *, int);
     38 static int get_none_info(char *, char *, dir_ent *, int);
     39 static int get_cap_dir(char *, const char *, dir_ent *, int);
     40 static int get_cap_info(char *, char *, dir_ent *, int);
     41 static int get_es_info(char *, char *, dir_ent *, int);
     42 static int get_dbl_info(char *, char *, dir_ent *, int);
     43 static int get_mb_info(char *, char *, dir_ent *, int);
     44 static int get_sgl_info(char *, char *, dir_ent *, int);
     45 static int get_fe_dir(char *, const char *, dir_ent *, int);
     46 static int get_fe_info(char *, char *, dir_ent *, int);
     47 static int get_sgi_dir(char *, const char *, dir_ent *, int);
     48 static int get_sgi_info(char *, char *, dir_ent *, int);
     49 
     50 void map_ext(char *, char **, char **, unsigned short *, char *);
     51 static afpmap	**map;				/* list of mappings */
     52 static afpmap	*defmap;			/* the default mapping */
     53 static int	last_ent;			/* previous mapped entry */
     54 static int	map_num;			/* number of mappings */
     55 static int	mlen;				/* min extension length */
     56 static char	tmp[MAXPATHLEN];		/* tmp working buffer */
     57 static int	hfs_num;			/* number of file types */
     58 static char	p_buf[MAXPATHLEN];		/* info working buffer */
     59 static FILE	*p_fp = NULL;			/* probe File pointer */
     60 static int	p_num = 0;			/* probe bytes read */
     61 static unsigned int	hselect;		/* type of HFS file selected */
     62 
     63 struct hfs_type {			/* Types of various HFS Unix files */
     64   int	type;					/* type of file */
     65   int	flags;					/* special flags */
     66   const char *info;           			/* finderinfo name */
     67   const char *rsrc;           			/* resource fork name */
     68   int  (*get_info)(char*, char*, dir_ent*,int);	/* finderinfo function */
     69   int  (*get_dir)(char*, const char*,dir_ent*,int); /* directory name function */
     70   const char *desc;				/* description */
     71 };
     72 
     73 /* Above filled in */
     74 static struct hfs_type hfs_types[] = {
     75     {TYPE_NONE,0,"", "", get_none_info, get_none_dir,"None"},
     76     {TYPE_CAP,0,".finderinfo/", ".resource/", get_cap_info, get_cap_dir,"CAP"},
     77     {TYPE_NETA,0,".AppleDouble/", ".AppleDouble/", get_dbl_info, get_none_dir,"Netatalk"},
     78     {TYPE_DBL,0,"%", "%", get_dbl_info, get_none_dir,"AppleDouble"},
     79     {TYPE_ESH, 0,".rsrc/", ".rsrc/", get_es_info, get_none_dir,"EtherShare/UShare"},
     80     {TYPE_FEU,2,"FINDER.DAT", "RESOURCE.FRK/", get_fe_info, get_fe_dir,"Exchange"},
     81     {TYPE_FEL,2,"finder.dat", "resource.frk/", get_fe_info, get_fe_dir,"Exchange"},
     82     {TYPE_SGI,2,".HSancillary", ".HSResource/", get_sgi_info, get_sgi_dir,"XINET/SGI"},
     83     {TYPE_MBIN,1,"", "", get_mb_info, get_none_dir,"MacBinary"},
     84     {TYPE_SGL,1,"", "", get_sgl_info, get_none_dir,"AppleSingle"}
     85 };
     86 
     87 /* used by get_magic_match() return */
     88 static char tmp_type[CT_SIZE+1], tmp_creator[CT_SIZE+1];
     89 
     90 /*
     91 **	cstrncopy: Cap Unix name to HFS name
     92 **
     93 **	':' is replaced by '%' and string is terminated with '\0'
     94 */
     95 static void
     96 cstrncpy(char *t, const char *f, int c)
     97 {
     98 	while (c-- && *f)
     99 	{
    100 	    switch (*f)
    101 	    {
    102 		case ':':
    103 		    *t = '%';
    104 		    break;
    105 		default:
    106 		    *t = *f;
    107 		    break;
    108 	    }
    109 	    t++; f++;
    110 	}
    111 
    112 	*t = '\0';
    113 }
    114 /*
    115 ** dehex()
    116 **
    117 ** Given a hexadecimal digit in ASCII, return the integer representation.
    118 **
    119 **	Taken from linux/fs/hfs/trans.c by Paul H. Hargrove
    120 */
    121 static unsigned char
    122 dehex(char c)
    123 {
    124 	if ((c>='0')&&(c<='9')) {
    125 	    return c-'0';
    126 	}
    127 	if ((c>='a')&&(c<='f')) {
    128 	    return c-'a'+10;
    129 	}
    130 	if ((c>='A')&&(c<='F')) {
    131 	    return c-'A'+10;
    132 	}
    133 /*	return 0xff; */
    134 	return (0);
    135 }
    136 
    137 static unsigned char
    138 hex2char(const char *s)
    139 {
    140 	unsigned char o;
    141 
    142 	if(strlen(++s) < 2)
    143 	    return(0);
    144 
    145 	if (!isxdigit((int)(u_char)*s) || !isxdigit((int)(u_char)*(s+1)))
    146 	    return(0);
    147 
    148 	o = (dehex(*s) << 4) & 0xf0;
    149 	s++;
    150 	o |= (dehex(*s) & 0xf);
    151 
    152 	return (o);
    153 }
    154 
    155 /*
    156 **	hstrncpy: Unix name to HFS name with special character
    157 **	translation.
    158 **
    159 **	"%xx" or ":xx" is assumed to be a "special" character and
    160 **	replaced by character code given by the hex characters "xx"
    161 **
    162 **	if "xx" is not a hex number, then it is left alone - except
    163 **	that ":" is replaced by "%"
    164 **
    165 */
    166 static void
    167 hstrncpy(unsigned char *t, const char *f, int c)
    168 {
    169 	unsigned char	o;
    170 	while (c-- && *f)
    171 	{
    172 	    switch (*f)
    173 	    {
    174 		case ':':
    175 		case '%':
    176 		    if ((o = hex2char(f)) == 0) {
    177 			*t = '%';
    178 		    }
    179 		    else {
    180 			*t = o;
    181 			f += 2;
    182 		    }
    183 		    break;
    184 		default:
    185 		    *t = *f;
    186 		    break;
    187 	    }
    188 	    t++; f++;
    189 	}
    190 
    191 	*t = '\0';
    192 }
    193 
    194 /*
    195 **	basename: find just the filename with any directory component
    196 */
    197 /* not used at the moment ...
    198 static char
    199 basename(char *a)
    200 {
    201 	char *b;
    202 
    203 	if((b = strchr(a, '/')))
    204 	    return(++b);
    205 	else
    206 	    return(a);
    207 }
    208 */
    209 
    210 /*
    211 **	get_none_dir: ordinary Unix directory
    212 */
    213 int
    214 get_none_dir(char *hname, const char *dname, dir_ent *s_entry, int ret)
    215 {
    216 	/* just copy the given name */
    217 	hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN);
    218 
    219 	return(ret);
    220 }
    221 
    222 /*
    223 **	get_none_info: ordinary Unix file - try to map extension
    224 */
    225 int
    226 get_none_info(char *hname, char *dname, dir_ent *s_entry, int ret)
    227 {
    228 	char	*t, *c;
    229 	hfsdirent *hfs_ent = s_entry->hfs_ent;
    230 
    231 	map_ext(dname, &t, &c, &s_entry->hfs_ent->fdflags, s_entry->whole_name);
    232 
    233 	/* just copy the given name */
    234 	hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN);
    235 
    236 	strncpy(hfs_ent->type, t, CT_SIZE);
    237 	strncpy(hfs_ent->creator, c, CT_SIZE);
    238 	hfs_ent->type[CT_SIZE] = '\0';
    239 	hfs_ent->creator[CT_SIZE] = '\0';
    240 
    241 	return(ret);
    242 }
    243 /*
    244 **	read_info_file:	open and read a finderinfo file for an HFS file
    245 **			or directory
    246 */
    247 static int
    248 read_info_file(char *name, void *info, int len)
    249 /* char		*name;				finderinfo filename */
    250 /* void	 	*info;				info buffer */
    251 /* int		len;				length of above */
    252 {
    253 	FILE	*fp;
    254 	int	num;
    255 
    256 	/* clear out any old finderinfo stuf */
    257 	memset(info, 0, len);
    258 
    259 	if ((fp = fopen(name,"rb")) == NULL)
    260 	    return(-1);
    261 
    262 	/* read and ignore if the file is short - checked later */
    263 	num = fread(info,1,len,fp);
    264 
    265 	fclose(fp);
    266 
    267 	return(num);
    268 }
    269 /*
    270 **	get_cap_dir: get the CAP name for a directory
    271 */
    272 int
    273 get_cap_dir(char *hname, const char *dname, dir_ent *s_entry, int ret)
    274 /* char		*hname				whole path */
    275 /* const char	*dname				this dir name */
    276 /* dir_ent	*s_entry			directory entry */
    277 {
    278 	FileInfo	info;			/* finderinfo struct */
    279 	int		num = -1;		/* bytes read */
    280 
    281 	num = read_info_file(hname, &info, sizeof(FileInfo));
    282 
    283 	/* check finder info is OK */
    284 	if (num > 0
    285 		&& info.fi_magic1 == FI_MAGIC1
    286 		&& info.fi_magic == FI_MAGIC
    287 		&& info.fi_bitmap & FI_BM_MACINTOSHFILENAME) {
    288 	    /* use the finderinfo name if it exists */
    289 	    cstrncpy(s_entry->hfs_ent->name, info.fi_macfilename, HFS_MAX_FLEN);
    290 	    return (ret);
    291 	}
    292 	else {
    293 	    /* otherwise give it it's Unix name */
    294 	    hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN);
    295 	    return (TYPE_NONE);
    296 	}
    297 }
    298 
    299 /*
    300 **	get_cap_info:	get CAP finderinfo for a file
    301 */
    302 int
    303 get_cap_info(char *hname, char *dname, dir_ent *s_entry, int ret)
    304 /* char		*hname				whole path */
    305 /* char		*dname				this dir name */
    306 /* dir_ent	*s_entry			directory entry */
    307 {
    308 	FileInfo 	info;			/* finderinfo struct */
    309 	int		num = -1;		/* bytes read */
    310 	char		*c;
    311 	char		*t;
    312 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
    313 
    314 	num = read_info_file(hname, &info, sizeof(info));
    315 
    316 	/* check finder info is OK */
    317 	if (num > 0
    318 		&& info.fi_magic1 == FI_MAGIC1
    319 		&& info.fi_magic == FI_MAGIC) {
    320 
    321 	    if (info.fi_bitmap & FI_BM_MACINTOSHFILENAME) {
    322 		/* use the finderinfo name if it exists */
    323 		cstrncpy(hfs_ent->name, info.fi_macfilename, HFS_MAX_FLEN);
    324 	    }
    325 	    else {
    326 		/* use Unix name */
    327 		hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN);
    328 	    }
    329 
    330 	    /* type and creator from finder info */
    331 	    t = info.fdType;
    332 	    c = info.fdCreator;
    333 
    334 	    strncpy(hfs_ent->type, t, CT_SIZE);
    335 	    strncpy(hfs_ent->creator, c, CT_SIZE);
    336 	    hfs_ent->type[CT_SIZE] = '\0';
    337 	    hfs_ent->creator[CT_SIZE] = '\0';
    338 
    339 	    /* finder flags */
    340 	    hfs_ent->fdflags = d_getw((unsigned char *)&info.fdFlags);
    341 	    /* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */
    342 	    hfs_ent->fdflags &= 0xfeff;
    343 
    344 #ifdef USE_MAC_DATES
    345 	    /* set created/modified dates - these date should have already
    346 	       been set from the Unix data fork dates. The finderinfo dates
    347 	       are in Mac format - but we have to convert them back to Unix
    348 	       for the time being  */
    349 	    if ((info.fi_datemagic & FI_CDATE)) {
    350 		/* use libhfs routines to get correct byte order */
    351 		hfs_ent->crdate = d_toutime(d_getl(info.fi_ctime));
    352 	    }
    353 	    if (info.fi_datemagic & FI_MDATE) {
    354 		hfs_ent->mddate = d_toutime(d_getl(info.fi_mtime));
    355 	    }
    356 #endif /* USE_MAC_DATES */
    357 	}
    358 	else {
    359 	    /* failed to open/read finderinfo - so try afpfile mapping */
    360 	    if (verbose > 2) {
    361 		fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
    362 	    	s_entry->whole_name, hfs_types[ret].desc);
    363 	    }
    364 
    365 	    ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
    366 	}
    367 
    368 	return (ret);
    369 }
    370 
    371 /*
    372 **	get_es_info:	get EtherShare/UShare finderinfo for a file
    373 **
    374 **	based on code from Jens-Uwe Mager (jum (at) helios.de) and Phil Sylvester
    375 **	<psylvstr (at) interaccess.com>
    376 */
    377 int
    378 get_es_info(char *hname, char *dname, dir_ent *s_entry, int ret)
    379 /* char		*hname				whole path */
    380 /* char		*dname				this dir name */
    381 /* dir_ent	*s_entry			directory entry */
    382 {
    383 	es_FileInfo 	*einfo;			/* EtherShare info struct */
    384 	us_FileInfo 	*uinfo;			/* UShare info struct */
    385 	char		info[ES_INFO_SIZE];	/* finderinfo buffer */
    386 	int		num = -1;		/* bytes read */
    387 	char		*c;
    388 	char		*t;
    389 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
    390 	dir_ent		*s_entry1;
    391 
    392 	/* the EtherShare and UShare file layout is the same, but they
    393 	   store finderinfo differently */
    394 	einfo = (es_FileInfo *)info;
    395 	uinfo = (us_FileInfo *)info;
    396 
    397 	num = read_info_file(hname, info, sizeof(info));
    398 
    399 	/* check finder info for EtherShare finderinfo */
    400 	if (num >= sizeof(es_FileInfo) &&
    401 		ntohl(einfo->magic) == ES_MAGIC &&
    402 		ntohs(einfo->version) == ES_VERSION) {
    403 
    404 	    /* type and creator from finder info */
    405 	    t = einfo->fdType;
    406 	    c = einfo->fdCreator;
    407 
    408 	    /* finder flags */
    409 	    hfs_ent->fdflags = d_getw((unsigned char *)&einfo->fdFlags);
    410 
    411 	    /* set create date - modified date set from the Unix data
    412 	       fork date */
    413 	    hfs_ent->crdate = d_getl((unsigned char *)&einfo->createTime);
    414 	}
    415 	else if (num >= sizeof(us_FileInfo)) {
    416 	    /* UShare has no magic number, so we assume that this is
    417 	       a valid info/resource file ... */
    418 
    419 	    /* type and creator from finder info */
    420 	    t = uinfo->fdType;
    421 	    c = uinfo->fdCreator;
    422 
    423 	    /* finder flags */
    424 	    hfs_ent->fdflags = d_getw((unsigned char *)&uinfo->fdFlags);
    425 
    426 	    /* set create and modified date - if they exist */
    427 	    if (uinfo->ctime)
    428 		hfs_ent->crdate = d_getl((unsigned char *)&uinfo->ctime);
    429 
    430 	    if (uinfo->mtime)
    431 		hfs_ent->mddate = d_getl((unsigned char *)&uinfo->mtime);
    432 	}
    433 	else {
    434 	    /* failed to open/read finderinfo - so try afpfile mapping */
    435 	    if (verbose > 2) {
    436 		fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
    437 	    	s_entry->whole_name, hfs_types[ret].desc);
    438 	    }
    439 
    440 	    ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
    441 	    return (ret);
    442 	}
    443 
    444 	/* this should exist ... */
    445 	if ((s_entry1 = s_entry->assoc) == NULL)
    446 	    errx(1, "TYPE_ESH error - shouldn't happen!");
    447 
    448 	/* fill in the HFS info stuff */
    449 	strncpy(hfs_ent->type, t, CT_SIZE);
    450 	strncpy(hfs_ent->creator, c, CT_SIZE);
    451 	hfs_ent->type[CT_SIZE] = '\0';
    452 	hfs_ent->creator[CT_SIZE] = '\0';
    453 
    454 	/* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */
    455 	hfs_ent->fdflags &= 0xfeff;
    456 
    457 	/* set name */
    458 	hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN);
    459 
    460 	/* real rsrc file starts ES_INFO_SIZE bytes into the file */
    461 	if(s_entry1->size <= ES_INFO_SIZE) {
    462 	    s_entry1->size = 0;
    463 	    hfs_ent->rsize = 0;
    464 	}
    465 	else {
    466 	    s_entry1->size -= ES_INFO_SIZE;
    467 	    hfs_ent->rsize = s_entry1->size;
    468 	    s_entry1->hfs_off = ES_INFO_SIZE;
    469 	}
    470 
    471 	set_733((char *) s_entry1->isorec.size, s_entry1->size);
    472 
    473 	return (ret);
    474 }
    475 
    476 /*
    477  * calc_crc() --
    478  *   Compute the MacBinary II-style CRC for the data pointed to by p, with the
    479  *   crc seeded to seed.
    480  *
    481  *   Modified by Jim Van Verth to use the magic array for efficiency.
    482  */
    483 static unsigned short
    484 calc_mb_crc(unsigned char *p, long len, unsigned short seed)
    485 {
    486   unsigned short hold;	/* crc computed so far */
    487   long  i;		/* index into data */
    488 
    489   hold = seed;     /* start with seed */
    490   for (i = 0; i < len; i++, p++) {
    491     hold ^= (*p << 8);
    492     hold = (hold << 8) ^ mb_magic[(unsigned char)(hold >> 8)];
    493   }
    494 
    495   return (hold);
    496 } /* calc_mb_crc() */
    497 
    498 int
    499 get_mb_info(char *hname, char *dname, dir_ent *s_entry, int ret)
    500 /* char		*hname				whole path */
    501 /* char		*dname				this dir name */
    502 /* dir_ent	*s_entry			directory entry */
    503 {
    504 	mb_info 	*info;			/* finderinfo struct */
    505 	char		*c;
    506 	char		*t;
    507 	hfsdirent	*hfs_ent;
    508 	dir_ent		*s_entry1;
    509 	int		i;
    510 #ifdef TEST_CODE
    511 	unsigned short	crc_file, crc_calc;
    512 #endif
    513 
    514 	info = (mb_info *)p_buf;
    515 
    516 	/* routine called twice for each file - first to check that
    517 	   it is a valid MacBinary file, second to fill in the HFS
    518 	   info. p_buf holds the required raw data and it *should*
    519 	   remain the same between the two calls */
    520 
    521 	if (s_entry == 0) {
    522 	    /* test that the CRC is OK - not set for MacBinary I files
    523 	       (and incorrect in some MacBinary II files!). If this
    524 	       fails, then perform some other checks */
    525 
    526 #ifdef TEST_CODE
    527 	    /* leave this out for the time being ... */
    528 	    if (p_num >= MB_SIZE && info->version == 0 && info->zero1 == 0) {
    529 		crc_calc = calc_mb_crc((unsigned char *)info, 124, 0);
    530 		crc_file = d_getw(info->crc);
    531 #ifdef DEBUG
    532 		fprintf(stderr,"%s: file %d, calc %d\n",hname,crc_file,crc_calc);
    533 #endif /* DEBUG */
    534 		if (crc_file == crc_calc)
    535 		    return (ret);
    536 	    }
    537 #endif /* TEST_CODE */
    538 
    539 	    /* check some of the fields for a valid MacBinary file
    540 	       not zero1 and zero2 SHOULD be zero - but some files incorrect */
    541 
    542 /*	    if (p_num < MB_SIZE || info->nlen > 63 || info->zero2 || */
    543 	    if (p_num < MB_SIZE || info->zero1 ||
    544 		info->zero2 || info->nlen > 63 ||
    545 			info->version || info->nlen == 0 || *info->name == 0)
    546 		return (TYPE_NONE);
    547 
    548 	    /* check that the filename is OKish */
    549 	    for (i=0;i<info->nlen;i++)
    550 		if(info->name[i] == 0)
    551 		    return (TYPE_NONE);
    552 
    553 	    /* check CREATOR and TYPE are valid */
    554 	    for (i=0;i<4;i++)
    555 		if(info->type[i] == 0 || info->auth[i] == 0)
    556 		    return (TYPE_NONE);
    557 	}
    558 	else {
    559 	    /* we have a vaild MacBinary file, so fill in the bits */
    560 
    561 	    /* this should exist ... */
    562 	    if((s_entry1 = s_entry->assoc) == NULL)
    563 		errx(1, "TYPE_MBIN error - shouldn't happen!");
    564 
    565 	    hfs_ent = s_entry->hfs_ent;
    566 
    567 	    /* type and creator from finder info */
    568 	    t = info->type;
    569 	    c = info->auth;
    570 
    571 	    strncpy(hfs_ent->type, t, CT_SIZE);
    572 	    strncpy(hfs_ent->creator, c, CT_SIZE);
    573 	    hfs_ent->type[CT_SIZE] = '\0';
    574 	    hfs_ent->creator[CT_SIZE] = '\0';
    575 
    576 	    /* finder flags */
    577 	    hfs_ent->fdflags = ((info->flags << 8) & 0xff00) | info->flags2;
    578 	    /* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */
    579 	    hfs_ent->fdflags &= 0xfeff;
    580 
    581 	    /* set created/modified dates - these date should have already
    582 	       been set from the Unix data fork dates. The finderinfo dates
    583 	       are in Mac format - but we have to convert them back to Unix
    584 	       for the time being  */
    585 
    586 	    hfs_ent->crdate = d_toutime(d_getl(info->cdate));
    587 	    hfs_ent->mddate = d_toutime(d_getl(info->mdate));
    588 
    589 	    /* set name */
    590 /*	    hstrncpy(hfs_ent->name, info->name, HFS_MAX_FLEN); */
    591 	    hstrncpy(hfs_ent->name, info->name, MIN(HFS_MAX_FLEN, info->nlen));
    592 
    593 	    /* set correct fork sizes */
    594 	    hfs_ent->dsize = d_getl(info->dflen);
    595 	    hfs_ent->rsize = d_getl(info->rflen);
    596 
    597 	    /* update directory entries for data fork */
    598 	    s_entry->size = hfs_ent->dsize;
    599 	    s_entry->hfs_off = MB_SIZE;
    600 	    set_733((char *) s_entry->isorec.size, s_entry->size);
    601 
    602 	    /* real rsrc file starts after data fork (must be a multiple
    603 	       of MB_SIZE) */
    604 	    s_entry1->size = hfs_ent->rsize;
    605 	    s_entry1->hfs_off = MB_SIZE + V_ROUND_UP(hfs_ent->dsize, MB_SIZE);
    606 	    set_733((char *) s_entry1->isorec.size, s_entry1->size);
    607 	}
    608 
    609 	return (ret);
    610 }
    611 
    612 /*
    613 **	get_dbl_info:	get Apple double finderinfo for a file
    614 **
    615 **	Based on code from cvt2cap.c (c) May 1988, Paul Campbell
    616 */
    617 int
    618 get_dbl_info(char *hname, char *dname, dir_ent *s_entry, int ret)
    619 /* char		*hname				whole path */
    620 /* char		*dname				this dir name */
    621 /* dir_ent	*s_entry			directory entry */
    622 {
    623 	FileInfo 	info;			/* finderinfo struct */
    624 	a_hdr		*hp;
    625 	a_entry		*ep;
    626 	int		num = -1;		/* bytes read */
    627 	char		*c;
    628 	char		*t;
    629 	int		nentries;
    630 	FILE		*fp;
    631 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
    632 	dir_ent		*s_entry1;
    633 	char		name[64];
    634 	int		i;
    635 	int		fail = 0;
    636 
    637 	hp = (a_hdr *)p_buf;;
    638 	memset(hp, 0, A_HDR_SIZE);
    639 
    640 	memset(name, 0, sizeof(name));
    641 
    642 	/* get the rsrc file info - should exist ... */
    643 	if ((s_entry1 = s_entry->assoc) == NULL)
    644 	    errx(1, "TYPE_DBL error - shouldn't happen!");
    645 
    646 	/* open and read the info/rsrc file (it's the same file) */
    647 	if ((fp = fopen(hname,"rb")) != NULL)
    648 	    num = fread(hp, 1, A_HDR_SIZE, fp);
    649 
    650 	/* check finder info is OK - some Netatalk files don't have
    651 	   magic or version set - ignore if it's a netatalk file */
    652 	if (num == A_HDR_SIZE && ((ret == TYPE_NETA) ||
    653 		(ntohl(hp->magic) == APPLE_DOUBLE &&
    654 		ntohl(hp->version) == A_VERSION))) {
    655 
    656 	    /* read TOC of the AppleDouble file */
    657 	    nentries = (int)ntohs(hp->nentries);
    658 	    if(fread(hp->entries, A_ENTRY_SIZE, nentries, fp) < 1) {
    659 		fail = 1;
    660 		nentries = 0;
    661 	    }
    662 
    663 	    /* extract what is needed */
    664 	    for (i=0, ep=hp->entries; i<nentries; i++,ep++) {
    665 		switch(ntohl(ep->id)) {
    666 		    case ID_FINDER:
    667 			/* get the finder info */
    668 			fseek(fp, ntohl(ep->offset), 0);
    669 			if (fread(&info, ntohl(ep->length), 1, fp) < 1) {
    670 			    fail = 1;
    671 			}
    672 			break;
    673 		    case ID_RESOURCE:
    674 			/* set the offset and correct rsrc fork size */
    675 			s_entry1->size = ntohl(ep->length);
    676 			hfs_ent->rsize = s_entry1->size;
    677 			/* offset to start of real rsrc fork */
    678 			s_entry1->hfs_off = ntohl(ep->offset);
    679 			set_733((char *) s_entry1->isorec.size, s_entry1->size);
    680 			break;
    681 		    case ID_NAME:
    682 			/* get Mac file name */
    683 			fseek(fp, ntohl(ep->offset), 0);
    684 			if(fread(name, ntohl(ep->length), 1, fp) < 1)
    685 			    *name = '\0';
    686 			break;
    687 		    default:
    688 			break;
    689 		}
    690 	    }
    691 
    692 	    fclose(fp);
    693 
    694 	    /* skip this if we had a problem */
    695 	    if (!fail) {
    696 		/* type and creator from finder info */
    697 		t = info.fdType;
    698 		c = info.fdCreator;
    699 
    700 		strncpy(hfs_ent->type, t, CT_SIZE);
    701 		strncpy(hfs_ent->creator, c, CT_SIZE);
    702 		hfs_ent->type[CT_SIZE] = '\0';
    703 		hfs_ent->creator[CT_SIZE] = '\0';
    704 
    705 		/* finder flags */
    706 		hfs_ent->fdflags = d_getw((unsigned char *)&info.fdFlags);
    707 		/* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */
    708 		hfs_ent->fdflags &= 0xfeff;
    709 
    710 		/* use stored name if it exists */
    711 		if (*name)
    712 		    cstrncpy(hfs_ent->name, name, HFS_MAX_FLEN);
    713 		else
    714 		    hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN);
    715 	    }
    716 	}
    717 	else {
    718 	    /* failed to open/read finderinfo */
    719 	    fail = 1;
    720 	    if (fp)
    721 		fclose(fp);
    722 	}
    723 
    724 	if (fail) {
    725 	    /* problem with the file - try mapping/magic */
    726 	    if (verbose > 2) {
    727 		fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
    728 		    s_entry->whole_name, hfs_types[ret].desc);
    729 	    }
    730 	    ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
    731 	}
    732 
    733 	return (ret);
    734 }
    735 /*
    736 **	get_sgl_info:	get Apple single finderinfo for a file
    737 **
    738 **	Based on code from cvt2cap.c (c) May 1988, Paul Campbell
    739 */
    740 int
    741 get_sgl_info(char *hname, char *dname, dir_ent *s_entry, int ret)
    742 /* char		*hname				whole path */
    743 /* char		*dname				this dir name */
    744 /* dir_ent	*s_entry			directory entry */
    745 {
    746 	FileInfo 	*info = 0;		/* finderinfo struct */
    747 	a_hdr		*hp;
    748 	static a_entry	*entries;
    749 	a_entry		*ep;
    750 	char		*c;
    751 	char		*t;
    752 	int		nentries;
    753 	hfsdirent	*hfs_ent;
    754 	dir_ent		*s_entry1;
    755 	char		name[64];
    756 	int		i;
    757 
    758 	/* routine called twice for each file - first to check that
    759 	   it is a valid MacBinary file, second to fill in the HFS
    760 	   info. p_buf holds the required raw data and it *should*
    761 	   remain the same between the two calls */
    762 
    763 	hp = (a_hdr *)p_buf;
    764 
    765 	if (s_entry == 0) {
    766 	    if (p_num < A_HDR_SIZE ||
    767 		    ntohl(hp->magic) != APPLE_SINGLE ||
    768 		    ntohl(hp->version) != A_VERSION)
    769 		return (TYPE_NONE);
    770 
    771 	    /* check we have TOC for the AppleSingle file */
    772 	    nentries = (int)ntohs(hp->nentries);
    773 	    if (p_num < (A_HDR_SIZE + nentries*A_ENTRY_SIZE))
    774 		return (TYPE_NONE);
    775 
    776 	    /* save the TOC */
    777 	    entries = (a_entry *)e_malloc(nentries*A_ENTRY_SIZE);
    778 
    779 	    memcpy(entries, (p_buf+A_HDR_SIZE), nentries*A_ENTRY_SIZE);
    780 	}
    781 	else {
    782 	    /* have a vaild AppleSingle File */
    783 	    memset(name, 0, sizeof(name));
    784 
    785 	    /* get the rsrc file info - should exist ... */
    786 	    if ((s_entry1 = s_entry->assoc) == NULL)
    787 		errx(1, "TYPE_SGL error - shouldn't happen!");
    788 
    789 	    hfs_ent = s_entry->hfs_ent;
    790 
    791 	    nentries = (int)ntohs(hp->nentries);
    792 
    793 	    /* extract what is needed */
    794 	    for (i=0, ep=entries; i<nentries; i++,ep++) {
    795 		switch(ntohl(ep->id)) {
    796 		    case ID_FINDER:
    797 			/* get the finder info */
    798 			info = (FileInfo *)(p_buf + ntohl(ep->offset));
    799 			break;
    800 		    case ID_DATA:
    801 			/* set the offset and correct data fork size */
    802 			hfs_ent->dsize = s_entry->size = ntohl(ep->length);
    803 			/* offset to start of real data fork */
    804 			s_entry->hfs_off = ntohl(ep->offset);
    805 			set_733((char *) s_entry->isorec.size, s_entry->size);
    806 			break;
    807 		    case ID_RESOURCE:
    808 			/* set the offset and correct rsrc fork size */
    809 			hfs_ent->rsize = s_entry1->size = ntohl(ep->length);
    810 			/* offset to start of real rsrc fork */
    811 			s_entry1->hfs_off = ntohl(ep->offset);
    812 			set_733((char *) s_entry1->isorec.size, s_entry1->size);
    813 			break;
    814 		    case ID_NAME:
    815 			strncpy(name, (p_buf+ntohl(ep->offset)),
    816 				ntohl(ep->length));
    817 			break;
    818 		    default:
    819 			break;
    820 		}
    821 	    }
    822 
    823 	    free(entries);
    824 
    825 	    if (info == NULL) {
    826 		/* failed to open/read finderinfo - so try afpfile mapping */
    827 		if (verbose > 2) {
    828 		    fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
    829 		        s_entry->whole_name, hfs_types[ret].desc);
    830 		}
    831 		ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
    832 		return (ret);
    833 	    }
    834 
    835 	    /* type and creator from finder info */
    836 	    t = info->fdType;
    837 	    c = info->fdCreator;
    838 
    839 	    strncpy(hfs_ent->type, t, CT_SIZE);
    840 	    strncpy(hfs_ent->creator, c, CT_SIZE);
    841 	    hfs_ent->type[CT_SIZE] = '\0';
    842 	    hfs_ent->creator[CT_SIZE] = '\0';
    843 
    844 	    /* finder flags */
    845 	    hfs_ent->fdflags = d_getw((unsigned char *)&info->fdFlags);
    846 	    /* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */
    847 	    hfs_ent->fdflags &= 0xfeff;
    848 
    849 	    /* use stored name if it exists */
    850 	    if (*name)
    851 		cstrncpy(hfs_ent->name, name, HFS_MAX_FLEN);
    852 	    else
    853 		hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN);
    854 	}
    855 
    856 	return (ret);
    857 }
    858 
    859 /*
    860 **	get_hfs_fe_info: read in the whole finderinfo for a PC Exchange
    861 **		directory - saves on reading this many times for each file.
    862 **
    863 **	Based of information provided by Mark Weinstein <mrwesq (at) earthlink.net>
    864 **
    865 **	Note: the FINDER.DAT file layout depends on the FAT cluster size
    866 **	therefore, files should only be read directly from the FAT media
    867 **
    868 **	Only tested with PC Exchange v2.1 - don't know if it will work
    869 **	with v2.2 and above.
    870 */
    871 static struct hfs_info *
    872 get_hfs_fe_info(struct hfs_info *hfs_info, char *name)
    873 {
    874 	FILE	*fp;
    875 	int	fe_num, fe_pad;
    876 	fe_info info;
    877 	int	c = 0;
    878 	struct hfs_info *hfs_info1 = NULL;
    879 	hfsdirent *hfs_ent;
    880 	char	keyname[12];
    881 	char	*s, *e, *k;
    882 	int	i;
    883 
    884 	if ((fp = fopen(name, "rb")) == NULL)
    885 	    return(NULL);
    886 
    887 	/*
    888 	 * no longer attempt to find out FAT cluster
    889 	 * - rely on command line parameter
    890 	 */
    891 	if (afe_size <= 0)
    892 	    return(NULL);
    893 
    894 	fe_num = afe_size / FE_SIZE;
    895 	fe_pad = afe_size % FE_SIZE;
    896 
    897 	while(fread(&info, 1, FE_SIZE, fp) != 0) {
    898 
    899 	    /* the Mac name may be NULL - so ignore this entry */
    900 	    if (info.nlen != 0) {
    901 
    902 		hfs_info1 = (struct hfs_info *)e_malloc(sizeof(struct hfs_info));
    903 		/* add this entry to the list */
    904 		hfs_info1->next = hfs_info;
    905 		hfs_info = hfs_info1;
    906 
    907 		hfs_ent = &hfs_info1->hfs_ent;
    908 
    909 		/* get the bits we need - ignore [cm]time for the moment */
    910 		cstrncpy(hfs_ent->name, info.name, info.nlen);
    911 
    912 		strncpy(hfs_ent->type, info.type, CT_SIZE);
    913 		strncpy(hfs_ent->creator, info.creator, CT_SIZE);
    914 
    915 		hfs_ent->type[CT_SIZE] = hfs_ent->creator[CT_SIZE] = '\0';
    916 
    917 		hfs_ent->fdflags = d_getw(info.flags);
    918 
    919 		s = info.sname;
    920 		e = info.ext;
    921 		k = keyname;
    922 
    923 		/* short (Unix) name is stored in PC format, so needs
    924 		   to be mangled a bit */
    925 
    926 		/* name part */
    927 		for(i=0;i<8;i++,s++,k++) {
    928 		    if(*s == ' ')
    929 			break;
    930 		    else
    931 			*k = *s;
    932 		}
    933 
    934 		/* extension - if it exists */
    935 		if (strncmp(info.ext, "   ", 3)) {
    936 		    *k = '.';
    937 		    k++;
    938 		    for(i=0;i<3;i++,e++,k++) {
    939 			if(*e == ' ')
    940 			    break;
    941 			else
    942 			    *k = *e;
    943 		    }
    944 		}
    945 		*k = '\0';
    946 
    947 		hfs_info1->keyname = strdup(keyname);
    948 	    }
    949 
    950 	    /* each record is FE_SIZE long, and there are FE_NUM
    951 		per each "cluster size", so we may need to skip the padding */
    952 	    if (++c == fe_num) {
    953 		c = 0;
    954 	        fseek(fp, fe_pad, 1);
    955 	    }
    956 	}
    957 	fclose (fp);
    958 
    959 	return (hfs_info);
    960 }
    961 
    962 /*
    963 **	get_hfs_sgi_info: read in the whole finderinfo for a SGI (XINET)
    964 **		directory - saves on reading this many times for each
    965 **		file.
    966 */
    967 static struct hfs_info *
    968 get_hfs_sgi_info(struct hfs_info *hfs_info, char *name)
    969 {
    970 	FILE	*fp;
    971 	sgi_info info;
    972 	struct hfs_info *hfs_info1 = NULL;
    973 	hfsdirent *hfs_ent;
    974 
    975 	if ((fp = fopen(name, "rb")) == NULL)
    976 	    return(NULL);
    977 
    978 	while(fread(&info, 1, SGI_SIZE, fp) != 0) {
    979 
    980 	    hfs_info1 = (struct hfs_info *)e_malloc(sizeof(struct hfs_info));
    981 	    /* add thsi entry to the list */
    982 	    hfs_info1->next = hfs_info;
    983 	    hfs_info = hfs_info1;
    984 
    985 	    hfs_ent = &hfs_info1->hfs_ent;
    986 
    987 	    /* get the bits we need - ignore [cm]time for the moment */
    988 	    cstrncpy(hfs_ent->name, info.name, HFS_MAX_FLEN);
    989 
    990 	    strncpy(hfs_ent->type, info.type, CT_SIZE);
    991 	    strncpy(hfs_ent->creator, info.creator, CT_SIZE);
    992 
    993 	    hfs_ent->type[CT_SIZE] = hfs_ent->creator[CT_SIZE] = '\0';
    994 
    995 	    /* don't know about flags at the moment */
    996 	/*  hfs_ent->fdflags = d_getw((unsigned char *)&info.flags); */
    997 
    998 	    /* use the HFS name as the key */
    999 	    hfs_info1->keyname = hfs_ent->name;
   1000 
   1001 	}
   1002 	fclose (fp);
   1003 
   1004 	return (hfs_info);
   1005 }
   1006 
   1007 /*
   1008 **	del_hfs_info: delete the info list and recover memory
   1009 */
   1010 void
   1011 del_hfs_info(struct hfs_info *hfs_info)
   1012 {
   1013 	struct hfs_info	*hfs_info1;
   1014 
   1015 	while (hfs_info) {
   1016 	    hfs_info1 = hfs_info;
   1017 	    hfs_info = hfs_info->next;
   1018 
   1019 	    /* key may be the same as the HFS name - so don't free it */
   1020 	    *hfs_info1->hfs_ent.name = '\0';
   1021 	    if (*hfs_info1->keyname)
   1022 		free(hfs_info1->keyname);
   1023 	    free(hfs_info1);
   1024 	}
   1025 }
   1026 
   1027 /*
   1028 **	match_key: find the correct hfs_ent using the Unix filename
   1029 **		as the key
   1030 */
   1031 static hfsdirent *
   1032 match_key(struct hfs_info *hfs_info, const char *key)
   1033 {
   1034 	while (hfs_info) {
   1035 	    if (!strcasecmp(key, hfs_info->keyname))
   1036 		return (&hfs_info->hfs_ent);
   1037 	    hfs_info = hfs_info->next;
   1038 	}
   1039 
   1040 	return (NULL);
   1041 }
   1042 
   1043 /*
   1044 **	get_fe_dir: get PC Exchange directory name
   1045 **
   1046 **	base on probing with od ...
   1047 */
   1048 int
   1049 get_fe_dir(char *hname, const char *dname, dir_ent *s_entry, int ret)
   1050 /* char		*hname				whole path */
   1051 /* const char	*dname				this dir name */
   1052 /* dir_ent	*s_entry			directory entry */
   1053 {
   1054 	struct hfs_info *hfs_info;
   1055 	hfsdirent	*hfs_ent;
   1056 
   1057 	/* cached finderinfo stored with parent directory */
   1058 	hfs_info = s_entry->filedir->hfs_info;
   1059 
   1060 	/* if we have no cache, then make one and store it */
   1061 	if (hfs_info == NULL) {
   1062 	    if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL)
   1063 		ret = TYPE_NONE;
   1064 	    else
   1065 		s_entry->filedir->hfs_info = hfs_info;
   1066 	}
   1067 
   1068 	if (ret != TYPE_NONE) {
   1069 	    /* see if we can find the details of this file */
   1070 	    if ((hfs_ent = match_key(hfs_info, dname)) != NULL) {
   1071 		strcpy(s_entry->hfs_ent->name, hfs_ent->name);
   1072 		return (ret);
   1073 	    }
   1074 	}
   1075 
   1076 	/* can't find the entry, so use the Unix name */
   1077 	hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN);
   1078 
   1079 	return(TYPE_NONE);
   1080 }
   1081 
   1082 /*
   1083 **	get_fe_info: get PC Exchange file details.
   1084 **
   1085 **	base on probing with od and details from Mark Weinstein
   1086 **	<mrwesq (at) earthlink.net>
   1087 */
   1088 int
   1089 get_fe_info(char *hname, char *dname, dir_ent *s_entry, int ret)
   1090 /* char		*hname				whole path */
   1091 /* char		*dname				this dir name */
   1092 /* dir_ent	*s_entry			directory entry */
   1093 {
   1094 	struct hfs_info *hfs_info;
   1095 	hfsdirent	*hfs_ent;
   1096 
   1097 	/* cached finderinfo stored with parent directory */
   1098 	hfs_info = s_entry->filedir->hfs_info;
   1099 
   1100 	/* if we have no cache, then make one and store it */
   1101 	if (hfs_info == NULL) {
   1102 	    if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL)
   1103 		ret = TYPE_NONE;
   1104 	    else
   1105 		s_entry->filedir->hfs_info = hfs_info;
   1106 	}
   1107 
   1108 	if (ret != TYPE_NONE) {
   1109 	    char  *dn = dname;
   1110 #ifdef _WIN32_TEST
   1111 	    /* may have a problem here - v2.2 has long filenames,
   1112 	       but we need to key on the short filename, so we need
   1113 	       do go a bit of win32 stuff ... */
   1114 
   1115 	    char  sname[1024], lname[1024];
   1116 
   1117 	    cygwin32_conv_to_full_win32_path(s_entry->whole_name, lname);
   1118 
   1119 	    if (GetShortPathName(lname, sname, sizeof(sname))) {
   1120 		if (dn = strrchr(sname, '\\'))
   1121 		    dn++;
   1122 		else
   1123 		    dn = sname;
   1124 	    }
   1125 #endif /* _WIN32 */
   1126 
   1127 	    /* see if we can find the details of this file */
   1128 	    if ((hfs_ent = match_key(hfs_info, dn)) != NULL) {
   1129 		strcpy(s_entry->hfs_ent->name, hfs_ent->name);
   1130 		strcpy(s_entry->hfs_ent->type, hfs_ent->type);
   1131 		strcpy(s_entry->hfs_ent->creator, hfs_ent->creator);
   1132 		/* clear HFS_FNDR_HASBEENINITED flag */
   1133 		s_entry->hfs_ent->fdflags = hfs_ent->fdflags & 0xfeff;
   1134 		return (ret);
   1135 	    }
   1136 	}
   1137 
   1138 	/* no entry found - use extension mapping */
   1139 	if (verbose > 2) {
   1140 	    fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
   1141 	        s_entry->whole_name, hfs_types[ret].desc);
   1142 	}
   1143 
   1144 	ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
   1145 
   1146 	return(TYPE_NONE);
   1147 }
   1148 
   1149 /*
   1150 **	get_sgi_dir: get SGI (XINET) HFS directory name
   1151 **
   1152 **	base on probing with od ...
   1153 */
   1154 int
   1155 get_sgi_dir(char *hname, const char *dname, dir_ent *s_entry, int ret)
   1156 /* char		*hname				whole path */
   1157 /* const char	*dname				this dir name */
   1158 /* dir_ent	*s_entry			directory entry */
   1159 {
   1160 	struct hfs_info *hfs_info;
   1161 	hfsdirent	*hfs_ent;
   1162 
   1163 	/* cached finderinfo stored with parent directory */
   1164 	hfs_info = s_entry->filedir->hfs_info;
   1165 
   1166 	/* if we haven't got a cache, then make one */
   1167 	if (hfs_info == NULL) {
   1168 	    if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL)
   1169 		ret = TYPE_NONE;
   1170 	    else
   1171 		s_entry->filedir->hfs_info = hfs_info;
   1172 	}
   1173 
   1174 	/* find the matching entry in the cache */
   1175 	if (ret != TYPE_NONE) {
   1176 	    /* key is (hopefully) the real Mac name */
   1177 	    cstrncpy(tmp, dname, strlen(dname));
   1178 	    if ((hfs_ent = match_key(hfs_info, tmp)) != NULL) {
   1179 		strcpy(s_entry->hfs_ent->name, hfs_ent->name);
   1180 		return (ret);
   1181 	    }
   1182 	}
   1183 
   1184 	/* no entry found - use Unix name */
   1185 	hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN);
   1186 
   1187 	return(TYPE_NONE);
   1188 }
   1189 
   1190 /*
   1191 **	get_sgi_info: get SGI (XINET) HFS finder info
   1192 **
   1193 **	base on probing with od ...
   1194 */
   1195 int
   1196 get_sgi_info(char *hname, char *dname, dir_ent *s_entry, int ret)
   1197 /* char		*hname				whole path */
   1198 /* char		*dname				this dir name */
   1199 /* dir_ent	*s_entry			directory entry */
   1200 {
   1201 	struct hfs_info *hfs_info;
   1202 	hfsdirent	*hfs_ent;
   1203 
   1204 	/* cached finderinfo stored with parent directory */
   1205 	hfs_info = s_entry->filedir->hfs_info;
   1206 
   1207 	/* if we haven't got a cache, then make one */
   1208 	if (hfs_info == NULL) {
   1209 	    if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL)
   1210 		ret = TYPE_NONE;
   1211 	    else
   1212 		s_entry->filedir->hfs_info = hfs_info;
   1213 	}
   1214 
   1215 	if (ret != TYPE_NONE) {
   1216 	    /* tmp is the same as hname here, but we don't need hname
   1217 	       anymore in this function  ...  see if we can find the
   1218 	       details of this file using the Unix name as the key */
   1219 	    cstrncpy(tmp, dname, strlen(dname));
   1220 	    if ((hfs_ent = match_key(hfs_info, tmp)) != NULL) {
   1221 		strcpy(s_entry->hfs_ent->name, hfs_ent->name);
   1222 		strcpy(s_entry->hfs_ent->type, hfs_ent->type);
   1223 		strcpy(s_entry->hfs_ent->creator, hfs_ent->creator);
   1224 	/*	s_entry->hfs_ent->fdflags = hfs_ent->fdflags; */
   1225 		return (ret);
   1226 	    }
   1227 	}
   1228 
   1229 	/* no entry found, so try file extension */
   1230 	if (verbose > 2) {
   1231 	    fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
   1232 	        s_entry->whole_name, hfs_types[ret].desc);
   1233 	}
   1234 
   1235 	ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
   1236 
   1237 	return(TYPE_NONE);
   1238 }
   1239 
   1240 /*
   1241 **	get_hfs_itype: get the type of HFS info for a file
   1242 */
   1243 static int
   1244 get_hfs_itype(const char *wname, const char *dname, char *htmp)
   1245 {
   1246 	int	wlen, i;
   1247 
   1248 	wlen = strlen(wname) - strlen(dname);
   1249 
   1250 	/* search through the known types looking for matches */
   1251 	for (i=1;i<hfs_num;i++) {
   1252 	    /* skip the ones that we don't care about */
   1253 	    if ((hfs_types[i].flags & 0x1) || *(hfs_types[i].info) == TYPE_NONE)
   1254 		continue;
   1255 
   1256 	    strcpy(htmp, wname);
   1257 
   1258 	    sprintf(htmp+wlen, "%s%s", hfs_types[i].info,
   1259 		(hfs_types[i].flags & 0x2) ? "" : dname);
   1260 	    if (!access(tmp, R_OK))
   1261 		return (hfs_types[i].type);
   1262 	}
   1263 
   1264 	return (TYPE_NONE);
   1265 }
   1266 
   1267 /*
   1268 **	get_hfs_dir: set the HFS directory name
   1269 */
   1270 int
   1271 get_hfs_dir(const char *wname, const const char *dname, dir_ent *s_entry)
   1272 {
   1273 	int	type;
   1274 
   1275 	/* get the HFS file type from the info file (if it exists) */
   1276 	type = get_hfs_itype(wname, dname, tmp);
   1277 
   1278 	/* try to get the required info */
   1279 	type = (*(hfs_types[type].get_dir))(tmp, dname, s_entry, type);
   1280 
   1281 	return (type);
   1282 }
   1283 
   1284 /*
   1285 **	get_hfs_info: set the HFS info for a file
   1286 */
   1287 int
   1288 get_hfs_info(char *wname, char *dname, dir_ent *s_entry)
   1289 {
   1290 	int	type, wlen, i;
   1291 
   1292 	wlen = strlen(wname) - strlen(dname);
   1293 
   1294 	/* we may already know the type of Unix/HFS file - so process */
   1295 	if (s_entry->hfs_type != TYPE_NONE) {
   1296 
   1297 /*
   1298 	    i = 0;
   1299 	    for(type=1;i<hfs_num;type++) {
   1300 		if (s_entry->hfs_type == hfs_types[type].type) {
   1301 		    i = type;
   1302 		    break;
   1303 		}
   1304 	    }
   1305 */
   1306 	    type = s_entry->hfs_type;
   1307 
   1308 	    strcpy(tmp, wname);
   1309 	    sprintf(tmp+wlen, "%s%s", hfs_types[type].info,
   1310 		(hfs_types[type].flags & 0x2) ? "" : dname);
   1311 	    type = (*(hfs_types[type].get_info))(tmp, dname, s_entry, type);
   1312 
   1313 	    /* if everything is as expected, then return */
   1314 	    if (s_entry->hfs_type == type)
   1315 		return(type);
   1316 	}
   1317 
   1318 	/* we don't know what type we have so, find out */
   1319 	for (i=1;i<hfs_num;i++) {
   1320 	    if ((hfs_types[i].flags & 0x1) || *(hfs_types[i].info) == TYPE_NONE)
   1321 		continue;
   1322 
   1323 	    strcpy(tmp, wname);
   1324 
   1325 	    sprintf(tmp+wlen, "%s%s", hfs_types[i].info,
   1326 		(hfs_types[i].flags & 0x2) ? "" : dname);
   1327 
   1328 	    /* if the file exists - and not a type we've already tried */
   1329 	    if (!access(tmp, R_OK) && i != s_entry->hfs_type) {
   1330 		type = (*(hfs_types[i].get_info))(tmp, dname, s_entry, i);
   1331 		s_entry->hfs_type = type;
   1332 		return (type);
   1333 	    }
   1334 	}
   1335 
   1336 	/* nothing found, so just a Unix file */
   1337 	type = (*(hfs_types[TYPE_NONE].get_info))(wname, dname, s_entry, TYPE_NONE);
   1338 
   1339 	return (type);
   1340 }
   1341 
   1342 /*
   1343 **	get_hfs_rname: set the name of the Unix rsrc file for a file
   1344 */
   1345 int
   1346 get_hfs_rname(char *wname, char *dname, char *rname)
   1347 {
   1348 	int	wlen, type, i;
   1349 	int	p_fd = -1;
   1350 
   1351 	wlen = strlen(wname) - strlen(dname);
   1352 
   1353 	/* try to find what sort of Unix HFS file type we have */
   1354 	for (i=1;i<hfs_num;i++) {
   1355 	    /* skip if don't want to probe the files - (default) */
   1356 	    if (hfs_types[i].flags & 0x1)
   1357 		continue;
   1358 
   1359 	    strcpy(rname, wname);
   1360 
   1361 	    /* if we have a different info file, the find out it's type */
   1362 	    if (*(hfs_types[i].rsrc)) {
   1363 		sprintf(rname+wlen, "%s%s", hfs_types[i].rsrc, dname);
   1364 		if (!access(rname, R_OK))
   1365 		    return (hfs_types[i].type);
   1366 	    }
   1367 	    else {
   1368 		/* if we are probing, then have a look at the contents to
   1369 		   find type */
   1370 		if (p_fd < 0) {
   1371 		    /* open file, if not already open */
   1372 		    if((p_fd = open(wname, O_RDONLY | O_BINARY)) < 0) {
   1373 			/* can't open it, then give up */
   1374 			return (TYPE_NONE);
   1375 		    } else {
   1376 			if((p_num = read(p_fd, p_buf, sizeof(p_buf))) <= 0) {
   1377 			/* can't read, or zero length - give up */
   1378 			    close(p_fd);
   1379 			    return(TYPE_NONE);
   1380 			}
   1381 			/* get file pointer and close file */
   1382 			p_fp = fdopen(p_fd, "rb");
   1383 			close(p_fd);
   1384 			if(p_fp == NULL)
   1385 			    return(TYPE_NONE);
   1386 		    }
   1387 		}
   1388 		/* call routine to do the work - use the given dname as
   1389 		   this is the name we may use on the CD */
   1390 		type = (*(hfs_types[i].get_info))(rname, dname, 0, i);
   1391 		if (type != 0) {
   1392 		    fclose(p_fp);
   1393 		    return (type);
   1394 		}
   1395 		if (p_fp) {
   1396 		    /* close file - just use contents of buffer next time */
   1397 		    fclose(p_fp);
   1398 		    p_fp = NULL;
   1399 		}
   1400 	    }
   1401 	}
   1402 
   1403 	return (0);
   1404 }
   1405 
   1406 /*
   1407 **	hfs_exclude: file/directory names that hold finder/resource
   1408 **		     information that we want to exclude from the tree.
   1409 **		     These files/directories are processed later ...
   1410 */
   1411 int
   1412 hfs_exclude(char *d_name)
   1413 {
   1414     /* we don't exclude "." and ".." */
   1415     if (!strcmp(d_name,"."))
   1416       return 0;
   1417     if (!strcmp(d_name,".."))
   1418       return 0;
   1419 
   1420     /* do not add the following to our list of dir entries */
   1421     if (DO_CAP & hselect) {
   1422       /* CAP */
   1423       if(!strcmp(d_name,".finderinfo"))
   1424 	return 1;
   1425       if(!strcmp(d_name,".resource"))
   1426 	return 1;
   1427       if(!strcmp(d_name,".ADeskTop"))
   1428 	return 1;
   1429       if(!strcmp(d_name,".IDeskTop"))
   1430 	return 1;
   1431       if(!strcmp(d_name,"Network Trash Folder"))
   1432 	return 1;
   1433       /* special case when HFS volume is mounted using Linux's hfs_fs
   1434 	 Brad Midgley <brad (at) pht.com> */
   1435       if(!strcmp(d_name,".rootinfo"))
   1436 	return 1;
   1437     }
   1438 
   1439     if (DO_ESH & hselect) {
   1440       /* Helios EtherShare files */
   1441       if(!strcmp(d_name,".rsrc"))
   1442 	return 1;
   1443       if(!strcmp(d_name,".Desktop"))
   1444 	return 1;
   1445       if(!strcmp(d_name,".DeskServer"))
   1446 	return 1;
   1447       if(!strcmp(d_name,".Label"))
   1448 	return 1;
   1449     }
   1450 
   1451     if (DO_DBL & hselect) {
   1452       /* Apple Double */
   1453       if (*d_name == '%')
   1454 	return 1;
   1455     }
   1456 
   1457     if (DO_NETA & hselect) {
   1458       if(!strcmp(d_name,".AppleDouble"))
   1459 	return 1;
   1460       if(!strcmp(d_name,".AppleDesktop"))
   1461 	return 1;
   1462     }
   1463 
   1464     if ((DO_FEU & hselect) || ( DO_FEL & hselect)) {
   1465 	/* PC Exchange */
   1466       if(!strcmp(d_name,"RESOURCE.FRK"))
   1467 	return 1;
   1468       if(!strcmp(d_name,"FINDER.DAT"))
   1469 	return 1;
   1470       if(!strcmp(d_name,"DESKTOP"))
   1471 	return 1;
   1472       if(!strcmp(d_name,"FILEID.DAT"))
   1473 	return 1;
   1474       if(!strcmp(d_name,"resource.frk"))
   1475 	return 1;
   1476       if(!strcmp(d_name,"finder.dat"))
   1477 	return 1;
   1478       if(!strcmp(d_name,"desktop"))
   1479 	return 1;
   1480       if(!strcmp(d_name,"fileid.dat"))
   1481 	return 1;
   1482     }
   1483 
   1484     if (DO_SGI | hselect) {
   1485       /* SGI */
   1486       if(!strcmp(d_name,".HSResource"))
   1487 	return 1;
   1488       if(!strcmp(d_name,".HSancillary"))
   1489 	return 1;
   1490     }
   1491 
   1492     return 0;
   1493 }
   1494 /*
   1495 **	print_hfs_info: print info about the HFS files.
   1496 **
   1497 */
   1498 void
   1499 print_hfs_info(dir_ent *s_entry)
   1500 {
   1501 	fprintf(stderr,"Name: %s\n",s_entry->whole_name);
   1502 	fprintf(stderr,"\tFile type: %s\n",hfs_types[s_entry->hfs_type].desc);
   1503 	fprintf(stderr,"\tHFS Name: %s\n",s_entry->hfs_ent->name);
   1504 	fprintf(stderr,"\tISO Name: %s\n",s_entry->isorec.name);
   1505 	fprintf(stderr,"\tCREATOR: %s\n",s_entry->hfs_ent->creator);
   1506 	fprintf(stderr,"\tTYPE:	%s\n", s_entry->hfs_ent->type);
   1507 }
   1508 
   1509 
   1510 /*
   1511 **	hfs_init: sets up the mapping list from the afpfile as well
   1512 **		 the default mapping (with or without) an afpfile
   1513 */
   1514 void
   1515 hfs_init(char *name, unsigned short fdflags, int probe, int nomacfiles,
   1516 	unsigned int hfs_select)
   1517 #if 0
   1518    char		*name;				/* afpfile name */
   1519    u_short	*fdflags;			/* default finder flags */
   1520    int		probe;				/* probe flag */
   1521    int		nomacfiles;			/* don't look for mac files */
   1522    u_int	hfs_select			/* select certain mac files */
   1523 #endif
   1524 {
   1525 	FILE	*fp;				/* File pointer */
   1526 	int	count = NUMMAP;			/* max number of entries */
   1527 	char	buf[MAXPATHLEN];		/* working buffer */
   1528 	afpmap	*amap;				/* mapping entry */
   1529 	char	*c, *t, *e;
   1530 	int	i;
   1531 
   1532 	/* setup number of Unix/HFS filetype - we may wish to not bother */
   1533 	if (nomacfiles)
   1534 	    hfs_num = 0;
   1535 	else
   1536 	    hfs_num = sizeof(hfs_types)/sizeof(struct hfs_type);
   1537 
   1538 	/* we may want to probe all files */
   1539 	if (probe || hfs_select)
   1540 	    for(i=0;i<hfs_num;i++)
   1541 		hfs_types[i].flags &= ~1;	/* 0xfffffffe */
   1542 
   1543 	/* if we have selected certain types of Mac/Unix files, then
   1544 	   turn off the filetype */
   1545 	if (hfs_select)
   1546 	    for(i=1;i<hfs_num;i++)
   1547 		if (!((1 << i) & hfs_select))
   1548 		    hfs_types[i].flags |= 0x1;
   1549 
   1550 	/* save what types have been selected (set all if none have) */
   1551 	if (hfs_select)
   1552 	    hselect = hfs_select;
   1553 	else
   1554 	    hselect = ~0;
   1555 
   1556 #ifdef DEBUG
   1557 	for(i=0;i<hfs_num;i++)
   1558 	    fprintf(stderr,"type = %d flags = %d\n", i, hfs_types[i].flags);
   1559 #endif /* DEBUG */
   1560 
   1561 	/* min length set to max to start with */
   1562 	mlen = MAXPATHLEN;
   1563 
   1564 	/* initialise magic file */
   1565 	if(magic_file && init_magic(magic_file) != 0)
   1566 	    errx(1, "unable to open magic file");
   1567 
   1568 	/* set defaults */
   1569 	map_num = last_ent = 0;
   1570 
   1571 	/* allocate memory for the default entry */
   1572 	if((defmap = (afpmap *)malloc(sizeof(afpmap))) == NULL)
   1573 	    errx(1, "not enough memory");
   1574 
   1575 	/* set default values */
   1576 	defmap->extn = DEFMATCH;
   1577 
   1578 	/* make sure creator and type are 4 chars long */
   1579 	strcpy(defmap->type, BLANK);
   1580 	strcpy(defmap->creator, BLANK);
   1581 
   1582 	e = deftype;
   1583 	t = defmap->type;
   1584 
   1585 	while(*e && (e - deftype) < CT_SIZE)
   1586 	    *t++ = *e++;
   1587 
   1588 	e = defcreator;
   1589 	c = defmap->creator;
   1590 
   1591 	while(*e && (e - defcreator) < CT_SIZE)
   1592 	    *c++ = *e++;
   1593 
   1594 	/* length is not important here */
   1595 	defmap->elen = 0;
   1596 
   1597 	/* no flags */
   1598 	defmap->fdflags = fdflags;
   1599 
   1600 	/* no afpfile - no mappings */
   1601 	if (*name == '\0') {
   1602 	    map = NULL;
   1603 	    return;
   1604 	}
   1605 
   1606 	if((fp = fopen(name,"r")) == NULL)
   1607 	    err(1, "unable to open mapping file: %s", name);
   1608 
   1609 	if((map = (afpmap **)malloc(NUMMAP * sizeof(afpmap *))) == NULL)
   1610 	    errx(1, "not enough memory");
   1611 
   1612 	/* read afpfile line by line */
   1613 	while(fgets(buf, MAXPATHLEN, fp) != NULL) {
   1614 	    /* ignore any comment lines */
   1615 	    c = tmp;
   1616 	    *c = '\0';
   1617 	    if (sscanf(buf,"%1s", c) == EOF || *c == '#')
   1618 		continue;
   1619 
   1620 	    /* increase list size if needed */
   1621 	    if (map_num == count) {
   1622 		count += NUMMAP;
   1623 		map = (afpmap **)realloc(map, count * sizeof(afpmap *));
   1624 		if (map == NULL)
   1625 		    errx(1, "not enough memory");
   1626 	    }
   1627 
   1628 	    /* allocate memory for this entry */
   1629 	    if((amap = (afpmap *)malloc(sizeof(afpmap))) == NULL)
   1630 		errx(1, "not enough memory");
   1631 
   1632 	    t = amap->type;
   1633 	    c = amap->creator;
   1634 
   1635 	    /* extract the info */
   1636 	    if(sscanf(buf, "%s%*s%*1s%c%c%c%c%*1s%*1s%c%c%c%c%*1s",
   1637 		    tmp, c, c+1, c+2, c+3, t, t+1, t+2, t+3) != 9) {
   1638   		fprintf(stderr,"error scanning afpfile %s - continuing", name);
   1639 		free(amap);
   1640 		continue;
   1641 	    }
   1642 
   1643 	    /* copy the extension found */
   1644 	    if ((amap->extn = (char *)strdup(tmp)) == NULL)
   1645 		errx(1, "not enough memory");
   1646 
   1647 	    /* set end-of-string */
   1648 	    *(t+4) = *(c+4) = '\0';
   1649 
   1650 	    /* find the length of the extension */
   1651 	    amap->elen = strlen(amap->extn);
   1652 
   1653 	    /* set flags */
   1654 	    amap->fdflags = fdflags;
   1655 
   1656 	    /* see if we have the default creator/type */
   1657 	    if(!strcmp(amap->extn, DEFMATCH)) {
   1658 		/* get rid of the old default */
   1659 		free(defmap);
   1660 		/* make this the default */
   1661 		defmap = amap;
   1662 		continue;
   1663 	    }
   1664 
   1665 	    /* update the smallest extension length */
   1666 	    mlen = MIN(mlen, amap->elen);
   1667 
   1668 	    /* add entry to the list */
   1669 	    map[map_num++] = amap;
   1670 
   1671 	}
   1672 
   1673 	/* free up some memory */
   1674 	if (map_num != count) {
   1675 	    map = (afpmap **)realloc(map, map_num * sizeof(afpmap *));
   1676 	    if (map == NULL)
   1677 		errx(1, "not enough memory");
   1678 	}
   1679 
   1680 }
   1681 
   1682 /*
   1683 **	map_ext: map a files extension with the list to get type/creator
   1684 */
   1685 void
   1686 map_ext(char *name, char **type, char **creator, unsigned short *fdflags,
   1687 	char *whole_name)
   1688 #if 0
   1689    char		*name;				/* filename */
   1690    char		**type;				/* set type */
   1691    char		**creator;			/* set creator */
   1692    u_short	*fdflags;			/* set finder flags */
   1693 #endif
   1694 {
   1695 	int	i;				/* loop counter */
   1696 	int	len;				/* filename length */
   1697 	afpmap	*amap;				/* mapping entry */
   1698 	char	*ret;
   1699 
   1700 	/* we don't take fdflags from the map or magic file */
   1701 	*fdflags = defmap->fdflags;
   1702 
   1703 	/* if we have a magic file and we want to search it first, then
   1704 	   try to get a match */
   1705 	if (magic_file && hfs_last == MAP_LAST) {
   1706 	    ret = get_magic_match(whole_name);
   1707 
   1708 	    if (ret) {
   1709 		if (sscanf(ret, "%4s%4s", tmp_creator, tmp_type) == 2) {
   1710 		    *type = tmp_type;
   1711 		    *creator = tmp_creator;
   1712 		    return;
   1713 		}
   1714 	    }
   1715 	}
   1716 
   1717 	len = strlen(name);
   1718 
   1719 	/* have an afpfile and filename if long enough */
   1720 	if(map && len >= mlen) {
   1721 	    /* search through the list - we start where we left
   1722 	       off last time in case this file is of the same type
   1723 	       as the last one */
   1724 	    for(i=0;i<map_num;i++) {
   1725 		amap = map[last_ent];
   1726 
   1727 		/* compare the end of the filename */
   1728 /*		if (!strcmp((name + len - amap->elen), amap->extn)) { */
   1729 		if (!strcasecmp((name + len - amap->elen), amap->extn)) {
   1730 		    /* set the required info */
   1731 		    *type = amap->type;
   1732 		    *creator = amap->creator;
   1733 		    *fdflags = amap->fdflags;
   1734 		    return;
   1735 		}
   1736 		/* move on to the next entry - wrapping round if neccessary */
   1737 		last_ent++;
   1738 		last_ent %= map_num;
   1739 	    }
   1740 	}
   1741 
   1742 	/* if no matches are found, file name too short, or no
   1743 	   afpfile, then take defaults */
   1744 	*type = defmap->type;
   1745 	*creator = defmap->creator;
   1746 
   1747 	/* if we have a magic file and we haven't searched yet, then try
   1748 	   to get a match */
   1749 	if (magic_file && hfs_last == MAG_LAST) {
   1750 	    ret = get_magic_match(whole_name);
   1751 
   1752 	    if (ret) {
   1753 		if (sscanf(ret, "%4s%4s", tmp_creator, tmp_type) == 2) {
   1754 		    *type = tmp_type;
   1755 		    *creator = tmp_creator;
   1756 		}
   1757 	    }
   1758 	}
   1759 }
   1760 
   1761 void
   1762 delete_rsrc_ent(dir_ent *s_entry)
   1763 {
   1764 	dir_ent	*s_entry1 = s_entry->next;
   1765 
   1766 	if (s_entry1 == NULL)
   1767 	    return;
   1768 
   1769 	s_entry->next = s_entry1->next;
   1770 	s_entry->assoc = NULL;
   1771 
   1772 	free(s_entry1->name);
   1773 	free(s_entry1->whole_name);
   1774 
   1775 	free(s_entry1);
   1776 }
   1777 
   1778 void
   1779 clean_hfs()
   1780 {
   1781 	if (map)
   1782 	    free(map);
   1783 
   1784 	if (defmap)
   1785 	    free(defmap);
   1786 
   1787 	if (magic_file)
   1788 	    clean_magic();
   1789 }
   1790 
   1791 #else
   1792 #include <stdio.h>
   1793 #endif /* APPLE_HYB */
   1794