2 * This file has been modified for the cdrkit suite.
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).
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.
13 /* @(#)apple.c 1.19 04/03/02 joerg, Copyright 1997, 1998, 1999, 2000 James Pearson */
15 * Copyright (c) 1997, 1998, 1999, 2000 James Pearson
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)
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.
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.
33 * Unix-HFS file interface including maping file extensions to TYPE/CREATOR
35 * Adapted from mkhfs routines for mkhybrid
37 * James Pearson 1/5/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
43 * Things still to de done:
45 * Check file size = finder + rsrc [+ data] is needed
51 #include "genisoimage.h"
56 #include <netinet/in.h>
62 magic_t magic_state = NULL;
64 /* workaround for older ´API */
67 #endif /* USE_MAGIC */
69 /* tidy up genisoimage definition ... */
70 typedef struct directory_entry dir_ent;
72 /* routines for getting HFS names and info */
73 #ifndef HAVE_STRCASECMP
74 static int strcasecmp(const char *s1, const char *s2);
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);
93 static int get_xhfs_dir(char *, char *, dir_ent *, int);
94 static int get_xhfs_info(char *, char *, dir_ent *, int);
96 #define get_xhfs_dir get_none_dir
97 #define get_xhfs_info get_none_info
98 #endif /* IS_MACOS_X */
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);
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 *);
114 static int get_hfs_itype(char *, char *, char *);
115 static void map_ext(char *, char **, char **, short *, char *);
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 */
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 */
136 int (*get_dir)(char *, char *, dir_ent *, int); /* directory */
139 char *desc; /* description */
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,
170 /* used by get_magic_match() return */
171 static char tmp_type[CT_SIZE + 1],
172 tmp_creator[CT_SIZE + 1];
176 * An array useful for CRC calculations that use 0x1021 as the "seed"
177 * taken from mcvert.c modified by Jim Van Verth.
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
215 #endif /* __used__ */
217 #ifndef HAVE_STRCASECMP
219 strcasecmp(const char *s1, const char *s2)
221 while (tolower(*s1) == tolower(*s2)) {
227 return (tolower(*s1) - tolower(*s2));
232 * set_ct: set CREATOR and TYPE in hfs_ent
234 * CREATOR and TYPE are padded with spaces if not CT_SIZE long
238 set_ct(hfsdirent *hfs_ent, char *c, char *t)
240 memset(hfs_ent->u.file.type, ' ', CT_SIZE);
241 memset(hfs_ent->u.file.creator, ' ', CT_SIZE);
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)));
246 hfs_ent->u.file.type[CT_SIZE] = '\0';
247 hfs_ent->u.file.creator[CT_SIZE] = '\0';
251 * cstrncopy: Cap Unix name to HFS name
253 * ':' is replaced by '%' and string is terminated with '\0'
256 cstrncpy(char *t, char *f, int c)
277 * Given a hexadecimal digit in ASCII, return the integer representation.
279 * Taken from linux/fs/hfs/trans.c by Paul H. Hargrove
284 if ((c >= '0') && (c <= '9')) {
287 if ((c >= 'a') && (c <= 'f')) {
288 return (c - 'a' + 10);
290 if ((c >= 'A') && (c <= 'F')) {
291 return (c - 'A' + 10);
307 i1 = (unsigned char) s[0];
308 i2 = (unsigned char) s[1];
310 if (!isxdigit(i1) || !isxdigit(i2))
313 o = (dehex(i1) << 4) & 0xf0;
314 o |= (dehex(i2) & 0xf);
321 * hstrncpy: Unix name to HFS name with special character
324 * "%xx" or ":xx" is assumed to be a "special" character and
325 * replaced by character code given by the hex characters "xx"
327 * if "xx" is not a hex number, then it is left alone - except
328 * that ":" is replaced by "%"
332 hstrncpy(unsigned char *t, char *f, int c)
340 if ((o = hex2char(f)) == 0) {
341 *t = conv_charset('%', in_nls, hfs_onls);
348 *t = conv_charset(*f, in_nls, hfs_onls);
359 * basename: find just the filename with any directory component
362 not used at the moment ...
369 if ((b = strchr(a, '/')))
377 * set_Dinfo: set directory info
380 set_Dinfo(byte *ptr, hfsdirent *ent)
382 Dinfo *dinfo = (Dinfo *)ptr;
385 ent->fdflags = d_getw((unsigned char *) dinfo->frFlags);
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]);
398 d_getw((unsigned char *) dinfo->frLocation[0]);
400 d_getw((unsigned char *) dinfo->frLocation[1]);
403 d_getw((unsigned char *) dinfo->frView);
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]);
412 * clear HFS_FNDR_HASBEENINITED to have tidy desktop ??
414 ent->fdflags &= 0xfeff;
419 * set_Finfo: set file info
422 set_Finfo(byte *ptr, hfsdirent *ent)
424 Finfo *finfo = (Finfo *)ptr;
426 /* type and creator from finder info */
427 set_ct(ent, finfo->fdCreator, finfo->fdType);
430 ent->fdflags = d_getw((unsigned char *) finfo->fdFlags);
434 d_getw((unsigned char *) finfo->fdLocation[0]);
436 d_getw((unsigned char *) finfo->fdLocation[1]);
439 * clear HFS_FNDR_HASBEENINITED to have tidy desktop ??
441 ent->fdflags &= 0xfeff;
446 * get_none_dir: ordinary Unix directory
449 get_none_dir(char *hname, char *dname, dir_ent *s_entry, int ret)
451 /* just copy the given name */
452 hstrncpy((unsigned char *) (s_entry->hfs_ent->name),
453 dname, HFS_MAX_FLEN);
459 * get_none_info: ordinary Unix file - try to map extension
462 get_none_info(char *hname, char *dname, dir_ent *s_entry, int ret)
466 hfsdirent *hfs_ent = s_entry->hfs_ent;
468 map_ext(dname, &t, &c, &s_entry->hfs_ent->fdflags, s_entry->whole_name);
470 /* just copy the given name */
471 hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN);
473 set_ct(hfs_ent, c, t);
479 * read_info_file: open and read a finderinfo file for an HFS file
483 read_info_file(char *name, /* finderinfo filename */
484 void *info, /* info buffer */
485 int len /* length of above */)
490 /* clear out any old finderinfo stuf */
491 memset(info, 0, len);
493 if ((fp = fopen(name, "rb")) == NULL)
496 /* read and ignore if the file is short - checked later */
497 num = fread(info, 1, len, fp);
505 * get_cap_dir: get the CAP name for a directory
508 get_cap_dir(char *hname, /* whole path */
509 char *dname, /* this dir name */
510 dir_ent *s_entry, /* directory entry */
513 FileInfo info; /* finderinfo struct */
514 int num = -1; /* bytes read */
515 hfsdirent *hfs_ent = s_entry->hfs_ent;
517 num = read_info_file(hname, &info, sizeof (FileInfo));
519 /* check finder info is OK */
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);
528 set_Dinfo(info.finderinfo, hfs_ent);
532 /* otherwise give it it's Unix name */
533 hstrncpy((unsigned char *) (s_entry->hfs_ent->name),
534 dname, HFS_MAX_FLEN);
540 ** get_cap_info: get CAP finderinfo for a file
543 get_cap_info(char *hname, /* whole path */
544 char *dname, /* this dir name */
545 dir_ent *s_entry, /* directory entry */
548 FileInfo info; /* finderinfo struct */
549 int num = -1; /* bytes read */
550 hfsdirent *hfs_ent = s_entry->hfs_ent;
552 num = read_info_file(hname, &info, sizeof (info));
554 /* check finder info is OK */
556 info.fi_magic1 == FI_MAGIC1 &&
557 info.fi_magic == FI_MAGIC) {
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);
565 hstrncpy((unsigned char *) (hfs_ent->name), dname,
569 set_Finfo(info.finderinfo, hfs_ent);
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
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));
581 if (info.fi_datemagic & FI_MDATE) {
582 hfs_ent->mddate = d_toutime(d_getl(info.fi_mtime));
584 #endif /* USE_MAC_DATES */
586 /* failed to open/read finderinfo - so try afpfile mapping */
589 "warning: %s doesn't appear to be a %s file\n",
590 s_entry->whole_name, hfs_types[ret].desc);
592 ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
599 * get_es_dir: get EtherShare/UShare finderinfo for a directory
601 * based on code from Jens-Uwe Mager (jum@helios.de) and Phil Sylvester
602 * <psylvstr@interaccess.com>
605 get_es_dir(char *hname, /* whole path */
606 char *dname, /* this dir name */
607 dir_ent *s_entry, /* directory entry */
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;
617 * the EtherShare and UShare file layout is the same, but they store
618 * finderinfo differently
620 einfo = (es_FileInfo *) info;
621 uinfo = (us_FileInfo *) info;
623 num = read_info_file(hname, info, sizeof (info));
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) {
630 set_Dinfo(einfo->finderinfo, hfs_ent);
632 } else if (num >= (int)sizeof (us_FileInfo)) {
634 * UShare has no magic number, so we assume that this is a valid
635 * info/resource file ...
638 set_Dinfo(uinfo->finderinfo, hfs_ent);
641 /* failed to open/read finderinfo - so try afpfile mapping */
644 "warning: %s doesn't appear to be a %s file\n",
645 s_entry->whole_name, hfs_types[ret].desc);
647 ret = get_none_dir(hname, dname, s_entry, TYPE_NONE);
652 hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN);
658 * get_es_info: get EtherShare/UShare finderinfo for a file
660 * based on code from Jens-Uwe Mager (jum@helios.de) and Phil Sylvester
661 * <psylvstr@interaccess.com>
664 get_es_info(char *hname, /* whole path */
665 char *dname, /* this dir name */
666 dir_ent *s_entry, /* directory entry */
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;
677 * the EtherShare and UShare file layout is the same, but they store
678 * finderinfo differently
680 einfo = (es_FileInfo *) info;
681 uinfo = (us_FileInfo *) info;
683 num = read_info_file(hname, info, sizeof (info));
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) {
690 set_Finfo(einfo->finderinfo, hfs_ent);
693 * set create date - modified date set from the Unix
697 hfs_ent->crdate = d_getl(einfo->createTime);
699 } else if (num >= (int)sizeof (us_FileInfo)) {
701 * UShare has no magic number, so we assume that this is a valid
702 * info/resource file ...
705 set_Finfo(uinfo->finderinfo, hfs_ent);
707 /* set create and modified date - if they exist */
710 d_getl(uinfo->ctime);
714 d_getl(uinfo->mtime);
716 /* failed to open/read finderinfo - so try afpfile mapping */
719 "warning: %s doesn't appear to be a %s file\n",
720 s_entry->whole_name, hfs_types[ret].desc);
722 ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
726 /* this should exist ... */
727 if ((s_entry1 = s_entry->assoc) == NULL)
728 perr("TYPE_ESH error - shouldn't happen!");
731 hstrncpy((unsigned char *) (hfs_ent->name), dname, HFS_MAX_FLEN);
733 /* real rsrc file starts ES_INFO_SIZE bytes into the file */
734 if (s_entry1->size <= ES_INFO_SIZE) {
736 hfs_ent->u.file.rsize = 0;
738 s_entry1->size -= ES_INFO_SIZE;
739 hfs_ent->u.file.rsize = s_entry1->size;
740 s_entry1->hfs_off = ES_INFO_SIZE;
743 set_733((char *) s_entry1->isorec.size, s_entry1->size);
750 * Compute the MacBinary II-style CRC for the data pointed to by p, with the
751 * crc seeded to seed.
753 * Modified by Jim Van Verth to use the magic array for efficiency.
756 static unsigned short
757 calc_mb_crc(unsigned char *p, long len, unsigned short seed)
759 unsigned short hold; /* crc computed so far */
760 long i; /* index into data */
762 hold = seed; /* start with seed */
763 for (i = 0; i < len; i++, p++) {
765 hold = (hold << 8) ^ mb_magic[(unsigned char) (hold >> 8)];
771 #endif /* __used__ */
774 get_mb_info(char *hname, /* whole path */
775 char *dname, /* this dir name */
776 dir_ent *s_entry, /* directory entry */
779 mb_info *info; /* finderinfo struct */
787 unsigned short crc_file,
792 info = (mb_info *) p_buf;
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
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
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);
813 fprintf(stderr, "%s: file %d, calc %d\n", hname,
816 if (crc_file == crc_calc)
819 #endif /* TEST_CODE */
822 * check some of the fields for a valid MacBinary file not
823 * zero1 and zero2 SHOULD be zero - but some files incorrect
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)
832 /* check that the filename is OKish */
833 for (i = 0; i < (int)info->nlen; i++)
834 if (info->name[i] == 0)
837 /* check CREATOR and TYPE are valid */
838 for (i = 0; i < 4; i++)
839 if (info->type[i] == 0 || info->auth[i] == 0)
842 /* we have a vaild MacBinary file, so fill in the bits */
844 /* this should exist ... */
845 if ((s_entry1 = s_entry->assoc) == NULL)
846 perr("TYPE_MBIN error - shouldn't happen!");
848 hfs_ent = s_entry->hfs_ent;
850 /* type and creator from finder info */
851 t = (char *) (info->type);
852 c = (char *) (info->auth);
854 set_ct(hfs_ent, c, t);
857 hfs_ent->fdflags = ((info->flags << 8) & 0xff00) | info->flags2;
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);
866 * clear HFS_FNDR_HASBEENINITED to have tidy desktop ??
868 hfs_ent->fdflags &= 0xfeff;
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
877 hfs_ent->crdate = d_toutime(d_getl(info->cdate));
878 hfs_ent->mddate = d_toutime(d_getl(info->mdate));
881 hstrncpy((unsigned char *) (hfs_ent->name),
882 (char *) (info->name), MIN(HFS_MAX_FLEN, info->nlen));
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);
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);
894 * real rsrc file starts after data fork (must be a multiple of
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);
906 * get_dbl_dir: get Apple double finderinfo for a directory
908 * Based on code from cvt2cap.c (c) May 1988, Paul Campbell
911 get_dbl_dir(char *hname, /* whole path */
912 char *dname, /* this dir name */
913 dir_ent *s_entry, /* directory entry */
916 FileInfo info; /* finderinfo struct */
919 int num = -1; /* bytes read */
922 hfsdirent *hfs_ent = s_entry->hfs_ent;
928 hp = (a_hdr *) p_buf;
929 memset(hp, 0, A_HDR_SIZE);
931 memset(name, 0, sizeof (name));
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);
938 * check finder info is OK - some Netatalk files don't have magic
939 * or version set - ignore if it's a netatalk file
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)))) {
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) {
952 /* extract what is needed */
953 for (i = 0, ep = hp->entries; i < nentries; i++, ep++) {
954 switch ((int)d_getl(ep->id)) {
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) {
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)
967 len = d_getl(ep->length);
976 /* skip this if we had a problem */
979 set_Dinfo(info.finderinfo, hfs_ent);
981 /* use stored name if it exists */
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
989 if (len == 32 && (int) name[0] < 32) {
990 cstrncpy(hfs_ent->name, &name[1],
991 MIN(name[0], HFS_MAX_FLEN));
993 cstrncpy(hfs_ent->name, name,
997 hstrncpy((unsigned char *) (hfs_ent->name),
998 dname, HFS_MAX_FLEN);
1002 /* failed to open/read finderinfo */
1009 /* problem with the file - try mapping/magic */
1012 "warning: %s doesn't appear to be a %s file\n",
1013 s_entry->whole_name, hfs_types[ret].desc);
1015 ret = get_none_dir(hname, dname, s_entry, TYPE_NONE);
1021 * Depending on the version, AppleDouble/Single stores dates
1022 * relative to 1st Jan 1904 (v1) or 1st Jan 2000 (v2)
1024 * The d_toutime() function uses 1st Jan 1904 to convert to
1025 * Unix time (1st Jan 1970).
1027 * The d_dtoutime() function uses 1st Jan 2000 to convert to
1028 * Unix time (1st Jan 1970).
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.
1038 * get_dbl_info: get Apple double finderinfo for a file
1040 * Based on code from cvt2cap.c (c) May 1988, Paul Campbell
1043 get_dbl_info(char *hname, /* whole path */
1044 char *dname, /* this dir name */
1045 dir_ent *s_entry, /* directory entry */
1048 FileInfo info; /* finderinfo struct */
1051 int num = -1; /* bytes read */
1054 hfsdirent *hfs_ent = s_entry->hfs_ent;
1060 unsigned char dates[A_DATE];
1063 hp = (a_hdr *) p_buf;
1064 memset(hp, 0, A_HDR_SIZE);
1066 memset(name, 0, sizeof (name));
1067 memset(dates, 0, sizeof (dates));
1069 /* get the rsrc file info - should exist ... */
1070 if ((s_entry1 = s_entry->assoc) == NULL)
1071 perr("TYPE_DBL error - shouldn't happen!");
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);
1078 * check finder info is OK - some Netatalk files don't have magic
1079 * or version set - ignore if it's a netatalk file
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)))) {
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) {
1093 /* extract what is needed */
1094 for (i = 0, ep = hp->entries; i < nentries; i++, ep++) {
1095 switch ((int)d_getl(ep->id)) {
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) {
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,
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)
1117 len = d_getl(ep->length);
1120 /* Workround for NetaTalk files ... */
1121 if (ret == TYPE_NETA && ver == A_VERSION1)
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) {
1131 /* get the correct Unix time */
1136 d_toutime(d_getl(dates));
1138 d_toutime(d_getl(dates+4));
1142 d_dtoutime(d_getl(dates));
1144 d_dtoutime(d_getl(dates+4));
1147 /* Use Unix dates */
1159 /* skip this if we had a problem */
1161 set_Finfo(info.finderinfo, hfs_ent);
1163 /* use stored name if it exists */
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
1171 if (len == 32 && (int) name[0] < 32) {
1172 cstrncpy(hfs_ent->name, &name[1],
1173 MIN(name[0], HFS_MAX_FLEN));
1175 cstrncpy(hfs_ent->name, name,
1179 hstrncpy((unsigned char *) (hfs_ent->name),
1180 dname, HFS_MAX_FLEN);
1184 /* failed to open/read finderinfo */
1191 /* problem with the file - try mapping/magic */
1194 "warning: %s doesn't appear to be a %s file\n",
1195 s_entry->whole_name, hfs_types[ret].desc);
1197 ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1203 * get_sgl_info: get Apple single finderinfo for a file
1205 * Based on code from cvt2cap.c (c) May 1988, Paul Campbell
1208 get_sgl_info(char *hname, /* whole path */
1209 char *dname, /* this dir name */
1210 dir_ent *s_entry, /* directory entry */
1213 FileInfo *info = 0; /* finderinfo struct */
1215 static a_entry *entries;
1223 unsigned char *dates;
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
1233 hp = (a_hdr *) p_buf;
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))
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))
1248 entries = (a_entry *) e_malloc(nentries * A_ENTRY_SIZE);
1250 memcpy(entries, (p_buf + A_HDR_SIZE), nentries * A_ENTRY_SIZE);
1252 /* have a vaild AppleSingle File */
1253 memset(name, 0, sizeof (name));
1255 /* get the rsrc file info - should exist ... */
1256 if ((s_entry1 = s_entry->assoc) == NULL)
1257 perr("TYPE_SGL error - shouldn't happen!");
1259 hfs_ent = s_entry->hfs_ent;
1261 nentries = (int) d_getw(hp->nentries);
1262 ver = d_getl(hp->version);
1264 /* extract what is needed */
1265 for (i = 0, ep = entries; i < nentries; i++, ep++) {
1266 switch ((int)d_getl(ep->id)) {
1268 /* get the finder info */
1269 info = (FileInfo *) (p_buf + d_getl(ep->offset));
1272 /* set the offset and correct data fork size */
1273 hfs_ent->u.file.dsize = s_entry->size =
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,
1281 /* set the offset and correct rsrc fork size */
1282 hfs_ent->u.file.rsize = s_entry1->size =
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,
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);
1296 /* get file info - ignore at the moment*/
1300 dates = (unsigned char *)p_buf + d_getl(ep->offset);
1301 /* get the correct Unix time */
1302 if (ver == A_VERSION1) {
1304 d_toutime(d_getl(dates));
1306 d_toutime(d_getl(dates+4));
1309 d_dtoutime(d_getl(dates));
1311 d_dtoutime(d_getl(dates+4));
1323 * failed to open/read finderinfo
1324 * - so try afpfile mapping
1328 "warning: %s doesn't appear to be a %s file\n",
1329 s_entry->whole_name,
1330 hfs_types[ret].desc);
1332 ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1336 set_Finfo(info->finderinfo, hfs_ent);
1338 /* use stored name if it exists */
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
1345 if (len == 32 && (int) name[0] < 32) {
1346 cstrncpy(hfs_ent->name, &name[1], MIN(name[0],
1349 cstrncpy(hfs_ent->name, name, HFS_MAX_FLEN);
1352 hstrncpy((unsigned char *) (hfs_ent->name), dname,
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.
1364 * Based of information provided by Mark Weinstein <mrwesq@earthlink.net>
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
1369 * Only tested with PC Exchange v2.1 - don't know if it will work
1370 * with v2.2 and above.
1372 static struct hfs_info *
1373 get_hfs_fe_info(struct hfs_info *hfs_info, char *name)
1380 struct hfs_info *hfs_info1 = NULL;
1387 if ((fp = fopen(name, "rb")) == NULL)
1391 * no longer attempt to find out FAT cluster
1392 * - rely on command line parameter
1397 fe_num = afe_size / FE_SIZE;
1398 fe_pad = afe_size % FE_SIZE;
1400 while (fread(&info, 1, FE_SIZE, fp) != 0) {
1402 /* the Mac name may be NULL - so ignore this entry */
1403 if (info.nlen != 0) {
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;
1412 * get the bits we need
1413 * - ignore [cm]time for the moment
1415 cstrncpy(hfs_info->name, (char *) (info.name),
1418 memcpy(hfs_info->finderinfo, info.finderinfo, INFOLEN);
1420 s = (char *) (info.sname);
1421 e = (char *) (info.ext);
1425 * short (Unix) name is stored in PC format,
1426 * so needs to be mangled a bit
1430 for (i = 0; i < 8; i++, s++, k++) {
1437 /* extension - if it exists */
1438 if (strncmp((const char *) (info.ext), " ", 3)) {
1441 for (i = 0; i < 3; i++, e++, k++) {
1450 hfs_info1->keyname = strdup(keyname);
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
1456 if (++c == fe_num) {
1458 fseek(fp, (off_t)fe_pad, SEEK_CUR);
1467 * get_hfs_sgi_info: read in the whole finderinfo for a SGI (XINET)
1468 * directory - saves on reading this many times for each
1471 static struct hfs_info *
1472 get_hfs_sgi_info(struct hfs_info *hfs_info, char *name)
1476 struct hfs_info *hfs_info1 = NULL;
1478 if ((fp = fopen(name, "rb")) == NULL)
1481 while (fread(&info, 1, SGI_SIZE, fp) != 0) {
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;
1488 /* get the bits we need - ignore [cm]time for the moment */
1489 cstrncpy(hfs_info->name, (char *)info.name, HFS_MAX_FLEN);
1491 memcpy(hfs_info->finderinfo, info.finderinfo, INFOLEN);
1493 /* use the HFS name as the key */
1494 hfs_info1->keyname = hfs_info->name;
1503 * del_hfs_info: delete the info list and recover memory
1506 del_hfs_info(struct hfs_info *hfs_info)
1508 struct hfs_info *hfs_info1;
1511 hfs_info1 = hfs_info;
1512 hfs_info = hfs_info->next;
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);
1523 * match_key: find the correct hfs_ent using the Unix filename
1526 static struct hfs_info *
1527 match_key(struct hfs_info *hfs_info, char *key)
1530 if (strcasecmp(key, hfs_info->keyname) == 0)
1532 hfs_info = hfs_info->next;
1539 * get_fe_dir: get PC Exchange directory name
1541 * base on probing with od ...
1544 get_fe_dir(char *hname, /* whole path */
1545 char *dname, /* this dir name */
1546 dir_ent *s_entry, /* directory entry */
1549 struct hfs_info *hfs_info;
1550 hfsdirent *hfs_ent = s_entry->hfs_ent;
1552 /* cached finderinfo stored with parent directory */
1553 hfs_info = s_entry->filedir->hfs_info;
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)
1560 s_entry->filedir->hfs_info = hfs_info;
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);
1567 set_Dinfo(hfs_info->finderinfo, hfs_ent);
1572 /* can't find the entry, so use the Unix name */
1573 hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN);
1579 * get_fe_info: get PC Exchange file details.
1581 * base on probing with od and details from Mark Weinstein
1582 * <mrwesq@earthlink.net>
1585 get_fe_info(char *hname, /* whole path */
1586 char *dname, /* this dir name */
1587 dir_ent *s_entry, /* directory entry */
1590 struct hfs_info *hfs_info;
1591 hfsdirent *hfs_ent = s_entry->hfs_ent;
1593 /* cached finderinfo stored with parent directory */
1594 hfs_info = s_entry->filedir->hfs_info;
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)
1601 s_entry->filedir->hfs_info = hfs_info;
1603 if (ret != TYPE_NONE) {
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
1616 cygwin32_conv_to_full_win32_path(s_entry->whole_name, lname);
1618 if (GetShortPathName(lname, sname, sizeof (sname))) {
1619 if (dn = strrchr(sname, '\\'))
1626 /* see if we can find the details of this file */
1627 if ((hfs_info = match_key(hfs_info, dn)) != NULL) {
1629 strcpy(hfs_ent->name, hfs_info->name);
1631 set_Finfo(hfs_info->finderinfo, hfs_ent);
1636 /* no entry found - use extension mapping */
1638 fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
1639 s_entry->whole_name, hfs_types[ret].desc);
1641 ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1647 * get_sgi_dir: get SGI (XINET) HFS directory name
1649 * base on probing with od ...
1652 get_sgi_dir(char *hname, /* whole path */
1653 char *dname, /* this dir name */
1654 dir_ent *s_entry, /* directory entry */
1657 struct hfs_info *hfs_info;
1658 hfsdirent *hfs_ent = s_entry->hfs_ent;
1660 /* cached finderinfo stored with parent directory */
1661 hfs_info = s_entry->filedir->hfs_info;
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)
1668 s_entry->filedir->hfs_info = hfs_info;
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);
1677 set_Dinfo(hfs_info->finderinfo, hfs_ent);
1682 /* no entry found - use Unix name */
1683 hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN);
1689 * get_sgi_info: get SGI (XINET) HFS finder info
1691 * base on probing with od ...
1694 get_sgi_info(char *hname, /* whole path */
1695 char *dname, /* this dir name */
1696 dir_ent *s_entry, /* directory entry */
1699 struct hfs_info *hfs_info;
1700 hfsdirent *hfs_ent = s_entry->hfs_ent;
1702 /* cached finderinfo stored with parent directory */
1703 hfs_info = s_entry->filedir->hfs_info;
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)
1710 s_entry->filedir->hfs_info = hfs_info;
1712 if (ret != TYPE_NONE) {
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
1718 cstrncpy(tmp, dname, strlen(dname));
1719 if ((hfs_info = match_key(hfs_info, tmp)) != NULL) {
1721 strcpy(hfs_ent->name, hfs_info->name);
1723 set_Finfo(hfs_info->finderinfo, hfs_ent);
1728 /* no entry found, so try file extension */
1730 fprintf(stderr, "warning: %s doesn't appear to be a %s file\n",
1731 s_entry->whole_name, hfs_types[ret].desc);
1733 ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1739 * get_sfm_info: get SFM finderinfo for a file
1742 static byte sfm_magic[4] = {0x41, 0x46, 0x50, 0x00};
1743 static byte sfm_version[4] = {0x00, 0x00, 0x01, 0x00};
1746 get_sfm_info(char *hname, /* whole path */
1747 char *dname, /* this dir name */
1748 dir_ent *s_entry, /* directory entry */
1751 sfm_info info; /* finderinfo struct */
1752 int num = -1; /* bytes read */
1753 hfsdirent *hfs_ent = s_entry->hfs_ent;
1755 num = read_info_file(hname, &info, sizeof (info));
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)) {
1762 hstrncpy((unsigned char *)(hfs_ent->name), dname, HFS_MAX_FLEN);
1764 set_Finfo(info.finderinfo, hfs_ent);
1767 /* failed to open/read finderinfo - so try afpfile mapping */
1770 "warning: %s doesn't appear to be a %s file\n",
1771 s_entry->whole_name, hfs_types[ret].desc);
1773 ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1781 * get_xhfs_dir: get MacOS X HFS finderinfo for a directory
1783 * Code ideas from 'hfstar' by Marcel Weiher marcel@metaobject.com
1784 * and another GNU hfstar by Torres Vedras paulotex@yahoo.com
1786 * Here we are dealing with actual HFS files - not some encoding
1787 * we have to use a system call to get the finderinfo
1789 * The file name here is the pseudo name for the resource fork
1792 get_xhfs_dir(char *hname, /* whole path */
1793 char *dname, /* this dir name */
1794 dir_ent *s_entry, /* directory entry */
1798 hfsdirent *hfs_ent = s_entry->hfs_ent;
1800 struct attrlist attrs;
1803 memset(&attrs, 0, sizeof (attrs));
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 |
1811 err = getattrlist(hname, &attrs, &ainfo, sizeof (ainfo), 0);
1815 * If the Finfo is blank then we assume it's not a
1816 * 'true' HFS directory ...
1819 for (i = 0; i < sizeof (ainfo.info); i++) {
1820 if (ainfo.info[i] != 0) {
1827 /* check finder info is OK */
1830 hstrncpy((unsigned char *) (s_entry->hfs_ent->name),
1831 dname, HFS_MAX_FLEN);
1833 set_Dinfo(ainfo.info, hfs_ent);
1837 /* otherwise give it it's Unix name */
1838 hstrncpy((unsigned char *) (s_entry->hfs_ent->name),
1839 dname, HFS_MAX_FLEN);
1845 * get_xhfs_info: get MacOS X HFS finderinfo for a file
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
1851 * Here we are dealing with actual HFS files - not some encoding
1852 * we have to use a system call to get the finderinfo
1854 * The file name here is the pseudo name for the resource fork
1857 get_xhfs_info(char *hname, /* whole path */
1858 char *dname, /* this dir name */
1859 dir_ent *s_entry, /* directory entry */
1863 hfsdirent *hfs_ent = s_entry->hfs_ent;
1865 struct attrlist attrs;
1869 memset(&attrs, 0, sizeof (attrs));
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 |
1877 err = getattrlist(hname, &attrs, &ainfo, sizeof (ainfo), 0);
1879 /* check finder info is OK */
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
1889 if (s_entry->assoc == NULL) {
1891 for (i = 0; i < sizeof (ainfo.info); i++) {
1892 if (ainfo.info[i] != 0) {
1902 hstrncpy((unsigned char *) (hfs_ent->name), dname,
1905 set_Finfo(ainfo.info, hfs_ent);
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
1913 hfs_ent->crdate = d_getl((byte *)&ainfo.ctime.tv_sec);
1915 hfs_ent->mddate = d_getl((byte *)&ainfo.mtime.tv_sec);
1921 /* not a 'true' HFS file - so try afpfile mapping */
1924 * don't print a warning as we will get lots on HFS
1929 "warning: %s doesn't appear to be a %s file\n",
1930 s_entry->whole_name, hfs_types[ret].desc);
1933 ret = get_none_info(hname, dname, s_entry, TYPE_NONE);
1938 #endif /* IS_MACOS_X */
1941 * get_hfs_itype: get the type of HFS info for a file
1944 get_hfs_itype(char *wname, char *dname, char *htmp)
1948 int no_type = TYPE_NONE;
1950 wlen = strlen(wname) - strlen(dname);
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) {
1960 strcpy(htmp, wname);
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 ...
1969 if (hfs_types[i].flags & NOINFO) {
1973 /* append or insert finderinfo filename part */
1974 if (hfs_types[i].flags & APPEND)
1975 strcat(htmp, hfs_types[i].info);
1977 sprintf(htmp + wlen, "%s%s", hfs_types[i].info,
1978 (hfs_types[i].flags & NOPEND) ? "" : dname);
1980 /* hack time ... Netatalk is a special case ... */
1981 if (i == TYPE_NETA) {
1982 strcpy(htmp, wname);
1983 strcat(htmp, "/.AppleDouble/.Parent");
1986 if (!access(htmp, R_OK))
1987 return (hfs_types[i].type);
1995 * set_root_info: set the root folder hfs_ent from given file
1998 set_root_info(char *name)
2004 s_entry = root->self;
2006 hfs_ent = (hfsdirent *) e_malloc(sizeof (hfsdirent));
2007 memset(hfs_ent, 0, sizeof (hfsdirent));
2009 /* make sure root has a valid hfs_ent */
2010 s_entry->hfs_ent = root->hfs_ent = hfs_ent;
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))
2018 if ((*(hfs_types[i].get_dir))(name, "", s_entry, i) == i)
2025 * get_hfs_dir: set the HFS directory name
2028 get_hfs_dir(char *wname, char *dname, dir_ent *s_entry)
2032 /* get the HFS file type from the info file (if it exists) */
2033 type = get_hfs_itype(wname, dname, tmp);
2035 /* try to get the required info */
2036 type = (*(hfs_types[type].get_dir)) (tmp, dname, s_entry, type);
2042 * get_hfs_info: set the HFS info for a file
2045 get_hfs_info(char *wname, char *dname, dir_ent *s_entry)
2051 wlen = strlen(wname) - strlen(dname);
2053 /* we may already know the type of Unix/HFS file - so process */
2054 if (s_entry->hfs_type != TYPE_NONE) {
2056 type = s_entry->hfs_type;
2060 /* append or insert finderinfo filename part */
2061 if (hfs_types[type].flags & APPEND)
2062 strcat(tmp, hfs_types[type].info);
2064 sprintf(tmp + wlen, "%s%s", hfs_types[type].info,
2065 (hfs_types[type].flags & NOPEND) ? "" : dname);
2067 type = (*(hfs_types[type].get_info))(tmp, dname, s_entry, type);
2069 /* if everything is as expected, then return */
2070 if (s_entry->hfs_type == type)
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) {
2082 /* append or insert finderinfo filename part */
2083 if (hfs_types[i].flags & APPEND) {
2084 strcat(tmp, hfs_types[i].info);
2086 sprintf(tmp + wlen, "%s%s", hfs_types[i].info,
2087 (hfs_types[i].flags & NOPEND) ? "" : dname);
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,
2094 s_entry->hfs_type = type;
2099 /* nothing found, so just a Unix file */
2100 type = (*(hfs_types[TYPE_NONE].get_info))(wname, dname,
2101 s_entry, TYPE_NONE);
2107 * get_hfs_rname: set the name of the Unix rsrc file for a file
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 ...
2115 get_hfs_rname(char *wname, char *dname, char *rname)
2122 wlen = strlen(wname) - strlen(dname);
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)
2130 strcpy(rname, wname);
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 */
2136 /* append or insert finderinfo filename part */
2137 if (hfs_types[i].flags & APPEND) {
2138 strcat(rname, hfs_types[i].info);
2140 sprintf(rname + wlen, "%s%s", hfs_types[i].info,
2141 (hfs_types[i].flags & NOPEND) ?
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,
2151 sprintf(rname + wlen, "%s%s",
2152 hfs_types[i].rsrc, dname);
2156 * for some types, a rsrc fork may not exist,
2157 * so just return the current type
2160 if (hfs_types[i].flags & NORSRC ||
2161 !access(rname, R_OK))
2162 return (hfs_types[i].type);
2166 * if we are probing,
2167 * then have a look at the contents to find type
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 */
2176 if ((p_num = read(p_fd, p_buf,
2177 sizeof (p_buf))) <= 0) {
2179 * can't read, or zero length
2185 /* get file pointer and close file */
2186 p_fp = fdopen(p_fd, "rb");
2193 * call routine to do the work
2194 * - use the given dname as this
2195 * is the name we may use on the CD
2197 type = (*(hfs_types[i].get_info)) (rname, dname, 0, i);
2205 * - just use contents of buffer next time
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 ...
2222 hfs_exclude(char *d_name)
2224 /* we don't exclude "." and ".." */
2225 if (strcmp(d_name, ".") == 0)
2227 if (strcmp(d_name, "..") == 0)
2230 /* do not add the following to our list of dir entries */
2231 if (DO_CAP & hselect) {
2233 if (strcmp(d_name, ".finderinfo") == 0)
2235 if (strcmp(d_name, ".resource") == 0)
2237 if (strcmp(d_name, ".ADeskTop") == 0)
2239 if (strcmp(d_name, ".IDeskTop") == 0)
2241 if (strcmp(d_name, "Network Trash Folder") == 0)
2244 * special case when HFS volume is mounted using Linux's hfs_fs
2245 * Brad Midgley <brad@pht.com>
2247 if (strcmp(d_name, ".rootinfo") == 0)
2250 if (DO_ESH & hselect) {
2251 /* Helios EtherShare files */
2252 if (strcmp(d_name, ".rsrc") == 0)
2254 if (strcmp(d_name, ".Desktop") == 0)
2256 if (strcmp(d_name, ".DeskServer") == 0)
2258 if (strcmp(d_name, ".Label") == 0)
2261 if (DO_DBL & hselect) {
2264 * special case when HFS volume is mounted using Linux's hfs_fs
2266 if (strcmp(d_name, "%RootInfo") == 0)
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
2275 if (hex2char(d_name) == 0)
2278 if (DO_NETA & hselect) {
2279 if (strcmp(d_name, ".AppleDouble") == 0)
2281 if (strcmp(d_name, ".AppleDesktop") == 0)
2284 if ((DO_FEU & hselect) || (DO_FEL & hselect)) {
2286 if (strcmp(d_name, "RESOURCE.FRK") == 0)
2288 if (strcmp(d_name, "FINDER.DAT") == 0)
2290 if (strcmp(d_name, "DESKTOP") == 0)
2292 if (strcmp(d_name, "FILEID.DAT") == 0)
2294 if (strcmp(d_name, "resource.frk") == 0)
2296 if (strcmp(d_name, "finder.dat") == 0)
2298 if (strcmp(d_name, "desktop") == 0)
2300 if (strcmp(d_name, "fileid.dat") == 0)
2303 if (DO_SGI & hselect) {
2305 if (strcmp(d_name, ".HSResource") == 0)
2307 if (strcmp(d_name, ".HSancillary") == 0)
2310 if (DO_DAVE & hselect) {
2312 if (strcmp(d_name, "resource.frk") == 0)
2314 if (strcmp(d_name, "DesktopFolderDB") == 0)
2319 * NTFS streams are not "seen" as files,
2320 * so WinNT will not see these files -
2321 * so ignore - used for testing under Unix
2323 if (DO_SFM & hselect) {
2325 char *dn = strrchr(d_name, ':');
2328 if (strcmp(dn, ":Afp_Resource") == 0)
2330 if (strcmp(dn, ":Comments") == 0)
2332 if (strcmp(dn, ":Afp_AfpInfo") == 0)
2338 if (DO_XDBL & hselect) {
2340 if (strncmp(d_name, "._", 2) == 0)
2348 * print_hfs_info: print info about the HFS files.
2352 print_hfs_info(dir_ent *s_entry)
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);
2364 * hfs_init: sets up the mapping list from the afpfile as well
2365 * the default mapping (with or without) an afpfile
2368 hfs_init(char *name, Ushort fdflags, Uint hfs_select)
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 */
2379 /* setup number of Unix/HFS filetype - we may wish to not bother */
2381 hfs_num = sizeof (hfs_types) / sizeof (struct hfs_type);
2384 * code below needs to be tidied up
2385 * - most can be made redundant
2387 for (i = 0; i < hfs_num; i++)
2388 hfs_types[i].flags &= ~1; /* 0xfffffffe */
2390 for (i = 1; i < hfs_num; i++)
2391 if (!((1 << i) & hfs_select))
2392 hfs_types[i].flags |= PROBE;
2394 hselect = hfs_select;
2396 hfs_num = hselect = 0;
2399 for (i = 0; i < hfs_num; i++)
2400 fprintf(stderr, "type = %d flags = %d\n",
2401 i, hfs_types[i].flags);
2404 /* min length set to max to start with */
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));
2419 #endif /* USE_MAGIC */
2422 map_num = last_ent = 0;
2424 /* allocate memory for the default entry */
2425 defmap = (afpmap *) e_malloc(sizeof (afpmap));
2427 /* set default values */
2428 defmap->extn = DEFMATCH;
2430 /* make sure creator and type are 4 chars long */
2431 strcpy(defmap->type, BLANK);
2432 strcpy(defmap->creator, BLANK);
2437 while (*e && (e - deftype) < CT_SIZE)
2441 c = defmap->creator;
2443 while (*e && (e - defcreator) < CT_SIZE)
2446 /* length is not important here */
2450 defmap->fdflags = fdflags;
2452 /* no afpfile - no mappings */
2453 if (*name == '\0') {
2457 if ((fp = fopen(name, "r")) == NULL)
2458 perr("unable to open mapping file");
2460 map = (afpmap **) e_malloc(NUMMAP * sizeof (afpmap *));
2462 /* read afpfile line by line */
2463 while (fgets(buf, PATH_MAX, fp) != NULL) {
2464 /* ignore any comment lines */
2467 if (sscanf(buf, "%1s", c) == EOF || *c == '#')
2470 /* increase list size if needed */
2471 if (map_num == count) {
2473 map = (afpmap **)realloc(map, count * sizeof (afpmap *));
2475 perr("not enough memory");
2477 /* allocate memory for this entry */
2478 amap = (afpmap *) e_malloc(sizeof (afpmap));
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) {
2488 "error scanning afpfile %s - continuing", name);
2492 /* copy the extension found */
2493 if ((amap->extn = (char *) strdup(tmp)) == NULL)
2494 perr("not enough memory");
2496 /* set end-of-string */
2497 *(t + 4) = *(c + 4) = '\0';
2499 /* find the length of the extension */
2500 amap->elen = strlen(amap->extn);
2503 amap->fdflags = fdflags;
2505 /* see if we have the default creator/type */
2506 if (strcmp(amap->extn, DEFMATCH) == 0) {
2507 /* get rid of the old default */
2509 /* make this the default */
2513 /* update the smallest extension length */
2514 mlen = MIN(mlen, amap->elen);
2516 /* add entry to the list */
2517 map[map_num++] = amap;
2521 /* free up some memory */
2522 if (map_num != count) {
2523 map = (afpmap **) realloc(map, map_num * sizeof (afpmap *));
2525 perr("not enough memory");
2531 try_map_magic(char *whole_name, char **type, /* set type */
2532 char **creator /* set creator */)
2534 const char * ret = magic_file(magic_state, whole_name);
2537 fprintf(stderr, "magic_file(magic_state, \"%s\"): %s\n",
2538 whole_name, ret ? ret : "NULL");
2541 * check that we found a match; ignore results in the
2542 * wrong format (probably due to libmagic's built-in rules)
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;
2552 fprintf(stderr, "tmp_type = \"%s\"; tmp_creator = \"%s\"\n",
2553 tmp_type, tmp_creator);
2556 *creator = tmp_creator;
2562 #endif /* USE_MAGIC */
2565 * map_ext: map a files extension with the list to get type/creator
2568 map_ext(char *name, /* filename */
2569 char **type, /* set type */
2570 char **creator, /* set creator */
2571 short *fdflags, /* set finder flags */
2574 int i; /* loop counter */
2575 int len; /* filename length */
2576 afpmap *amap; /* mapping entry */
2579 /* we don't take fdflags from the map or magic file */
2580 *fdflags = defmap->fdflags;
2584 * if we have a magic file and we want to search it first,
2585 * then try to get a match
2587 if (magic_state && hfs_last == MAP_LAST
2588 && try_map_magic(whole_name, type, creator))
2590 #endif /* USE_MAGIC */
2594 /* have an afpfile and filename if long enough */
2595 if (map && len >= mlen) {
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
2601 for (i = 0; i < map_num; i++) {
2602 amap = map[last_ent];
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 */
2609 *creator = amap->creator;
2610 *fdflags = amap->fdflags;
2614 * move on to the next entry - wrapping round
2618 last_ent %= map_num;
2622 * if no matches are found, file name too short, or no afpfile,
2623 * then take defaults
2625 *type = defmap->type;
2626 *creator = defmap->creator;
2630 * if we have a magic file and we haven't searched yet,
2631 * then try to get a match
2633 if (magic_state && hfs_last == MAG_LAST)
2634 try_map_magic(whole_name, type, creator);
2635 #endif /* USE_MAGIC */
2639 delete_rsrc_ent(dir_ent *s_entry)
2641 dir_ent *s_entry1 = s_entry->next;
2643 if (s_entry1 == NULL)
2646 s_entry->next = s_entry1->next;
2647 s_entry->assoc = NULL;
2649 free(s_entry1->name);
2650 free(s_entry1->whole_name);
2666 magic_close(magic_state);
2669 #endif /* USE_MAGIC */
2672 #endif /* APPLE_HYB */
2677 #ifdef USE_LIBSCHILY
2681 comerr("<no error message given>\n");
2684 fprintf(stderr, "mkhybrid: %s\n", a);