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