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