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