static int FuseHFS_statfs(const char *path, struct statvfs *stbuf) { memset(stbuf, 0, sizeof(*stbuf)); hfsvolent vstat; hfs_vstat(NULL, &vstat); stbuf->f_bsize = stbuf->f_frsize = vstat.alblocksz; stbuf->f_blocks = vstat.totbytes / vstat.alblocksz; stbuf->f_bfree = stbuf->f_bavail = vstat.freebytes / vstat.alblocksz; stbuf->f_files = vstat.numfiles + vstat.numdirs + 1; stbuf->f_namemax = HFS_MAX_FLEN; return 0; }
void * FuseHFS_init(struct fuse_conn_info *conn) { struct fuse_context *cntx=fuse_get_context(); struct fusehfs_options *options = cntx->private_data; #if (__FreeBSD__ >= 10) FUSE_ENABLE_SETVOLNAME(conn); // this actually doesn't do anything FUSE_ENABLE_XTIMES(conn); // and apparently this doesn't either #endif #ifdef DEBUG //char logfn[128]; //sprintf(logfn, "/fusefs_hfs/FuseHFS.%d.log", getpid()); //stderr = freopen(logfn, "a", stderr); log_to_file(); fprintf(stderr, "FuseHFS_init\n"); fflush(stderr); #endif // create iconv iconv_to_utf8 = iconv_open("UTF-8", options->encoding); if (iconv_to_utf8 == (iconv_t)-1) { perror("iconv_open"); exit(1); } iconv_to_mac = iconv_open(options->encoding, "UTF-8"); if (iconv_to_mac == (iconv_t)-1) { perror("iconv_open"); exit(1); } // mount volume int mode = options->readonly?HFS_MODE_RDONLY:HFS_MODE_ANY; if (NULL == hfs_mount(options->path, 0, mode)) { perror("hfs_mount"); exit(1); } // initialize some globals _readonly = options->readonly; hfsvolent vstat; hfs_vstat(NULL, &vstat); strcpy(_volname, vstat.name); return NULL; }
static int FuseHFS_rename(const char *from, const char *to) { dprintf("rename %s %s\n", from, to); if (_readonly) return -EPERM; // convert to hfs paths char *hfspath1 = mkhfspath(from); char *hfspath2 = mkhfspath(to); // delete destination file if it exists hfsdirent ent; if (hfs_stat(NULL, hfspath2, &ent) == 0) if (!(ent.flags & HFS_ISDIR)) hfs_delete(NULL, hfspath2); // rename if (hfs_rename(NULL, hfspath1, hfspath2) != 0) { free(hfspath1); free(hfspath2); perror("hfs_rename"); return -errno; } // bless parent folder if it's a system file if (hfs_stat(NULL, hfspath2, &ent) == -1) { free(hfspath1); free(hfspath2); return -ENOENT; } if ((strcmp(ent.u.file.type, "zsys") == 0) && (strcmp(ent.u.file.creator, "MACS") == 0) && (strcmp(ent.name, "System") == 0)) { // bless dprintf("rename: blessing folder %lu\n", ent.parid); hfsvolent volent; hfs_vstat(NULL, &volent); volent.blessed = ent.parid; hfs_vsetattr(NULL, &volent); } // success free(hfspath1); free(hfspath2); 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; }
short int FS_MOUNT(unsigned short flag, struct vpfsi *pvpfsi, struct vpfsd *pvpfsd, unsigned short hVPB, unsigned short vol_descr, unsigned char *pBoot) { unsigned short oldVPB; unsigned long len_parm; unsigned char label[CCHMAXPATH], maclabel[HFS_MAX_VLEN+1]; hfsvolent volent; #ifdef DEBUG printf("Mount, flag = %hu, hVPB = %hu\n", flag, hVPB); #endif switch(flag) { case MOUNT_MOUNT: /* The cache uses hVPB as part of the key, so we flush it here. */ flush_cache(); /* Check for duplicate VPB */ oldVPB = hVPB; if( do_FSCtl(NULL, 0, NULL, &oldVPB, sizeof(unsigned short), &len_parm, FSCTL_FUNC_FINDDUPHVPB) == NO_ERROR ) { /* We should read the vol info and bitmap again here for the old VPB, as the volume may have been written while it was removed. */ /* Mark the VPB as duplicate */ set_vol_status(hVPB, pvpfsi->vpi_drive, MTSTAT_DUPLICATE); /* If necessary, mark the old VPB as mounted */ if(get_mount_status(oldVPB)==MTSTAT_REMOVED) set_vol_status(oldVPB, pvpfsi->vpi_drive, MTSTAT_MOUNTED); return NO_ERROR; } /* Mount the volume */ pvpfsd->vol = hfs_mount(hVPB, 1, pvpfsi->vpi_bsize, 0); if(pvpfsd->vol == NULL) { #ifdef DEBUG printf("hfs_mount failed!\n"); #endif return ERROR_VOLUME_NOT_MOUNTED; } if(hfs_vstat(pvpfsd->vol, &volent) < 0) { #ifdef DEBUG printf("hfs_vstat failed!\n"); #endif return ERROR_VOLUME_NOT_MOUNTED; } /* Fill vpfsi fields */ /* Use creation timestamp as ID */ pvpfsi->vpi_vid = volent.crdate; strcpy(maclabel, pvpfsd->vol->mdb.drVN); mac_to_os2_label(maclabel, label); strncpy(pvpfsi->vpi_text, label, 12); pvpfsi->vpi_text[11]=0; set_vol_status(hVPB, pvpfsi->vpi_drive, MTSTAT_MOUNTED); if(is_readonly(hVPB, pvpfsd->vol)) pvpfsd->vol->flags |= HFS_READONLY; #ifdef DEBUG printf("Got HFS volume\n"); #endif return NO_ERROR; case MOUNT_VOL_REMOVED: flush_cache(); /* If the disk was removed, forget about flushing. We should do a setvolume() here if volume is dirty, but it does not work. */ pvpfsd->vol->flags |= HFS_READONLY; return NO_ERROR; case MOUNT_RELEASE: switch(get_mount_status(hVPB)) { case MTSTAT_REMOVED: case MTSTAT_MOUNTED: hfs_umount(pvpfsd->vol); break; case MTSTAT_DUPLICATE: #ifdef DEBUG printf("Trying to unmount non-mounted volume!\n"); #endif break; } flush_cache(); set_vol_status(hVPB, 0, MTSTAT_FREE); return NO_ERROR; case MOUNT_ACCEPT: return ERROR_NOT_SUPPORTED; default: return ERROR_NOT_SUPPORTED; } }
/* * NAME: hformat->main() * DESCRIPTION: implement hformat command */ int hformat_main(int argc, char *argv[]) { const char *vname, *path; hfsvol *vol; hfsvolent ent; int nparts, partno, options = 0, result = 0; vname = "Untitled"; while (1) { int opt; opt = getopt(argc, argv, "fl:"); if (opt == EOF) break; switch (opt) { case '?': return usage(); case 'f': options |= O_FORCE; break; case 'l': vname = optarg; break; } } if (argc - optind < 1 || argc - optind > 2) return usage(); path = argv[optind]; nparts = hfs_nparts(path); if (argc - optind == 2) { partno = atoi(argv[optind + 1]); if (nparts != -1 && partno == 0) { if (options & O_FORCE) { fprintf(stderr, "%s: warning: erasing partition information\n", argv0); } else { fprintf(stderr, "%s: medium is partitioned; " "select partition > 0 or use -f\n", argv0); return 1; } } } else { if (nparts > 1) { fprintf(stderr, "%s: must specify partition number (%d available)\n", argv0, nparts); return 1; } else if (nparts == -1) partno = 0; else partno = 1; } vol = do_format(path, partno, vname); if (vol == 0) { hfsutil_perror(path); return 1; } hfs_vstat(vol, &ent); hfsutil_pinfo(&ent); if (hcwd_mounted(ent.name, ent.crdate, path, partno) == -1) { perror("Failed to record mount"); result = 1; } hfsutil_unmount(vol, &result); return result; }