xref: /netbsd-src/external/gpl2/mkhybrid/dist/apple.c (revision 61549db5f15a0e24ae58567abcbc4f1f9328b9e6)
1 /*
2 **	Unix-HFS file interface including maping file extensions to TYPE/CREATOR
3 **
4 **	Adapted from mkhfs routines for mkhybrid
5 **
6 **	James Pearson 1/5/97
7 **	Bug fix JCP 4/12/97
8 **	Updated for 1.12 and added more Unix HFS filetypes. JCP 21/1/98
9 **
10 **	Things still to de done:
11 **
12 **		Check SGI (XINET) structs
13 **		Check file size = finder + rsrc [+ data] is needed
14 **		AppleSingle/Double version 2?
15 **		Clean up byte order swapping.
16 */
17 
18 #ifdef APPLE_HYB
19 
20 #include <ctype.h>
21 #include <errno.h>
22 #include <unistd.h>
23 #include <err.h>
24 #include <fcntl.h>
25 #include <config.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <apple.h>
30 #include "apple_proto.h"
31 #include <mkisofs.h>
32 
33 /* tidy up mkisofs definition ... */
34 typedef struct directory_entry dir_ent;
35 
36 /* routines for getting HFS names and info */
37 static int get_none_dir(char *, const char *, dir_ent *, int);
38 static int get_none_info(char *, char *, dir_ent *, int);
39 static int get_cap_dir(char *, const char *, dir_ent *, int);
40 static int get_cap_info(char *, char *, dir_ent *, int);
41 static int get_es_info(char *, char *, dir_ent *, int);
42 static int get_dbl_info(char *, char *, dir_ent *, int);
43 static int get_mb_info(char *, char *, dir_ent *, int);
44 static int get_sgl_info(char *, char *, dir_ent *, int);
45 static int get_fe_dir(char *, const char *, dir_ent *, int);
46 static int get_fe_info(char *, char *, dir_ent *, int);
47 static int get_sgi_dir(char *, const char *, dir_ent *, int);
48 static int get_sgi_info(char *, char *, dir_ent *, int);
49 
50 void map_ext(char *, char **, char **, unsigned short *, char *);
51 static afpmap	**map;				/* list of mappings */
52 static afpmap	*defmap;			/* the default mapping */
53 static int	last_ent;			/* previous mapped entry */
54 static int	map_num;			/* number of mappings */
55 static int	mlen;				/* min extension length */
56 static char	tmp[MAXPATHLEN];		/* tmp working buffer */
57 static int	hfs_num;			/* number of file types */
58 static char	p_buf[MAXPATHLEN];		/* info working buffer */
59 static FILE	*p_fp = NULL;			/* probe File pointer */
60 static int	p_num = 0;			/* probe bytes read */
61 static unsigned int	hselect;		/* type of HFS file selected */
62 
63 struct hfs_type {			/* Types of various HFS Unix files */
64   int	type;					/* type of file */
65   int	flags;					/* special flags */
66   const char *info;           			/* finderinfo name */
67   const char *rsrc;           			/* resource fork name */
68   int  (*get_info)(char*, char*, dir_ent*,int);	/* finderinfo function */
69   int  (*get_dir)(char*, const char*,dir_ent*,int); /* directory name function */
70   const char *desc;				/* description */
71 };
72 
73 /* Above filled in */
74 static struct hfs_type hfs_types[] = {
75     {TYPE_NONE,0,"", "", get_none_info, get_none_dir,"None"},
76     {TYPE_CAP,0,".finderinfo/", ".resource/", get_cap_info, get_cap_dir,"CAP"},
77     {TYPE_NETA,0,".AppleDouble/", ".AppleDouble/", get_dbl_info, get_none_dir,"Netatalk"},
78     {TYPE_DBL,0,"%", "%", get_dbl_info, get_none_dir,"AppleDouble"},
79     {TYPE_ESH, 0,".rsrc/", ".rsrc/", get_es_info, get_none_dir,"EtherShare/UShare"},
80     {TYPE_FEU,2,"FINDER.DAT", "RESOURCE.FRK/", get_fe_info, get_fe_dir,"Exchange"},
81     {TYPE_FEL,2,"finder.dat", "resource.frk/", get_fe_info, get_fe_dir,"Exchange"},
82     {TYPE_SGI,2,".HSancillary", ".HSResource/", get_sgi_info, get_sgi_dir,"XINET/SGI"},
83     {TYPE_MBIN,1,"", "", get_mb_info, get_none_dir,"MacBinary"},
84     {TYPE_SGL,1,"", "", get_sgl_info, get_none_dir,"AppleSingle"}
85 };
86 
87 /* used by get_magic_match() return */
88 static char tmp_type[CT_SIZE+1], tmp_creator[CT_SIZE+1];
89 
90 /*
91 **	cstrncopy: Cap Unix name to HFS name
92 **
93 **	':' is replaced by '%' and string is terminated with '\0'
94 */
95 static void
cstrncpy(char * t,const char * f,int c)96 cstrncpy(char *t, const char *f, int c)
97 {
98 	while (c-- && *f)
99 	{
100 	    switch (*f)
101 	    {
102 		case ':':
103 		    *t = '%';
104 		    break;
105 		default:
106 		    *t = *f;
107 		    break;
108 	    }
109 	    t++; f++;
110 	}
111 
112 	*t = '\0';
113 }
114 /*
115 ** dehex()
116 **
117 ** Given a hexadecimal digit in ASCII, return the integer representation.
118 **
119 **	Taken from linux/fs/hfs/trans.c by Paul H. Hargrove
120 */
121 static unsigned char
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(const char * s)138 hex2char(const char *s)
139 {
140 	unsigned char o;
141 
142 	if(strlen(++s) < 2)
143 	    return(0);
144 
145 	if (!isxdigit((int)(u_char)*s) || !isxdigit((int)(u_char)*(s+1)))
146 	    return(0);
147 
148 	o = (dehex(*s) << 4) & 0xf0;
149 	s++;
150 	o |= (dehex(*s) & 0xf);
151 
152 	return (o);
153 }
154 
155 /*
156 **	hstrncpy: Unix name to HFS name with special character
157 **	translation.
158 **
159 **	"%xx" or ":xx" is assumed to be a "special" character and
160 **	replaced by character code given by the hex characters "xx"
161 **
162 **	if "xx" is not a hex number, then it is left alone - except
163 **	that ":" is replaced by "%"
164 **
165 */
166 static void
hstrncpy(unsigned char * t,const char * f,int c)167 hstrncpy(unsigned char *t, const char *f, int c)
168 {
169 	unsigned char	o;
170 	while (c-- && *f)
171 	{
172 	    switch (*f)
173 	    {
174 		case ':':
175 		case '%':
176 		    if ((o = hex2char(f)) == 0) {
177 			*t = '%';
178 		    }
179 		    else {
180 			*t = o;
181 			f += 2;
182 		    }
183 		    break;
184 		default:
185 		    *t = *f;
186 		    break;
187 	    }
188 	    t++; f++;
189 	}
190 
191 	*t = '\0';
192 }
193 
194 /*
195 **	basename: find just the filename with any directory component
196 */
197 /* not used at the moment ...
198 static char
199 basename(char *a)
200 {
201 	char *b;
202 
203 	if((b = strchr(a, '/')))
204 	    return(++b);
205 	else
206 	    return(a);
207 }
208 */
209 
210 /*
211 **	get_none_dir: ordinary Unix directory
212 */
213 int
get_none_dir(char * hname,const char * dname,dir_ent * s_entry,int ret)214 get_none_dir(char *hname, const char *dname, dir_ent *s_entry, int ret)
215 {
216 	/* just copy the given name */
217 	hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN);
218 
219 	return(ret);
220 }
221 
222 /*
223 **	get_none_info: ordinary Unix file - try to map extension
224 */
225 int
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 static 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,const char * dname,dir_ent * s_entry,int ret)273 get_cap_dir(char *hname, const char *dname, dir_ent *s_entry, int ret)
274 /* char		*hname				whole path */
275 /* const char	*dname				this dir name */
276 /* dir_ent	*s_entry			directory entry */
277 {
278 	FileInfo	info;			/* finderinfo struct */
279 	int		num = -1;		/* bytes read */
280 
281 	num = read_info_file(hname, &info, sizeof(FileInfo));
282 
283 	/* check finder info is OK */
284 	if (num > 0
285 		&& info.fi_magic1 == FI_MAGIC1
286 		&& info.fi_magic == FI_MAGIC
287 		&& info.fi_bitmap & FI_BM_MACINTOSHFILENAME) {
288 	    /* use the finderinfo name if it exists */
289 	    cstrncpy(s_entry->hfs_ent->name, info.fi_macfilename, HFS_MAX_FLEN);
290 	    return (ret);
291 	}
292 	else {
293 	    /* otherwise give it it's Unix name */
294 	    hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN);
295 	    return (TYPE_NONE);
296 	}
297 }
298 
299 /*
300 **	get_cap_info:	get CAP finderinfo for a file
301 */
302 int
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 static 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 	int	fe_num, fe_pad;
876 	fe_info info;
877 	int	c = 0;
878 	struct hfs_info *hfs_info1 = NULL;
879 	hfsdirent *hfs_ent;
880 	char	keyname[12];
881 	char	*s, *e, *k;
882 	int	i;
883 
884 	if ((fp = fopen(name, "rb")) == NULL)
885 	    return(NULL);
886 
887 	/*
888 	 * no longer attempt to find out FAT cluster
889 	 * - rely on command line parameter
890 	 */
891 	if (afe_size <= 0)
892 	    return(NULL);
893 
894 	fe_num = afe_size / FE_SIZE;
895 	fe_pad = afe_size % FE_SIZE;
896 
897 	while(fread(&info, 1, FE_SIZE, fp) != 0) {
898 
899 	    /* the Mac name may be NULL - so ignore this entry */
900 	    if (info.nlen != 0) {
901 
902 		hfs_info1 = (struct hfs_info *)e_malloc(sizeof(struct hfs_info));
903 		/* add this entry to the list */
904 		hfs_info1->next = hfs_info;
905 		hfs_info = hfs_info1;
906 
907 		hfs_ent = &hfs_info1->hfs_ent;
908 
909 		/* get the bits we need - ignore [cm]time for the moment */
910 		cstrncpy(hfs_ent->name, info.name, info.nlen);
911 
912 		strncpy(hfs_ent->type, info.type, CT_SIZE);
913 		strncpy(hfs_ent->creator, info.creator, CT_SIZE);
914 
915 		hfs_ent->type[CT_SIZE] = hfs_ent->creator[CT_SIZE] = '\0';
916 
917 		hfs_ent->fdflags = d_getw(info.flags);
918 
919 		s = info.sname;
920 		e = info.ext;
921 		k = keyname;
922 
923 		/* short (Unix) name is stored in PC format, so needs
924 		   to be mangled a bit */
925 
926 		/* name part */
927 		for(i=0;i<8;i++,s++,k++) {
928 		    if(*s == ' ')
929 			break;
930 		    else
931 			*k = *s;
932 		}
933 
934 		/* extension - if it exists */
935 		if (strncmp(info.ext, "   ", 3)) {
936 		    *k = '.';
937 		    k++;
938 		    for(i=0;i<3;i++,e++,k++) {
939 			if(*e == ' ')
940 			    break;
941 			else
942 			    *k = *e;
943 		    }
944 		}
945 		*k = '\0';
946 
947 		hfs_info1->keyname = strdup(keyname);
948 	    }
949 
950 	    /* each record is FE_SIZE long, and there are FE_NUM
951 		per each "cluster size", so we may need to skip the padding */
952 	    if (++c == fe_num) {
953 		c = 0;
954 	        fseek(fp, fe_pad, 1);
955 	    }
956 	}
957 	fclose (fp);
958 
959 	return (hfs_info);
960 }
961 
962 /*
963 **	get_hfs_sgi_info: read in the whole finderinfo for a SGI (XINET)
964 **		directory - saves on reading this many times for each
965 **		file.
966 */
967 static struct hfs_info *
get_hfs_sgi_info(struct hfs_info * hfs_info,char * name)968 get_hfs_sgi_info(struct hfs_info *hfs_info, char *name)
969 {
970 	FILE	*fp;
971 	sgi_info info;
972 	struct hfs_info *hfs_info1 = NULL;
973 	hfsdirent *hfs_ent;
974 
975 	if ((fp = fopen(name, "rb")) == NULL)
976 	    return(NULL);
977 
978 	while(fread(&info, 1, SGI_SIZE, fp) != 0) {
979 
980 	    hfs_info1 = (struct hfs_info *)e_malloc(sizeof(struct hfs_info));
981 	    /* add thsi entry to the list */
982 	    hfs_info1->next = hfs_info;
983 	    hfs_info = hfs_info1;
984 
985 	    hfs_ent = &hfs_info1->hfs_ent;
986 
987 	    /* get the bits we need - ignore [cm]time for the moment */
988 	    cstrncpy(hfs_ent->name, info.name, HFS_MAX_FLEN);
989 
990 	    strncpy(hfs_ent->type, info.type, CT_SIZE);
991 	    strncpy(hfs_ent->creator, info.creator, CT_SIZE);
992 
993 	    hfs_ent->type[CT_SIZE] = hfs_ent->creator[CT_SIZE] = '\0';
994 
995 	    /* don't know about flags at the moment */
996 	/*  hfs_ent->fdflags = d_getw((unsigned char *)&info.flags); */
997 
998 	    /* use the HFS name as the key */
999 	    hfs_info1->keyname = hfs_ent->name;
1000 
1001 	}
1002 	fclose (fp);
1003 
1004 	return (hfs_info);
1005 }
1006 
1007 /*
1008 **	del_hfs_info: delete the info list and recover memory
1009 */
1010 void
del_hfs_info(struct hfs_info * hfs_info)1011 del_hfs_info(struct hfs_info *hfs_info)
1012 {
1013 	struct hfs_info	*hfs_info1;
1014 
1015 	while (hfs_info) {
1016 	    hfs_info1 = hfs_info;
1017 	    hfs_info = hfs_info->next;
1018 
1019 	    /* key may be the same as the HFS name - so don't free it */
1020 	    *hfs_info1->hfs_ent.name = '\0';
1021 	    if (*hfs_info1->keyname)
1022 		free(hfs_info1->keyname);
1023 	    free(hfs_info1);
1024 	}
1025 }
1026 
1027 /*
1028 **	match_key: find the correct hfs_ent using the Unix filename
1029 **		as the key
1030 */
1031 static hfsdirent *
match_key(struct hfs_info * hfs_info,const char * key)1032 match_key(struct hfs_info *hfs_info, const char *key)
1033 {
1034 	while (hfs_info) {
1035 	    if (!strcasecmp(key, hfs_info->keyname))
1036 		return (&hfs_info->hfs_ent);
1037 	    hfs_info = hfs_info->next;
1038 	}
1039 
1040 	return (NULL);
1041 }
1042 
1043 /*
1044 **	get_fe_dir: get PC Exchange directory name
1045 **
1046 **	base on probing with od ...
1047 */
1048 int
get_fe_dir(char * hname,const char * dname,dir_ent * s_entry,int ret)1049 get_fe_dir(char *hname, const char *dname, dir_ent *s_entry, int ret)
1050 /* char		*hname				whole path */
1051 /* const char	*dname				this dir name */
1052 /* dir_ent	*s_entry			directory entry */
1053 {
1054 	struct hfs_info *hfs_info;
1055 	hfsdirent	*hfs_ent;
1056 
1057 	/* cached finderinfo stored with parent directory */
1058 	hfs_info = s_entry->filedir->hfs_info;
1059 
1060 	/* if we have no cache, then make one and store it */
1061 	if (hfs_info == NULL) {
1062 	    if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL)
1063 		ret = TYPE_NONE;
1064 	    else
1065 		s_entry->filedir->hfs_info = hfs_info;
1066 	}
1067 
1068 	if (ret != TYPE_NONE) {
1069 	    /* see if we can find the details of this file */
1070 	    if ((hfs_ent = match_key(hfs_info, dname)) != NULL) {
1071 		strcpy(s_entry->hfs_ent->name, hfs_ent->name);
1072 		return (ret);
1073 	    }
1074 	}
1075 
1076 	/* can't find the entry, so use the Unix name */
1077 	hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN);
1078 
1079 	return(TYPE_NONE);
1080 }
1081 
1082 /*
1083 **	get_fe_info: get PC Exchange file details.
1084 **
1085 **	base on probing with od and details from Mark Weinstein
1086 **	<mrwesq@earthlink.net>
1087 */
1088 int
get_fe_info(char * hname,char * dname,dir_ent * s_entry,int ret)1089 get_fe_info(char *hname, char *dname, dir_ent *s_entry, int ret)
1090 /* char		*hname				whole path */
1091 /* char		*dname				this dir name */
1092 /* dir_ent	*s_entry			directory entry */
1093 {
1094 	struct hfs_info *hfs_info;
1095 	hfsdirent	*hfs_ent;
1096 
1097 	/* cached finderinfo stored with parent directory */
1098 	hfs_info = s_entry->filedir->hfs_info;
1099 
1100 	/* if we have no cache, then make one and store it */
1101 	if (hfs_info == NULL) {
1102 	    if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL)
1103 		ret = TYPE_NONE;
1104 	    else
1105 		s_entry->filedir->hfs_info = hfs_info;
1106 	}
1107 
1108 	if (ret != TYPE_NONE) {
1109 	    char  *dn = dname;
1110 #ifdef _WIN32_TEST
1111 	    /* may have a problem here - v2.2 has long filenames,
1112 	       but we need to key on the short filename, so we need
1113 	       do go a bit of win32 stuff ... */
1114 
1115 	    char  sname[1024], lname[1024];
1116 
1117 	    cygwin32_conv_to_full_win32_path(s_entry->whole_name, lname);
1118 
1119 	    if (GetShortPathName(lname, sname, sizeof(sname))) {
1120 		if (dn = strrchr(sname, '\\'))
1121 		    dn++;
1122 		else
1123 		    dn = sname;
1124 	    }
1125 #endif /* _WIN32 */
1126 
1127 	    /* see if we can find the details of this file */
1128 	    if ((hfs_ent = match_key(hfs_info, dn)) != NULL) {
1129 		strcpy(s_entry->hfs_ent->name, hfs_ent->name);
1130 		strcpy(s_entry->hfs_ent->type, hfs_ent->type);
1131 		strcpy(s_entry->hfs_ent->creator, hfs_ent->creator);
1132 		/* clear HFS_FNDR_HASBEENINITED flag */
1133 		s_entry->hfs_ent->fdflags = hfs_ent->fdflags & 0xfeff;
1134 		return (ret);
1135 	    }
1136 	}
1137 
1138 	/* no entry found - use extension mapping */
1139 	if (verbose > 2) {
1140 	    fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
1141 	        s_entry->whole_name, hfs_types[ret].desc);
1142 	}
1143 
1144 	ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1145 
1146 	return(TYPE_NONE);
1147 }
1148 
1149 /*
1150 **	get_sgi_dir: get SGI (XINET) HFS directory name
1151 **
1152 **	base on probing with od ...
1153 */
1154 int
get_sgi_dir(char * hname,const char * dname,dir_ent * s_entry,int ret)1155 get_sgi_dir(char *hname, const char *dname, dir_ent *s_entry, int ret)
1156 /* char		*hname				whole path */
1157 /* const char	*dname				this dir name */
1158 /* dir_ent	*s_entry			directory entry */
1159 {
1160 	struct hfs_info *hfs_info;
1161 	hfsdirent	*hfs_ent;
1162 
1163 	/* cached finderinfo stored with parent directory */
1164 	hfs_info = s_entry->filedir->hfs_info;
1165 
1166 	/* if we haven't got a cache, then make one */
1167 	if (hfs_info == NULL) {
1168 	    if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL)
1169 		ret = TYPE_NONE;
1170 	    else
1171 		s_entry->filedir->hfs_info = hfs_info;
1172 	}
1173 
1174 	/* find the matching entry in the cache */
1175 	if (ret != TYPE_NONE) {
1176 	    /* key is (hopefully) the real Mac name */
1177 	    cstrncpy(tmp, dname, strlen(dname));
1178 	    if ((hfs_ent = match_key(hfs_info, tmp)) != NULL) {
1179 		strcpy(s_entry->hfs_ent->name, hfs_ent->name);
1180 		return (ret);
1181 	    }
1182 	}
1183 
1184 	/* no entry found - use Unix name */
1185 	hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN);
1186 
1187 	return(TYPE_NONE);
1188 }
1189 
1190 /*
1191 **	get_sgi_info: get SGI (XINET) HFS finder info
1192 **
1193 **	base on probing with od ...
1194 */
1195 int
get_sgi_info(char * hname,char * dname,dir_ent * s_entry,int ret)1196 get_sgi_info(char *hname, char *dname, dir_ent *s_entry, int ret)
1197 /* char		*hname				whole path */
1198 /* char		*dname				this dir name */
1199 /* dir_ent	*s_entry			directory entry */
1200 {
1201 	struct hfs_info *hfs_info;
1202 	hfsdirent	*hfs_ent;
1203 
1204 	/* cached finderinfo stored with parent directory */
1205 	hfs_info = s_entry->filedir->hfs_info;
1206 
1207 	/* if we haven't got a cache, then make one */
1208 	if (hfs_info == NULL) {
1209 	    if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL)
1210 		ret = TYPE_NONE;
1211 	    else
1212 		s_entry->filedir->hfs_info = hfs_info;
1213 	}
1214 
1215 	if (ret != TYPE_NONE) {
1216 	    /* tmp is the same as hname here, but we don't need hname
1217 	       anymore in this function  ...  see if we can find the
1218 	       details of this file using the Unix name as the key */
1219 	    cstrncpy(tmp, dname, strlen(dname));
1220 	    if ((hfs_ent = match_key(hfs_info, tmp)) != NULL) {
1221 		strcpy(s_entry->hfs_ent->name, hfs_ent->name);
1222 		strcpy(s_entry->hfs_ent->type, hfs_ent->type);
1223 		strcpy(s_entry->hfs_ent->creator, hfs_ent->creator);
1224 	/*	s_entry->hfs_ent->fdflags = hfs_ent->fdflags; */
1225 		return (ret);
1226 	    }
1227 	}
1228 
1229 	/* no entry found, so try file extension */
1230 	if (verbose > 2) {
1231 	    fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
1232 	        s_entry->whole_name, hfs_types[ret].desc);
1233 	}
1234 
1235 	ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1236 
1237 	return(TYPE_NONE);
1238 }
1239 
1240 /*
1241 **	get_hfs_itype: get the type of HFS info for a file
1242 */
1243 static int
get_hfs_itype(const char * wname,const char * dname,char * htmp)1244 get_hfs_itype(const char *wname, const char *dname, char *htmp)
1245 {
1246 	int	wlen, i;
1247 
1248 	wlen = strlen(wname) - strlen(dname);
1249 
1250 	/* search through the known types looking for matches */
1251 	for (i=1;i<hfs_num;i++) {
1252 	    /* skip the ones that we don't care about */
1253 	    if ((hfs_types[i].flags & 0x1) || *(hfs_types[i].info) == TYPE_NONE)
1254 		continue;
1255 
1256 	    strcpy(htmp, wname);
1257 
1258 	    sprintf(htmp+wlen, "%s%s", hfs_types[i].info,
1259 		(hfs_types[i].flags & 0x2) ? "" : dname);
1260 	    if (!access(tmp, R_OK))
1261 		return (hfs_types[i].type);
1262 	}
1263 
1264 	return (TYPE_NONE);
1265 }
1266 
1267 /*
1268 **	get_hfs_dir: set the HFS directory name
1269 */
1270 int
get_hfs_dir(const char * wname,const const char * dname,dir_ent * s_entry)1271 get_hfs_dir(const char *wname, const const char *dname, dir_ent *s_entry)
1272 {
1273 	int	type;
1274 
1275 	/* get the HFS file type from the info file (if it exists) */
1276 	type = get_hfs_itype(wname, dname, tmp);
1277 
1278 	/* try to get the required info */
1279 	type = (*(hfs_types[type].get_dir))(tmp, dname, s_entry, type);
1280 
1281 	return (type);
1282 }
1283 
1284 /*
1285 **	get_hfs_info: set the HFS info for a file
1286 */
1287 int
get_hfs_info(char * wname,char * dname,dir_ent * s_entry)1288 get_hfs_info(char *wname, char *dname, dir_ent *s_entry)
1289 {
1290 	int	type, wlen, i;
1291 
1292 	wlen = strlen(wname) - strlen(dname);
1293 
1294 	/* we may already know the type of Unix/HFS file - so process */
1295 	if (s_entry->hfs_type != TYPE_NONE) {
1296 
1297 /*
1298 	    i = 0;
1299 	    for(type=1;i<hfs_num;type++) {
1300 		if (s_entry->hfs_type == hfs_types[type].type) {
1301 		    i = type;
1302 		    break;
1303 		}
1304 	    }
1305 */
1306 	    type = s_entry->hfs_type;
1307 
1308 	    strcpy(tmp, wname);
1309 	    sprintf(tmp+wlen, "%s%s", hfs_types[type].info,
1310 		(hfs_types[type].flags & 0x2) ? "" : dname);
1311 	    type = (*(hfs_types[type].get_info))(tmp, dname, s_entry, type);
1312 
1313 	    /* if everything is as expected, then return */
1314 	    if (s_entry->hfs_type == type)
1315 		return(type);
1316 	}
1317 
1318 	/* we don't know what type we have so, find out */
1319 	for (i=1;i<hfs_num;i++) {
1320 	    if ((hfs_types[i].flags & 0x1) || *(hfs_types[i].info) == TYPE_NONE)
1321 		continue;
1322 
1323 	    strcpy(tmp, wname);
1324 
1325 	    sprintf(tmp+wlen, "%s%s", hfs_types[i].info,
1326 		(hfs_types[i].flags & 0x2) ? "" : dname);
1327 
1328 	    /* if the file exists - and not a type we've already tried */
1329 	    if (!access(tmp, R_OK) && i != s_entry->hfs_type) {
1330 		type = (*(hfs_types[i].get_info))(tmp, dname, s_entry, i);
1331 		s_entry->hfs_type = type;
1332 		return (type);
1333 	    }
1334 	}
1335 
1336 	/* nothing found, so just a Unix file */
1337 	type = (*(hfs_types[TYPE_NONE].get_info))(wname, dname, s_entry, TYPE_NONE);
1338 
1339 	return (type);
1340 }
1341 
1342 /*
1343 **	get_hfs_rname: set the name of the Unix rsrc file for a file
1344 */
1345 int
get_hfs_rname(char * wname,char * dname,char * rname)1346 get_hfs_rname(char *wname, char *dname, char *rname)
1347 {
1348 	int	wlen, type, i;
1349 	int	p_fd = -1;
1350 
1351 	wlen = strlen(wname) - strlen(dname);
1352 
1353 	/* try to find what sort of Unix HFS file type we have */
1354 	for (i=1;i<hfs_num;i++) {
1355 	    /* skip if don't want to probe the files - (default) */
1356 	    if (hfs_types[i].flags & 0x1)
1357 		continue;
1358 
1359 	    strcpy(rname, wname);
1360 
1361 	    /* if we have a different info file, the find out it's type */
1362 	    if (*(hfs_types[i].rsrc)) {
1363 		sprintf(rname+wlen, "%s%s", hfs_types[i].rsrc, dname);
1364 		if (!access(rname, R_OK))
1365 		    return (hfs_types[i].type);
1366 	    }
1367 	    else {
1368 		/* if we are probing, then have a look at the contents to
1369 		   find type */
1370 		if (p_fd < 0) {
1371 		    /* open file, if not already open */
1372 		    if((p_fd = open(wname, O_RDONLY | O_BINARY)) < 0) {
1373 			/* can't open it, then give up */
1374 			return (TYPE_NONE);
1375 		    } else {
1376 			if((p_num = read(p_fd, p_buf, sizeof(p_buf))) <= 0) {
1377 			/* can't read, or zero length - give up */
1378 			    close(p_fd);
1379 			    return(TYPE_NONE);
1380 			}
1381 			/* get file pointer and close file */
1382 			p_fp = fdopen(p_fd, "rb");
1383 			close(p_fd);
1384 			if(p_fp == NULL)
1385 			    return(TYPE_NONE);
1386 		    }
1387 		}
1388 		/* call routine to do the work - use the given dname as
1389 		   this is the name we may use on the CD */
1390 		type = (*(hfs_types[i].get_info))(rname, dname, 0, i);
1391 		if (type != 0) {
1392 		    fclose(p_fp);
1393 		    return (type);
1394 		}
1395 		if (p_fp) {
1396 		    /* close file - just use contents of buffer next time */
1397 		    fclose(p_fp);
1398 		    p_fp = NULL;
1399 		}
1400 	    }
1401 	}
1402 
1403 	return (0);
1404 }
1405 
1406 /*
1407 **	hfs_exclude: file/directory names that hold finder/resource
1408 **		     information that we want to exclude from the tree.
1409 **		     These files/directories are processed later ...
1410 */
1411 int
hfs_exclude(char * d_name)1412 hfs_exclude(char *d_name)
1413 {
1414     /* we don't exclude "." and ".." */
1415     if (!strcmp(d_name,"."))
1416       return 0;
1417     if (!strcmp(d_name,".."))
1418       return 0;
1419 
1420     /* do not add the following to our list of dir entries */
1421     if (DO_CAP & hselect) {
1422       /* CAP */
1423       if(!strcmp(d_name,".finderinfo"))
1424 	return 1;
1425       if(!strcmp(d_name,".resource"))
1426 	return 1;
1427       if(!strcmp(d_name,".ADeskTop"))
1428 	return 1;
1429       if(!strcmp(d_name,".IDeskTop"))
1430 	return 1;
1431       if(!strcmp(d_name,"Network Trash Folder"))
1432 	return 1;
1433       /* special case when HFS volume is mounted using Linux's hfs_fs
1434 	 Brad Midgley <brad@pht.com> */
1435       if(!strcmp(d_name,".rootinfo"))
1436 	return 1;
1437     }
1438 
1439     if (DO_ESH & hselect) {
1440       /* Helios EtherShare files */
1441       if(!strcmp(d_name,".rsrc"))
1442 	return 1;
1443       if(!strcmp(d_name,".Desktop"))
1444 	return 1;
1445       if(!strcmp(d_name,".DeskServer"))
1446 	return 1;
1447       if(!strcmp(d_name,".Label"))
1448 	return 1;
1449     }
1450 
1451     if (DO_DBL & hselect) {
1452       /* Apple Double */
1453       if (*d_name == '%')
1454 	return 1;
1455     }
1456 
1457     if (DO_NETA & hselect) {
1458       if(!strcmp(d_name,".AppleDouble"))
1459 	return 1;
1460       if(!strcmp(d_name,".AppleDesktop"))
1461 	return 1;
1462     }
1463 
1464     if ((DO_FEU & hselect) || ( DO_FEL & hselect)) {
1465 	/* PC Exchange */
1466       if(!strcmp(d_name,"RESOURCE.FRK"))
1467 	return 1;
1468       if(!strcmp(d_name,"FINDER.DAT"))
1469 	return 1;
1470       if(!strcmp(d_name,"DESKTOP"))
1471 	return 1;
1472       if(!strcmp(d_name,"FILEID.DAT"))
1473 	return 1;
1474       if(!strcmp(d_name,"resource.frk"))
1475 	return 1;
1476       if(!strcmp(d_name,"finder.dat"))
1477 	return 1;
1478       if(!strcmp(d_name,"desktop"))
1479 	return 1;
1480       if(!strcmp(d_name,"fileid.dat"))
1481 	return 1;
1482     }
1483 
1484     if (DO_SGI | hselect) {
1485       /* SGI */
1486       if(!strcmp(d_name,".HSResource"))
1487 	return 1;
1488       if(!strcmp(d_name,".HSancillary"))
1489 	return 1;
1490     }
1491 
1492     return 0;
1493 }
1494 /*
1495 **	print_hfs_info: print info about the HFS files.
1496 **
1497 */
1498 void
print_hfs_info(dir_ent * s_entry)1499 print_hfs_info(dir_ent *s_entry)
1500 {
1501 	fprintf(stderr,"Name: %s\n",s_entry->whole_name);
1502 	fprintf(stderr,"\tFile type: %s\n",hfs_types[s_entry->hfs_type].desc);
1503 	fprintf(stderr,"\tHFS Name: %s\n",s_entry->hfs_ent->name);
1504 	fprintf(stderr,"\tISO Name: %s\n",s_entry->isorec.name);
1505 	fprintf(stderr,"\tCREATOR: %s\n",s_entry->hfs_ent->creator);
1506 	fprintf(stderr,"\tTYPE:	%s\n", s_entry->hfs_ent->type);
1507 }
1508 
1509 
1510 /*
1511 **	hfs_init: sets up the mapping list from the afpfile as well
1512 **		 the default mapping (with or without) an afpfile
1513 */
1514 void
hfs_init(char * name,unsigned short fdflags,int probe,int nomacfiles,unsigned int hfs_select)1515 hfs_init(char *name, unsigned short fdflags, int probe, int nomacfiles,
1516 	unsigned int hfs_select)
1517 #if 0
1518    char		*name;				/* afpfile name */
1519    u_short	*fdflags;			/* default finder flags */
1520    int		probe;				/* probe flag */
1521    int		nomacfiles;			/* don't look for mac files */
1522    u_int	hfs_select			/* select certain mac files */
1523 #endif
1524 {
1525 	FILE	*fp;				/* File pointer */
1526 	int	count = NUMMAP;			/* max number of entries */
1527 	char	buf[MAXPATHLEN];		/* working buffer */
1528 	afpmap	*amap;				/* mapping entry */
1529 	char	*c, *t, *e;
1530 	int	i;
1531 
1532 	/* setup number of Unix/HFS filetype - we may wish to not bother */
1533 	if (nomacfiles)
1534 	    hfs_num = 0;
1535 	else
1536 	    hfs_num = sizeof(hfs_types)/sizeof(struct hfs_type);
1537 
1538 	/* we may want to probe all files */
1539 	if (probe || hfs_select)
1540 	    for(i=0;i<hfs_num;i++)
1541 		hfs_types[i].flags &= ~1;	/* 0xfffffffe */
1542 
1543 	/* if we have selected certain types of Mac/Unix files, then
1544 	   turn off the filetype */
1545 	if (hfs_select)
1546 	    for(i=1;i<hfs_num;i++)
1547 		if (!((1 << i) & hfs_select))
1548 		    hfs_types[i].flags |= 0x1;
1549 
1550 	/* save what types have been selected (set all if none have) */
1551 	if (hfs_select)
1552 	    hselect = hfs_select;
1553 	else
1554 	    hselect = ~0;
1555 
1556 #ifdef DEBUG
1557 	for(i=0;i<hfs_num;i++)
1558 	    fprintf(stderr,"type = %d flags = %d\n", i, hfs_types[i].flags);
1559 #endif /* DEBUG */
1560 
1561 	/* min length set to max to start with */
1562 	mlen = MAXPATHLEN;
1563 
1564 	/* initialise magic file */
1565 	if(magic_file && init_magic(magic_file) != 0)
1566 	    errx(1, "unable to open magic file");
1567 
1568 	/* set defaults */
1569 	map_num = last_ent = 0;
1570 
1571 	/* allocate memory for the default entry */
1572 	if((defmap = (afpmap *)malloc(sizeof(afpmap))) == NULL)
1573 	    errx(1, "not enough memory");
1574 
1575 	/* set default values */
1576 	defmap->extn = DEFMATCH;
1577 
1578 	/* make sure creator and type are 4 chars long */
1579 	strcpy(defmap->type, BLANK);
1580 	strcpy(defmap->creator, BLANK);
1581 
1582 	e = deftype;
1583 	t = defmap->type;
1584 
1585 	while(*e && (e - deftype) < CT_SIZE)
1586 	    *t++ = *e++;
1587 
1588 	e = defcreator;
1589 	c = defmap->creator;
1590 
1591 	while(*e && (e - defcreator) < CT_SIZE)
1592 	    *c++ = *e++;
1593 
1594 	/* length is not important here */
1595 	defmap->elen = 0;
1596 
1597 	/* no flags */
1598 	defmap->fdflags = fdflags;
1599 
1600 	/* no afpfile - no mappings */
1601 	if (*name == '\0') {
1602 	    map = NULL;
1603 	    return;
1604 	}
1605 
1606 	if((fp = fopen(name,"r")) == NULL)
1607 	    err(1, "unable to open mapping file: %s", name);
1608 
1609 	if((map = (afpmap **)malloc(NUMMAP * sizeof(afpmap *))) == NULL)
1610 	    errx(1, "not enough memory");
1611 
1612 	/* read afpfile line by line */
1613 	while(fgets(buf, MAXPATHLEN, fp) != NULL) {
1614 	    /* ignore any comment lines */
1615 	    c = tmp;
1616 	    *c = '\0';
1617 	    if (sscanf(buf,"%1s", c) == EOF || *c == '#')
1618 		continue;
1619 
1620 	    /* increase list size if needed */
1621 	    if (map_num == count) {
1622 		count += NUMMAP;
1623 		map = (afpmap **)realloc(map, count * sizeof(afpmap *));
1624 		if (map == NULL)
1625 		    errx(1, "not enough memory");
1626 	    }
1627 
1628 	    /* allocate memory for this entry */
1629 	    if((amap = (afpmap *)malloc(sizeof(afpmap))) == NULL)
1630 		errx(1, "not enough memory");
1631 
1632 	    t = amap->type;
1633 	    c = amap->creator;
1634 
1635 	    /* extract the info */
1636 	    if(sscanf(buf, "%s%*s%*1s%c%c%c%c%*1s%*1s%c%c%c%c%*1s",
1637 		    tmp, c, c+1, c+2, c+3, t, t+1, t+2, t+3) != 9) {
1638   		fprintf(stderr,"error scanning afpfile %s - continuing", name);
1639 		free(amap);
1640 		continue;
1641 	    }
1642 
1643 	    /* copy the extension found */
1644 	    if ((amap->extn = (char *)strdup(tmp)) == NULL)
1645 		errx(1, "not enough memory");
1646 
1647 	    /* set end-of-string */
1648 	    *(t+4) = *(c+4) = '\0';
1649 
1650 	    /* find the length of the extension */
1651 	    amap->elen = strlen(amap->extn);
1652 
1653 	    /* set flags */
1654 	    amap->fdflags = fdflags;
1655 
1656 	    /* see if we have the default creator/type */
1657 	    if(!strcmp(amap->extn, DEFMATCH)) {
1658 		/* get rid of the old default */
1659 		free(defmap);
1660 		/* make this the default */
1661 		defmap = amap;
1662 		continue;
1663 	    }
1664 
1665 	    /* update the smallest extension length */
1666 	    mlen = MIN(mlen, amap->elen);
1667 
1668 	    /* add entry to the list */
1669 	    map[map_num++] = amap;
1670 
1671 	}
1672 
1673 	/* free up some memory */
1674 	if (map_num != count) {
1675 	    map = (afpmap **)realloc(map, map_num * sizeof(afpmap *));
1676 	    if (map == NULL)
1677 		errx(1, "not enough memory");
1678 	}
1679 
1680 }
1681 
1682 /*
1683 **	map_ext: map a files extension with the list to get type/creator
1684 */
1685 void
map_ext(char * name,char ** type,char ** creator,unsigned short * fdflags,char * whole_name)1686 map_ext(char *name, char **type, char **creator, unsigned short *fdflags,
1687 	char *whole_name)
1688 #if 0
1689    char		*name;				/* filename */
1690    char		**type;				/* set type */
1691    char		**creator;			/* set creator */
1692    u_short	*fdflags;			/* set finder flags */
1693 #endif
1694 {
1695 	int	i;				/* loop counter */
1696 	int	len;				/* filename length */
1697 	afpmap	*amap;				/* mapping entry */
1698 	char	*ret;
1699 
1700 	/* we don't take fdflags from the map or magic file */
1701 	*fdflags = defmap->fdflags;
1702 
1703 	/* if we have a magic file and we want to search it first, then
1704 	   try to get a match */
1705 	if (magic_file && hfs_last == MAP_LAST) {
1706 	    ret = get_magic_match(whole_name);
1707 
1708 	    if (ret) {
1709 		if (sscanf(ret, "%4s%4s", tmp_creator, tmp_type) == 2) {
1710 		    *type = tmp_type;
1711 		    *creator = tmp_creator;
1712 		    return;
1713 		}
1714 	    }
1715 	}
1716 
1717 	len = strlen(name);
1718 
1719 	/* have an afpfile and filename if long enough */
1720 	if(map && len >= mlen) {
1721 	    /* search through the list - we start where we left
1722 	       off last time in case this file is of the same type
1723 	       as the last one */
1724 	    for(i=0;i<map_num;i++) {
1725 		amap = map[last_ent];
1726 
1727 		/* compare the end of the filename */
1728 /*		if (!strcmp((name + len - amap->elen), amap->extn)) { */
1729 		if (!strcasecmp((name + len - amap->elen), amap->extn)) {
1730 		    /* set the required info */
1731 		    *type = amap->type;
1732 		    *creator = amap->creator;
1733 		    *fdflags = amap->fdflags;
1734 		    return;
1735 		}
1736 		/* move on to the next entry - wrapping round if neccessary */
1737 		last_ent++;
1738 		last_ent %= map_num;
1739 	    }
1740 	}
1741 
1742 	/* if no matches are found, file name too short, or no
1743 	   afpfile, then take defaults */
1744 	*type = defmap->type;
1745 	*creator = defmap->creator;
1746 
1747 	/* if we have a magic file and we haven't searched yet, then try
1748 	   to get a match */
1749 	if (magic_file && hfs_last == MAG_LAST) {
1750 	    ret = get_magic_match(whole_name);
1751 
1752 	    if (ret) {
1753 		if (sscanf(ret, "%4s%4s", tmp_creator, tmp_type) == 2) {
1754 		    *type = tmp_type;
1755 		    *creator = tmp_creator;
1756 		}
1757 	    }
1758 	}
1759 }
1760 
1761 void
delete_rsrc_ent(dir_ent * s_entry)1762 delete_rsrc_ent(dir_ent *s_entry)
1763 {
1764 	dir_ent	*s_entry1 = s_entry->next;
1765 
1766 	if (s_entry1 == NULL)
1767 	    return;
1768 
1769 	s_entry->next = s_entry1->next;
1770 	s_entry->assoc = NULL;
1771 
1772 	free(s_entry1->name);
1773 	free(s_entry1->whole_name);
1774 
1775 	free(s_entry1);
1776 }
1777 
1778 void
clean_hfs()1779 clean_hfs()
1780 {
1781 	if (map)
1782 	    free(map);
1783 
1784 	if (defmap)
1785 	    free(defmap);
1786 
1787 	if (magic_file)
1788 	    clean_magic();
1789 }
1790 
1791 #else
1792 #include <stdio.h>
1793 #endif /* APPLE_HYB */
1794