1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12 
13 /* @(#)apple.c	1.19 04/03/02 joerg, Copyright 1997, 1998, 1999, 2000 James Pearson */
14 /*
15  *      Copyright (c) 1997, 1998, 1999, 2000 James Pearson
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2, or (at your option)
20  * any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; see the file COPYING.  If not, write to
29  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30  */
31 
32 /*
33  *	Unix-HFS file interface including maping file extensions to TYPE/CREATOR
34  *
35  *	Adapted from mkhfs routines for mkhybrid
36  *
37  *	James Pearson 1/5/97
38  *	Bug fix JCP 4/12/97
39  *	Updated for 1.12 and added more Unix HFS filetypes. JCP 21/1/98
40  *	Tidy up to use Finfo and Dinfo for all formats where
41  *		possible JCP 25/4/2000
42  *
43  *	Things still to de done:
44  *
45  *		Check file size = finder + rsrc [+ data] is needed
46  */
47 
48 #ifdef APPLE_HYB
49 
50 #include <mconfig.h>
51 #include "genisoimage.h"
52 #include <errno.h>
53 #include <fctldefs.h>
54 #include <utypes.h>
55 #include <ctype.h>
56 #include <netinet/in.h>
57 #include "apple.h"
58 #include <schily.h>
59 
60 #ifdef USE_MAGIC
61 #include <magic.h>
62 magic_t magic_state = NULL;
63 #ifndef MAGIC_ERROR
64 /* workaround for older ´API */
65 #define MAGIC_ERROR 0
66 #endif
67 #endif /* USE_MAGIC */
68 
69 /* tidy up genisoimage definition ... */
70 typedef struct directory_entry dir_ent;
71 
72 /* routines for getting HFS names and info */
73 #ifndef	HAVE_STRCASECMP
74 static int	strcasecmp(const char *s1, const char *s2);
75 #endif
76 static int	get_none_dir(char *, char *, dir_ent *, int);
77 static int	get_none_info(char *, char *, dir_ent *, int);
78 static int	get_cap_dir(char *, char *, dir_ent *, int);
79 static int	get_cap_info(char *, char *, dir_ent *, int);
80 static int	get_es_dir(char *, char *, dir_ent *, int);
81 static int	get_es_info(char *, char *, dir_ent *, int);
82 static int	get_dbl_dir(char *, char *, dir_ent *, int);
83 static int	get_dbl_info(char *, char *, dir_ent *, int);
84 static int	get_mb_info(char *, char *, dir_ent *, int);
85 static int	get_sgl_info(char *, char *, dir_ent *, int);
86 static int	get_fe_dir(char *, char *, dir_ent *, int);
87 static int	get_fe_info(char *, char *, dir_ent *, int);
88 static int	get_sgi_dir(char *, char *, dir_ent *, int);
89 static int	get_sgi_info(char *, char *, dir_ent *, int);
90 static int	get_sfm_info(char *, char *, dir_ent *, int);
91 
92 #ifdef IS_MACOS_X
93 static int	get_xhfs_dir(char *, char *, dir_ent *, int);
94 static int	get_xhfs_info(char *, char *, dir_ent *, int);
95 #else
96 #define	get_xhfs_dir	get_none_dir
97 #define	get_xhfs_info	get_none_info
98 #endif /* IS_MACOS_X */
99 
100 static void	set_ct(hfsdirent *, char *, char *);
101 static void	set_Dinfo(byte *, hfsdirent *);
102 static void	set_Finfo(byte *, hfsdirent *);
103 static void	cstrncpy(char *, char *, int);
104 static unsigned char dehex(char);
105 static unsigned char hex2char(char *);
106 static void	hstrncpy(unsigned char *, char *, int);
107 static int	read_info_file(char *, void *, int);
108 
109 /*static unsigned short	calc_mb_crc	__PR((unsigned char *, long, unsigned short));*/
110 static struct hfs_info *get_hfs_fe_info(struct hfs_info *, char *);
111 static struct hfs_info *get_hfs_sgi_info(struct hfs_info *, char *);
112 static struct hfs_info *match_key(struct hfs_info *, char *);
113 
114 static int	get_hfs_itype(char *, char *, char *);
115 static void	map_ext(char *, char **, char **, short *, char *);
116 
117 static afpmap	**map;		/* list of mappings */
118 static afpmap	*defmap;	/* the default mapping */
119 static int	last_ent;	/* previous mapped entry */
120 static int	map_num;	/* number of mappings */
121 static int	mlen;		/* min extension length */
122 static char	tmp[PATH_MAX];	/* tmp working buffer */
123 static int	hfs_num;	/* number of file types */
124 static char	p_buf[PATH_MAX]; /* info working buffer */
125 static FILE	*p_fp = NULL;	/* probe File pointer */
126 static int	p_num = 0;	/* probe bytes read */
127 static unsigned	int hselect;	/* type of HFS file selected */
128 
129 struct hfs_type {	/* Types of various HFS Unix files */
130 	int	type;	/* type of file */
131 	int	flags;	/* special flags */
132 	char	*info;	/* finderinfo name */
133 	char	*rsrc;	/* resource fork name */
134 	int	(*get_info)(char *, char *, dir_ent *, int); /* finderinfo */
135 								    /*	function */
136 	int	(*get_dir)(char *, char *, dir_ent *, int);  /* directory */
137 								    /* name */
138 								    /* function */
139 	char	*desc;	/* description */
140 };
141 
142 /* Above filled in */
143 static struct hfs_type hfs_types[] = {
144 	{TYPE_NONE, INSERT, "", "", get_none_info, get_none_dir, "None"},
145 	{TYPE_CAP, INSERT, ".finderinfo/", ".resource/",
146 				get_cap_info, get_cap_dir, "CAP"},
147 	{TYPE_NETA, INSERT, ".AppleDouble/", ".AppleDouble/",
148 				get_dbl_info, get_dbl_dir, "Netatalk"},
149 	{TYPE_DBL, INSERT, "%", "%", get_dbl_info, get_dbl_dir, "AppleDouble"},
150 	{TYPE_ESH, INSERT, ".rsrc/", ".rsrc/",
151 				get_es_info, get_es_dir, "EtherShare/UShare"},
152 	{TYPE_FEU, NOPEND, "FINDER.DAT", "RESOURCE.FRK/",
153 				get_fe_info, get_fe_dir, "Exchange"},
154 	{TYPE_FEL, NOPEND, "finder.dat", "resource.frk/",
155 				get_fe_info, get_fe_dir, "Exchange"},
156 	{TYPE_SGI, NOPEND, ".HSancillary", ".HSResource/",
157 				get_sgi_info, get_sgi_dir, "XINET/SGI"},
158 	{TYPE_MBIN, PROBE, "", "", get_mb_info, get_none_dir, "MacBinary"},
159 	{TYPE_SGL, PROBE, "", "", get_sgl_info, get_none_dir, "AppleSingle"},
160 	{TYPE_DAVE, INSERT, "resource.frk/", "resource.frk/",
161 				get_dbl_info, get_dbl_dir, "DAVE"},
162 	{TYPE_SFM, APPEND | NORSRC, ":Afp_AfpInfo", ":Afp_Resource",
163 				get_sfm_info, get_none_dir, "SFM"},
164 	{TYPE_XDBL, INSERT, "._", "._", get_dbl_info, get_dbl_dir,
165 				"MacOS X AppleDouble"},
166 	{TYPE_XHFS, APPEND | NOINFO, "/rsrc", "/rsrc", get_xhfs_info, get_xhfs_dir,
167 				"MacOS X HFS"}
168 };
169 
170 /* used by get_magic_match() return */
171 static char	tmp_type[CT_SIZE + 1],
172 		tmp_creator[CT_SIZE + 1];
173 
174 #ifdef	__used__
175 /*
176  *	An array useful for CRC calculations that use 0x1021 as the "seed"
177  *	taken from mcvert.c modified by Jim Van Verth.
178  */
179 
180 static unsigned short mb_magic[] = {
181 	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
182 	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
183 	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
184 	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
185 	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
186 	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
187 	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
188 	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
189 	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
190 	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
191 	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
192 	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
193 	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
194 	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
195 	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
196 	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
197 	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
198 	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
199 	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
200 	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
201 	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
202 	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
203 	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
204 	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
205 	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
206 	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
207 	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
208 	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
209 	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
210 	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
211 	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
212 	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
213 };
214 
215 #endif	/* __used__ */
216 
217 #ifndef	HAVE_STRCASECMP
218 static int
219 strcasecmp(const char *s1, const char *s2)
220 {
221 	while (tolower(*s1) == tolower(*s2)) {
222 		if (*s1 == 0)
223 			return (0);
224 		s1++;
225 		s2++;
226 	}
227 	return (tolower(*s1) - tolower(*s2));
228 }
229 #endif
230 
231 /*
232  *	set_ct: set CREATOR and TYPE in hfs_ent
233  *
234  *	CREATOR and TYPE are padded with spaces if not CT_SIZE long
235  */
236 
237 static void
238 set_ct(hfsdirent *hfs_ent, char *c, char *t)
239 {
240 	memset(hfs_ent->u.file.type, ' ', CT_SIZE);
241 	memset(hfs_ent->u.file.creator, ' ', CT_SIZE);
242 
243 	strncpy(hfs_ent->u.file.type, t, MIN(CT_SIZE, strlen(t)));
244 	strncpy(hfs_ent->u.file.creator, c, MIN(CT_SIZE, strlen(c)));
245 
246 	hfs_ent->u.file.type[CT_SIZE] = '\0';
247 	hfs_ent->u.file.creator[CT_SIZE] = '\0';
248 }
249 
250 /*
251  *	cstrncopy: Cap Unix name to HFS name
252  *
253  *	':' is replaced by '%' and string is terminated with '\0'
254  */
255 static void
256 cstrncpy(char *t, char *f, int c)
257 {
258 	while (c-- && *f) {
259 		switch (*f) {
260 		case ':':
261 			*t = '%';
262 			break;
263 		default:
264 			*t = *f;
265 			break;
266 		}
267 		t++;
268 		f++;
269 	}
270 
271 	*t = '\0';
272 }
273 
274 /*
275  * dehex()
276  *
277  * Given a hexadecimal digit in ASCII, return the integer representation.
278  *
279  *	Taken from linux/fs/hfs/trans.c by Paul H. Hargrove
280  */
281 static unsigned char
282 dehex(char c)
283 {
284 	if ((c >= '0') && (c <= '9')) {
285 		return (c - '0');
286 	}
287 	if ((c >= 'a') && (c <= 'f')) {
288 		return (c - 'a' + 10);
289 	}
290 	if ((c >= 'A') && (c <= 'F')) {
291 		return (c - 'A' + 10);
292 	}
293 /*	return (0xff); */
294 	return (0);
295 }
296 
297 static unsigned char
298 hex2char(char *s)
299 {
300 	unsigned char	i1;
301 	unsigned char	i2;
302 	unsigned char	o;
303 
304 	if (strlen(++s) < 2)
305 		return (0);
306 
307 	i1 = (unsigned char) s[0];
308 	i2 = (unsigned char) s[1];
309 
310 	if (!isxdigit(i1) || !isxdigit(i2))
311 		return (0);
312 
313 	o = (dehex(i1) << 4) & 0xf0;
314 	o |= (dehex(i2) & 0xf);
315 
316 	return (o);
317 }
318 
319 
320 /*
321  *	hstrncpy: Unix name to HFS name with special character
322  *	translation.
323  *
324  *	"%xx" or ":xx" is assumed to be a "special" character and
325  *	replaced by character code given by the hex characters "xx"
326  *
327  *	if "xx" is not a hex number, then it is left alone - except
328  *	that ":" is replaced by "%"
329  *
330  */
331 static void
332 hstrncpy(unsigned char *t, char *f, int c)
333 {
334 	unsigned char	o;
335 
336 	while (c-- && *f) {
337 		switch (*f) {
338 		case ':':
339 		case '%':
340 			if ((o = hex2char(f)) == 0) {
341 				*t = conv_charset('%', in_nls, hfs_onls);
342 			} else {
343 				*t = o;
344 				f += 2;
345 			}
346 			break;
347 		default:
348 			*t = conv_charset(*f, in_nls, hfs_onls);
349 			break;
350 		}
351 		t++;
352 		f++;
353 	}
354 
355 	*t = '\0';
356 }
357 
358 /*
359  *	basename: find just the filename with any directory component
360  */
361 /*
362 	not used at the moment ...
363 static char
364 basename(a)
365 	char	*a;
366 {
367 	char	*b;
368 
369 	if ((b = strchr(a, '/')))
370 		return (++b);
371 	else
372 		return (a);
373 }
374 */
375 
376 /*
377  *	set_Dinfo: set directory info
378  */
379 static void
380 set_Dinfo(byte *ptr, hfsdirent *ent)
381 {
382 	Dinfo	*dinfo = (Dinfo *)ptr;
383 
384 	/* finder flags */
385 	ent->fdflags = d_getw((unsigned char *) dinfo->frFlags);
386 
387 	if (icon_pos) {
388 		ent->u.dir.rect.top =
389 		d_getw((unsigned char *) dinfo->frRect[0]);
390 		ent->u.dir.rect.left =
391 		d_getw((unsigned char *) dinfo->frRect[1]);
392 		ent->u.dir.rect.bottom =
393 		d_getw((unsigned char *) dinfo->frRect[2]);
394 		ent->u.dir.rect.right =
395 		d_getw((unsigned char *) dinfo->frRect[3]);
396 
397 		ent->fdlocation.v =
398 		d_getw((unsigned char *) dinfo->frLocation[0]);
399 		ent->fdlocation.h =
400 		d_getw((unsigned char *) dinfo->frLocation[1]);
401 
402 		ent->u.dir.view =
403 		d_getw((unsigned char *) dinfo->frView);
404 
405 		ent->u.dir.frscroll.v =
406 		d_getw((unsigned char *) dinfo->frScroll[0]);
407 		ent->u.dir.frscroll.h =
408 		d_getw((unsigned char *) dinfo->frScroll[1]);
409 
410 	} else {
411 		/*
412 		 * clear HFS_FNDR_HASBEENINITED to have tidy desktop ??
413 		 */
414 		ent->fdflags &= 0xfeff;
415 	}
416 }
417 
418 /*
419  *	set_Finfo: set file info
420  */
421 static void
422 set_Finfo(byte *ptr, hfsdirent *ent)
423 {
424 	Finfo	*finfo = (Finfo *)ptr;
425 
426 	/* type and creator from finder info */
427 	set_ct(ent, finfo->fdCreator, finfo->fdType);
428 
429 	/* finder flags */
430 	ent->fdflags = d_getw((unsigned char *) finfo->fdFlags);
431 
432 	if (icon_pos) {
433 		ent->fdlocation.v =
434 		d_getw((unsigned char *) finfo->fdLocation[0]);
435 		ent->fdlocation.h =
436 		d_getw((unsigned char *) finfo->fdLocation[1]);
437 	} else {
438 		/*
439 		 * clear HFS_FNDR_HASBEENINITED to have tidy desktop ??
440 		 */
441 		ent->fdflags &= 0xfeff;
442 	}
443 }
444 
445 /*
446  *	get_none_dir: ordinary Unix directory
447  */
448 static int
449 get_none_dir(char *hname, char *dname, dir_ent *s_entry, int ret)
450 {
451 	/* just copy the given name */
452 	hstrncpy((unsigned char *) (s_entry->hfs_ent->name),
453 							dname, HFS_MAX_FLEN);
454 
455 	return (ret);
456 }
457 
458 /*
459  *	get_none_info: ordinary Unix file - try to map extension
460  */
461 static int
462 get_none_info(char *hname, char *dname, dir_ent *s_entry, int ret)
463 {
464 	char		*t,
465 			*c;
466 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
467 
468 	map_ext(dname, &t, &c, &s_entry->hfs_ent->fdflags, s_entry->whole_name);
469 
470 	/* just copy the given name */
471 	hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN);
472 
473 	set_ct(hfs_ent, c, t);
474 
475 	return (ret);
476 }
477 
478 /*
479  *	read_info_file:	open and read a finderinfo file for an HFS file
480  *			or directory
481  */
482 static int
483 read_info_file(char *name, /* finderinfo filename */
484 					void *info, /* info buffer */
485 					int len		/* length of above */)
486 {
487 	FILE		*fp;
488 	int		num;
489 
490 	/* clear out any old finderinfo stuf */
491 	memset(info, 0, len);
492 
493 	if ((fp = fopen(name, "rb")) == NULL)
494 		return (-1);
495 
496 	/* read and ignore if the file is short - checked later */
497 	num = fread(info, 1, len, fp);
498 
499 	fclose(fp);
500 
501 	return (num);
502 }
503 
504 /*
505  *	get_cap_dir: get the CAP name for a directory
506  */
507 static int
508 get_cap_dir(char *hname, /* whole path */
509 				char *dname, /* this dir name */
510 				dir_ent *s_entry, /* directory entry */
511 				int ret)
512 {
513 	FileInfo	info;		/* finderinfo struct */
514 	int		num = -1;	/* bytes read */
515 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
516 
517 	num = read_info_file(hname, &info, sizeof (FileInfo));
518 
519 	/* check finder info is OK */
520 	if (num > 0 &&
521 		info.fi_magic1 == FI_MAGIC1 &&
522 		info.fi_magic == FI_MAGIC &&
523 		info.fi_bitmap & FI_BM_MACINTOSHFILENAME) {
524 		/* use the finderinfo name if it exists */
525 		cstrncpy((char *) (hfs_ent->name),
526 				(char *) (info.fi_macfilename), HFS_MAX_FLEN);
527 
528 		set_Dinfo(info.finderinfo, hfs_ent);
529 
530 		return (ret);
531 	} else {
532 		/* otherwise give it it's Unix name */
533 		hstrncpy((unsigned char *) (s_entry->hfs_ent->name),
534 							dname, HFS_MAX_FLEN);
535 		return (TYPE_NONE);
536 	}
537 }
538 
539 /*
540 **	get_cap_info:	get CAP finderinfo for a file
541 */
542 static int
543 get_cap_info(char *hname, /* whole path */
544 				 char *dname, /* this dir name */
545 				 dir_ent *s_entry, /* directory entry */
546 				 int ret)
547 {
548 	FileInfo	info;		/* finderinfo struct */
549 	int		num = -1;	/* bytes read */
550 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
551 
552 	num = read_info_file(hname, &info, sizeof (info));
553 
554 	/* check finder info is OK */
555 	if (num > 0 &&
556 		info.fi_magic1 == FI_MAGIC1 &&
557 		info.fi_magic == FI_MAGIC) {
558 
559 		if (info.fi_bitmap & FI_BM_MACINTOSHFILENAME) {
560 			/* use the finderinfo name if it exists */
561 			cstrncpy((char *) (hfs_ent->name),
562 				(char *) (info.fi_macfilename), HFS_MAX_FLEN);
563 		} else {
564 			/* use Unix name */
565 			hstrncpy((unsigned char *) (hfs_ent->name), dname,
566 								HFS_MAX_FLEN);
567 		}
568 
569 		set_Finfo(info.finderinfo, hfs_ent);
570 #ifdef USE_MAC_DATES
571 		/*
572 		 * set created/modified dates - these date should have already
573 		 * been set from the Unix data fork dates. The finderinfo dates
574 		 * are in Mac format - but we have to convert them back to Unix
575 		 * for the time being
576 		 */
577 		if ((info.fi_datemagic & FI_CDATE)) {
578 			/* use libhfs routines to get correct byte order */
579 			hfs_ent->crdate = d_toutime(d_getl(info.fi_ctime));
580 		}
581 		if (info.fi_datemagic & FI_MDATE) {
582 			hfs_ent->mddate = d_toutime(d_getl(info.fi_mtime));
583 		}
584 #endif	/* USE_MAC_DATES */
585 	} else {
586 		/* failed to open/read finderinfo - so try afpfile mapping */
587 		if (verbose > 2) {
588 			fprintf(stderr,
589 				"warning: %s doesn't appear to be a %s file\n",
590 				s_entry->whole_name, hfs_types[ret].desc);
591 		}
592 		ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
593 	}
594 
595 	return (ret);
596 }
597 
598 /*
599  *	get_es_dir:	get EtherShare/UShare finderinfo for a directory
600  *
601  *	based on code from Jens-Uwe Mager (jum@helios.de) and Phil Sylvester
602  *	<psylvstr@interaccess.com>
603  */
604 static int
605 get_es_dir(char *hname, /* whole path */
606 			  char *dname, /* this dir name */
607 			  dir_ent *s_entry, /* directory entry */
608 			  int ret)
609 {
610 	es_FileInfo	*einfo;		/* EtherShare info struct */
611 	us_FileInfo	*uinfo;		/* UShare info struct */
612 	char		info[ES_INFO_SIZE];	/* finderinfo buffer */
613 	int		num = -1;	/* bytes read */
614 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
615 
616 	/*
617 	 * the EtherShare and UShare file layout is the same, but they store
618 	 * finderinfo differently
619 	 */
620 	einfo = (es_FileInfo *) info;
621 	uinfo = (us_FileInfo *) info;
622 
623 	num = read_info_file(hname, info, sizeof (info));
624 
625 	/* check finder info for EtherShare finderinfo */
626 	if (num >= (int)sizeof (es_FileInfo) &&
627 		d_getl(einfo->magic) == ES_MAGIC &&
628 		d_getw(einfo->version) == ES_VERSION) {
629 
630 		set_Dinfo(einfo->finderinfo, hfs_ent);
631 
632 	} else if (num >= (int)sizeof (us_FileInfo)) {
633 		/*
634 		 * UShare has no magic number, so we assume that this is a valid
635 		 * info/resource file ...
636 		 */
637 
638 		set_Dinfo(uinfo->finderinfo, hfs_ent);
639 
640 	} else {
641 		/* failed to open/read finderinfo - so try afpfile mapping */
642 		if (verbose > 2) {
643 			fprintf(stderr,
644 				"warning: %s doesn't appear to be a %s file\n",
645 				s_entry->whole_name, hfs_types[ret].desc);
646 		}
647 		ret = get_none_dir(hname, dname, s_entry, TYPE_NONE);
648 		return (ret);
649 	}
650 
651 	/* set name */
652 	hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN);
653 
654 	return (ret);
655 }
656 
657 /*
658  *	get_es_info:	get EtherShare/UShare finderinfo for a file
659  *
660  *	based on code from Jens-Uwe Mager (jum@helios.de) and Phil Sylvester
661  *	<psylvstr@interaccess.com>
662  */
663 static int
664 get_es_info(char *hname, /* whole path */
665 				char *dname, /* this dir name */
666 				dir_ent *s_entry, /* directory entry */
667 				int ret)
668 {
669 	es_FileInfo	*einfo;		/* EtherShare info struct */
670 	us_FileInfo	*uinfo;		/* UShare info struct */
671 	char		info[ES_INFO_SIZE];	/* finderinfo buffer */
672 	int		num = -1;	/* bytes read */
673 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
674 	dir_ent		*s_entry1;
675 
676 	/*
677 	 * the EtherShare and UShare file layout is the same, but they store
678 	 * finderinfo differently
679 	 */
680 	einfo = (es_FileInfo *) info;
681 	uinfo = (us_FileInfo *) info;
682 
683 	num = read_info_file(hname, info, sizeof (info));
684 
685 	/* check finder info for EtherShare finderinfo */
686 	if (num >= (int)sizeof (es_FileInfo) &&
687 		d_getl(einfo->magic) == ES_MAGIC &&
688 		d_getw(einfo->version) == ES_VERSION) {
689 
690 		set_Finfo(einfo->finderinfo, hfs_ent);
691 
692 		/*
693 		 * set create date - modified date set from the Unix
694 		 * data fork date
695 		 */
696 
697 		hfs_ent->crdate = d_getl(einfo->createTime);
698 
699 	} else if (num >= (int)sizeof (us_FileInfo)) {
700 		/*
701 		 * UShare has no magic number, so we assume that this is a valid
702 		 * info/resource file ...
703 		 */
704 
705 		set_Finfo(uinfo->finderinfo, hfs_ent);
706 
707 		/* set create and modified date - if they exist */
708 		if (uinfo->ctime)
709 			hfs_ent->crdate =
710 				d_getl(uinfo->ctime);
711 
712 		if (uinfo->mtime)
713 			hfs_ent->mddate =
714 				d_getl(uinfo->mtime);
715 	} else {
716 		/* failed to open/read finderinfo - so try afpfile mapping */
717 		if (verbose > 2) {
718 			fprintf(stderr,
719 				"warning: %s doesn't appear to be a %s file\n",
720 				s_entry->whole_name, hfs_types[ret].desc);
721 		}
722 		ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
723 		return (ret);
724 	}
725 
726 	/* this should exist ... */
727 	if ((s_entry1 = s_entry->assoc) == NULL)
728 		perr("TYPE_ESH error - shouldn't happen!");
729 
730 	/* set name */
731 	hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN);
732 
733 	/* real rsrc file starts ES_INFO_SIZE bytes into the file */
734 	if (s_entry1->size <= ES_INFO_SIZE) {
735 		s_entry1->size = 0;
736 		hfs_ent->u.file.rsize = 0;
737 	} else {
738 		s_entry1->size -= ES_INFO_SIZE;
739 		hfs_ent->u.file.rsize = s_entry1->size;
740 		s_entry1->hfs_off = ES_INFO_SIZE;
741 	}
742 
743 	set_733((char *) s_entry1->isorec.size, s_entry1->size);
744 
745 	return (ret);
746 }
747 
748 /*
749  * calc_crc() --
750  *   Compute the MacBinary II-style CRC for the data pointed to by p, with the
751  *   crc seeded to seed.
752  *
753  *   Modified by Jim Van Verth to use the magic array for efficiency.
754  */
755 #ifdef	__used__
756 static unsigned short
757 calc_mb_crc(unsigned char *p, long len, unsigned short seed)
758 {
759 	unsigned short	hold;	/* crc computed so far */
760 	long		i;	/* index into data */
761 
762 	hold = seed;	/* start with seed */
763 	for (i = 0; i < len; i++, p++) {
764 		hold ^= (*p << 8);
765 		hold = (hold << 8) ^ mb_magic[(unsigned char) (hold >> 8)];
766 	}
767 
768 	return (hold);
769 }/* calc_mb_crc() */
770 
771 #endif	/* __used__ */
772 
773 static int
774 get_mb_info(char *hname, /* whole path */
775 				char *dname, /* this dir name */
776 				dir_ent *s_entry, /* directory entry */
777 				int ret)
778 {
779 	mb_info		*info;		/* finderinfo struct */
780 	char		*c;
781 	char		*t;
782 	hfsdirent	*hfs_ent;
783 	dir_ent		*s_entry1;
784 	int		i;
785 
786 #ifdef TEST_CODE
787 	unsigned short	crc_file,
788 			crc_calc;
789 
790 #endif
791 
792 	info = (mb_info *) p_buf;
793 
794 	/*
795 	 * routine called twice for each file - first to check that it is a
796 	 * valid MacBinary file, second to fill in the HFS info. p_buf holds
797 	 * the required raw data and it *should* remain the same between the
798 	 * two calls
799 	 */
800 	if (s_entry == 0) {
801 		/*
802 		 * test that the CRC is OK - not set for MacBinary I files (and
803 		 * incorrect in some MacBinary II files!). If this fails, then
804 		 * perform some other checks
805 		 */
806 
807 #ifdef TEST_CODE
808 		/* leave this out for the time being ... */
809 		if (p_num >= MB_SIZE && info->version == 0 && info->zero1 == 0) {
810 			crc_calc = calc_mb_crc((unsigned char *) info, 124, 0);
811 			crc_file = d_getw(info->crc);
812 #ifdef DEBUG
813 			fprintf(stderr, "%s: file %d, calc %d\n", hname,
814 							crc_file, crc_calc);
815 #endif	/* DEBUG */
816 			if (crc_file == crc_calc)
817 				return (ret);
818 		}
819 #endif	/* TEST_CODE */
820 
821 		/*
822 		 * check some of the fields for a valid MacBinary file not
823 		 * zero1 and zero2 SHOULD be zero - but some files incorrect
824 		 */
825 
826 /*	    if (p_num < MB_SIZE || info->nlen > 63 || info->zero2 || */
827 		if (p_num < MB_SIZE || info->zero1 ||
828 			info->zero2 || info->nlen > 63 ||
829 			info->version || info->nlen == 0 || *info->name == 0)
830 			return (TYPE_NONE);
831 
832 		/* check that the filename is OKish */
833 		for (i = 0; i < (int)info->nlen; i++)
834 			if (info->name[i] == 0)
835 				return (TYPE_NONE);
836 
837 		/* check CREATOR and TYPE are valid */
838 		for (i = 0; i < 4; i++)
839 			if (info->type[i] == 0 || info->auth[i] == 0)
840 				return (TYPE_NONE);
841 	} else {
842 		/* we have a vaild MacBinary file, so fill in the bits */
843 
844 		/* this should exist ... */
845 		if ((s_entry1 = s_entry->assoc) == NULL)
846 			perr("TYPE_MBIN error - shouldn't happen!");
847 
848 		hfs_ent = s_entry->hfs_ent;
849 
850 		/* type and creator from finder info */
851 		t = (char *) (info->type);
852 		c = (char *) (info->auth);
853 
854 		set_ct(hfs_ent, c, t);
855 
856 		/* finder flags */
857 		hfs_ent->fdflags = ((info->flags << 8) & 0xff00) | info->flags2;
858 
859 		if (icon_pos) {
860 			hfs_ent->fdlocation.v =
861 				d_getw((unsigned char *) info->icon_vert);
862 			hfs_ent->fdlocation.h =
863 				d_getw((unsigned char *) info->icon_horiz);
864 		} else {
865 			/*
866 			 * clear HFS_FNDR_HASBEENINITED to have tidy desktop ??
867 			 */
868 			hfs_ent->fdflags &= 0xfeff;
869 		}
870 
871 		/*
872 		 * set created/modified dates - these date should have already
873 		 * been set from the Unix data fork dates. The finderinfo dates
874 		 * are in Mac format - but we have to convert them back to Unix
875 		 * for the time being
876 		 */
877 		hfs_ent->crdate = d_toutime(d_getl(info->cdate));
878 		hfs_ent->mddate = d_toutime(d_getl(info->mdate));
879 
880 		/* set name */
881 		hstrncpy((unsigned char *) (hfs_ent->name),
882 			(char *) (info->name), MIN(HFS_MAX_FLEN, info->nlen));
883 
884 		/* set correct fork sizes */
885 		hfs_ent->u.file.dsize = d_getl(info->dflen);
886 		hfs_ent->u.file.rsize = d_getl(info->rflen);
887 
888 		/* update directory entries for data fork */
889 		s_entry->size = hfs_ent->u.file.dsize;
890 		s_entry->hfs_off = MB_SIZE;
891 		set_733((char *) s_entry->isorec.size, s_entry->size);
892 
893 		/*
894 		 * real rsrc file starts after data fork (must be a multiple of
895 		 * MB_SIZE)
896 		 */
897 		s_entry1->size = hfs_ent->u.file.rsize;
898 		s_entry1->hfs_off = MB_SIZE + ROUND_UP(hfs_ent->u.file.dsize, MB_SIZE);
899 		set_733((char *) s_entry1->isorec.size, s_entry1->size);
900 	}
901 
902 	return (ret);
903 }
904 
905 /*
906  *	get_dbl_dir:	get Apple double finderinfo for a directory
907  *
908  *	Based on code from cvt2cap.c (c) May 1988, Paul Campbell
909  */
910 static int
911 get_dbl_dir(char *hname, /* whole path */
912 				char *dname, /* this dir name */
913 				dir_ent *s_entry, /* directory entry */
914 				int ret)
915 {
916 	FileInfo	info;		/* finderinfo struct */
917 	a_hdr		*hp;
918 	a_entry		*ep;
919 	int		num = -1;	/* bytes read */
920 	int		nentries;
921 	FILE		*fp;
922 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
923 	char		name[64];
924 	int		i;
925 	int		fail = 0;
926 	int		len = 0;
927 
928 	hp = (a_hdr *) p_buf;
929 	memset(hp, 0, A_HDR_SIZE);
930 
931 	memset(name, 0, sizeof (name));
932 
933 	/* open and read the info/rsrc file (it's the same file) */
934 	if ((fp = fopen(hname, "rb")) != NULL)
935 		num = fread(hp, 1, A_HDR_SIZE, fp);
936 
937 	/*
938 	 * check finder info is OK - some Netatalk files don't have magic
939 	 * or version set - ignore if it's a netatalk file
940 	 */
941 	if (num == A_HDR_SIZE && ((ret == TYPE_NETA) ||
942 			(d_getl(hp->magic) == APPLE_DOUBLE &&
943 				(d_getl(hp->version) == A_VERSION1 ||
944 					d_getl(hp->version) == A_VERSION2)))) {
945 
946 		/* read TOC of the AppleDouble file */
947 		nentries = (int) d_getw(hp->nentries);
948 		if (fread(hp->entries, A_ENTRY_SIZE, nentries, fp) < 1) {
949 			fail = 1;
950 			nentries = 0;
951 		}
952 		/* extract what is needed */
953 		for (i = 0, ep = hp->entries; i < nentries; i++, ep++) {
954 			switch ((int)d_getl(ep->id)) {
955 			case ID_FINDER:
956 				/* get the finder info */
957 				fseek(fp, (off_t)d_getl(ep->offset), SEEK_SET);
958 				if (fread(&info, d_getl(ep->length), 1, fp) < 1) {
959 					fail = 1;
960 				}
961 				break;
962 			case ID_NAME:
963 				/* get Mac file name */
964 				fseek(fp, (off_t)d_getl(ep->offset), SEEK_SET);
965 				if (fread(name, d_getl(ep->length), 1, fp) < 1)
966 					*name = '\0';
967 				len = d_getl(ep->length);
968 				break;
969 			default:
970 				break;
971 			}
972 		}
973 
974 		fclose(fp);
975 
976 		/* skip this if we had a problem */
977 		if (!fail) {
978 
979 			set_Dinfo(info.finderinfo, hfs_ent);
980 
981 			/* use stored name if it exists */
982 			if (*name) {
983 				/*
984 				 * In some cases the name is stored in the
985 				 * Pascal string format - first char is the
986 				 * length, the rest is the actual string.
987 				 * The following *should* be OK
988 				 */
989 				if (len == 32 && (int) name[0] < 32) {
990 					cstrncpy(hfs_ent->name, &name[1],
991 						MIN(name[0], HFS_MAX_FLEN));
992 				} else {
993 					cstrncpy(hfs_ent->name, name,
994 							HFS_MAX_FLEN);
995 				}
996 			} else {
997 				hstrncpy((unsigned char *) (hfs_ent->name),
998 							dname, HFS_MAX_FLEN);
999 			}
1000 		}
1001 	} else {
1002 		/* failed to open/read finderinfo */
1003 		fail = 1;
1004 		if (fp)
1005 			fclose(fp);
1006 	}
1007 
1008 	if (fail) {
1009 		/* problem with the file - try mapping/magic */
1010 		if (verbose > 2) {
1011 			fprintf(stderr,
1012 				"warning: %s doesn't appear to be a %s file\n",
1013 				s_entry->whole_name, hfs_types[ret].desc);
1014 		}
1015 		ret = get_none_dir(hname, dname, s_entry, TYPE_NONE);
1016 	}
1017 	return (ret);
1018 }
1019 
1020 /*
1021  *	Depending on the version, AppleDouble/Single stores dates
1022  *	relative to 1st Jan 1904 (v1) or 1st Jan 2000 (v2)
1023  *
1024  *	The d_toutime() function uses 1st Jan 1904 to convert to
1025  *	Unix time (1st Jan 1970).
1026  *
1027  *	The d_dtoutime() function uses 1st Jan 2000 to convert to
1028  *	Unix time (1st Jan 1970).
1029  *
1030  *	However, NetaTalk files seem to do their own thing - older
1031  *	Netatalk files don't have a magic number of version and
1032  *	store dates in ID=7 (don't know how). Newer Netatalk files
1033  *	claim to be version 1, but store dates in ID=7 as if they
1034  *	were version 2 files.
1035  */
1036 
1037 /*
1038  *	get_dbl_info:	get Apple double finderinfo for a file
1039  *
1040  *	Based on code from cvt2cap.c (c) May 1988, Paul Campbell
1041  */
1042 static int
1043 get_dbl_info(char *hname, /* whole path */
1044 				 char *dname, /* this dir name */
1045 				 dir_ent *s_entry, /* directory entry */
1046 				 int ret)
1047 {
1048 	FileInfo	info;		/* finderinfo struct */
1049 	a_hdr		*hp;
1050 	a_entry		*ep;
1051 	int		num = -1;	/* bytes read */
1052 	int		nentries;
1053 	FILE		*fp;
1054 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
1055 	dir_ent		*s_entry1;
1056 	char		name[64];
1057 	int		i;
1058 	int		fail = 0;
1059 	int		len = 0;
1060 	unsigned char	dates[A_DATE];
1061 	int		ver = 0, dlen;
1062 
1063 	hp = (a_hdr *) p_buf;
1064 	memset(hp, 0, A_HDR_SIZE);
1065 
1066 	memset(name, 0, sizeof (name));
1067 	memset(dates, 0, sizeof (dates));
1068 
1069 	/* get the rsrc file info - should exist ... */
1070 	if ((s_entry1 = s_entry->assoc) == NULL)
1071 		perr("TYPE_DBL error - shouldn't happen!");
1072 
1073 	/* open and read the info/rsrc file (it's the same file) */
1074 	if ((fp = fopen(hname, "rb")) != NULL)
1075 		num = fread(hp, 1, A_HDR_SIZE, fp);
1076 
1077 	/*
1078 	 * check finder info is OK - some Netatalk files don't have magic
1079 	 * or version set - ignore if it's a netatalk file
1080 	 */
1081 
1082 	ver = d_getl(hp->version);
1083 	if (num == A_HDR_SIZE && ((ret == TYPE_NETA) ||
1084 			(d_getl(hp->magic) == APPLE_DOUBLE &&
1085 				(ver == A_VERSION1 || ver == A_VERSION2)))) {
1086 
1087 		/* read TOC of the AppleDouble file */
1088 		nentries = (int) d_getw(hp->nentries);
1089 		if (fread(hp->entries, A_ENTRY_SIZE, nentries, fp) < 1) {
1090 			fail = 1;
1091 			nentries = 0;
1092 		}
1093 		/* extract what is needed */
1094 		for (i = 0, ep = hp->entries; i < nentries; i++, ep++) {
1095 			switch ((int)d_getl(ep->id)) {
1096 			case ID_FINDER:
1097 				/* get the finder info */
1098 				fseek(fp, (off_t)d_getl(ep->offset), SEEK_SET);
1099 				if (fread(&info, d_getl(ep->length), 1, fp) < 1) {
1100 					fail = 1;
1101 				}
1102 				break;
1103 			case ID_RESOURCE:
1104 				/* set the offset and correct rsrc fork size */
1105 				s_entry1->size = d_getl(ep->length);
1106 				hfs_ent->u.file.rsize = s_entry1->size;
1107 				/* offset to start of real rsrc fork */
1108 				s_entry1->hfs_off = d_getl(ep->offset);
1109 				set_733((char *) s_entry1->isorec.size,
1110 								s_entry1->size);
1111 				break;
1112 			case ID_NAME:
1113 				/* get Mac file name */
1114 				fseek(fp, (off_t)d_getl(ep->offset), SEEK_SET);
1115 				if (fread(name, d_getl(ep->length), 1, fp) < 1)
1116 					*name = '\0';
1117 				len = d_getl(ep->length);
1118 				break;
1119 			case ID_FILEI:
1120 				/* Workround for NetaTalk files ... */
1121 				if (ret == TYPE_NETA && ver == A_VERSION1)
1122 					ver = A_VERSION2;
1123 				/* fall through */
1124 			case ID_FILEDATESI:
1125 				/* get file info */
1126 				fseek(fp, d_getl(ep->offset), 0);
1127 				dlen = MIN(d_getl(ep->length), A_DATE);
1128 				if (fread(dates, dlen, 1, fp) < 1) {
1129 					fail = 1;
1130 				} else {
1131 					/* get the correct Unix time */
1132 					switch (ver) {
1133 
1134 					case (A_VERSION1):
1135 						hfs_ent->crdate =
1136 						d_toutime(d_getl(dates));
1137 						hfs_ent->mddate =
1138 						d_toutime(d_getl(dates+4));
1139 						break;
1140 					case (A_VERSION2):
1141 						hfs_ent->crdate =
1142 						d_dtoutime(d_getl(dates));
1143 						hfs_ent->mddate =
1144 						d_dtoutime(d_getl(dates+4));
1145 						break;
1146 					default:
1147 						/* Use Unix dates */
1148 						break;
1149 					}
1150 				}
1151 				break;
1152 			default:
1153 				break;
1154 			}
1155 		}
1156 
1157 		fclose(fp);
1158 
1159 		/* skip this if we had a problem */
1160 		if (!fail) {
1161 			set_Finfo(info.finderinfo, hfs_ent);
1162 
1163 			/* use stored name if it exists */
1164 			if (*name) {
1165 				/*
1166 				 * In some cases the name is stored in the
1167 				 * Pascal string format - first char is the
1168 				 * length, the rest is the actual string.
1169 				 * The following *should* be OK
1170 				 */
1171 				if (len == 32 && (int) name[0] < 32) {
1172 					cstrncpy(hfs_ent->name, &name[1],
1173 						MIN(name[0], HFS_MAX_FLEN));
1174 				} else {
1175 					cstrncpy(hfs_ent->name, name,
1176 							HFS_MAX_FLEN);
1177 				}
1178 			} else {
1179 				hstrncpy((unsigned char *) (hfs_ent->name),
1180 							dname, HFS_MAX_FLEN);
1181 			}
1182 		}
1183 	} else {
1184 		/* failed to open/read finderinfo */
1185 		fail = 1;
1186 		if (fp)
1187 			fclose(fp);
1188 	}
1189 
1190 	if (fail) {
1191 		/* problem with the file - try mapping/magic */
1192 		if (verbose > 2) {
1193 			fprintf(stderr,
1194 				"warning: %s doesn't appear to be a %s file\n",
1195 				s_entry->whole_name, hfs_types[ret].desc);
1196 		}
1197 		ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1198 	}
1199 	return (ret);
1200 }
1201 
1202 /*
1203  *	get_sgl_info:	get Apple single finderinfo for a file
1204  *
1205  *	Based on code from cvt2cap.c (c) May 1988, Paul Campbell
1206  */
1207 static int
1208 get_sgl_info(char *hname, /* whole path */
1209 				 char *dname, /* this dir name */
1210 				 dir_ent *s_entry, /* directory entry */
1211 				 int ret)
1212 {
1213 	FileInfo	*info = 0;	/* finderinfo struct */
1214 	a_hdr		*hp;
1215 	static a_entry	*entries;
1216 	a_entry		*ep;
1217 	int		nentries;
1218 	hfsdirent	*hfs_ent;
1219 	dir_ent		*s_entry1;
1220 	char		name[64];
1221 	int		i;
1222 	int		len = 0;
1223 	unsigned char	*dates;
1224 	int		ver = 0;
1225 
1226 	/*
1227 	 * routine called twice for each file
1228 	 * - first to check that it is a valid
1229 	 * AppleSingle file, second to fill in the HFS info.
1230 	 * p_buf holds the required
1231 	 * raw data and it *should* remain the same between the two calls
1232 	 */
1233 	hp = (a_hdr *) p_buf;
1234 
1235 	if (s_entry == 0) {
1236 		if (p_num < A_HDR_SIZE ||
1237 			d_getl(hp->magic) != APPLE_SINGLE ||
1238 			(d_getl(hp->version) != A_VERSION1 &&
1239 				d_getl(hp->version) != A_VERSION2))
1240 			return (TYPE_NONE);
1241 
1242 		/* check we have TOC for the AppleSingle file */
1243 		nentries = (int) d_getw(hp->nentries);
1244 		if (p_num < (int)(A_HDR_SIZE + nentries * A_ENTRY_SIZE))
1245 			return (TYPE_NONE);
1246 
1247 		/* save the TOC */
1248 		entries = (a_entry *) e_malloc(nentries * A_ENTRY_SIZE);
1249 
1250 		memcpy(entries, (p_buf + A_HDR_SIZE), nentries * A_ENTRY_SIZE);
1251 	} else {
1252 		/* have a vaild AppleSingle File */
1253 		memset(name, 0, sizeof (name));
1254 
1255 		/* get the rsrc file info - should exist ... */
1256 		if ((s_entry1 = s_entry->assoc) == NULL)
1257 			perr("TYPE_SGL error - shouldn't happen!");
1258 
1259 		hfs_ent = s_entry->hfs_ent;
1260 
1261 		nentries = (int) d_getw(hp->nentries);
1262 		ver = d_getl(hp->version);
1263 
1264 		/* extract what is needed */
1265 		for (i = 0, ep = entries; i < nentries; i++, ep++) {
1266 			switch ((int)d_getl(ep->id)) {
1267 			case ID_FINDER:
1268 				/* get the finder info */
1269 				info = (FileInfo *) (p_buf + d_getl(ep->offset));
1270 				break;
1271 			case ID_DATA:
1272 				/* set the offset and correct data fork size */
1273 				hfs_ent->u.file.dsize = s_entry->size =
1274 							d_getl(ep->length);
1275 				/* offset to start of real data fork */
1276 				s_entry->hfs_off = d_getl(ep->offset);
1277 				set_733((char *) s_entry->isorec.size,
1278 								s_entry->size);
1279 				break;
1280 			case ID_RESOURCE:
1281 				/* set the offset and correct rsrc fork size */
1282 				hfs_ent->u.file.rsize = s_entry1->size =
1283 							d_getl(ep->length);
1284 				/* offset to start of real rsrc fork */
1285 				s_entry1->hfs_off = d_getl(ep->offset);
1286 				set_733((char *) s_entry1->isorec.size,
1287 								s_entry1->size);
1288 				break;
1289 			case ID_NAME:
1290 				/* get Mac file name */
1291 				strncpy(name, (p_buf + d_getl(ep->offset)),
1292 					d_getl(ep->length));
1293 				len = d_getl(ep->length);
1294 				break;
1295 			case ID_FILEI:
1296 				/* get file info - ignore at the moment*/
1297 				break;
1298 			case ID_FILEDATESI:
1299 				/* get file info */
1300 				dates = (unsigned char *)p_buf + d_getl(ep->offset);
1301 				/* get the correct Unix time */
1302 				if (ver == A_VERSION1) {
1303 					hfs_ent->crdate =
1304 						d_toutime(d_getl(dates));
1305 					hfs_ent->mddate =
1306 						d_toutime(d_getl(dates+4));
1307 				} else {
1308 					hfs_ent->crdate =
1309 						d_dtoutime(d_getl(dates));
1310 					hfs_ent->mddate =
1311 						d_dtoutime(d_getl(dates+4));
1312 				}
1313 				break;
1314 			default:
1315 				break;
1316 			}
1317 		}
1318 
1319 		free(entries);
1320 
1321 		if (info == NULL) {
1322 			/*
1323 			 * failed to open/read finderinfo
1324 			 * - so try afpfile mapping
1325 			 */
1326 			if (verbose > 2) {
1327 				fprintf(stderr,
1328 				"warning: %s doesn't appear to be a %s file\n",
1329 					s_entry->whole_name,
1330 					hfs_types[ret].desc);
1331 			}
1332 			ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1333 			return (ret);
1334 		}
1335 
1336 		set_Finfo(info->finderinfo, hfs_ent);
1337 
1338 		/* use stored name if it exists */
1339 		if (*name) {
1340 			/*
1341 			 * In some cases the name is stored in the Pascal string
1342 			 * format - first char is the length, the rest is the
1343 			 * actual string. The following *should* be OK
1344 			 */
1345 			if (len == 32 && (int) name[0] < 32) {
1346 				cstrncpy(hfs_ent->name, &name[1], MIN(name[0],
1347 								HFS_MAX_FLEN));
1348 			} else {
1349 				cstrncpy(hfs_ent->name, name, HFS_MAX_FLEN);
1350 			}
1351 		} else {
1352 			hstrncpy((unsigned char *) (hfs_ent->name), dname,
1353 								HFS_MAX_FLEN);
1354 		}
1355 	}
1356 
1357 	return (ret);
1358 }
1359 
1360 /*
1361  *	get_hfs_fe_info: read in the whole finderinfo for a PC Exchange
1362  *		directory - saves on reading this many times for each file.
1363  *
1364  *	Based of information provided by Mark Weinstein <mrwesq@earthlink.net>
1365  *
1366  *	Note: the FINDER.DAT file layout depends on the FAT cluster size
1367  *	therefore, files should only be read directly from the FAT media
1368  *
1369  *	Only tested with PC Exchange v2.1 - don't know if it will work
1370  *	with v2.2 and above.
1371  */
1372 static struct hfs_info *
1373 get_hfs_fe_info(struct hfs_info *hfs_info, char *name)
1374 {
1375 	FILE		*fp;
1376 	int		fe_num,
1377 			fe_pad;
1378 	fe_info		info;
1379 	int		c = 0;
1380 	struct hfs_info	*hfs_info1 = NULL;
1381 	char		keyname[12];
1382 	char		*s,
1383 			*e,
1384 			*k;
1385 	int		i;
1386 
1387 	if ((fp = fopen(name, "rb")) == NULL)
1388 		return (NULL);
1389 
1390 	/*
1391 	 * no longer attempt to find out FAT cluster
1392 	 * - rely on command line parameter
1393 	 */
1394 	if (afe_size <= 0)
1395 		return (NULL);
1396 
1397 	fe_num = afe_size / FE_SIZE;
1398 	fe_pad = afe_size % FE_SIZE;
1399 
1400 	while (fread(&info, 1, FE_SIZE, fp) != 0) {
1401 
1402 		/* the Mac name may be NULL - so ignore this entry */
1403 		if (info.nlen != 0) {
1404 
1405 			hfs_info1 =
1406 			(struct hfs_info *)e_malloc(sizeof (struct hfs_info));
1407 			/* add this entry to the list */
1408 			hfs_info1->next = hfs_info;
1409 			hfs_info = hfs_info1;
1410 
1411 			/*
1412 			 * get the bits we need
1413 			 * - ignore [cm]time for the moment
1414 			 */
1415 			cstrncpy(hfs_info->name, (char *) (info.name),
1416 					info.nlen);
1417 
1418 			memcpy(hfs_info->finderinfo, info.finderinfo, INFOLEN);
1419 
1420 			s = (char *) (info.sname);
1421 			e = (char *) (info.ext);
1422 			k = keyname;
1423 
1424 			/*
1425 			 * short (Unix) name is stored in PC format,
1426 			 * so needs to be mangled a bit
1427 			 */
1428 
1429 			/* name part */
1430 			for (i = 0; i < 8; i++, s++, k++) {
1431 				if (*s == ' ')
1432 					break;
1433 				else
1434 					*k = *s;
1435 			}
1436 
1437 			/* extension - if it exists */
1438 			if (strncmp((const char *) (info.ext), "   ", 3)) {
1439 				*k = '.';
1440 				k++;
1441 				for (i = 0; i < 3; i++, e++, k++) {
1442 					if (*e == ' ')
1443 						break;
1444 					else
1445 						*k = *e;
1446 				}
1447 			}
1448 			*k = '\0';
1449 
1450 			hfs_info1->keyname = strdup(keyname);
1451 		}
1452 		/*
1453 		 * each record is FE_SIZE long, and there are FE_NUM
1454 		 * per each "cluster size", so we may need to skip the padding
1455 		 */
1456 		if (++c == fe_num) {
1457 			c = 0;
1458 			fseek(fp, (off_t)fe_pad, SEEK_CUR);
1459 		}
1460 	}
1461 	fclose(fp);
1462 
1463 	return (hfs_info);
1464 }
1465 
1466 /*
1467  *	get_hfs_sgi_info: read in the whole finderinfo for a SGI (XINET)
1468  *		directory - saves on reading this many times for each
1469  *		file.
1470  */
1471 static struct hfs_info *
1472 get_hfs_sgi_info(struct hfs_info *hfs_info, char *name)
1473 {
1474 	FILE		*fp;
1475 	sgi_info	info;
1476 	struct hfs_info	*hfs_info1 = NULL;
1477 
1478 	if ((fp = fopen(name, "rb")) == NULL)
1479 		return (NULL);
1480 
1481 	while (fread(&info, 1, SGI_SIZE, fp) != 0) {
1482 
1483 		hfs_info1 = (struct hfs_info *)e_malloc(sizeof (struct hfs_info));
1484 		/* add this entry to the list */
1485 		hfs_info1->next = hfs_info;
1486 		hfs_info = hfs_info1;
1487 
1488 		/* get the bits we need - ignore [cm]time for the moment */
1489 		cstrncpy(hfs_info->name, (char *)info.name, HFS_MAX_FLEN);
1490 
1491 		memcpy(hfs_info->finderinfo, info.finderinfo, INFOLEN);
1492 
1493 		/* use the HFS name as the key */
1494 		hfs_info1->keyname = hfs_info->name;
1495 
1496 	}
1497 	fclose(fp);
1498 
1499 	return (hfs_info);
1500 }
1501 
1502 /*
1503  *	del_hfs_info: delete the info list and recover memory
1504  */
1505 void
1506 del_hfs_info(struct hfs_info *hfs_info)
1507 {
1508 	struct hfs_info	*hfs_info1;
1509 
1510 	while (hfs_info) {
1511 		hfs_info1 = hfs_info;
1512 		hfs_info = hfs_info->next;
1513 
1514 		/* key may be the same as the HFS name - so don't free it */
1515 		*hfs_info1->name = '\0';
1516 		if (*hfs_info1->keyname)
1517 			free(hfs_info1->keyname);
1518 		free(hfs_info1);
1519 	}
1520 }
1521 
1522 /*
1523  *	match_key: find the correct hfs_ent using the Unix filename
1524  *		as the key
1525  */
1526 static struct hfs_info *
1527 match_key(struct hfs_info *hfs_info, char *key)
1528 {
1529 	while (hfs_info) {
1530 		if (strcasecmp(key, hfs_info->keyname) == 0)
1531 			return (hfs_info);
1532 		hfs_info = hfs_info->next;
1533 	}
1534 
1535 	return (NULL);
1536 }
1537 
1538 /*
1539  *	get_fe_dir: get PC Exchange directory name
1540  *
1541  *	base on probing with od ...
1542  */
1543 static int
1544 get_fe_dir(char *hname, /* whole path */
1545 			  char *dname, /* this dir name */
1546 			  dir_ent *s_entry, /* directory entry */
1547 			  int ret)
1548 {
1549 	struct hfs_info	*hfs_info;
1550 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
1551 
1552 	/* cached finderinfo stored with parent directory */
1553 	hfs_info = s_entry->filedir->hfs_info;
1554 
1555 	/* if we have no cache, then make one and store it */
1556 	if (hfs_info == NULL) {
1557 		if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL)
1558 			ret = TYPE_NONE;
1559 		else
1560 			s_entry->filedir->hfs_info = hfs_info;
1561 	}
1562 	if (ret != TYPE_NONE) {
1563 		/* see if we can find the details of this file */
1564 		if ((hfs_info = match_key(hfs_info, dname)) != NULL) {
1565 			strcpy(hfs_ent->name, hfs_info->name);
1566 
1567 			set_Dinfo(hfs_info->finderinfo, hfs_ent);
1568 
1569 			return (ret);
1570 		}
1571 	}
1572 	/* can't find the entry, so use the Unix name */
1573 	hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN);
1574 
1575 	return (TYPE_NONE);
1576 }
1577 
1578 /*
1579  *	get_fe_info: get PC Exchange file details.
1580  *
1581  *	base on probing with od and details from Mark Weinstein
1582  *	<mrwesq@earthlink.net>
1583  */
1584 static int
1585 get_fe_info(char *hname, /* whole path */
1586 			   char *dname, /* this dir name */
1587 			   dir_ent *s_entry, /* directory entry */
1588 			   int ret)
1589 {
1590 	struct hfs_info	*hfs_info;
1591 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
1592 
1593 	/* cached finderinfo stored with parent directory */
1594 	hfs_info = s_entry->filedir->hfs_info;
1595 
1596 	/* if we have no cache, then make one and store it */
1597 	if (hfs_info == NULL) {
1598 		if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL)
1599 			ret = TYPE_NONE;
1600 		else
1601 			s_entry->filedir->hfs_info = hfs_info;
1602 	}
1603 	if (ret != TYPE_NONE) {
1604 		char	*dn = dname;
1605 
1606 #ifdef _WIN32_TEST
1607 		/*
1608 		 * may have a problem here - v2.2 has long filenames,
1609 		 * but we need to key on the short filename,
1610 		 * so we need do go a bit of win32 stuff
1611 		 * ...
1612 		 */
1613 		char	sname[1024];
1614 		char	lname[1024];
1615 
1616 		cygwin32_conv_to_full_win32_path(s_entry->whole_name, lname);
1617 
1618 		if (GetShortPathName(lname, sname, sizeof (sname))) {
1619 			if (dn = strrchr(sname, '\\'))
1620 				dn++;
1621 			else
1622 				dn = sname;
1623 		}
1624 #endif	/* _WIN32 */
1625 
1626 		/* see if we can find the details of this file */
1627 		if ((hfs_info = match_key(hfs_info, dn)) != NULL) {
1628 
1629 			strcpy(hfs_ent->name, hfs_info->name);
1630 
1631 			set_Finfo(hfs_info->finderinfo, hfs_ent);
1632 
1633 			return (ret);
1634 		}
1635 	}
1636 	/* no entry found - use extension mapping */
1637 	if (verbose > 2) {
1638 		fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
1639 			s_entry->whole_name, hfs_types[ret].desc);
1640 	}
1641 	ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1642 
1643 	return (TYPE_NONE);
1644 }
1645 
1646 /*
1647  *	get_sgi_dir: get SGI (XINET) HFS directory name
1648  *
1649  *	base on probing with od ...
1650  */
1651 static int
1652 get_sgi_dir(char *hname, /* whole path */
1653 			   char *dname, /* this dir name */
1654 			   dir_ent *s_entry, /* directory entry */
1655 			   int ret)
1656 {
1657 	struct hfs_info	*hfs_info;
1658 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
1659 
1660 	/* cached finderinfo stored with parent directory */
1661 	hfs_info = s_entry->filedir->hfs_info;
1662 
1663 	/* if we haven't got a cache, then make one */
1664 	if (hfs_info == NULL) {
1665 		if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL)
1666 			ret = TYPE_NONE;
1667 		else
1668 			s_entry->filedir->hfs_info = hfs_info;
1669 	}
1670 	/* find the matching entry in the cache */
1671 	if (ret != TYPE_NONE) {
1672 		/* key is (hopefully) the real Mac name */
1673 		cstrncpy(tmp, dname, strlen(dname));
1674 		if ((hfs_info = match_key(hfs_info, tmp)) != NULL) {
1675 			strcpy(hfs_ent->name, hfs_info->name);
1676 
1677 			set_Dinfo(hfs_info->finderinfo, hfs_ent);
1678 
1679 			return (ret);
1680 		}
1681 	}
1682 	/* no entry found - use Unix name */
1683 	hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN);
1684 
1685 	return (TYPE_NONE);
1686 }
1687 
1688 /*
1689  *	get_sgi_info: get SGI (XINET) HFS finder info
1690  *
1691  *	base on probing with od ...
1692  */
1693 static int
1694 get_sgi_info(char *hname, /* whole path */
1695 			    char *dname, /* this dir name */
1696 			    dir_ent *s_entry, /* directory entry */
1697 			    int ret)
1698 {
1699 	struct hfs_info	*hfs_info;
1700 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
1701 
1702 	/* cached finderinfo stored with parent directory */
1703 	hfs_info = s_entry->filedir->hfs_info;
1704 
1705 	/* if we haven't got a cache, then make one */
1706 	if (hfs_info == NULL) {
1707 		if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL)
1708 			ret = TYPE_NONE;
1709 		else
1710 			s_entry->filedir->hfs_info = hfs_info;
1711 	}
1712 	if (ret != TYPE_NONE) {
1713 		/*
1714 		 * tmp is the same as hname here, but we don't need hname
1715 		 * anymore in this function  ...  see if we can find the
1716 		 * details of this file using the Unix name as the key
1717 		 */
1718 		cstrncpy(tmp, dname, strlen(dname));
1719 		if ((hfs_info = match_key(hfs_info, tmp)) != NULL) {
1720 
1721 			strcpy(hfs_ent->name, hfs_info->name);
1722 
1723 			set_Finfo(hfs_info->finderinfo, hfs_ent);
1724 
1725 			return (ret);
1726 		}
1727 	}
1728 	/* no entry found, so try file extension */
1729 	if (verbose > 2) {
1730 		fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
1731 			s_entry->whole_name, hfs_types[ret].desc);
1732 	}
1733 	ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1734 
1735 	return (TYPE_NONE);
1736 }
1737 
1738 /*
1739  *	get_sfm_info:	get SFM finderinfo for a file
1740  */
1741 
1742 static byte	sfm_magic[4] = {0x41, 0x46, 0x50, 0x00};
1743 static byte	sfm_version[4] = {0x00, 0x00, 0x01, 0x00};
1744 
1745 static int
1746 get_sfm_info(char *hname, /* whole path */
1747 			    char *dname, /* this dir name */
1748 			    dir_ent *s_entry, /* directory entry */
1749 			    int ret)
1750 {
1751 	sfm_info	info;	/* finderinfo struct */
1752 	int		num = -1; /* bytes read */
1753 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
1754 
1755 	num = read_info_file(hname, &info, sizeof (info));
1756 
1757 	/* check finder info is OK */
1758 	if (num == sizeof (info) &&
1759 		!memcmp((char *)info.afpi_Signature, (char *)sfm_magic, 4) &&
1760 		!memcmp((char *)info.afpi_Version, (char *)sfm_version, 4)) {
1761 		/* use Unix name */
1762 		hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN);
1763 
1764 		set_Finfo(info.finderinfo, hfs_ent);
1765 
1766 	} else {
1767 		/* failed to open/read finderinfo - so try afpfile mapping */
1768 		if (verbose > 2) {
1769 			fprintf(stderr,
1770 				"warning: %s doesn't appear to be a %s file\n",
1771 				s_entry->whole_name, hfs_types[ret].desc);
1772 		}
1773 		ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1774 	}
1775 
1776 	return (ret);
1777 }
1778 
1779 #ifdef IS_MACOS_X
1780 /*
1781  *	get_xhfs_dir:	get MacOS X HFS finderinfo for a directory
1782  *
1783  *	Code ideas from 'hfstar' by Marcel Weiher marcel@metaobject.com
1784  *	and another GNU hfstar by Torres Vedras paulotex@yahoo.com
1785  *
1786  *	Here we are dealing with actual HFS files - not some encoding
1787  *	we have to use a system call to get the finderinfo
1788  *
1789  *	The file name here is the pseudo name for the resource fork
1790  */
1791 static int
1792 get_xhfs_dir(char *hname, /* whole path */
1793 			    char *dname, /* this dir name */
1794 			    dir_ent *s_entry, /* directory entry */
1795 			    int ret)
1796 {
1797 	int		err;
1798 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
1799 	attrinfo	ainfo;
1800 	struct attrlist attrs;
1801 	int		i;
1802 
1803 	memset(&attrs, 0, sizeof (attrs));
1804 
1805 	/* set flags we need to get info from getattrlist() */
1806 	attrs.bitmapcount = ATTR_BIT_MAP_COUNT;
1807 	attrs.commonattr  = ATTR_CMN_CRTIME | ATTR_CMN_MODTIME |
1808 				ATTR_CMN_FNDRINFO;
1809 
1810 	/* get the info */
1811 	err = getattrlist(hname, &attrs, &ainfo, sizeof (ainfo), 0);
1812 
1813 	if (err == 0) {
1814 		/*
1815 		 * If the Finfo is blank then we assume it's not a
1816 		 * 'true' HFS directory ...
1817 		 */
1818 		err = 1;
1819 		for (i = 0; i < sizeof (ainfo.info); i++) {
1820 			if (ainfo.info[i] != 0) {
1821 				err = 0;
1822 				break;
1823 			}
1824 		}
1825 	}
1826 
1827 	/* check finder info is OK */
1828 	if (err == 0) {
1829 
1830 		hstrncpy((unsigned char *) (s_entry->hfs_ent->name),
1831 							dname, HFS_MAX_FLEN);
1832 
1833 		set_Dinfo(ainfo.info, hfs_ent);
1834 
1835 		return (ret);
1836 	} else {
1837 		/* otherwise give it it's Unix name */
1838 		hstrncpy((unsigned char *) (s_entry->hfs_ent->name),
1839 							dname, HFS_MAX_FLEN);
1840 		return (TYPE_NONE);
1841 	}
1842 }
1843 
1844 /*
1845  *	get_xhfs_info:	get MacOS X HFS finderinfo for a file
1846  *
1847  *	Code ideas from 'hfstar' by Marcel Weiher marcel@metaobject.com,
1848  *	another GNU hfstar by Torres Vedras paulotex@yahoo.com and
1849  *	hfspax by Howard Oakley howard@quercus.demon.co.uk
1850  *
1851  *	Here we are dealing with actual HFS files - not some encoding
1852  *	we have to use a system call to get the finderinfo
1853  *
1854  *	The file name here is the pseudo name for the resource fork
1855  */
1856 static int
1857 get_xhfs_info(char *hname, /* whole path */
1858 			     char *dname, /* this dir name */
1859 			     dir_ent *s_entry, /* directory entry */
1860 			     int ret)
1861 {
1862 	int		err;
1863 	hfsdirent	*hfs_ent = s_entry->hfs_ent;
1864 	attrinfo	ainfo;
1865 	struct attrlist attrs;
1866 	int		i;
1867 	int		size;
1868 
1869 	memset(&attrs, 0, sizeof (attrs));
1870 
1871 	/* set flags we need to get info from getattrlist() */
1872 	attrs.bitmapcount = ATTR_BIT_MAP_COUNT;
1873 	attrs.commonattr  = ATTR_CMN_CRTIME | ATTR_CMN_MODTIME |
1874 				ATTR_CMN_FNDRINFO;
1875 
1876 	/* get the info */
1877 	err = getattrlist(hname, &attrs, &ainfo, sizeof (ainfo), 0);
1878 
1879 	/* check finder info is OK */
1880 	if (err == 0) {
1881 
1882 		/*
1883 		 * If the Finfo is blank and the resource file is empty,
1884 		 * then we assume it's not a 'true' HFS file ...
1885 		 * There will be not associated file if the resource fork
1886 		 * is empty
1887 		 */
1888 
1889 		if (s_entry->assoc == NULL) {
1890 			err = 1;
1891 			for (i = 0; i < sizeof (ainfo.info); i++) {
1892 				if (ainfo.info[i] != 0) {
1893 					err = 0;
1894 					break;
1895 				}
1896 			}
1897 		}
1898 
1899 		if (err == 0) {
1900 
1901 			/* use Unix name */
1902 			hstrncpy((unsigned char *) (hfs_ent->name), dname,
1903 						HFS_MAX_FLEN);
1904 
1905 			set_Finfo(ainfo.info, hfs_ent);
1906 
1907 			/*
1908 			 * dates have already been set - but we will
1909 			 * set them here as well from the HFS info
1910 			 * shouldn't need to check for byte order, as
1911 			 * the source is HFS ... but we will just in case
1912 			 */
1913 			hfs_ent->crdate = d_getl((byte *)&ainfo.ctime.tv_sec);
1914 
1915 			hfs_ent->mddate = d_getl((byte *)&ainfo.mtime.tv_sec);
1916 		}
1917 
1918 	}
1919 
1920 	if (err) {
1921 		/* not a 'true' HFS file - so try afpfile mapping */
1922 #if 0
1923 		/*
1924 		 * don't print a warning as we will get lots on HFS
1925 		 * file systems ...
1926 		 */
1927 		if (verbose > 2) {
1928 			fprintf(stderr,
1929 				"warning: %s doesn't appear to be a %s file\n",
1930 				s_entry->whole_name, hfs_types[ret].desc);
1931 		}
1932 #endif
1933 		ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1934 	}
1935 
1936 	return (ret);
1937 }
1938 #endif /* IS_MACOS_X */
1939 
1940 /*
1941  *	get_hfs_itype: get the type of HFS info for a file
1942  */
1943 static int
1944 get_hfs_itype(char *wname, char *dname, char *htmp)
1945 {
1946 	int	wlen,
1947 		i;
1948 	int	no_type = TYPE_NONE;
1949 
1950 	wlen = strlen(wname) - strlen(dname);
1951 
1952 	/* search through the known types looking for matches */
1953 	for (i = 1; i < hfs_num; i++) {
1954 		/* skip the ones that we don't care about */
1955 		if ((hfs_types[i].flags & PROBE) ||
1956 				*(hfs_types[i].info) == TYPE_NONE) {
1957 			continue;
1958 		}
1959 
1960 		strcpy(htmp, wname);
1961 
1962 		/*
1963 		 * special case - if the info file doesn't exist
1964 		 * for a requested type, then remember the type -
1965 		 * we don't return here, as we _may_ find another type
1966 		 * so we save the type here in case - we will have
1967 		 * problems if more than one of this type ever exists ...
1968 		 */
1969 		if (hfs_types[i].flags & NOINFO) {
1970 			no_type = i;
1971 		} else {
1972 
1973 			/* append or insert finderinfo filename part */
1974 			if (hfs_types[i].flags & APPEND)
1975 				strcat(htmp, hfs_types[i].info);
1976 			else
1977 				sprintf(htmp + wlen, "%s%s", hfs_types[i].info,
1978 					(hfs_types[i].flags & NOPEND) ? "" : dname);
1979 
1980 			/* hack time ... Netatalk is a special case ... */
1981 			if (i == TYPE_NETA) {
1982 				strcpy(htmp, wname);
1983 				strcat(htmp, "/.AppleDouble/.Parent");
1984 			}
1985 
1986 			if (!access(htmp, R_OK))
1987 				return (hfs_types[i].type);
1988 		}
1989 	}
1990 
1991 	return (no_type);
1992 }
1993 
1994 /*
1995  *	set_root_info: set the root folder hfs_ent from given file
1996  */
1997 void
1998 set_root_info(char *name)
1999 {
2000 	dir_ent		*s_entry;
2001 	hfsdirent	*hfs_ent;
2002 	int		i;
2003 
2004 	s_entry = root->self;
2005 
2006 	hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
2007 	memset(hfs_ent, 0, sizeof (hfsdirent));
2008 
2009 	/* make sure root has a valid hfs_ent */
2010 	s_entry->hfs_ent = root->hfs_ent = hfs_ent;
2011 
2012 	/* search for correct type of root info data */
2013 	for (i = 1; i < hfs_num; i++) {
2014 		if ((hfs_types[i].flags & PROBE) ||
2015 				(hfs_types[i].get_info == get_none_info))
2016 			continue;
2017 
2018 		if ((*(hfs_types[i].get_dir))(name, "", s_entry, i) == i)
2019 			return;
2020 	}
2021 }
2022 
2023 
2024 /*
2025  *	get_hfs_dir: set the HFS directory name
2026  */
2027 int
2028 get_hfs_dir(char *wname, char *dname, dir_ent *s_entry)
2029 {
2030 	int	type;
2031 
2032 	/* get the HFS file type from the info file (if it exists) */
2033 	type = get_hfs_itype(wname, dname, tmp);
2034 
2035 	/* try to get the required info */
2036 	type = (*(hfs_types[type].get_dir)) (tmp, dname, s_entry, type);
2037 
2038 	return (type);
2039 }
2040 
2041 /*
2042  *	get_hfs_info: set the HFS info for a file
2043  */
2044 int
2045 get_hfs_info(char *wname, char *dname, dir_ent *s_entry)
2046 {
2047 	int	type,
2048 		wlen,
2049 		i;
2050 
2051 	wlen = strlen(wname) - strlen(dname);
2052 
2053 	/* we may already know the type of Unix/HFS file - so process */
2054 	if (s_entry->hfs_type != TYPE_NONE) {
2055 
2056 		type = s_entry->hfs_type;
2057 
2058 		strcpy(tmp, wname);
2059 
2060 		/* append or insert finderinfo filename part */
2061 		if (hfs_types[type].flags & APPEND)
2062 			strcat(tmp, hfs_types[type].info);
2063 		else
2064 			sprintf(tmp + wlen, "%s%s", hfs_types[type].info,
2065 				(hfs_types[type].flags & NOPEND) ? "" : dname);
2066 
2067 		type = (*(hfs_types[type].get_info))(tmp, dname, s_entry, type);
2068 
2069 		/* if everything is as expected, then return */
2070 		if (s_entry->hfs_type == type)
2071 			return (type);
2072 	}
2073 	/* we don't know what type we have so, find out */
2074 	for (i = 1; i < hfs_num; i++) {
2075 		if ((hfs_types[i].flags & PROBE) ||
2076 				*(hfs_types[i].info) == TYPE_NONE) {
2077 			continue;
2078 		}
2079 
2080 		strcpy(tmp, wname);
2081 
2082 		/* append or insert finderinfo filename part */
2083 		if (hfs_types[i].flags & APPEND) {
2084 			strcat(tmp, hfs_types[i].info);
2085 		} else {
2086 			sprintf(tmp + wlen, "%s%s", hfs_types[i].info,
2087 				(hfs_types[i].flags & NOPEND) ? "" : dname);
2088 		}
2089 
2090 		/* if the file exists - and not a type we've already tried */
2091 		if (!access(tmp, R_OK) && i != s_entry->hfs_type) {
2092 			type = (*(hfs_types[i].get_info))(tmp, dname,
2093 							s_entry, i);
2094 			s_entry->hfs_type = type;
2095 			return (type);
2096 		}
2097 	}
2098 
2099 	/* nothing found, so just a Unix file */
2100 	type = (*(hfs_types[TYPE_NONE].get_info))(wname, dname,
2101 							s_entry, TYPE_NONE);
2102 
2103 	return (type);
2104 }
2105 
2106 /*
2107  *	get_hfs_rname: set the name of the Unix rsrc file for a file
2108  *
2109  *	For the time being we ignore the 'NOINFO' flag - the only case
2110  *	at the moment is for MacOS X HFS files - for files the resource
2111  *	fork exists - so testing the "filename/rsrc" pseudo file as
2112  *	the 'info' filename is OK ...
2113  */
2114 int
2115 get_hfs_rname(char *wname, char *dname, char *rname)
2116 {
2117 	int	wlen,
2118 		type,
2119 		i;
2120 	int	p_fd = -1;
2121 
2122 	wlen = strlen(wname) - strlen(dname);
2123 
2124 	/* try to find what sort of Unix HFS file type we have */
2125 	for (i = 1; i < hfs_num; i++) {
2126 		/* skip if don't want to probe the files - (default) */
2127 		if (hfs_types[i].flags & PROBE)
2128 			continue;
2129 
2130 		strcpy(rname, wname);
2131 
2132 		/* if we have a different info file, the find out it's type */
2133 		if (*(hfs_types[i].rsrc) && *(hfs_types[i].info)) {
2134 			/* first test the Info file */
2135 
2136 			/* append or insert finderinfo filename part */
2137 			if (hfs_types[i].flags & APPEND) {
2138 				strcat(rname, hfs_types[i].info);
2139 			} else {
2140 				sprintf(rname + wlen, "%s%s", hfs_types[i].info,
2141 					(hfs_types[i].flags & NOPEND) ?
2142 								"" : dname);
2143 			}
2144 
2145 			/* if it exists, then check the Rsrc file */
2146 			if (!access(rname, R_OK)) {
2147 				if (hfs_types[i].flags & APPEND) {
2148 					sprintf(rname + wlen, "%s%s", dname,
2149 						hfs_types[i].rsrc);
2150 				} else {
2151 					sprintf(rname + wlen, "%s%s",
2152 						hfs_types[i].rsrc, dname);
2153 				}
2154 
2155 				/*
2156 				 * for some types, a rsrc fork may not exist,
2157 				 * so just return the current type
2158 				 * in these cases
2159 				 */
2160 				if (hfs_types[i].flags & NORSRC ||
2161 							!access(rname, R_OK))
2162 					return (hfs_types[i].type);
2163 			}
2164 		} else {
2165 			/*
2166 			 * if we are probing,
2167 			 * then have a look at the contents to find type
2168 			 */
2169 			if (p_fd < 0) {
2170 				/* open file, if not already open */
2171 				if ((p_fd = open(wname,
2172 						O_RDONLY | O_BINARY)) < 0) {
2173 					/* can't open it, then give up */
2174 					return (TYPE_NONE);
2175 				} else {
2176 					if ((p_num = read(p_fd, p_buf,
2177 							sizeof (p_buf))) <= 0) {
2178 						/*
2179 						 * can't read, or zero length
2180 						 * - give up
2181 						 */
2182 						close(p_fd);
2183 						return (TYPE_NONE);
2184 					}
2185 					/* get file pointer and close file */
2186 					p_fp = fdopen(p_fd, "rb");
2187 					close(p_fd);
2188 					if (p_fp == NULL)
2189 						return (TYPE_NONE);
2190 				}
2191 			}
2192 			/*
2193 			 * call routine to do the work
2194 			 * - use the given dname as this
2195 			 * is the name we may use on the CD
2196 			 */
2197 			type = (*(hfs_types[i].get_info)) (rname, dname, 0, i);
2198 			if (type != 0) {
2199 				fclose(p_fp);
2200 				return (type);
2201 			}
2202 			if (p_fp) {
2203 				/*
2204 				 * close file
2205 				 * - just use contents of buffer next time
2206 				 */
2207 				fclose(p_fp);
2208 				p_fp = NULL;
2209 			}
2210 		}
2211 	}
2212 
2213 	return (0);
2214 }
2215 
2216 /*
2217  *	hfs_exclude: file/directory names that hold finder/resource
2218  *		     information that we want to exclude from the tree.
2219  *		     These files/directories are processed later ...
2220  */
2221 int
2222 hfs_exclude(char *d_name)
2223 {
2224 	/* we don't exclude "." and ".." */
2225 	if (strcmp(d_name, ".") == 0)
2226 		return (0);
2227 	if (strcmp(d_name, "..") == 0)
2228 		return (0);
2229 
2230 	/* do not add the following to our list of dir entries */
2231 	if (DO_CAP & hselect) {
2232 		/* CAP */
2233 		if (strcmp(d_name, ".finderinfo") == 0)
2234 			return (1);
2235 		if (strcmp(d_name, ".resource") == 0)
2236 			return (1);
2237 		if (strcmp(d_name, ".ADeskTop") == 0)
2238 			return (1);
2239 		if (strcmp(d_name, ".IDeskTop") == 0)
2240 			return (1);
2241 		if (strcmp(d_name, "Network Trash Folder") == 0)
2242 			return (1);
2243 		/*
2244 		 * special case when HFS volume is mounted using Linux's hfs_fs
2245 		 * Brad Midgley <brad@pht.com>
2246 		 */
2247 		if (strcmp(d_name, ".rootinfo") == 0)
2248 			return (1);
2249 	}
2250 	if (DO_ESH & hselect) {
2251 		/* Helios EtherShare files */
2252 		if (strcmp(d_name, ".rsrc") == 0)
2253 			return (1);
2254 		if (strcmp(d_name, ".Desktop") == 0)
2255 			return (1);
2256 		if (strcmp(d_name, ".DeskServer") == 0)
2257 			return (1);
2258 		if (strcmp(d_name, ".Label") == 0)
2259 			return (1);
2260 	}
2261 	if (DO_DBL & hselect) {
2262 	/* Apple Double */
2263 		/*
2264 		 * special case when HFS volume is mounted using Linux's hfs_fs
2265 		 */
2266 		if (strcmp(d_name, "%RootInfo") == 0)
2267 			return (1);
2268 		/*
2269 		 * have to be careful here - a filename starting with '%'
2270 		 * may be vaild if the next two letters are a hex character -
2271 		 * unfortunately '%' 'digit' 'digit' may be a valid resource
2272 		 * file name ...
2273 		 */
2274 		if (*d_name == '%')
2275 			if (hex2char(d_name) == 0)
2276 				return (1);
2277 	}
2278 	if (DO_NETA & hselect) {
2279 		if (strcmp(d_name, ".AppleDouble") == 0)
2280 			return (1);
2281 		if (strcmp(d_name, ".AppleDesktop") == 0)
2282 			return (1);
2283 	}
2284 	if ((DO_FEU & hselect) || (DO_FEL & hselect)) {
2285 		/* PC Exchange */
2286 		if (strcmp(d_name, "RESOURCE.FRK") == 0)
2287 			return (1);
2288 		if (strcmp(d_name, "FINDER.DAT") == 0)
2289 			return (1);
2290 		if (strcmp(d_name, "DESKTOP") == 0)
2291 			return (1);
2292 		if (strcmp(d_name, "FILEID.DAT") == 0)
2293 			return (1);
2294 		if (strcmp(d_name, "resource.frk") == 0)
2295 			return (1);
2296 		if (strcmp(d_name, "finder.dat") == 0)
2297 			return (1);
2298 		if (strcmp(d_name, "desktop") == 0)
2299 			return (1);
2300 		if (strcmp(d_name, "fileid.dat") == 0)
2301 			return (1);
2302 	}
2303 	if (DO_SGI & hselect) {
2304 		/* SGI */
2305 		if (strcmp(d_name, ".HSResource") == 0)
2306 			return (1);
2307 		if (strcmp(d_name, ".HSancillary") == 0)
2308 			return (1);
2309 	}
2310 	if (DO_DAVE & hselect) {
2311 		/* DAVE */
2312 		if (strcmp(d_name, "resource.frk") == 0)
2313 			return (1);
2314 		if (strcmp(d_name, "DesktopFolderDB") == 0)
2315 			return (1);
2316 	}
2317 #ifndef _WIN32
2318 	/*
2319 	 * NTFS streams are not "seen" as files,
2320 	 * so WinNT will not see these files -
2321 	 * so ignore - used for testing under Unix
2322 	 */
2323 	if (DO_SFM & hselect) {
2324 		/* SFM */
2325 		char	*dn = strrchr(d_name, ':');
2326 
2327 		if (dn) {
2328 			if (strcmp(dn, ":Afp_Resource") == 0)
2329 				return (1);
2330 			if (strcmp(dn, ":Comments") == 0)
2331 				return (1);
2332 			if (strcmp(dn, ":Afp_AfpInfo") == 0)
2333 				return (1);
2334 		}
2335 	}
2336 #endif	/* _WIN32 */
2337 
2338 	if (DO_XDBL & hselect) {
2339 		/* XDB */
2340 		if (strncmp(d_name, "._", 2) == 0)
2341 			return (1);
2342 	}
2343 
2344 	return (0);
2345 }
2346 
2347 /*
2348  *	print_hfs_info: print info about the HFS files.
2349  *
2350  */
2351 void
2352 print_hfs_info(dir_ent *s_entry)
2353 {
2354 	fprintf(stderr, "Name: %s\n", s_entry->whole_name);
2355 	fprintf(stderr, "\tFile type: %s\n", hfs_types[s_entry->hfs_type].desc);
2356 	fprintf(stderr, "\tHFS Name: %s\n", s_entry->hfs_ent->name);
2357 	fprintf(stderr, "\tISO Name: %s\n", s_entry->isorec.name);
2358 	fprintf(stderr, "\tCREATOR: %s\n", s_entry->hfs_ent->u.file.creator);
2359 	fprintf(stderr, "\tTYPE:	%s\n", s_entry->hfs_ent->u.file.type);
2360 }
2361 
2362 
2363 /*
2364  *	hfs_init: sets up the mapping list from the afpfile as well
2365  *		 the default mapping (with or without) an afpfile
2366  */
2367 void
2368 hfs_init(char *name, Ushort fdflags, Uint hfs_select)
2369 {
2370 	FILE	*fp;		/* File pointer */
2371 	int	count = NUMMAP;	/* max number of entries */
2372 	char	buf[PATH_MAX];	/* working buffer */
2373 	afpmap	*amap;		/* mapping entry */
2374 	char	*c,
2375 		*t,
2376 		*e;
2377 	int	i;
2378 
2379 	/* setup number of Unix/HFS filetype - we may wish to not bother */
2380 	if (hfs_select) {
2381 		hfs_num = sizeof (hfs_types) / sizeof (struct hfs_type);
2382 
2383 		/*
2384 		 * code below needs to be tidied up
2385 		 * - most can be made redundant
2386 		 */
2387 		for (i = 0; i < hfs_num; i++)
2388 			hfs_types[i].flags &= ~1;	/* 0xfffffffe */
2389 
2390 		for (i = 1; i < hfs_num; i++)
2391 			if (!((1 << i) & hfs_select))
2392 				hfs_types[i].flags |= PROBE;
2393 
2394 		hselect = hfs_select;
2395 	} else
2396 		hfs_num = hselect = 0;
2397 
2398 #ifdef DEBUG
2399 	for (i = 0; i < hfs_num; i++)
2400 		fprintf(stderr, "type = %d flags = %d\n",
2401 					i, hfs_types[i].flags);
2402 #endif	/* DEBUG */
2403 
2404 	/* min length set to max to start with */
2405 	mlen = PATH_MAX;
2406 
2407 #ifdef USE_MAGIC
2408 	/* initialise magic state */
2409 	if (magic_filename) {
2410 		magic_state = magic_open(MAGIC_ERROR);
2411 		if (magic_state == NULL)
2412 			perr("failed to initialise libmagic");
2413 		if (magic_load(magic_state, magic_filename) == -1) {
2414 			fprintf(stderr, "failed to open magic file: %s\n",
2415 				magic_error(magic_state));
2416 			exit(1);
2417 		}
2418 	}
2419 #endif /* USE_MAGIC */
2420 
2421 	/* set defaults */
2422 	map_num = last_ent = 0;
2423 
2424 	/* allocate memory for the default entry */
2425 	defmap = (afpmap *) e_malloc(sizeof (afpmap));
2426 
2427 	/* set default values */
2428 	defmap->extn = DEFMATCH;
2429 
2430 	/* make sure creator and type are 4 chars long */
2431 	strcpy(defmap->type, BLANK);
2432 	strcpy(defmap->creator, BLANK);
2433 
2434 	e = deftype;
2435 	t = defmap->type;
2436 
2437 	while (*e && (e - deftype) < CT_SIZE)
2438 		*t++ = *e++;
2439 
2440 	e = defcreator;
2441 	c = defmap->creator;
2442 
2443 	while (*e && (e - defcreator) < CT_SIZE)
2444 		*c++ = *e++;
2445 
2446 	/* length is not important here */
2447 	defmap->elen = 0;
2448 
2449 	/* no flags */
2450 	defmap->fdflags = fdflags;
2451 
2452 	/* no afpfile - no mappings */
2453 	if (*name == '\0') {
2454 		map = NULL;
2455 		return;
2456 	}
2457 	if ((fp = fopen(name, "r")) == NULL)
2458 		perr("unable to open mapping file");
2459 
2460 	map = (afpmap **) e_malloc(NUMMAP * sizeof (afpmap *));
2461 
2462 	/* read afpfile line by line */
2463 	while (fgets(buf, PATH_MAX, fp) != NULL) {
2464 		/* ignore any comment lines */
2465 		c = tmp;
2466 		*c = '\0';
2467 		if (sscanf(buf, "%1s", c) == EOF || *c == '#')
2468 			continue;
2469 
2470 		/* increase list size if needed */
2471 		if (map_num == count) {
2472 			count += NUMMAP;
2473 			map = (afpmap **)realloc(map, count * sizeof (afpmap *));
2474 			if (map == NULL)
2475 				perr("not enough memory");
2476 		}
2477 		/* allocate memory for this entry */
2478 		amap = (afpmap *) e_malloc(sizeof (afpmap));
2479 
2480 		t = amap->type;
2481 		c = amap->creator;
2482 
2483 		/* extract the info */
2484 		if (sscanf(buf, "%s%*s%*1s%c%c%c%c%*1s%*1s%c%c%c%c%*1s",
2485 				tmp, c, c + 1, c + 2, c + 3,
2486 				t, t + 1, t + 2, t + 3) != 9) {
2487 			fprintf(stderr,
2488 				"error scanning afpfile %s - continuing", name);
2489 			free(amap);
2490 			continue;
2491 		}
2492 		/* copy the extension found */
2493 		if ((amap->extn = (char *) strdup(tmp)) == NULL)
2494 			perr("not enough memory");
2495 
2496 		/* set end-of-string */
2497 		*(t + 4) = *(c + 4) = '\0';
2498 
2499 		/* find the length of the extension */
2500 		amap->elen = strlen(amap->extn);
2501 
2502 		/* set flags */
2503 		amap->fdflags = fdflags;
2504 
2505 		/* see if we have the default creator/type */
2506 		if (strcmp(amap->extn, DEFMATCH) == 0) {
2507 			/* get rid of the old default */
2508 			free(defmap);
2509 			/* make this the default */
2510 			defmap = amap;
2511 			continue;
2512 		}
2513 		/* update the smallest extension length */
2514 		mlen = MIN(mlen, amap->elen);
2515 
2516 		/* add entry to the list */
2517 		map[map_num++] = amap;
2518 
2519 	}
2520 
2521 	/* free up some memory */
2522 	if (map_num != count) {
2523 		map = (afpmap **) realloc(map, map_num * sizeof (afpmap *));
2524 		if (map == NULL)
2525 			perr("not enough memory");
2526 	}
2527 }
2528 
2529 #ifdef USE_MAGIC
2530 static int
2531 try_map_magic(char *whole_name, char **type, /* set type */
2532 				  char **creator /* set creator */)
2533 {
2534 	const char * ret = magic_file(magic_state, whole_name);
2535 
2536 #ifdef DEBUG
2537 	fprintf(stderr, "magic_file(magic_state, \"%s\"): %s\n",
2538 		whole_name, ret ? ret : "NULL");
2539 #endif
2540 	/*
2541 	 * check that we found a match; ignore results in the
2542 	 * wrong format (probably due to libmagic's built-in rules)
2543 	 */
2544 	if (ret && strcspn(ret, " ") == CT_SIZE
2545 	    && ret[CT_SIZE] == ' '
2546 	    && strcspn(ret + CT_SIZE + 1, " ") == CT_SIZE) {
2547 		memcpy(tmp_type, ret, CT_SIZE);
2548 		tmp_type[CT_SIZE] = 0;
2549 		memcpy(tmp_creator, ret + CT_SIZE + 1, CT_SIZE);
2550 		tmp_creator[CT_SIZE] = 0;
2551 #ifdef DEBUG
2552 		fprintf(stderr, "tmp_type = \"%s\"; tmp_creator = \"%s\"\n",
2553 			tmp_type, tmp_creator);
2554 #endif
2555 		*type = tmp_type;
2556 		*creator = tmp_creator;
2557 		return (1);
2558 	}
2559 
2560 	return (0);
2561 }
2562 #endif /* USE_MAGIC */
2563 
2564 /*
2565  *	map_ext: map a files extension with the list to get type/creator
2566  */
2567 static void
2568 map_ext(char *name, /* filename */
2569 		  char **type, /* set type */
2570 		  char **creator, /* set creator */
2571 		  short *fdflags, /* set finder flags */
2572 		  char *whole_name)
2573 {
2574 	int	i;		/* loop counter */
2575 	int	len;		/* filename length */
2576 	afpmap	*amap;		/* mapping entry */
2577 	const char	*ret;
2578 
2579 	/* we don't take fdflags from the map or magic file */
2580 	*fdflags = defmap->fdflags;
2581 
2582 #ifdef USE_MAGIC
2583 	/*
2584 	 * if we have a magic file and we want to search it first,
2585 	 * then try to get a match
2586 	 */
2587 	if (magic_state && hfs_last == MAP_LAST
2588 	    && try_map_magic(whole_name, type, creator))
2589 				return;
2590 #endif /* USE_MAGIC */
2591 
2592 	len = strlen(name);
2593 
2594 	/* have an afpfile and filename if long enough */
2595 	if (map && len >= mlen) {
2596 		/*
2597 		 * search through the list - we start where we left off
2598 		 * last time in case this file is of the same type as the
2599 		 * last one
2600 		 */
2601 		for (i = 0; i < map_num; i++) {
2602 			amap = map[last_ent];
2603 
2604 			/* compare the end of the filename */
2605 /*			if (strcmp((name+len - amap->elen), amap->extn) == 0) { */
2606 			if (strcasecmp((name+len - amap->elen), amap->extn) == 0) {
2607 				/* set the required info */
2608 				*type = amap->type;
2609 				*creator = amap->creator;
2610 				*fdflags = amap->fdflags;
2611 				return;
2612 			}
2613 			/*
2614 			 * move on to the next entry - wrapping round
2615 			 * if neccessary
2616 			 */
2617 			last_ent++;
2618 			last_ent %= map_num;
2619 		}
2620 	}
2621 	/*
2622 	 * if no matches are found, file name too short, or no afpfile,
2623 	 * then take defaults
2624 	 */
2625 	*type = defmap->type;
2626 	*creator = defmap->creator;
2627 
2628 #ifdef USE_MAGIC
2629 	/*
2630 	 * if we have a magic file and we haven't searched yet,
2631 	 * then try to get a match
2632 	 */
2633 	if (magic_state && hfs_last == MAG_LAST)
2634 		try_map_magic(whole_name, type, creator);
2635 #endif /* USE_MAGIC */
2636 }
2637 
2638 void
2639 delete_rsrc_ent(dir_ent *s_entry)
2640 {
2641 	dir_ent	*s_entry1 = s_entry->next;
2642 
2643 	if (s_entry1 == NULL)
2644 		return;
2645 
2646 	s_entry->next = s_entry1->next;
2647 	s_entry->assoc = NULL;
2648 
2649 	free(s_entry1->name);
2650 	free(s_entry1->whole_name);
2651 
2652 	free(s_entry1);
2653 }
2654 
2655 void
2656 clean_hfs()
2657 {
2658 	if (map)
2659 		free(map);
2660 
2661 	if (defmap)
2662 		free(defmap);
2663 
2664 #ifdef USE_MAGIC
2665 	if (magic_state) {
2666 		magic_close(magic_state);
2667 		magic_state = NULL;
2668 	}
2669 #endif /* USE_MAGIC */
2670 }
2671 
2672 #endif	/* APPLE_HYB */
2673 
2674 void
2675 perr(char *a)
2676 {
2677 #ifdef	USE_LIBSCHILY
2678 	if (a)
2679 		comerr("%s\n", a);
2680 	else
2681 		comerr("<no error message given>\n");
2682 #else
2683 	if (a)
2684 		fprintf(stderr, "mkhybrid: %s\n", a);
2685 	perror("mkhybrid");
2686 	exit(1);
2687 #endif
2688 }
2689