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