/* Read bytes from resource fork. */ static int read_res(hfsfile *file, unsigned start, unsigned count, char *buf, unsigned *bytes_read) { hfs_setfork(file, 1); if(hfs_lseek(file, start, SEEK_SET) < 0 || (*bytes_read=hfs_read(file, buf, count)) == -1) { hfs_setfork(file, 0); return 1; } hfs_setfork(file, 0); return 0; }
static int FuseHFS_removexattr(const char *path, const char *name) { dprintf("removexattr %s %s\n", path, name); if (_readonly) return -EPERM; // convert to hfs path char *hfspath = mkhfspath(path); if (hfspath == NULL) return -ENOENT; // find file hfsdirent ent; if (hfs_stat(NULL, hfspath, &ent) == -1) { free(hfspath); return -ENOENT; } if (strcmp(name, XATTR_FINDERINFO_NAME) == 0) { free(hfspath); // not really removing it return 0; } else if (strcmp(name, XATTR_RESOURCEFORK_NAME) == 0 && (!(ent.flags & HFS_ISDIR))) { // resource fork hfsfile *fp = hfs_open(NULL, hfspath); hfs_setfork(fp, 1); hfs_seek(fp, 0, SEEK_SET); hfs_truncate(fp, 0); hfs_close(fp); free(hfspath); return 0; } free(hfspath); return -ENOATTR; }
static int FuseHFS_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { dprintf("read %s\n", path); hfsfile *file = (hfsfile*)fi->fh; hfs_setfork(file, 0); hfs_seek(file, offset, SEEK_SET); return hfs_read(file, buf, size); }
static int FuseHFS_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { dprintf("write %s\n", path); if (_readonly) return -EPERM; hfsfile *file = (hfsfile*)fi->fh; hfs_setfork(file, 0); hfs_seek(file, offset, SEEK_SET); return (hfs_write(file, buf, size)); }
static int FuseHFS_release(const char *path, struct fuse_file_info *fi) { dprintf("close %s\n", path); // convert to hfs path char *hfspath = mkhfspath(path); if (hfspath == NULL) return -ENOENT; hfsfile *file = (hfsfile*)fi->fh; hfs_setfork(file, 0); hfs_close(file); free(hfspath); return 0; }
static int FuseHFS_setxattr(const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position) { dprintf("setxattr %s %s %p %lu %02x %u\n", path, name, value, size, flags, position); if (_readonly) return -EPERM; // convert to hfs path char *hfspath = mkhfspath(path); if (hfspath == NULL) return -ENOENT; // find file hfsdirent ent; if (hfs_stat(NULL, hfspath, &ent) == -1) { free(hfspath); return -ENOENT; } if (strcmp(name, XATTR_FINDERINFO_NAME) == 0) { if (size != 32) { dprintf("setxattr: finder info is not 32 bytes\n"); free(hfspath); return -ERANGE; } // write finder info to dirent if (ent.flags & HFS_ISDIR) { // directory ent.u.dir.rect.top = OSReadBigInt16(value, 0); ent.u.dir.rect.left = OSReadBigInt16(value, 2); ent.u.dir.rect.bottom = OSReadBigInt16(value, 4); ent.u.dir.rect.right = OSReadBigInt16(value, 6); ent.fdflags = OSReadBigInt16(value, 8); ent.fdlocation.v = OSReadBigInt16(value, 10); ent.fdlocation.h = OSReadBigInt16(value, 12); ent.u.dir.view = OSReadBigInt16(value, 14); // DXInfo ((DXInfo*)(ent.u.dir.xinfo))->frScroll.v = OSReadBigInt16(value, 16); ((DXInfo*)(ent.u.dir.xinfo))->frScroll.h = OSReadBigInt16(value, 18); ((DXInfo*)(ent.u.dir.xinfo))->frOpenChain = OSReadBigInt32(value, 20); ((DXInfo*)(ent.u.dir.xinfo))->frUnused = OSReadBigInt16(value, 24); ((DXInfo*)(ent.u.dir.xinfo))->frComment = OSReadBigInt16(value, 26); ((DXInfo*)(ent.u.dir.xinfo))->frPutAway = OSReadBigInt32(value, 28); } else { // regular file memcpy(ent.u.file.type, value, 4); memcpy(ent.u.file.creator, value+4, 4); ent.u.file.type[4] = ent.u.file.type[4] = '\0'; ent.fdflags = OSReadBigInt16(value, 8); ent.fdlocation.v = OSReadBigInt16(value, 10); ent.fdlocation.h = OSReadBigInt16(value, 12); ent.u.file.window = OSReadBigInt16(value, 14); // FXInfo ((FXInfo*)(ent.u.file.xinfo))->fdIconID = OSReadBigInt16(value, 16); ((FXInfo*)(ent.u.file.xinfo))->fdUnused[0] = OSReadBigInt16(value, 18); ((FXInfo*)(ent.u.file.xinfo))->fdUnused[1] = OSReadBigInt16(value, 20); ((FXInfo*)(ent.u.file.xinfo))->fdUnused[2] = OSReadBigInt16(value, 22); ((FXInfo*)(ent.u.file.xinfo))->fdUnused[3] = OSReadBigInt16(value, 24); ((FXInfo*)(ent.u.file.xinfo))->fdComment = OSReadBigInt16(value, 26); ((FXInfo*)(ent.u.file.xinfo))->fdPutAway = OSReadBigInt32(value, 28); // bless parent folder if it's a system file if ((strcmp(ent.u.file.type, "zsys") == 0) && (strcmp(ent.u.file.creator, "MACS") == 0) && (strcmp(ent.name, "System") == 0)) { // bless dprintf("setxattr: blessing folder %lu\n", ent.parid); hfsvolent volent; hfs_vstat(NULL, &volent); volent.blessed = ent.parid; hfs_vsetattr(NULL, &volent); } } // update file hfs_setattr(NULL, hfspath, &ent); free(hfspath); return 0; } else if (strcmp(name, XATTR_RESOURCEFORK_NAME) == 0 && (!(ent.flags & HFS_ISDIR))) { // resource fork // TODO: how are resource forks truncated? hfsfile *fp = hfs_open(NULL, hfspath); hfs_setfork(fp, 1); hfs_seek(fp, position, SEEK_SET); hfs_write(fp, value, size); hfs_close(fp); // the end free(hfspath); return 0; } else { free(hfspath); return 0; } free(hfspath); return -ENOATTR; }
static int FuseHFS_getxattr(const char *path, const char *name, char *value, size_t size, uint32_t position) { //dprintf("getxattr %s %s %p %lu %u\n", path, name, value, size, position); // convert to hfs path char *hfspath = mkhfspath(path); if (hfspath == NULL) return -ENOENT; // find file hfsdirent ent; if (hfs_stat(NULL, hfspath, &ent) == -1) { free(hfspath); return -ENOENT; } if (strcmp(name, XATTR_FINDERINFO_NAME) == 0) { if (value == NULL) { free(hfspath); return 32; } if (size < 32) { free(hfspath); return -ERANGE; } // return finder info if (ent.flags & HFS_ISDIR) { // directory info OSWriteBigInt16(value, 0, ent.u.dir.rect.top); OSWriteBigInt16(value, 2, ent.u.dir.rect.left); OSWriteBigInt16(value, 4, ent.u.dir.rect.bottom); OSWriteBigInt16(value, 6, ent.u.dir.rect.right); OSWriteBigInt16(value, 8, ent.fdflags); OSWriteBigInt16(value, 10, ent.fdlocation.v); OSWriteBigInt16(value, 12, ent.fdlocation.h); OSWriteBigInt16(value, 14, ent.u.dir.view); // DXInfo OSWriteBigInt16(value, 16, ((DXInfo*)(ent.u.dir.xinfo))->frScroll.v); OSWriteBigInt16(value, 18, ((DXInfo*)(ent.u.dir.xinfo))->frScroll.h); OSWriteBigInt32(value, 20, ((DXInfo*)(ent.u.dir.xinfo))->frOpenChain); OSWriteBigInt16(value, 24, ((DXInfo*)(ent.u.dir.xinfo))->frUnused); OSWriteBigInt16(value, 26, ((DXInfo*)(ent.u.dir.xinfo))->frComment); OSWriteBigInt32(value, 28, ((DXInfo*)(ent.u.dir.xinfo))->frPutAway); } else { // file info memcpy(value, ent.u.file.type, 4); memcpy(value+4, ent.u.file.creator, 4); OSWriteBigInt16(value, 8, ent.fdflags); OSWriteBigInt16(value, 10, ent.fdlocation.v); OSWriteBigInt16(value, 12, ent.fdlocation.h); OSWriteBigInt16(value, 14, ent.u.file.window); // FXInfo OSWriteBigInt16(value, 16, ((FXInfo*)(ent.u.file.xinfo))->fdIconID); OSWriteBigInt16(value, 18, ((FXInfo*)(ent.u.file.xinfo))->fdUnused[0]); OSWriteBigInt16(value, 20, ((FXInfo*)(ent.u.file.xinfo))->fdUnused[1]); OSWriteBigInt16(value, 22, ((FXInfo*)(ent.u.file.xinfo))->fdUnused[2]); OSWriteBigInt16(value, 24, ((FXInfo*)(ent.u.file.xinfo))->fdUnused[3]); OSWriteBigInt16(value, 26, ((FXInfo*)(ent.u.file.xinfo))->fdComment); OSWriteBigInt32(value, 28, ((FXInfo*)(ent.u.file.xinfo))->fdPutAway); } free(hfspath); return 32; } else if (strcmp(name, XATTR_RESOURCEFORK_NAME) == 0 && (!(ent.flags & HFS_ISDIR)) && ent.u.file.rsize) { // resource fork if (value == NULL) { free(hfspath); return ent.u.file.rsize-position; } int bw = ent.u.file.rsize-position; if (bw > size) bw = size; // copy resource fork hfsfile *fp = hfs_open(NULL, hfspath); hfs_setfork(fp, 1); hfs_seek(fp, position, SEEK_SET); hfs_read(fp, value, bw); hfs_close(fp); // the end free(hfspath); return bw; } free(hfspath); dprintf("getxattr: ENOATTR\n"); return -ENOATTR; }
/* * NAME: binhx() * DESCRIPTION: auxiliary BinHex routine */ static int binhx(hfsfile *ifile) { hfsdirent ent; unsigned char byte, word[2], lword[4]; if (hfs_fstat(ifile, &ent) == -1) { ERROR(errno, hfs_error); return -1; } byte = strlen(ent.name); if (bh_insert(&byte, 1) == -1 || bh_insert(ent.name, byte + 1) == -1 || bh_insert(ent.u.file.type, 4) == -1 || bh_insert(ent.u.file.creator, 4) == -1) { ERROR(errno, bh_error); return -1; } d_putsw(word, ent.fdflags); if (bh_insert(word, 2) == -1) { ERROR(errno, bh_error); return -1; } d_putul(lword, ent.u.file.dsize); if (bh_insert(lword, 4) == -1) { ERROR(errno, bh_error); return -1; } d_putul(lword, ent.u.file.rsize); if (bh_insert(lword, 4) == -1 || bh_insertcrc() == -1) { ERROR(errno, bh_error); return -1; } if (hfs_setfork(ifile, 0) == -1) { ERROR(errno, hfs_error); return -1; } if (fork_binh(ifile, ent.u.file.dsize) == -1) return -1; if (hfs_setfork(ifile, 1) == -1) { ERROR(errno, hfs_error); return -1; } if (fork_binh(ifile, ent.u.file.rsize) == -1) return -1; return 0; }
/* * NAME: do_macb() * DESCRIPTION: perform copy using MacBinary II translation */ static int do_macb(hfsfile *ifile, int ofile) { hfsdirent ent; unsigned char buf[MACB_BLOCKSZ]; long bytes; if (hfs_fstat(ifile, &ent) == -1) { ERROR(errno, hfs_error); return -1; } memset(buf, 0, MACB_BLOCKSZ); buf[1] = strlen(ent.name); strcpy((char *) &buf[2], ent.name); memcpy(&buf[65], ent.u.file.type, 4); memcpy(&buf[69], ent.u.file.creator, 4); buf[73] = ent.fdflags >> 8; d_putul(&buf[83], ent.u.file.dsize); d_putul(&buf[87], ent.u.file.rsize); d_putul(&buf[91], d_mtime(ent.crdate)); d_putul(&buf[95], d_mtime(ent.mddate)); buf[101] = ent.fdflags & 0xff; buf[122] = buf[123] = 129; d_putuw(&buf[124], crc_macb(buf, 124, 0x0000)); bytes = write(ofile, buf, MACB_BLOCKSZ); if (bytes == -1) { ERROR(errno, "error writing data"); return -1; } else if (bytes != MACB_BLOCKSZ) { ERROR(EIO, "wrote incomplete chunk"); return -1; } if (hfs_setfork(ifile, 0) == -1) { ERROR(errno, hfs_error); return -1; } if (fork_macb(ifile, ofile, ent.u.file.dsize) == -1) return -1; if (hfs_setfork(ifile, 1) == -1) { ERROR(errno, hfs_error); return -1; } if (fork_macb(ifile, ofile, ent.u.file.rsize) == -1) return -1; return 0; }
/* copy_to_mac_vol: copy all files in a directory to corresponding ** Mac folder. ** ** Files are copied recursively to corresponding folders on the Mac ** volume. The caller routine needs to do a hfs_chdir before calling this ** routine. */ int FDECL2(copy_to_mac_vol, hfsvol *, vol, struct directory *, node) { struct directory_entry * s_entry; /* ISO directory entry */ struct directory_entry * s_entry1; /* tmp ISO directory entry */ struct directory *dpnt; /* ISO directory */ hfsfile *hfp; /* HFS file */ hfsdirent *ent; /* HFS file entities */ long id; /* current HFS folder */ long dext, rext; /* real data/rsrc start blk */ int ret; /* result code */ int new_name; /* HFS file has modified name */ int tens; int digits; int i; /* store the current HFS directory ID */ if ((id = hfs_getcwd(vol)) == 0) return(-1); if (verbose > 1) fprintf(stderr,"HFS scanning %s\n", node->whole_name); /* loop through the ISO directory entries and process files */ for(s_entry = node->contents; s_entry; s_entry = s_entry->next) { /* ignore directory and associated (rsrc) files */ if(s_entry->isorec.flags[0]) continue; /* ignore any non-Mac type file */ if(!s_entry->hfs_ent) continue; #ifdef DEBUG fprintf(stderr," Name = %s", s_entry->whole_name); fprintf(stderr," Startb = %d\n", s_entry->starting_block); #endif /* DEBUG */ ent = s_entry->hfs_ent; /* create file */ i = HFS_MAX_FLEN - strlen(ent->name); new_name = 0; tens = TEN; digits = 1; while (1) { /* try to open file - if it exists, then append '_' to the name and try again */ errno = 0; if ((hfs_create(vol, ent->name, ent->type, ent->creator)) < 0) { if (errno != EEXIST ) { /* not an "exist" error, or we can't append as the filename is already HFS_MAX_FLEN chars */ snprintf(hce->error, ERROR_SIZE, "can't HFS create file %s", s_entry->whole_name); return(-1); } else if (i == 0) { /* File name at max HFS length - make unique name */ if (!new_name) new_name++; sprintf(ent->name + HFS_MAX_FLEN - digits - 1, "%s%d", LCHAR, new_name); new_name++; if (new_name == tens) { tens *= TEN; digits++; } } else { /* append '_' to get new name */ strcat(ent->name, LCHAR); i--; new_name = 1; } } else break; } /* warn that we have a new name */ if (new_name && verbose > 0) { fprintf(stderr, "Using HFS name: %s for %s\n", ent->name, s_entry->whole_name); } /* open file */ if ((hfp = hfs_open(vol, ent->name)) == 0) { snprintf(hce->error, ERROR_SIZE, "can't HFS open %s", s_entry->whole_name); return(-1); } /* if it has a data fork, then "write" it out */ if (ent->dsize) write_fork(hfp, ent->dsize); /* if it has a resource fork, set the fork and "write" it out */ if (ent->rsize) { if ((hfs_setfork(hfp, 1)) < 0) return(-1); write_fork(hfp, ent->rsize); } /* update any HFS file attributes */ if ((hfs_fsetattr(hfp, ent)) < 0) { snprintf(hce->error, ERROR_SIZE, "can't HFS set attributes %s", s_entry->whole_name); return(-1); } /* get the ISO starting block of data fork (may be zero) and convert to the equivalent HFS block */ if (ent->dsize) dext = s_entry->starting_block * BLK_CONV; else dext = 0; /* if the file has a resource fork (associated file), get it's ISO starting block and convert as above */ if (s_entry->assoc && ent->rsize) rext = s_entry->assoc->starting_block * BLK_CONV; else rext = 0; /* close the file and update the starting blocks */ if (hfs_close(hfp, dext, rext) < 0) { snprintf(hce->error, ERROR_SIZE, "can't HFS close file %s", s_entry->whole_name); return(-1); } } /* process sub-directories - have a slight problem here, if the directory had been relocated, then we need to find the real directory - we do this by first finding the real directory_entry, and then finding it's directory info */ /* following code taken from joliet.c */ for(s_entry=node->contents;s_entry;s_entry=s_entry->next) { if((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) { /* if the directory has been reloacted, then search the relocated directory for the real entry */ for(s_entry1=reloc_dir->contents;s_entry1;s_entry1=s_entry1->next) { if(s_entry1->parent_rec == s_entry) break; } /* have a problem - can't find the real directory */ if(s_entry1 == NULL) { snprintf(hce->error, ERROR_SIZE, "can't locate relocated directory %s", s_entry->whole_name); return(-1); } } else s_entry1 = s_entry; /* now have the correct entry - now find the actual directory */ if ((s_entry1->isorec.flags[0] & 2) && strcmp(s_entry1->name,".") && strcmp(s_entry1->name,"..")) { if((s_entry->de_flags & RELOCATED_DIRECTORY) != 0) dpnt = reloc_dir->subdir; else dpnt = node->subdir; while(1) { if (dpnt->self == s_entry1) break; dpnt = dpnt->next; if(!dpnt) { snprintf(hce->error, ERROR_SIZE, "can't find directory location %s", s_entry1->whole_name); return (-1); } } /* now have the correct directory - so do the HFS stuff */ ent = dpnt->hfs_ent; /* if we don't have hfs entries, then this is a "deep" directory - this will be processed later */ if (!ent) continue; /* make sub-folder */ i = HFS_MAX_FLEN - strlen(ent->name); new_name = 0; tens = TEN; digits = 1; while (1) { /* try to create new directory - if it exists, then append '_' to the name and try again */ errno = 0; if (hfs_mkdir(vol, ent->name) < 0) { if (errno != EEXIST) { /* not an "exist" error, or we can't append as the filename is already HFS_MAX_FLEN chars */ snprintf(hce->error, ERROR_SIZE, "can't HFS create folder %s", s_entry->whole_name); return(-1); } else if (i == 0) { /* File name at max HFS length - make unique name */ if (!new_name) new_name++; sprintf(ent->name + HFS_MAX_FLEN - digits - 1, "%s%d", LCHAR, new_name); new_name++; if (new_name == tens) { tens *= TEN; digits++; } } else { /* append '_' to get new name */ strcat(ent->name, LCHAR); i--; new_name = 1; } } else break; } /* warn that we have a new name */ if (new_name && verbose > 0) { fprintf(stderr, "Using HFS name: %s for %s\n", ent->name, s_entry->whole_name); } /* see if we need to "bless" this folder */ if (hfs_bless && strcmp(s_entry->whole_name, hfs_bless) == 0) { hfs_stat(vol, ent->name, ent); hfs_vsetbless(vol, ent->cnid); if (verbose > 0) { fprintf(stderr, "Blessing %s (%s)\n", ent->name, s_entry->whole_name); } /* stop any further checks */ hfs_bless = NULL; } /* change to sub-folder */ if (hfs_chdir(vol, ent->name) < 0) return(-1); /* recursively copy files ... */ ret = copy_to_mac_vol(vol, dpnt); if (ret < 0) return(ret); /* change back to this folder */ if (hfs_setcwd(vol, id) < 0) return(-1); } } return(0); }