static errno_t fuse_vfsop_setattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context) { int error = 0; fuse_trace_printf_vfsop(); kauth_cred_t cred = vfs_context_ucred(context); if (!fuse_vfs_context_issuser(context) && (kauth_cred_getuid(cred) != vfs_statfs(mp)->f_owner)) { return EACCES; } struct fuse_data *data = fuse_get_mpdata(mp); if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) { if (!fuse_implemented(data, FSESS_NOIMPLBIT(SETVOLNAME))) { error = ENOTSUP; goto out; } if (fsap->f_vol_name[0] == 0) { error = EINVAL; goto out; } size_t namelen = strlen(fsap->f_vol_name); if (namelen >= MAXPATHLEN) { error = ENAMETOOLONG; goto out; } vnode_t root_vp; error = fuse_vfsop_root(mp, &root_vp, context); if (error) { goto out; } struct fuse_dispatcher fdi; fdisp_init(&fdi, namelen + 1); fdisp_make_vp(&fdi, FUSE_SETVOLNAME, root_vp, context); memcpy((char *)fdi.indata, fsap->f_vol_name, namelen); ((char *)fdi.indata)[namelen] = '\0'; if (!(error = fdisp_wait_answ(&fdi))) { fuse_ticket_drop(fdi.tick); } (void)vnode_put(root_vp); if (error) { if (error == ENOSYS) { error = ENOTSUP; fuse_clear_implemented(data, FSESS_NOIMPLBIT(SETVOLNAME)); } goto out; } copystr(fsap->f_vol_name, data->volname, MAXPATHLEN - 1, &namelen); bzero(data->volname + namelen, MAXPATHLEN - namelen); VFSATTR_SET_SUPPORTED(fsap, f_vol_name); } out: return error; }
static errno_t fuse_vfsop_getattr(mount_t mp, struct vfs_attr *attr, vfs_context_t context) { int err = 0; bool deading = false, faking = false; struct fuse_dispatcher fdi; struct fuse_statfs_out *fsfo; struct fuse_statfs_out faked; struct fuse_data *data; fuse_trace_printf_vfsop(); data = fuse_get_mpdata(mp); if (!data) { panic("fuse4x: no private data for mount point?"); } if (!(data->dataflags & FSESS_INITED)) { // coreservices process requests ATTR_VOL_CAPABILITIES on the mountpoint right before // returning from mount() syscall. We need to fake the output because daemon might // not be ready to response yet (and deadlock will happen). faking = true; goto dostatfs; } fdisp_init(&fdi, 0); fdisp_make(&fdi, FUSE_STATFS, mp, FUSE_ROOT_ID, context); if ((err = fdisp_wait_answ(&fdi))) { // If we cannot communicate with the daemon (most likely because // it's dead), we still want to portray that we are a bonafide // file system so that we can be gracefully unmounted. if (err == ENOTCONN) { deading = faking = true; goto dostatfs; } return err; } dostatfs: if (faking) { bzero(&faked, sizeof(faked)); fsfo = &faked; } else { fsfo = fdi.answ; } if (fsfo->st.bsize == 0) { fsfo->st.bsize = FUSE_DEFAULT_IOSIZE; } if (fsfo->st.frsize == 0) { fsfo->st.frsize = FUSE_DEFAULT_BLOCKSIZE; } /* optimal transfer block size; will go into f_iosize in the kernel */ fsfo->st.bsize = fuse_round_size(fsfo->st.bsize, FUSE_MIN_IOSIZE, FUSE_MAX_IOSIZE); /* file system fragment size; will go into f_bsize in the kernel */ fsfo->st.frsize = fuse_round_size(fsfo->st.frsize, FUSE_MIN_BLOCKSIZE, FUSE_MAX_BLOCKSIZE); /* We must have: f_iosize >= f_bsize (fsfo->st.bsize >= fsfo->st_frsize) */ if (fsfo->st.bsize < fsfo->st.frsize) { fsfo->st.bsize = fsfo->st.frsize; } /* * TBD: Possibility: * * For actual I/O to fuse4x's "virtual" storage device, we use * data->blocksize and data->iosize. These are really meant to be * constant across the lifetime of a single mount. If necessary, we * can experiment by updating the mount point's stat with the frsize * and bsize values we come across here. */ /* * FUSE user daemon will (might) give us this: * * __u64 blocks; // total data blocks in the file system * __u64 bfree; // free blocks in the file system * __u64 bavail; // free blocks available to non-superuser * __u64 files; // total file nodes in the file system * __u64 ffree; // free file nodes in the file system * __u32 bsize; // preferred/optimal file system block size * __u32 namelen; // maximum length of filenames * __u32 frsize; // fundamental file system block size * * On Mac OS X, we will map this data to struct vfs_attr as follows: * * Mac OS X FUSE * -------- ---- * uint64_t f_supported <- // handled here * uint64_t f_active <- // handled here * uint64_t f_objcount <- - * uint64_t f_filecount <- files * uint64_t f_dircount <- - * uint32_t f_bsize <- frsize * size_t f_iosize <- bsize * uint64_t f_blocks <- blocks * uint64_t f_bfree <- bfree * uint64_t f_bavail <- bavail * uint64_t f_bused <- blocks - bfree * uint64_t f_files <- files * uint64_t f_ffree <- ffree * fsid_t f_fsid <- // handled elsewhere * uid_t f_owner <- // handled elsewhere * ... capabilities <- // handled here * ... attributes <- // handled here * f_create_time <- - * f_modify_time <- - * f_access_time <- - * f_backup_time <- - * uint32_t f_fssubtype <- // daemon provides * char *f_vol_name <- // handled here * uint16_t f_signature <- // handled here * uint16_t f_carbon_fsid <- // handled here */ VFSATTR_RETURN(attr, f_filecount, fsfo->st.files); VFSATTR_RETURN(attr, f_bsize, fsfo->st.frsize); VFSATTR_RETURN(attr, f_iosize, fsfo->st.bsize); VFSATTR_RETURN(attr, f_blocks, fsfo->st.blocks); VFSATTR_RETURN(attr, f_bfree, fsfo->st.bfree); VFSATTR_RETURN(attr, f_bavail, fsfo->st.bavail); VFSATTR_RETURN(attr, f_bused, (fsfo->st.blocks - fsfo->st.bfree)); VFSATTR_RETURN(attr, f_files, fsfo->st.files); VFSATTR_RETURN(attr, f_ffree, fsfo->st.ffree); /* f_fsid and f_owner handled elsewhere. */ /* Handle capabilities and attributes. */ handle_capabilities_and_attributes(mp, attr); VFSATTR_RETURN(attr, f_create_time, kZeroTime); VFSATTR_RETURN(attr, f_modify_time, kZeroTime); VFSATTR_RETURN(attr, f_access_time, kZeroTime); VFSATTR_RETURN(attr, f_backup_time, kZeroTime); if (deading) { VFSATTR_RETURN(attr, f_fssubtype, (uint32_t)FUSE_FSSUBTYPE_INVALID); } else { VFSATTR_RETURN(attr, f_fssubtype, data->fssubtype); } /* Daemon needs to pass this. */ if (VFSATTR_IS_ACTIVE(attr, f_vol_name)) { if (data->volname[0] != 0) { strncpy(attr->f_vol_name, data->volname, MAXPATHLEN); attr->f_vol_name[MAXPATHLEN - 1] = 0; VFSATTR_SET_SUPPORTED(attr, f_vol_name); } } VFSATTR_RETURN(attr, f_signature, OSSwapBigToHostInt16(FUSEFS_SIGNATURE)); VFSATTR_RETURN(attr, f_carbon_fsid, 0); if (!faking) fuse_ticket_drop(fdi.tick); return 0; }
static int zfs_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, __unused vfs_context_t context) { zfsvfs_t *zfsvfs = vfs_fsprivate(mp); uint64_t refdbytes, availbytes, usedobjs, availobjs; ZFS_ENTER(zfsvfs); dmu_objset_space(zfsvfs->z_os, &refdbytes, &availbytes, &usedobjs, &availobjs); VFSATTR_RETURN(fsap, f_objcount, usedobjs); VFSATTR_RETURN(fsap, f_maxobjcount, 0x7fffffffffffffff); /* * Carbon depends on f_filecount and f_dircount so * make up some values based on total objects. */ VFSATTR_RETURN(fsap, f_filecount, usedobjs - (usedobjs / 4)); VFSATTR_RETURN(fsap, f_dircount, usedobjs / 4); /* * The underlying storage pool actually uses multiple block sizes. * We report the fragsize as the smallest block size we support, * and we report our blocksize as the filesystem's maximum blocksize. */ VFSATTR_RETURN(fsap, f_bsize, 1UL << SPA_MINBLOCKSHIFT); VFSATTR_RETURN(fsap, f_iosize, zfsvfs->z_max_blksz); /* * The following report "total" blocks of various kinds in the * file system, but reported in terms of f_frsize - the * "fragment" size. */ VFSATTR_RETURN(fsap, f_blocks, (u_int64_t)((refdbytes + availbytes) >> SPA_MINBLOCKSHIFT)); VFSATTR_RETURN(fsap, f_bfree, (u_int64_t)(availbytes >> SPA_MINBLOCKSHIFT)); VFSATTR_RETURN(fsap, f_bavail, fsap->f_bfree); /* no root reservation */ VFSATTR_RETURN(fsap, f_bused, fsap->f_blocks - fsap->f_bfree); /* * statvfs() should really be called statufs(), because it assumes * static metadata. ZFS doesn't preallocate files, so the best * we can do is report the max that could possibly fit in f_files, * and that minus the number actually used in f_ffree. * For f_ffree, report the smaller of the number of object available * and the number of blocks (each object will take at least a block). */ VFSATTR_RETURN(fsap, f_ffree, (u_int64_t)MIN(availobjs, fsap->f_bfree)); VFSATTR_RETURN(fsap, f_files, fsap->f_ffree + usedobjs); #if 0 statp->f_flag = vf_to_stf(vfsp->vfs_flag); #endif if (VFSATTR_IS_ACTIVE(fsap, f_fsid)) { VFSATTR_RETURN(fsap, f_fsid, vfs_statfs(mp)->f_fsid); } if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) { bcopy(&zfs_capabilities, &fsap->f_capabilities, sizeof (zfs_capabilities)); VFSATTR_SET_SUPPORTED(fsap, f_capabilities); } if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) { bcopy(&zfs_attributes, &fsap->f_attributes.validattr, sizeof (zfs_attributes)); bcopy(&zfs_attributes, &fsap->f_attributes.nativeattr, sizeof (zfs_attributes)); VFSATTR_SET_SUPPORTED(fsap, f_attributes); } if (VFSATTR_IS_ACTIVE(fsap, f_create_time)) { dmu_objset_stats_t dmu_stat; dmu_objset_fast_stat(zfsvfs->z_os, &dmu_stat); fsap->f_create_time.tv_sec = dmu_stat.dds_creation_time; fsap->f_create_time.tv_nsec = 0; VFSATTR_SET_SUPPORTED(fsap, f_create_time); } if (VFSATTR_IS_ACTIVE(fsap, f_modify_time)) { if (zfsvfs->z_mtime_vp != NULL) { znode_t *mzp; mzp = VTOZ(zfsvfs->z_mtime_vp); ZFS_TIME_DECODE(&fsap->f_modify_time, mzp->z_phys->zp_mtime); } else { fsap->f_modify_time.tv_sec = 0; fsap->f_modify_time.tv_nsec = 0; } VFSATTR_SET_SUPPORTED(fsap, f_modify_time); } /* * For Carbon compatibility, pretend to support this legacy/unused * attribute */ if (VFSATTR_IS_ACTIVE(fsap, f_backup_time)) { fsap->f_backup_time.tv_sec = 0; fsap->f_backup_time.tv_nsec = 0; VFSATTR_SET_SUPPORTED(fsap, f_backup_time); } if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) { spa_t *spa = dmu_objset_spa(zfsvfs->z_os); spa_config_enter(spa, RW_READER, FTAG); strlcpy(fsap->f_vol_name, spa_name(spa), MAXPATHLEN); spa_config_exit(spa, FTAG); VFSATTR_SET_SUPPORTED(fsap, f_vol_name); } VFSATTR_RETURN(fsap, f_fssubtype, 0); VFSATTR_RETURN(fsap, f_signature, 0x5a21); /* 'Z!' */ VFSATTR_RETURN(fsap, f_carbon_fsid, 0); ZFS_EXIT(zfsvfs); return (0); }
static int devfs_vfs_getattr(__unused mount_t mp, struct vfs_attr *fsap, __unused vfs_context_t ctx) { VFSATTR_RETURN(fsap, f_objcount, devfs_stats.nodes); VFSATTR_RETURN(fsap, f_maxobjcount, devfs_stats.nodes); VFSATTR_RETURN(fsap, f_bsize, 512); VFSATTR_RETURN(fsap, f_iosize, 512); if (VFSATTR_IS_ACTIVE(fsap, f_blocks) || VFSATTR_IS_ACTIVE(fsap, f_bused)) { fsap->f_blocks = (devfs_stats.mounts * sizeof(struct devfsmount) + devfs_stats.nodes * sizeof(devnode_t) + devfs_stats.entries * sizeof(devdirent_t) + devfs_stats.stringspace ) / fsap->f_bsize; fsap->f_bused = fsap->f_blocks; VFSATTR_SET_SUPPORTED(fsap, f_blocks); VFSATTR_SET_SUPPORTED(fsap, f_bused); } VFSATTR_RETURN(fsap, f_bfree, 0); VFSATTR_RETURN(fsap, f_bavail, 0); VFSATTR_RETURN(fsap, f_files, devfs_stats.nodes); VFSATTR_RETURN(fsap, f_ffree, 0); VFSATTR_RETURN(fsap, f_fssubtype, 0); if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) { fsap->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS | VOL_CAP_FMT_NO_ROOT_TIMES | VOL_CAP_FMT_CASE_SENSITIVE | VOL_CAP_FMT_CASE_PRESERVING | VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_2TB_FILESIZE | VOL_CAP_FMT_HIDDEN_FILES; fsap->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] = VOL_CAP_INT_ATTRLIST ; fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0; fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0; fsap->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS | VOL_CAP_FMT_JOURNAL | VOL_CAP_FMT_JOURNAL_ACTIVE | VOL_CAP_FMT_NO_ROOT_TIMES | VOL_CAP_FMT_SPARSE_FILES | VOL_CAP_FMT_ZERO_RUNS | VOL_CAP_FMT_CASE_SENSITIVE | VOL_CAP_FMT_CASE_PRESERVING | VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_2TB_FILESIZE | VOL_CAP_FMT_OPENDENYMODES | VOL_CAP_FMT_HIDDEN_FILES | VOL_CAP_FMT_PATH_FROM_ID | VOL_CAP_FMT_NO_VOLUME_SIZES; fsap->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] = VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | VOL_CAP_INT_READDIRATTR | VOL_CAP_INT_EXCHANGEDATA | VOL_CAP_INT_COPYFILE | VOL_CAP_INT_ALLOCATE | VOL_CAP_INT_VOL_RENAME | VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK | VOL_CAP_INT_EXTENDED_SECURITY | VOL_CAP_INT_USERACCESS | VOL_CAP_INT_MANLOCK | VOL_CAP_INT_EXTENDED_ATTR | VOL_CAP_INT_NAMEDSTREAMS; fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0; fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0; VFSATTR_SET_SUPPORTED(fsap, f_capabilities); } if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) { fsap->f_attributes.validattr.commonattr = ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_PAROBJID | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS | ATTR_CMN_FILEID; fsap->f_attributes.validattr.volattr = ATTR_VOL_FSTYPE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_OBJCOUNT | ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES; fsap->f_attributes.validattr.dirattr = ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS; fsap->f_attributes.validattr.fileattr = ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH; fsap->f_attributes.validattr.forkattr = 0; fsap->f_attributes.nativeattr.commonattr = ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_PAROBJID | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS | ATTR_CMN_FILEID; fsap->f_attributes.nativeattr.volattr = ATTR_VOL_FSTYPE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_OBJCOUNT | ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES; fsap->f_attributes.nativeattr.dirattr = ATTR_DIR_MOUNTSTATUS; fsap->f_attributes.nativeattr.fileattr = ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_DATALENGTH; fsap->f_attributes.nativeattr.forkattr = 0; VFSATTR_SET_SUPPORTED(fsap, f_attributes); } return 0; }
static int nullfs_vfs_getattr(struct mount * mp, struct vfs_attr * vfap, vfs_context_t ctx) { struct vnode * coveredvp = NULL; struct vfs_attr vfa; struct null_mount * null_mp = MOUNTTONULLMOUNT(mp); vol_capabilities_attr_t capabilities; struct vfsstatfs * sp = vfs_statfs(mp); struct timespec tzero = {0, 0}; NULLFSDEBUG("%s\n", __FUNCTION__); /* Set default capabilities in case the lower file system is gone */ memset(&capabilities, 0, sizeof(capabilities)); capabilities.capabilities[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_HIDDEN_FILES; capabilities.valid[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_HIDDEN_FILES; if (nullfs_vfs_getlowerattr(vnode_mount(null_mp->nullm_lowerrootvp), &vfa, ctx) == 0) { if (VFSATTR_IS_SUPPORTED(&vfa, f_capabilities)) { memcpy(&capabilities, &vfa.f_capabilities, sizeof(capabilities)); /* don't support vget */ capabilities.capabilities[VOL_CAPABILITIES_FORMAT] &= ~(VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_PATH_FROM_ID); capabilities.capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_HIDDEN_FILES; /* Always support UF_HIDDEN */ capabilities.valid[VOL_CAPABILITIES_FORMAT] &= ~(VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_PATH_FROM_ID); capabilities.valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_HIDDEN_FILES; /* Always support UF_HIDDEN */ /* dont' support interfaces that only make sense on a writable file system * or one with specific vnops implemented */ capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] = 0; capabilities.valid[VOL_CAPABILITIES_INTERFACES] &= ~(VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_READDIRATTR | VOL_CAP_INT_EXCHANGEDATA | VOL_CAP_INT_COPYFILE | VOL_CAP_INT_ALLOCATE | VOL_CAP_INT_VOL_RENAME | VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK); } } if (VFSATTR_IS_ACTIVE(vfap, f_create_time)) VFSATTR_RETURN(vfap, f_create_time, tzero); if (VFSATTR_IS_ACTIVE(vfap, f_modify_time)) VFSATTR_RETURN(vfap, f_modify_time, tzero); if (VFSATTR_IS_ACTIVE(vfap, f_access_time)) VFSATTR_RETURN(vfap, f_access_time, tzero); if (VFSATTR_IS_ACTIVE(vfap, f_bsize)) VFSATTR_RETURN(vfap, f_bsize, sp->f_bsize); if (VFSATTR_IS_ACTIVE(vfap, f_iosize)) VFSATTR_RETURN(vfap, f_iosize, sp->f_iosize); if (VFSATTR_IS_ACTIVE(vfap, f_owner)) VFSATTR_RETURN(vfap, f_owner, 0); if (VFSATTR_IS_ACTIVE(vfap, f_blocks)) VFSATTR_RETURN(vfap, f_blocks, sp->f_blocks); if (VFSATTR_IS_ACTIVE(vfap, f_bfree)) VFSATTR_RETURN(vfap, f_bfree, sp->f_bfree); if (VFSATTR_IS_ACTIVE(vfap, f_bavail)) VFSATTR_RETURN(vfap, f_bavail, sp->f_bavail); if (VFSATTR_IS_ACTIVE(vfap, f_bused)) VFSATTR_RETURN(vfap, f_bused, sp->f_bused); if (VFSATTR_IS_ACTIVE(vfap, f_files)) VFSATTR_RETURN(vfap, f_files, sp->f_files); if (VFSATTR_IS_ACTIVE(vfap, f_ffree)) VFSATTR_RETURN(vfap, f_ffree, sp->f_ffree); if (VFSATTR_IS_ACTIVE(vfap, f_fssubtype)) VFSATTR_RETURN(vfap, f_fssubtype, 0); if (VFSATTR_IS_ACTIVE(vfap, f_capabilities)) { memcpy(&vfap->f_capabilities, &capabilities, sizeof(vol_capabilities_attr_t)); VFSATTR_SET_SUPPORTED(vfap, f_capabilities); } if (VFSATTR_IS_ACTIVE(vfap, f_attributes)) { vol_attributes_attr_t * volattr = &vfap->f_attributes; volattr->validattr.commonattr = 0; volattr->validattr.volattr = ATTR_VOL_NAME | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES; volattr->validattr.dirattr = 0; volattr->validattr.fileattr = 0; volattr->validattr.forkattr = 0; volattr->nativeattr.commonattr = 0; volattr->nativeattr.volattr = ATTR_VOL_NAME | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES; volattr->nativeattr.dirattr = 0; volattr->nativeattr.fileattr = 0; volattr->nativeattr.forkattr = 0; VFSATTR_SET_SUPPORTED(vfap, f_attributes); } if (VFSATTR_IS_ACTIVE(vfap, f_vol_name)) { /* The name of the volume is the same as the directory we mounted on */ coveredvp = vfs_vnodecovered(mp); if (coveredvp) { const char * name = vnode_getname_printable(coveredvp); strlcpy(vfap->f_vol_name, name, MAXPATHLEN); vnode_putname_printable(name); VFSATTR_SET_SUPPORTED(vfap, f_vol_name); vnode_put(coveredvp); } } return 0; }
static int vfs_getattr_9p(mount_t mp, struct vfs_attr *ap, vfs_context_t ctx) { #pragma unused(ctx) struct vfsstatfs *sp; mount_9p *nmp; TRACE(); nmp = MTO9P(mp); sp = vfs_statfs(mp); VFSATTR_RETURN(ap, f_bsize, sp->f_bsize); VFSATTR_RETURN(ap, f_iosize, sp->f_iosize); // VFSATTR_RETURN(ap, f_blocks, sp->f_blocks); // VFSATTR_RETURN(ap, f_bfree, sp->f_bfree); // VFSATTR_RETURN(ap, f_bavail, sp->f_bavail); // VFSATTR_RETURN(ap, f_bused, sp->f_bused); VFSATTR_RETURN(ap, f_files, sp->f_files); VFSATTR_RETURN(ap, f_ffree, sp->f_ffree); if (VFSATTR_IS_ACTIVE(ap, f_capabilities)) { ap->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] = 0 | VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS | VOL_CAP_FMT_JOURNAL | VOL_CAP_FMT_JOURNAL_ACTIVE | VOL_CAP_FMT_NO_ROOT_TIMES | VOL_CAP_FMT_SPARSE_FILES | VOL_CAP_FMT_ZERO_RUNS | VOL_CAP_FMT_CASE_SENSITIVE | VOL_CAP_FMT_CASE_PRESERVING | VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_2TB_FILESIZE | VOL_CAP_FMT_OPENDENYMODES | VOL_CAP_FMT_HIDDEN_FILES | VOL_CAP_FMT_PATH_FROM_ID | VOL_CAP_FMT_NO_VOLUME_SIZES | VOL_CAP_FMT_DECMPFS_COMPRESSION ; ap->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] = 0 | VOL_CAP_FMT_NO_ROOT_TIMES | VOL_CAP_FMT_CASE_SENSITIVE | VOL_CAP_FMT_CASE_PRESERVING | VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_2TB_FILESIZE | VOL_CAP_FMT_NO_VOLUME_SIZES ; ap->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] = 0 | VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | VOL_CAP_INT_READDIRATTR | VOL_CAP_INT_EXCHANGEDATA | VOL_CAP_INT_COPYFILE | VOL_CAP_INT_ALLOCATE | VOL_CAP_INT_VOL_RENAME | VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK | VOL_CAP_INT_EXTENDED_SECURITY | VOL_CAP_INT_USERACCESS | VOL_CAP_INT_MANLOCK | VOL_CAP_INT_NAMEDSTREAMS | VOL_CAP_INT_EXTENDED_ATTR ; ap->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] = 0 | VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK ; ap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0; ap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0; ap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0; ap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0; VFSATTR_SET_SUPPORTED(ap, f_capabilities); } if (VFSATTR_IS_ACTIVE(ap, f_attributes)) { ap->f_attributes.nativeattr.commonattr = ap->f_attributes.validattr.commonattr = 0; ap->f_attributes.nativeattr.volattr = ap->f_attributes.validattr.volattr = 0 | ATTR_VOL_IOBLOCKSIZE | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES ; ap->f_attributes.nativeattr.dirattr = ap->f_attributes.validattr.dirattr = 0; ap->f_attributes.nativeattr.fileattr = ap->f_attributes.validattr.fileattr = 0; ap->f_attributes.nativeattr.forkattr = ap->f_attributes.validattr.forkattr = 0; VFSATTR_SET_SUPPORTED(ap, f_attributes); } if (VFSATTR_IS_ACTIVE(ap, f_vol_name)) { strlcpy(ap->f_vol_name, nmp->volume, MAXPATHLEN); VFSATTR_SET_SUPPORTED(ap, f_vol_name); } return 0; }
/** * VBoxVFS get VFS layer object attribute callback. * * @param mp Mount data provided by VFS layer. * @param pAttr Output buffer to return attributes. * @param pContext kAuth context needed in order to authentificate mount operation. * * @returns 0 for success, else an error code. */ static int vboxvfs_getattr(struct mount *mp, struct vfs_attr *pAttr, vfs_context_t pContext) { NOREF(pContext); vboxvfs_mount_t *pMount; SHFLVOLINFO SHFLVolumeInfo; int rc; uint32_t cbBuffer = sizeof(SHFLVolumeInfo); uint32_t u32bsize; uint64_t u64blocks; uint64_t u64bfree; PDEBUG("Getting attribute...\n"); AssertReturn(mp, EINVAL); pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); AssertReturn(pMount->pShareName, EINVAL); rc = VbglR0SfFsInfo(&g_vboxSFClient, &pMount->pMap, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbBuffer, (PSHFLDIRINFO)&SHFLVolumeInfo); AssertReturn(rc == 0, EPROTO); u32bsize = (uint32_t)SHFLVolumeInfo.ulBytesPerAllocationUnit; AssertReturn(u32bsize > 0, ENOTSUP); u64blocks = (uint64_t)SHFLVolumeInfo.ullTotalAllocationBytes / (uint64_t)u32bsize; u64bfree = (uint64_t)SHFLVolumeInfo.ullAvailableAllocationBytes / (uint64_t)u32bsize; VFSATTR_RETURN(pAttr, f_bsize, u32bsize); VFSATTR_RETURN(pAttr, f_blocks, u64blocks); VFSATTR_RETURN(pAttr, f_bfree, u64bfree); VFSATTR_RETURN(pAttr, f_bavail, u64bfree); VFSATTR_RETURN(pAttr, f_bused, u64blocks - u64bfree); VFSATTR_RETURN(pAttr, f_owner, pMount->owner); VFSATTR_CLEAR_ACTIVE(pAttr, f_iosize); VFSATTR_CLEAR_ACTIVE(pAttr, f_files); VFSATTR_CLEAR_ACTIVE(pAttr, f_ffree); VFSATTR_CLEAR_ACTIVE(pAttr, f_fssubtype); /* todo: take care about f_capabilities and f_attributes, f_fsid */ VFSATTR_CLEAR_ACTIVE(pAttr, f_capabilities); VFSATTR_CLEAR_ACTIVE(pAttr, f_attributes); VFSATTR_CLEAR_ACTIVE(pAttr, f_fsid); /* todo: take care about f_create_time, f_modify_time, f_access_time, f_backup_time */ VFSATTR_CLEAR_ACTIVE(pAttr, f_create_time); VFSATTR_CLEAR_ACTIVE(pAttr, f_modify_time); VFSATTR_CLEAR_ACTIVE(pAttr, f_access_time); VFSATTR_CLEAR_ACTIVE(pAttr, f_backup_time); VFSATTR_CLEAR_ACTIVE(pAttr, f_signature); VFSATTR_CLEAR_ACTIVE(pAttr, f_carbon_fsid); VFSATTR_CLEAR_ACTIVE(pAttr, f_uuid); if (VFSATTR_IS_ACTIVE(pAttr, f_vol_name)) { strlcpy(pAttr->f_vol_name, (char*)pMount->pShareName->String.utf8, MAXPATHLEN); VFSATTR_SET_SUPPORTED(pAttr, f_vol_name); } VFSATTR_ALL_SUPPORTED(pAttr); return 0; }