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