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