1 /* 2 ** Unix-HFS file interface including maping file extensions to TYPE/CREATOR 3 ** 4 ** Adapted from mkhfs routines for mkhybrid 5 ** 6 ** James Pearson 1/5/97 7 ** Bug fix JCP 4/12/97 8 ** Updated for 1.12 and added more Unix HFS filetypes. JCP 21/1/98 9 ** 10 ** Things still to de done: 11 ** 12 ** Check SGI (XINET) structs 13 ** Check file size = finder + rsrc [+ data] is needed 14 ** AppleSingle/Double version 2? 15 ** Clean up byte order swapping. 16 */ 17 18 #ifdef APPLE_HYB 19 20 #include <ctype.h> 21 #include <errno.h> 22 #include <unistd.h> 23 #include <err.h> 24 #include <fcntl.h> 25 #include <config.h> 26 #include <stdlib.h> 27 #include <sys/types.h> 28 #include <netinet/in.h> 29 #include <apple.h> 30 #include "apple_proto.h" 31 #include <mkisofs.h> 32 33 /* tidy up mkisofs definition ... */ 34 typedef struct directory_entry dir_ent; 35 36 /* routines for getting HFS names and info */ 37 static int get_none_dir(char *, char *, dir_ent *, int); 38 static int get_none_info(char *, char *, dir_ent *, int); 39 static int get_cap_dir(char *, char *, dir_ent *, int); 40 static int get_cap_info(char *, char *, dir_ent *, int); 41 static int get_es_info(char *, char *, dir_ent *, int); 42 static int get_dbl_info(char *, char *, dir_ent *, int); 43 static int get_mb_info(char *, char *, dir_ent *, int); 44 static int get_sgl_info(char *, char *, dir_ent *, int); 45 static int get_fe_dir(char *, char *, dir_ent *, int); 46 static int get_fe_info(char *, char *, dir_ent *, int); 47 static int get_sgi_dir(char *, char *, dir_ent *, int); 48 static int get_sgi_info(char *, char *, dir_ent *, int); 49 50 void map_ext(char *, char **, char **, unsigned short *, char *); 51 static afpmap **map; /* list of mappings */ 52 static afpmap *defmap; /* the default mapping */ 53 static int last_ent; /* previous mapped entry */ 54 static int map_num; /* number of mappings */ 55 static int mlen; /* min extension length */ 56 static char tmp[MAXPATHLEN]; /* tmp working buffer */ 57 static int hfs_num; /* number of file types */ 58 static char p_buf[MAXPATHLEN]; /* info working buffer */ 59 static FILE *p_fp = NULL; /* probe File pointer */ 60 static int p_num = 0; /* probe bytes read */ 61 static unsigned int hselect; /* type of HFS file selected */ 62 63 struct hfs_type { /* Types of various HFS Unix files */ 64 int type; /* type of file */ 65 int flags; /* special flags */ 66 char *info; /* finderinfo name */ 67 char *rsrc; /* resource fork name */ 68 int (*get_info)(char*, char*, dir_ent*,int); /* finderinfo function */ 69 int (*get_dir)(char*, char*,dir_ent*,int); /* directory name function */ 70 char *desc; /* description */ 71 }; 72 73 /* Above filled in */ 74 static struct hfs_type hfs_types[] = { 75 {TYPE_NONE,0,"", "", get_none_info, get_none_dir,"None"}, 76 {TYPE_CAP,0,".finderinfo/", ".resource/", get_cap_info, get_cap_dir,"CAP"}, 77 {TYPE_NETA,0,".AppleDouble/", ".AppleDouble/", get_dbl_info, get_none_dir,"Netatalk"}, 78 {TYPE_DBL,0,"%", "%", get_dbl_info, get_none_dir,"AppleDouble"}, 79 {TYPE_ESH, 0,".rsrc/", ".rsrc/", get_es_info, get_none_dir,"EtherShare/UShare"}, 80 {TYPE_FEU,2,"FINDER.DAT", "RESOURCE.FRK/", get_fe_info, get_fe_dir,"Exchange"}, 81 {TYPE_FEL,2,"finder.dat", "resource.frk/", get_fe_info, get_fe_dir,"Exchange"}, 82 {TYPE_SGI,2,".HSancillary", ".HSResource/", get_sgi_info, get_sgi_dir,"XINET/SGI"}, 83 {TYPE_MBIN,1,"", "", get_mb_info, get_none_dir,"MacBinary"}, 84 {TYPE_SGL,1,"", "", get_sgl_info, get_none_dir,"AppleSingle"} 85 }; 86 87 /* used by get_magic_match() return */ 88 static char tmp_type[CT_SIZE+1], tmp_creator[CT_SIZE+1]; 89 90 /* 91 ** cstrncopy: Cap Unix name to HFS name 92 ** 93 ** ':' is replaced by '%' and string is terminated with '\0' 94 */ 95 void 96 cstrncpy(char *t, char *f, int c) 97 { 98 while (c-- && *f) 99 { 100 switch (*f) 101 { 102 case ':': 103 *t = '%'; 104 break; 105 default: 106 *t = *f; 107 break; 108 } 109 t++; f++; 110 } 111 112 *t = '\0'; 113 } 114 /* 115 ** dehex() 116 ** 117 ** Given a hexadecimal digit in ASCII, return the integer representation. 118 ** 119 ** Taken from linux/fs/hfs/trans.c by Paul H. Hargrove 120 */ 121 static unsigned char 122 dehex(char c) 123 { 124 if ((c>='0')&&(c<='9')) { 125 return c-'0'; 126 } 127 if ((c>='a')&&(c<='f')) { 128 return c-'a'+10; 129 } 130 if ((c>='A')&&(c<='F')) { 131 return c-'A'+10; 132 } 133 /* return 0xff; */ 134 return (0); 135 } 136 137 static unsigned char 138 hex2char(char *s) 139 { 140 unsigned char o; 141 142 if(strlen(++s) < 2) 143 return(0); 144 145 if (!isxdigit(*s) || !isxdigit(*(s+1))) 146 return(0); 147 148 o = (dehex(*s) << 4) & 0xf0; 149 s++; 150 o |= (dehex(*s) & 0xf); 151 152 return (o); 153 } 154 155 /* 156 ** hstrncpy: Unix name to HFS name with special character 157 ** translation. 158 ** 159 ** "%xx" or ":xx" is assumed to be a "special" character and 160 ** replaced by character code given by the hex characters "xx" 161 ** 162 ** if "xx" is not a hex number, then it is left alone - except 163 ** that ":" is replaced by "%" 164 ** 165 */ 166 void 167 hstrncpy(unsigned char *t, char *f, int c) 168 { 169 unsigned char o; 170 while (c-- && *f) 171 { 172 switch (*f) 173 { 174 case ':': 175 case '%': 176 if ((o = hex2char(f)) == 0) { 177 *t = '%'; 178 } 179 else { 180 *t = o; 181 f += 2; 182 } 183 break; 184 default: 185 *t = *f; 186 break; 187 } 188 t++; f++; 189 } 190 191 *t = '\0'; 192 } 193 194 /* 195 ** basename: find just the filename with any directory component 196 */ 197 /* not used at the moment ... 198 static char 199 basename(char *a) 200 { 201 char *b; 202 203 if((b = strchr(a, '/'))) 204 return(++b); 205 else 206 return(a); 207 } 208 */ 209 210 /* 211 ** get_none_dir: ordinary Unix directory 212 */ 213 int 214 get_none_dir(char *hname, char *dname, dir_ent *s_entry, int ret) 215 { 216 /* just copy the given name */ 217 hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN); 218 219 return(ret); 220 } 221 222 /* 223 ** get_none_info: ordinary Unix file - try to map extension 224 */ 225 int 226 get_none_info(char *hname, char *dname, dir_ent *s_entry, int ret) 227 { 228 char *t, *c; 229 hfsdirent *hfs_ent = s_entry->hfs_ent; 230 231 map_ext(dname, &t, &c, &s_entry->hfs_ent->fdflags, s_entry->whole_name); 232 233 /* just copy the given name */ 234 hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN); 235 236 strncpy(hfs_ent->type, t, CT_SIZE); 237 strncpy(hfs_ent->creator, c, CT_SIZE); 238 hfs_ent->type[CT_SIZE] = '\0'; 239 hfs_ent->creator[CT_SIZE] = '\0'; 240 241 return(ret); 242 } 243 /* 244 ** read_info_file: open and read a finderinfo file for an HFS file 245 ** or directory 246 */ 247 int 248 read_info_file(char *name, void *info, int len) 249 /* char *name; finderinfo filename */ 250 /* void *info; info buffer */ 251 /* int len; length of above */ 252 { 253 FILE *fp; 254 int num; 255 256 /* clear out any old finderinfo stuf */ 257 memset(info, 0, len); 258 259 if ((fp = fopen(name,"rb")) == NULL) 260 return(-1); 261 262 /* read and ignore if the file is short - checked later */ 263 num = fread(info,1,len,fp); 264 265 fclose(fp); 266 267 return(num); 268 } 269 /* 270 ** get_cap_dir: get the CAP name for a directory 271 */ 272 int 273 get_cap_dir(char *hname, char *dname, dir_ent *s_entry, int ret) 274 /* char *hname whole path */ 275 /* char *dname this dir name */ 276 /* dir_ent *s_entry directory entry */ 277 { 278 FileInfo info; /* finderinfo struct */ 279 int num = -1; /* bytes read */ 280 281 num = read_info_file(hname, &info, sizeof(FileInfo)); 282 283 /* check finder info is OK */ 284 if (num > 0 285 && info.fi_magic1 == FI_MAGIC1 286 && info.fi_magic == FI_MAGIC 287 && info.fi_bitmap & FI_BM_MACINTOSHFILENAME) { 288 /* use the finderinfo name if it exists */ 289 cstrncpy(s_entry->hfs_ent->name, info.fi_macfilename, HFS_MAX_FLEN); 290 return (ret); 291 } 292 else { 293 /* otherwise give it it's Unix name */ 294 hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN); 295 return (TYPE_NONE); 296 } 297 } 298 299 /* 300 ** get_cap_info: get CAP finderinfo for a file 301 */ 302 int 303 get_cap_info(char *hname, char *dname, dir_ent *s_entry, int ret) 304 /* char *hname whole path */ 305 /* char *dname this dir name */ 306 /* dir_ent *s_entry directory entry */ 307 { 308 FileInfo info; /* finderinfo struct */ 309 int num = -1; /* bytes read */ 310 char *c; 311 char *t; 312 hfsdirent *hfs_ent = s_entry->hfs_ent; 313 314 num = read_info_file(hname, &info, sizeof(info)); 315 316 /* check finder info is OK */ 317 if (num > 0 318 && info.fi_magic1 == FI_MAGIC1 319 && info.fi_magic == FI_MAGIC) { 320 321 if (info.fi_bitmap & FI_BM_MACINTOSHFILENAME) { 322 /* use the finderinfo name if it exists */ 323 cstrncpy(hfs_ent->name, info.fi_macfilename, HFS_MAX_FLEN); 324 } 325 else { 326 /* use Unix name */ 327 hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN); 328 } 329 330 /* type and creator from finder info */ 331 t = info.fdType; 332 c = info.fdCreator; 333 334 strncpy(hfs_ent->type, t, CT_SIZE); 335 strncpy(hfs_ent->creator, c, CT_SIZE); 336 hfs_ent->type[CT_SIZE] = '\0'; 337 hfs_ent->creator[CT_SIZE] = '\0'; 338 339 /* finder flags */ 340 hfs_ent->fdflags = d_getw((unsigned char *)&info.fdFlags); 341 /* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */ 342 hfs_ent->fdflags &= 0xfeff; 343 344 #ifdef USE_MAC_DATES 345 /* set created/modified dates - these date should have already 346 been set from the Unix data fork dates. The finderinfo dates 347 are in Mac format - but we have to convert them back to Unix 348 for the time being */ 349 if ((info.fi_datemagic & FI_CDATE)) { 350 /* use libhfs routines to get correct byte order */ 351 hfs_ent->crdate = d_toutime(d_getl(info.fi_ctime)); 352 } 353 if (info.fi_datemagic & FI_MDATE) { 354 hfs_ent->mddate = d_toutime(d_getl(info.fi_mtime)); 355 } 356 #endif /* USE_MAC_DATES */ 357 } 358 else { 359 /* failed to open/read finderinfo - so try afpfile mapping */ 360 if (verbose > 2) { 361 fprintf(stderr, "warning: %s doesn't appear to be a %s file\n", 362 s_entry->whole_name, hfs_types[ret].desc); 363 } 364 365 ret = get_none_info(hname, dname, s_entry, TYPE_NONE); 366 } 367 368 return (ret); 369 } 370 371 /* 372 ** get_es_info: get EtherShare/UShare finderinfo for a file 373 ** 374 ** based on code from Jens-Uwe Mager (jum@helios.de) and Phil Sylvester 375 ** <psylvstr@interaccess.com> 376 */ 377 int 378 get_es_info(char *hname, char *dname, dir_ent *s_entry, int ret) 379 /* char *hname whole path */ 380 /* char *dname this dir name */ 381 /* dir_ent *s_entry directory entry */ 382 { 383 es_FileInfo *einfo; /* EtherShare info struct */ 384 us_FileInfo *uinfo; /* UShare info struct */ 385 char info[ES_INFO_SIZE]; /* finderinfo buffer */ 386 int num = -1; /* bytes read */ 387 char *c; 388 char *t; 389 hfsdirent *hfs_ent = s_entry->hfs_ent; 390 dir_ent *s_entry1; 391 392 /* the EtherShare and UShare file layout is the same, but they 393 store finderinfo differently */ 394 einfo = (es_FileInfo *)info; 395 uinfo = (us_FileInfo *)info; 396 397 num = read_info_file(hname, info, sizeof(info)); 398 399 /* check finder info for EtherShare finderinfo */ 400 if (num >= sizeof(es_FileInfo) && 401 ntohl(einfo->magic) == ES_MAGIC && 402 ntohs(einfo->version) == ES_VERSION) { 403 404 /* type and creator from finder info */ 405 t = einfo->fdType; 406 c = einfo->fdCreator; 407 408 /* finder flags */ 409 hfs_ent->fdflags = d_getw((unsigned char *)&einfo->fdFlags); 410 411 /* set create date - modified date set from the Unix data 412 fork date */ 413 hfs_ent->crdate = d_getl((unsigned char *)&einfo->createTime); 414 } 415 else if (num >= sizeof(us_FileInfo)) { 416 /* UShare has no magic number, so we assume that this is 417 a valid info/resource file ... */ 418 419 /* type and creator from finder info */ 420 t = uinfo->fdType; 421 c = uinfo->fdCreator; 422 423 /* finder flags */ 424 hfs_ent->fdflags = d_getw((unsigned char *)&uinfo->fdFlags); 425 426 /* set create and modified date - if they exist */ 427 if (uinfo->ctime) 428 hfs_ent->crdate = d_getl((unsigned char *)&uinfo->ctime); 429 430 if (uinfo->mtime) 431 hfs_ent->mddate = d_getl((unsigned char *)&uinfo->mtime); 432 } 433 else { 434 /* failed to open/read finderinfo - so try afpfile mapping */ 435 if (verbose > 2) { 436 fprintf(stderr, "warning: %s doesn't appear to be a %s file\n", 437 s_entry->whole_name, hfs_types[ret].desc); 438 } 439 440 ret = get_none_info(hname, dname, s_entry, TYPE_NONE); 441 return (ret); 442 } 443 444 /* this should exist ... */ 445 if ((s_entry1 = s_entry->assoc) == NULL) 446 errx(1, "TYPE_ESH error - shouldn't happen!"); 447 448 /* fill in the HFS info stuff */ 449 strncpy(hfs_ent->type, t, CT_SIZE); 450 strncpy(hfs_ent->creator, c, CT_SIZE); 451 hfs_ent->type[CT_SIZE] = '\0'; 452 hfs_ent->creator[CT_SIZE] = '\0'; 453 454 /* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */ 455 hfs_ent->fdflags &= 0xfeff; 456 457 /* set name */ 458 hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN); 459 460 /* real rsrc file starts ES_INFO_SIZE bytes into the file */ 461 if(s_entry1->size <= ES_INFO_SIZE) { 462 s_entry1->size = 0; 463 hfs_ent->rsize = 0; 464 } 465 else { 466 s_entry1->size -= ES_INFO_SIZE; 467 hfs_ent->rsize = s_entry1->size; 468 s_entry1->hfs_off = ES_INFO_SIZE; 469 } 470 471 set_733((char *) s_entry1->isorec.size, s_entry1->size); 472 473 return (ret); 474 } 475 476 /* 477 * calc_crc() -- 478 * Compute the MacBinary II-style CRC for the data pointed to by p, with the 479 * crc seeded to seed. 480 * 481 * Modified by Jim Van Verth to use the magic array for efficiency. 482 */ 483 static unsigned short 484 calc_mb_crc(unsigned char *p, long len, unsigned short seed) 485 { 486 unsigned short hold; /* crc computed so far */ 487 long i; /* index into data */ 488 489 hold = seed; /* start with seed */ 490 for (i = 0; i < len; i++, p++) { 491 hold ^= (*p << 8); 492 hold = (hold << 8) ^ mb_magic[(unsigned char)(hold >> 8)]; 493 } 494 495 return (hold); 496 } /* calc_mb_crc() */ 497 498 int 499 get_mb_info(char *hname, char *dname, dir_ent *s_entry, int ret) 500 /* char *hname whole path */ 501 /* char *dname this dir name */ 502 /* dir_ent *s_entry directory entry */ 503 { 504 mb_info *info; /* finderinfo struct */ 505 char *c; 506 char *t; 507 hfsdirent *hfs_ent; 508 dir_ent *s_entry1; 509 int i; 510 #ifdef TEST_CODE 511 unsigned short crc_file, crc_calc; 512 #endif 513 514 info = (mb_info *)p_buf; 515 516 /* routine called twice for each file - first to check that 517 it is a valid MacBinary file, second to fill in the HFS 518 info. p_buf holds the required raw data and it *should* 519 remain the same between the two calls */ 520 521 if (s_entry == 0) { 522 /* test that the CRC is OK - not set for MacBinary I files 523 (and incorrect in some MacBinary II files!). If this 524 fails, then perform some other checks */ 525 526 #ifdef TEST_CODE 527 /* leave this out for the time being ... */ 528 if (p_num >= MB_SIZE && info->version == 0 && info->zero1 == 0) { 529 crc_calc = calc_mb_crc((unsigned char *)info, 124, 0); 530 crc_file = d_getw(info->crc); 531 #ifdef DEBUG 532 fprintf(stderr,"%s: file %d, calc %d\n",hname,crc_file,crc_calc); 533 #endif /* DEBUG */ 534 if (crc_file == crc_calc) 535 return (ret); 536 } 537 #endif /* TEST_CODE */ 538 539 /* check some of the fields for a valid MacBinary file 540 not zero1 and zero2 SHOULD be zero - but some files incorrect */ 541 542 /* if (p_num < MB_SIZE || info->nlen > 63 || info->zero2 || */ 543 if (p_num < MB_SIZE || info->zero1 || 544 info->zero2 || info->nlen > 63 || 545 info->version || info->nlen == 0 || *info->name == 0) 546 return (TYPE_NONE); 547 548 /* check that the filename is OKish */ 549 for (i=0;i<info->nlen;i++) 550 if(info->name[i] == 0) 551 return (TYPE_NONE); 552 553 /* check CREATOR and TYPE are valid */ 554 for (i=0;i<4;i++) 555 if(info->type[i] == 0 || info->auth[i] == 0) 556 return (TYPE_NONE); 557 } 558 else { 559 /* we have a vaild MacBinary file, so fill in the bits */ 560 561 /* this should exist ... */ 562 if((s_entry1 = s_entry->assoc) == NULL) 563 errx(1, "TYPE_MBIN error - shouldn't happen!"); 564 565 hfs_ent = s_entry->hfs_ent; 566 567 /* type and creator from finder info */ 568 t = info->type; 569 c = info->auth; 570 571 strncpy(hfs_ent->type, t, CT_SIZE); 572 strncpy(hfs_ent->creator, c, CT_SIZE); 573 hfs_ent->type[CT_SIZE] = '\0'; 574 hfs_ent->creator[CT_SIZE] = '\0'; 575 576 /* finder flags */ 577 hfs_ent->fdflags = ((info->flags << 8) & 0xff00) | info->flags2; 578 /* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */ 579 hfs_ent->fdflags &= 0xfeff; 580 581 /* set created/modified dates - these date should have already 582 been set from the Unix data fork dates. The finderinfo dates 583 are in Mac format - but we have to convert them back to Unix 584 for the time being */ 585 586 hfs_ent->crdate = d_toutime(d_getl(info->cdate)); 587 hfs_ent->mddate = d_toutime(d_getl(info->mdate)); 588 589 /* set name */ 590 /* hstrncpy(hfs_ent->name, info->name, HFS_MAX_FLEN); */ 591 hstrncpy(hfs_ent->name, info->name, MIN(HFS_MAX_FLEN, info->nlen)); 592 593 /* set correct fork sizes */ 594 hfs_ent->dsize = d_getl(info->dflen); 595 hfs_ent->rsize = d_getl(info->rflen); 596 597 /* update directory entries for data fork */ 598 s_entry->size = hfs_ent->dsize; 599 s_entry->hfs_off = MB_SIZE; 600 set_733((char *) s_entry->isorec.size, s_entry->size); 601 602 /* real rsrc file starts after data fork (must be a multiple 603 of MB_SIZE) */ 604 s_entry1->size = hfs_ent->rsize; 605 s_entry1->hfs_off = MB_SIZE + V_ROUND_UP(hfs_ent->dsize, MB_SIZE); 606 set_733((char *) s_entry1->isorec.size, s_entry1->size); 607 } 608 609 return (ret); 610 } 611 612 /* 613 ** get_dbl_info: get Apple double finderinfo for a file 614 ** 615 ** Based on code from cvt2cap.c (c) May 1988, Paul Campbell 616 */ 617 int 618 get_dbl_info(char *hname, char *dname, dir_ent *s_entry, int ret) 619 /* char *hname whole path */ 620 /* char *dname this dir name */ 621 /* dir_ent *s_entry directory entry */ 622 { 623 FileInfo info; /* finderinfo struct */ 624 a_hdr *hp; 625 a_entry *ep; 626 int num = -1; /* bytes read */ 627 char *c; 628 char *t; 629 int nentries; 630 FILE *fp; 631 hfsdirent *hfs_ent = s_entry->hfs_ent; 632 dir_ent *s_entry1; 633 char name[64]; 634 int i; 635 int fail = 0; 636 637 hp = (a_hdr *)p_buf;; 638 memset(hp, 0, A_HDR_SIZE); 639 640 memset(name, 0, sizeof(name)); 641 642 /* get the rsrc file info - should exist ... */ 643 if ((s_entry1 = s_entry->assoc) == NULL) 644 errx(1, "TYPE_DBL error - shouldn't happen!"); 645 646 /* open and read the info/rsrc file (it's the same file) */ 647 if ((fp = fopen(hname,"rb")) != NULL) 648 num = fread(hp, 1, A_HDR_SIZE, fp); 649 650 /* check finder info is OK - some Netatalk files don't have 651 magic or version set - ignore if it's a netatalk file */ 652 if (num == A_HDR_SIZE && ((ret == TYPE_NETA) || 653 (ntohl(hp->magic) == APPLE_DOUBLE && 654 ntohl(hp->version) == A_VERSION))) { 655 656 /* read TOC of the AppleDouble file */ 657 nentries = (int)ntohs(hp->nentries); 658 if(fread(hp->entries, A_ENTRY_SIZE, nentries, fp) < 1) { 659 fail = 1; 660 nentries = 0; 661 } 662 663 /* extract what is needed */ 664 for (i=0, ep=hp->entries; i<nentries; i++,ep++) { 665 switch(ntohl(ep->id)) { 666 case ID_FINDER: 667 /* get the finder info */ 668 fseek(fp, ntohl(ep->offset), 0); 669 if (fread(&info, ntohl(ep->length), 1, fp) < 1) { 670 fail = 1; 671 } 672 break; 673 case ID_RESOURCE: 674 /* set the offset and correct rsrc fork size */ 675 s_entry1->size = ntohl(ep->length); 676 hfs_ent->rsize = s_entry1->size; 677 /* offset to start of real rsrc fork */ 678 s_entry1->hfs_off = ntohl(ep->offset); 679 set_733((char *) s_entry1->isorec.size, s_entry1->size); 680 break; 681 case ID_NAME: 682 /* get Mac file name */ 683 fseek(fp, ntohl(ep->offset), 0); 684 if(fread(name, ntohl(ep->length), 1, fp) < 1) 685 *name = '\0'; 686 break; 687 default: 688 break; 689 } 690 } 691 692 fclose(fp); 693 694 /* skip this if we had a problem */ 695 if (!fail) { 696 /* type and creator from finder info */ 697 t = info.fdType; 698 c = info.fdCreator; 699 700 strncpy(hfs_ent->type, t, CT_SIZE); 701 strncpy(hfs_ent->creator, c, CT_SIZE); 702 hfs_ent->type[CT_SIZE] = '\0'; 703 hfs_ent->creator[CT_SIZE] = '\0'; 704 705 /* finder flags */ 706 hfs_ent->fdflags = d_getw((unsigned char *)&info.fdFlags); 707 /* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */ 708 hfs_ent->fdflags &= 0xfeff; 709 710 /* use stored name if it exists */ 711 if (*name) 712 cstrncpy(hfs_ent->name, name, HFS_MAX_FLEN); 713 else 714 hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN); 715 } 716 } 717 else { 718 /* failed to open/read finderinfo */ 719 fail = 1; 720 if (fp) 721 fclose(fp); 722 } 723 724 if (fail) { 725 /* problem with the file - try mapping/magic */ 726 if (verbose > 2) { 727 fprintf(stderr, "warning: %s doesn't appear to be a %s file\n", 728 s_entry->whole_name, hfs_types[ret].desc); 729 } 730 ret = get_none_info(hname, dname, s_entry, TYPE_NONE); 731 } 732 733 return (ret); 734 } 735 /* 736 ** get_sgl_info: get Apple single finderinfo for a file 737 ** 738 ** Based on code from cvt2cap.c (c) May 1988, Paul Campbell 739 */ 740 int 741 get_sgl_info(char *hname, char *dname, dir_ent *s_entry, int ret) 742 /* char *hname whole path */ 743 /* char *dname this dir name */ 744 /* dir_ent *s_entry directory entry */ 745 { 746 FileInfo *info = 0; /* finderinfo struct */ 747 a_hdr *hp; 748 static a_entry *entries; 749 a_entry *ep; 750 char *c; 751 char *t; 752 int nentries; 753 hfsdirent *hfs_ent; 754 dir_ent *s_entry1; 755 char name[64]; 756 int i; 757 758 /* routine called twice for each file - first to check that 759 it is a valid MacBinary file, second to fill in the HFS 760 info. p_buf holds the required raw data and it *should* 761 remain the same between the two calls */ 762 763 hp = (a_hdr *)p_buf; 764 765 if (s_entry == 0) { 766 if (p_num < A_HDR_SIZE || 767 ntohl(hp->magic) != APPLE_SINGLE || 768 ntohl(hp->version) != A_VERSION) 769 return (TYPE_NONE); 770 771 /* check we have TOC for the AppleSingle file */ 772 nentries = (int)ntohs(hp->nentries); 773 if (p_num < (A_HDR_SIZE + nentries*A_ENTRY_SIZE)) 774 return (TYPE_NONE); 775 776 /* save the TOC */ 777 entries = (a_entry *)e_malloc(nentries*A_ENTRY_SIZE); 778 779 memcpy(entries, (p_buf+A_HDR_SIZE), nentries*A_ENTRY_SIZE); 780 } 781 else { 782 /* have a vaild AppleSingle File */ 783 memset(name, 0, sizeof(name)); 784 785 /* get the rsrc file info - should exist ... */ 786 if ((s_entry1 = s_entry->assoc) == NULL) 787 errx(1, "TYPE_SGL error - shouldn't happen!"); 788 789 hfs_ent = s_entry->hfs_ent; 790 791 nentries = (int)ntohs(hp->nentries); 792 793 /* extract what is needed */ 794 for (i=0, ep=entries; i<nentries; i++,ep++) { 795 switch(ntohl(ep->id)) { 796 case ID_FINDER: 797 /* get the finder info */ 798 info = (FileInfo *)(p_buf + ntohl(ep->offset)); 799 break; 800 case ID_DATA: 801 /* set the offset and correct data fork size */ 802 hfs_ent->dsize = s_entry->size = ntohl(ep->length); 803 /* offset to start of real data fork */ 804 s_entry->hfs_off = ntohl(ep->offset); 805 set_733((char *) s_entry->isorec.size, s_entry->size); 806 break; 807 case ID_RESOURCE: 808 /* set the offset and correct rsrc fork size */ 809 hfs_ent->rsize = s_entry1->size = ntohl(ep->length); 810 /* offset to start of real rsrc fork */ 811 s_entry1->hfs_off = ntohl(ep->offset); 812 set_733((char *) s_entry1->isorec.size, s_entry1->size); 813 break; 814 case ID_NAME: 815 strncpy(name, (p_buf+ntohl(ep->offset)), 816 ntohl(ep->length)); 817 break; 818 default: 819 break; 820 } 821 } 822 823 free(entries); 824 825 if (info == NULL) { 826 /* failed to open/read finderinfo - so try afpfile mapping */ 827 if (verbose > 2) { 828 fprintf(stderr, "warning: %s doesn't appear to be a %s file\n", 829 s_entry->whole_name, hfs_types[ret].desc); 830 } 831 ret = get_none_info(hname, dname, s_entry, TYPE_NONE); 832 return (ret); 833 } 834 835 /* type and creator from finder info */ 836 t = info->fdType; 837 c = info->fdCreator; 838 839 strncpy(hfs_ent->type, t, CT_SIZE); 840 strncpy(hfs_ent->creator, c, CT_SIZE); 841 hfs_ent->type[CT_SIZE] = '\0'; 842 hfs_ent->creator[CT_SIZE] = '\0'; 843 844 /* finder flags */ 845 hfs_ent->fdflags = d_getw((unsigned char *)&info->fdFlags); 846 /* clear HFS_FNDR_HASBEENINITED to have tidy desktop ?? */ 847 hfs_ent->fdflags &= 0xfeff; 848 849 /* use stored name if it exists */ 850 if (*name) 851 cstrncpy(hfs_ent->name, name, HFS_MAX_FLEN); 852 else 853 hstrncpy(hfs_ent->name, dname, HFS_MAX_FLEN); 854 } 855 856 return (ret); 857 } 858 859 /* 860 ** get_hfs_fe_info: read in the whole finderinfo for a PC Exchange 861 ** directory - saves on reading this many times for each file. 862 ** 863 ** Based of information provided by Mark Weinstein <mrwesq@earthlink.net> 864 ** 865 ** Note: the FINDER.DAT file layout depends on the FAT cluster size 866 ** therefore, files should only be read directly from the FAT media 867 ** 868 ** Only tested with PC Exchange v2.1 - don't know if it will work 869 ** with v2.2 and above. 870 */ 871 struct hfs_info * 872 get_hfs_fe_info(struct hfs_info *hfs_info, char *name) 873 { 874 FILE *fp; 875 #ifdef __svr4__ 876 struct statvfs fsbuf; 877 #else 878 struct statfs fsbuf; 879 #endif /* __svr4__ */ 880 int fe_num, fe_pad; 881 fe_info info; 882 int c = 0; 883 struct hfs_info *hfs_info1 = NULL; 884 hfsdirent *hfs_ent; 885 char keyname[12]; 886 char *s, *e, *k; 887 int i; 888 889 if ((fp = fopen(name, "rb")) == NULL) 890 return(NULL); 891 892 /* The FAT cluster size may have been given on the command line 893 - if not they try and find *guess* it */ 894 if (!bsize) { 895 /* FINDER.DAT layout depends on the FAT cluster size - assume 896 this is mapped to the "fundamental file system block size" 897 For SVR4 we use statvfs(), others use statfs() */ 898 #ifdef __svr4__ 899 if (statvfs(name, &fsbuf) < 0) 900 return(NULL); 901 902 bsize = fsbuf.f_frsize; 903 #else 904 if (statfs(name, &fsbuf) < 0) 905 return(NULL); 906 907 bsize = fsbuf.f_bsize; 908 #endif /* __svr4__ */ 909 } 910 911 if (bsize <= 0) 912 return(NULL); 913 914 fe_num = bsize/FE_SIZE; 915 fe_pad = bsize%FE_SIZE; 916 917 while(fread(&info, 1, FE_SIZE, fp) != 0) { 918 919 /* the Mac name may be NULL - so ignore this entry */ 920 if (info.nlen != 0) { 921 922 hfs_info1 = (struct hfs_info *)e_malloc(sizeof(struct hfs_info)); 923 /* add this entry to the list */ 924 hfs_info1->next = hfs_info; 925 hfs_info = hfs_info1; 926 927 hfs_ent = &hfs_info1->hfs_ent; 928 929 /* get the bits we need - ignore [cm]time for the moment */ 930 cstrncpy(hfs_ent->name, info.name, info.nlen); 931 932 strncpy(hfs_ent->type, info.type, CT_SIZE); 933 strncpy(hfs_ent->creator, info.creator, CT_SIZE); 934 935 hfs_ent->type[CT_SIZE] = hfs_ent->creator[CT_SIZE] = '\0'; 936 937 hfs_ent->fdflags = d_getw(info.flags); 938 939 s = info.sname; 940 e = info.ext; 941 k = keyname; 942 943 /* short (Unix) name is stored in PC format, so needs 944 to be mangled a bit */ 945 946 /* name part */ 947 for(i=0;i<8;i++,s++,k++) { 948 if(*s == ' ') 949 break; 950 else 951 *k = *s; 952 } 953 954 /* extension - if it exists */ 955 if (strncmp(info.ext, " ", 3)) { 956 *k = '.'; 957 k++; 958 for(i=0;i<3;i++,e++,k++) { 959 if(*e == ' ') 960 break; 961 else 962 *k = *e; 963 } 964 } 965 *k = '\0'; 966 967 hfs_info1->keyname = strdup(keyname); 968 } 969 970 /* each record is FE_SIZE long, and there are FE_NUM 971 per each "cluster size", so we may need to skip the padding */ 972 if (++c == fe_num) { 973 c = 0; 974 fseek(fp, fe_pad, 1); 975 } 976 } 977 fclose (fp); 978 979 return (hfs_info); 980 } 981 982 /* 983 ** get_hfs_sgi_info: read in the whole finderinfo for a SGI (XINET) 984 ** directory - saves on reading this many times for each 985 ** file. 986 */ 987 struct hfs_info * 988 get_hfs_sgi_info(struct hfs_info *hfs_info, char *name) 989 { 990 FILE *fp; 991 sgi_info info; 992 struct hfs_info *hfs_info1 = NULL; 993 hfsdirent *hfs_ent; 994 995 if ((fp = fopen(name, "rb")) == NULL) 996 return(NULL); 997 998 while(fread(&info, 1, SGI_SIZE, fp) != 0) { 999 1000 hfs_info1 = (struct hfs_info *)e_malloc(sizeof(struct hfs_info)); 1001 /* add thsi entry to the list */ 1002 hfs_info1->next = hfs_info; 1003 hfs_info = hfs_info1; 1004 1005 hfs_ent = &hfs_info1->hfs_ent; 1006 1007 /* get the bits we need - ignore [cm]time for the moment */ 1008 cstrncpy(hfs_ent->name, info.name, HFS_MAX_FLEN); 1009 1010 strncpy(hfs_ent->type, info.type, CT_SIZE); 1011 strncpy(hfs_ent->creator, info.creator, CT_SIZE); 1012 1013 hfs_ent->type[CT_SIZE] = hfs_ent->creator[CT_SIZE] = '\0'; 1014 1015 /* don't know about flags at the moment */ 1016 /* hfs_ent->fdflags = d_getw((unsigned char *)&info.flags); */ 1017 1018 /* use the HFS name as the key */ 1019 hfs_info1->keyname = hfs_ent->name; 1020 1021 } 1022 fclose (fp); 1023 1024 return (hfs_info); 1025 } 1026 1027 /* 1028 ** del_hfs_info: delete the info list and recover memory 1029 */ 1030 void 1031 del_hfs_info(struct hfs_info *hfs_info) 1032 { 1033 struct hfs_info *hfs_info1; 1034 1035 while (hfs_info) { 1036 hfs_info1 = hfs_info; 1037 hfs_info = hfs_info->next; 1038 1039 /* key may be the same as the HFS name - so don't free it */ 1040 *hfs_info1->hfs_ent.name = '\0'; 1041 if (*hfs_info1->keyname) 1042 free(hfs_info1->keyname); 1043 free(hfs_info1); 1044 } 1045 } 1046 1047 /* 1048 ** match_key: find the correct hfs_ent using the Unix filename 1049 ** as the key 1050 */ 1051 hfsdirent * 1052 match_key(struct hfs_info *hfs_info, char *key) 1053 { 1054 while (hfs_info) { 1055 if (!strcasecmp(key, hfs_info->keyname)) 1056 return (&hfs_info->hfs_ent); 1057 hfs_info = hfs_info->next; 1058 } 1059 1060 return (NULL); 1061 } 1062 1063 /* 1064 ** get_fe_dir: get PC Exchange directory name 1065 ** 1066 ** base on probing with od ... 1067 */ 1068 int 1069 get_fe_dir(char *hname, char *dname, dir_ent *s_entry, int ret) 1070 /* char *hname whole path */ 1071 /* char *dname this dir name */ 1072 /* dir_ent *s_entry directory entry */ 1073 { 1074 struct hfs_info *hfs_info; 1075 hfsdirent *hfs_ent; 1076 1077 /* cached finderinfo stored with parent directory */ 1078 hfs_info = s_entry->filedir->hfs_info; 1079 1080 /* if we have no cache, then make one and store it */ 1081 if (hfs_info == NULL) { 1082 if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL) 1083 ret = TYPE_NONE; 1084 else 1085 s_entry->filedir->hfs_info = hfs_info; 1086 } 1087 1088 if (ret != TYPE_NONE) { 1089 /* see if we can find the details of this file */ 1090 if ((hfs_ent = match_key(hfs_info, dname)) != NULL) { 1091 strcpy(s_entry->hfs_ent->name, hfs_ent->name); 1092 return (ret); 1093 } 1094 } 1095 1096 /* can't find the entry, so use the Unix name */ 1097 hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN); 1098 1099 return(TYPE_NONE); 1100 } 1101 1102 /* 1103 ** get_fe_info: get PC Exchange file details. 1104 ** 1105 ** base on probing with od and details from Mark Weinstein 1106 ** <mrwesq@earthlink.net> 1107 */ 1108 int 1109 get_fe_info(char *hname, char *dname, dir_ent *s_entry, int ret) 1110 /* char *hname whole path */ 1111 /* char *dname this dir name */ 1112 /* dir_ent *s_entry directory entry */ 1113 { 1114 struct hfs_info *hfs_info; 1115 hfsdirent *hfs_ent; 1116 1117 /* cached finderinfo stored with parent directory */ 1118 hfs_info = s_entry->filedir->hfs_info; 1119 1120 /* if we have no cache, then make one and store it */ 1121 if (hfs_info == NULL) { 1122 if ((hfs_info = get_hfs_fe_info(hfs_info, hname)) == NULL) 1123 ret = TYPE_NONE; 1124 else 1125 s_entry->filedir->hfs_info = hfs_info; 1126 } 1127 1128 if (ret != TYPE_NONE) { 1129 char *dn = dname; 1130 #ifdef _WIN32_TEST 1131 /* may have a problem here - v2.2 has long filenames, 1132 but we need to key on the short filename, so we need 1133 do go a bit of win32 stuff ... */ 1134 1135 char sname[1024], lname[1024]; 1136 1137 cygwin32_conv_to_full_win32_path(s_entry->whole_name, lname); 1138 1139 if (GetShortPathName(lname, sname, sizeof(sname))) { 1140 if (dn = strrchr(sname, '\\')) 1141 dn++; 1142 else 1143 dn = sname; 1144 } 1145 #endif /* _WIN32 */ 1146 1147 /* see if we can find the details of this file */ 1148 if ((hfs_ent = match_key(hfs_info, dn)) != NULL) { 1149 strcpy(s_entry->hfs_ent->name, hfs_ent->name); 1150 strcpy(s_entry->hfs_ent->type, hfs_ent->type); 1151 strcpy(s_entry->hfs_ent->creator, hfs_ent->creator); 1152 /* clear HFS_FNDR_HASBEENINITED flag */ 1153 s_entry->hfs_ent->fdflags = hfs_ent->fdflags & 0xfeff; 1154 return (ret); 1155 } 1156 } 1157 1158 /* no entry found - use extension mapping */ 1159 if (verbose > 2) { 1160 fprintf(stderr, "warning: %s doesn't appear to be a %s file\n", 1161 s_entry->whole_name, hfs_types[ret].desc); 1162 } 1163 1164 ret = get_none_info(hname, dname, s_entry, TYPE_NONE); 1165 1166 return(TYPE_NONE); 1167 } 1168 1169 /* 1170 ** get_sgi_dir: get SGI (XINET) HFS directory name 1171 ** 1172 ** base on probing with od ... 1173 */ 1174 int 1175 get_sgi_dir(char *hname, char *dname, dir_ent *s_entry, int ret) 1176 /* char *hname whole path */ 1177 /* char *dname this dir name */ 1178 /* dir_ent *s_entry directory entry */ 1179 { 1180 struct hfs_info *hfs_info; 1181 hfsdirent *hfs_ent; 1182 1183 /* cached finderinfo stored with parent directory */ 1184 hfs_info = s_entry->filedir->hfs_info; 1185 1186 /* if we haven't got a cache, then make one */ 1187 if (hfs_info == NULL) { 1188 if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL) 1189 ret = TYPE_NONE; 1190 else 1191 s_entry->filedir->hfs_info = hfs_info; 1192 } 1193 1194 /* find the matching entry in the cache */ 1195 if (ret != TYPE_NONE) { 1196 /* key is (hopefully) the real Mac name */ 1197 cstrncpy(tmp, dname, strlen(dname)); 1198 if ((hfs_ent = match_key(hfs_info, tmp)) != NULL) { 1199 strcpy(s_entry->hfs_ent->name, hfs_ent->name); 1200 return (ret); 1201 } 1202 } 1203 1204 /* no entry found - use Unix name */ 1205 hstrncpy(s_entry->hfs_ent->name, dname, HFS_MAX_FLEN); 1206 1207 return(TYPE_NONE); 1208 } 1209 1210 /* 1211 ** get_sgi_info: get SGI (XINET) HFS finder info 1212 ** 1213 ** base on probing with od ... 1214 */ 1215 int 1216 get_sgi_info(char *hname, char *dname, dir_ent *s_entry, int ret) 1217 /* char *hname whole path */ 1218 /* char *dname this dir name */ 1219 /* dir_ent *s_entry directory entry */ 1220 { 1221 struct hfs_info *hfs_info; 1222 hfsdirent *hfs_ent; 1223 1224 /* cached finderinfo stored with parent directory */ 1225 hfs_info = s_entry->filedir->hfs_info; 1226 1227 /* if we haven't got a cache, then make one */ 1228 if (hfs_info == NULL) { 1229 if ((hfs_info = get_hfs_sgi_info(hfs_info, hname)) == NULL) 1230 ret = TYPE_NONE; 1231 else 1232 s_entry->filedir->hfs_info = hfs_info; 1233 } 1234 1235 if (ret != TYPE_NONE) { 1236 /* tmp is the same as hname here, but we don't need hname 1237 anymore in this function ... see if we can find the 1238 details of this file using the Unix name as the key */ 1239 cstrncpy(tmp, dname, strlen(dname)); 1240 if ((hfs_ent = match_key(hfs_info, tmp)) != NULL) { 1241 strcpy(s_entry->hfs_ent->name, hfs_ent->name); 1242 strcpy(s_entry->hfs_ent->type, hfs_ent->type); 1243 strcpy(s_entry->hfs_ent->creator, hfs_ent->creator); 1244 /* s_entry->hfs_ent->fdflags = hfs_ent->fdflags; */ 1245 return (ret); 1246 } 1247 } 1248 1249 /* no entry found, so try file extension */ 1250 if (verbose > 2) { 1251 fprintf(stderr, "warning: %s doesn't appear to be a %s file\n", 1252 s_entry->whole_name, hfs_types[ret].desc); 1253 } 1254 1255 ret = get_none_info(hname, dname, s_entry, TYPE_NONE); 1256 1257 return(TYPE_NONE); 1258 } 1259 1260 /* 1261 ** get_hfs_itype: get the type of HFS info for a file 1262 */ 1263 int 1264 get_hfs_itype(char *wname, char *dname, char *htmp) 1265 { 1266 int wlen, i; 1267 1268 wlen = strlen(wname) - strlen(dname); 1269 1270 /* search through the known types looking for matches */ 1271 for (i=1;i<hfs_num;i++) { 1272 /* skip the ones that we don't care about */ 1273 if ((hfs_types[i].flags & 0x1) || *(hfs_types[i].info) == TYPE_NONE) 1274 continue; 1275 1276 strcpy(htmp, wname); 1277 1278 sprintf(htmp+wlen, "%s%s", hfs_types[i].info, 1279 (hfs_types[i].flags & 0x2) ? "" : dname); 1280 if (!access(tmp, R_OK)) 1281 return (hfs_types[i].type); 1282 } 1283 1284 return (TYPE_NONE); 1285 } 1286 1287 /* 1288 ** get_hfs_dir: set the HFS directory name 1289 */ 1290 int 1291 get_hfs_dir(char *wname, char *dname, dir_ent *s_entry) 1292 { 1293 int type; 1294 1295 /* get the HFS file type from the info file (if it exists) */ 1296 type = get_hfs_itype(wname, dname, tmp); 1297 1298 /* try to get the required info */ 1299 type = (*(hfs_types[type].get_dir))(tmp, dname, s_entry, type); 1300 1301 return (type); 1302 } 1303 1304 /* 1305 ** get_hfs_info: set the HFS info for a file 1306 */ 1307 int 1308 get_hfs_info(char *wname, char *dname, dir_ent *s_entry) 1309 { 1310 int type, wlen, i; 1311 1312 wlen = strlen(wname) - strlen(dname); 1313 1314 /* we may already know the type of Unix/HFS file - so process */ 1315 if (s_entry->hfs_type != TYPE_NONE) { 1316 1317 /* 1318 i = 0; 1319 for(type=1;i<hfs_num;type++) { 1320 if (s_entry->hfs_type == hfs_types[type].type) { 1321 i = type; 1322 break; 1323 } 1324 } 1325 */ 1326 type = s_entry->hfs_type; 1327 1328 strcpy(tmp, wname); 1329 sprintf(tmp+wlen, "%s%s", hfs_types[type].info, 1330 (hfs_types[type].flags & 0x2) ? "" : dname); 1331 type = (*(hfs_types[type].get_info))(tmp, dname, s_entry, type); 1332 1333 /* if everything is as expected, then return */ 1334 if (s_entry->hfs_type == type) 1335 return(type); 1336 } 1337 1338 /* we don't know what type we have so, find out */ 1339 for (i=1;i<hfs_num;i++) { 1340 if ((hfs_types[i].flags & 0x1) || *(hfs_types[i].info) == TYPE_NONE) 1341 continue; 1342 1343 strcpy(tmp, wname); 1344 1345 sprintf(tmp+wlen, "%s%s", hfs_types[i].info, 1346 (hfs_types[i].flags & 0x2) ? "" : dname); 1347 1348 /* if the file exists - and not a type we've already tried */ 1349 if (!access(tmp, R_OK) && i != s_entry->hfs_type) { 1350 type = (*(hfs_types[i].get_info))(tmp, dname, s_entry, i); 1351 s_entry->hfs_type = type; 1352 return (type); 1353 } 1354 } 1355 1356 /* nothing found, so just a Unix file */ 1357 type = (*(hfs_types[TYPE_NONE].get_info))(wname, dname, s_entry, TYPE_NONE); 1358 1359 return (type); 1360 } 1361 1362 /* 1363 ** get_hfs_rname: set the name of the Unix rsrc file for a file 1364 */ 1365 int 1366 get_hfs_rname(char *wname, char *dname, char *rname) 1367 { 1368 int wlen, type, i; 1369 int p_fd = -1; 1370 1371 wlen = strlen(wname) - strlen(dname); 1372 1373 /* try to find what sort of Unix HFS file type we have */ 1374 for (i=1;i<hfs_num;i++) { 1375 /* skip if don't want to probe the files - (default) */ 1376 if (hfs_types[i].flags & 0x1) 1377 continue; 1378 1379 strcpy(rname, wname); 1380 1381 /* if we have a different info file, the find out it's type */ 1382 if (*(hfs_types[i].rsrc)) { 1383 sprintf(rname+wlen, "%s%s", hfs_types[i].rsrc, dname); 1384 if (!access(rname, R_OK)) 1385 return (hfs_types[i].type); 1386 } 1387 else { 1388 /* if we are probing, then have a look at the contents to 1389 find type */ 1390 if (p_fd < 0) { 1391 /* open file, if not already open */ 1392 if((p_fd = open(wname, O_RDONLY | O_BINARY)) < 0) { 1393 /* can't open it, then give up */ 1394 return (TYPE_NONE); 1395 } else { 1396 if((p_num = read(p_fd, p_buf, sizeof(p_buf))) <= 0) { 1397 /* can't read, or zero length - give up */ 1398 close(p_fd); 1399 return(TYPE_NONE); 1400 } 1401 /* get file pointer and close file */ 1402 p_fp = fdopen(p_fd, "rb"); 1403 close(p_fd); 1404 if(p_fp == NULL) 1405 return(TYPE_NONE); 1406 } 1407 } 1408 /* call routine to do the work - use the given dname as 1409 this is the name we may use on the CD */ 1410 type = (*(hfs_types[i].get_info))(rname, dname, 0, i); 1411 if (type != 0) { 1412 fclose(p_fp); 1413 return (type); 1414 } 1415 if (p_fp) { 1416 /* close file - just use contents of buffer next time */ 1417 fclose(p_fp); 1418 p_fp = NULL; 1419 } 1420 } 1421 } 1422 1423 return (0); 1424 } 1425 1426 /* 1427 ** hfs_exclude: file/directory names that hold finder/resource 1428 ** information that we want to exclude from the tree. 1429 ** These files/directories are processed later ... 1430 */ 1431 int 1432 hfs_exclude(char *d_name) 1433 { 1434 /* we don't exclude "." and ".." */ 1435 if (!strcmp(d_name,".")) 1436 return 0; 1437 if (!strcmp(d_name,"..")) 1438 return 0; 1439 1440 /* do not add the following to our list of dir entries */ 1441 if (DO_CAP & hselect) { 1442 /* CAP */ 1443 if(!strcmp(d_name,".finderinfo")) 1444 return 1; 1445 if(!strcmp(d_name,".resource")) 1446 return 1; 1447 if(!strcmp(d_name,".ADeskTop")) 1448 return 1; 1449 if(!strcmp(d_name,".IDeskTop")) 1450 return 1; 1451 if(!strcmp(d_name,"Network Trash Folder")) 1452 return 1; 1453 /* special case when HFS volume is mounted using Linux's hfs_fs 1454 Brad Midgley <brad@pht.com> */ 1455 if(!strcmp(d_name,".rootinfo")) 1456 return 1; 1457 } 1458 1459 if (DO_ESH & hselect) { 1460 /* Helios EtherShare files */ 1461 if(!strcmp(d_name,".rsrc")) 1462 return 1; 1463 if(!strcmp(d_name,".Desktop")) 1464 return 1; 1465 if(!strcmp(d_name,".DeskServer")) 1466 return 1; 1467 if(!strcmp(d_name,".Label")) 1468 return 1; 1469 } 1470 1471 if (DO_DBL & hselect) { 1472 /* Apple Double */ 1473 if (*d_name == '%') 1474 return 1; 1475 } 1476 1477 if (DO_NETA & hselect) { 1478 if(!strcmp(d_name,".AppleDouble")) 1479 return 1; 1480 if(!strcmp(d_name,".AppleDesktop")) 1481 return 1; 1482 } 1483 1484 if ((DO_FEU & hselect) || ( DO_FEL & hselect)) { 1485 /* PC Exchange */ 1486 if(!strcmp(d_name,"RESOURCE.FRK")) 1487 return 1; 1488 if(!strcmp(d_name,"FINDER.DAT")) 1489 return 1; 1490 if(!strcmp(d_name,"DESKTOP")) 1491 return 1; 1492 if(!strcmp(d_name,"FILEID.DAT")) 1493 return 1; 1494 if(!strcmp(d_name,"resource.frk")) 1495 return 1; 1496 if(!strcmp(d_name,"finder.dat")) 1497 return 1; 1498 if(!strcmp(d_name,"desktop")) 1499 return 1; 1500 if(!strcmp(d_name,"fileid.dat")) 1501 return 1; 1502 } 1503 1504 if (DO_SGI | hselect) { 1505 /* SGI */ 1506 if(!strcmp(d_name,".HSResource")) 1507 return 1; 1508 if(!strcmp(d_name,".HSancillary")) 1509 return 1; 1510 } 1511 1512 return 0; 1513 } 1514 /* 1515 ** print_hfs_info: print info about the HFS files. 1516 ** 1517 */ 1518 void 1519 print_hfs_info(dir_ent *s_entry) 1520 { 1521 fprintf(stderr,"Name: %s\n",s_entry->whole_name); 1522 fprintf(stderr,"\tFile type: %s\n",hfs_types[s_entry->hfs_type].desc); 1523 fprintf(stderr,"\tHFS Name: %s\n",s_entry->hfs_ent->name); 1524 fprintf(stderr,"\tISO Name: %s\n",s_entry->isorec.name); 1525 fprintf(stderr,"\tCREATOR: %s\n",s_entry->hfs_ent->creator); 1526 fprintf(stderr,"\tTYPE: %s\n", s_entry->hfs_ent->type); 1527 } 1528 1529 1530 /* 1531 ** hfs_init: sets up the mapping list from the afpfile as well 1532 ** the default mapping (with or without) an afpfile 1533 */ 1534 void 1535 hfs_init(char *name, unsigned short fdflags, int probe, int nomacfiles, 1536 unsigned int hfs_select) 1537 #if 0 1538 char *name; /* afpfile name */ 1539 u_short *fdflags; /* default finder flags */ 1540 int probe; /* probe flag */ 1541 int nomacfiles; /* don't look for mac files */ 1542 u_int hfs_select /* select certain mac files */ 1543 #endif 1544 { 1545 FILE *fp; /* File pointer */ 1546 int count = NUMMAP; /* max number of entries */ 1547 char buf[MAXPATHLEN]; /* working buffer */ 1548 afpmap *amap; /* mapping entry */ 1549 char *c, *t, *e; 1550 int i; 1551 1552 /* setup number of Unix/HFS filetype - we may wish to not bother */ 1553 if (nomacfiles) 1554 hfs_num = 0; 1555 else 1556 hfs_num = sizeof(hfs_types)/sizeof(struct hfs_type); 1557 1558 /* we may want to probe all files */ 1559 if (probe || hfs_select) 1560 for(i=0;i<hfs_num;i++) 1561 hfs_types[i].flags &= ~1; /* 0xfffffffe */ 1562 1563 /* if we have selected certain types of Mac/Unix files, then 1564 turn off the filetype */ 1565 if (hfs_select) 1566 for(i=1;i<hfs_num;i++) 1567 if (!((1 << i) & hfs_select)) 1568 hfs_types[i].flags |= 0x1; 1569 1570 /* save what types have been selected (set all if none have) */ 1571 if (hfs_select) 1572 hselect = hfs_select; 1573 else 1574 hselect = ~0; 1575 1576 #ifdef DEBUG 1577 for(i=0;i<hfs_num;i++) 1578 fprintf(stderr,"type = %d flags = %d\n", i, hfs_types[i].flags); 1579 #endif /* DEBUG */ 1580 1581 /* min length set to max to start with */ 1582 mlen = MAXPATHLEN; 1583 1584 /* initialise magic file */ 1585 if(magic_file && init_magic(magic_file) != 0) 1586 errx(1, "unable to open magic file"); 1587 1588 /* set defaults */ 1589 map_num = last_ent = 0; 1590 1591 /* allocate memory for the default entry */ 1592 if((defmap = (afpmap *)malloc(sizeof(afpmap))) == NULL) 1593 errx(1, "not enough memory"); 1594 1595 /* set default values */ 1596 defmap->extn = DEFMATCH; 1597 1598 /* make sure creator and type are 4 chars long */ 1599 strcpy(defmap->type, BLANK); 1600 strcpy(defmap->creator, BLANK); 1601 1602 e = deftype; 1603 t = defmap->type; 1604 1605 while(*e && (e - deftype) < CT_SIZE) 1606 *t++ = *e++; 1607 1608 e = defcreator; 1609 c = defmap->creator; 1610 1611 while(*e && (e - defcreator) < CT_SIZE) 1612 *c++ = *e++; 1613 1614 /* length is not important here */ 1615 defmap->elen = 0; 1616 1617 /* no flags */ 1618 defmap->fdflags = fdflags; 1619 1620 /* no afpfile - no mappings */ 1621 if (*name == '\0') { 1622 map = NULL; 1623 return; 1624 } 1625 1626 if((fp = fopen(name,"r")) == NULL) 1627 err(1, "unable to open mapping file: %s", name); 1628 1629 if((map = (afpmap **)malloc(NUMMAP * sizeof(afpmap *))) == NULL) 1630 errx(1, "not enough memory"); 1631 1632 /* read afpfile line by line */ 1633 while(fgets(buf, MAXPATHLEN, fp) != NULL) { 1634 /* ignore any comment lines */ 1635 c = tmp; 1636 *c = '\0'; 1637 if (sscanf(buf,"%1s", c) == EOF || *c == '#') 1638 continue; 1639 1640 /* increase list size if needed */ 1641 if (map_num == count) { 1642 count += NUMMAP; 1643 map = (afpmap **)realloc(map, count * sizeof(afpmap *)); 1644 if (map == NULL) 1645 errx(1, "not enough memory"); 1646 } 1647 1648 /* allocate memory for this entry */ 1649 if((amap = (afpmap *)malloc(sizeof(afpmap))) == NULL) 1650 errx(1, "not enough memory"); 1651 1652 t = amap->type; 1653 c = amap->creator; 1654 1655 /* extract the info */ 1656 if(sscanf(buf, "%s%*s%*1s%c%c%c%c%*1s%*1s%c%c%c%c%*1s", 1657 tmp, c, c+1, c+2, c+3, t, t+1, t+2, t+3) != 9) { 1658 fprintf(stderr,"error scanning afpfile %s - continuing", name); 1659 free(amap); 1660 continue; 1661 } 1662 1663 /* copy the extension found */ 1664 if ((amap->extn = (char *)strdup(tmp)) == NULL) 1665 errx(1, "not enough memory"); 1666 1667 /* set end-of-string */ 1668 *(t+4) = *(c+4) = '\0'; 1669 1670 /* find the length of the extension */ 1671 amap->elen = strlen(amap->extn); 1672 1673 /* set flags */ 1674 amap->fdflags = fdflags; 1675 1676 /* see if we have the default creator/type */ 1677 if(!strcmp(amap->extn, DEFMATCH)) { 1678 /* get rid of the old default */ 1679 free(defmap); 1680 /* make this the default */ 1681 defmap = amap; 1682 continue; 1683 } 1684 1685 /* update the smallest extension length */ 1686 mlen = MIN(mlen, amap->elen); 1687 1688 /* add entry to the list */ 1689 map[map_num++] = amap; 1690 1691 } 1692 1693 /* free up some memory */ 1694 if (map_num != count) { 1695 map = (afpmap **)realloc(map, map_num * sizeof(afpmap *)); 1696 if (map == NULL) 1697 errx(1, "not enough memory"); 1698 } 1699 1700 } 1701 1702 /* 1703 ** map_ext: map a files extension with the list to get type/creator 1704 */ 1705 void 1706 map_ext(char *name, char **type, char **creator, unsigned short *fdflags, 1707 char *whole_name) 1708 #if 0 1709 char *name; /* filename */ 1710 char **type; /* set type */ 1711 char **creator; /* set creator */ 1712 u_short *fdflags; /* set finder flags */ 1713 #endif 1714 { 1715 int i; /* loop counter */ 1716 int len; /* filename length */ 1717 afpmap *amap; /* mapping entry */ 1718 char *ret; 1719 1720 /* we don't take fdflags from the map or magic file */ 1721 *fdflags = defmap->fdflags; 1722 1723 /* if we have a magic file and we want to search it first, then 1724 try to get a match */ 1725 if (magic_file && hfs_last == MAP_LAST) { 1726 ret = get_magic_match(whole_name); 1727 1728 if (ret) { 1729 if (sscanf(ret, "%4s%4s", tmp_creator, tmp_type) == 2) { 1730 *type = tmp_type; 1731 *creator = tmp_creator; 1732 return; 1733 } 1734 } 1735 } 1736 1737 len = strlen(name); 1738 1739 /* have an afpfile and filename if long enough */ 1740 if(map && len >= mlen) { 1741 /* search through the list - we start where we left 1742 off last time in case this file is of the same type 1743 as the last one */ 1744 for(i=0;i<map_num;i++) { 1745 amap = map[last_ent]; 1746 1747 /* compare the end of the filename */ 1748 /* if (!strcmp((name + len - amap->elen), amap->extn)) { */ 1749 if (!strcasecmp((name + len - amap->elen), amap->extn)) { 1750 /* set the required info */ 1751 *type = amap->type; 1752 *creator = amap->creator; 1753 *fdflags = amap->fdflags; 1754 return; 1755 } 1756 /* move on to the next entry - wrapping round if neccessary */ 1757 last_ent++; 1758 last_ent %= map_num; 1759 } 1760 } 1761 1762 /* if no matches are found, file name too short, or no 1763 afpfile, then take defaults */ 1764 *type = defmap->type; 1765 *creator = defmap->creator; 1766 1767 /* if we have a magic file and we haven't searched yet, then try 1768 to get a match */ 1769 if (magic_file && hfs_last == MAG_LAST) { 1770 ret = get_magic_match(whole_name); 1771 1772 if (ret) { 1773 if (sscanf(ret, "%4s%4s", tmp_creator, tmp_type) == 2) { 1774 *type = tmp_type; 1775 *creator = tmp_creator; 1776 } 1777 } 1778 } 1779 } 1780 1781 void 1782 delete_rsrc_ent(dir_ent *s_entry) 1783 { 1784 dir_ent *s_entry1 = s_entry->next; 1785 1786 if (s_entry1 == NULL) 1787 return; 1788 1789 s_entry->next = s_entry1->next; 1790 s_entry->assoc = NULL; 1791 1792 free(s_entry1->name); 1793 free(s_entry1->whole_name); 1794 1795 free(s_entry1); 1796 } 1797 1798 void 1799 clean_hfs() 1800 { 1801 if (map) 1802 free(map); 1803 1804 if (defmap) 1805 free(defmap); 1806 1807 if (magic_file) 1808 clean_magic(); 1809 } 1810 1811 #else 1812 #include <stdio.h> 1813 #endif /* APPLE_HYB */ 1814