static int zfsfuse_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); znode_t *znode; int error = zfs_zget(zfsvfs, ino, &znode, B_TRUE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vnode_t *vp = ZTOV(znode); ASSERT(vp != NULL); cred_t cred; zfsfuse_getcred(req, &cred); struct stat stbuf; error = zfsfuse_stat(vp, &stbuf, &cred); VN_RELE(vp); ZFS_EXIT(zfsvfs); if(!error) fuse_reply_attr(req, &stbuf, 0.0); return error; }
void hsx_fuse_readdir_plus(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { struct hsfs_readdir_ctx *saved_ctx, *ctx = NULL; struct hsfs_inode *parent; struct hsfs_super *sb; size_t res, len = 0; char * buf; int err, count = 0; DEBUG_IN("P_I(%lu), Size(%lld), Off(0x%llx)", ino, size, off); (void)fi; sb = fuse_req_userdata(req); FUSE_ASSERT(sb != NULL); parent = hsfs_ilookup(sb, ino); FUSE_ASSERT(parent != NULL); err = hsi_nfs3_readdir_plus(parent, size, off, &ctx, size); if(err) goto out1; saved_ctx = ctx; buf = (char *) malloc(size); if( NULL == buf){ err = ENOMEM; goto out2; } while(ctx != NULL){ struct fuse_entry_param e; hsx_fuse_fill_reply(ctx->inode, &e); res = fuse_add_direntry_plus(req, buf + len, size - len, ctx->name, &e, ctx->off); if(res > size - len) break; else if (res == size - len){ ctx = ctx->next; break; } count++; hsx_fuse_ref_inc(ctx->inode, 1); len += res; ctx = ctx->next; } if (!err) fuse_reply_buf(req, buf, len); free(buf); out2: __free_ctx(saved_ctx, 0); out1: if(err) fuse_reply_err(req, err); DEBUG_OUT("with %d, %d entries returned", err, count); return; }
void hsx_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags _U_) { struct hsfs_inode *hi = NULL; struct hsfs_super *sb = NULL; int type = 0; int err = 0; DEBUG_IN(" ino %lu.\n", ino); if ((sb = fuse_req_userdata(req)) == NULL) { ERR("ERR in fuse_req_userdata"); goto out; } if ((hi = hsfs_ilookup(sb, ino)) == NULL) { ERR("ERR in hsfs_ilookup"); goto out; } if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) type = ACL_TYPE_ACCESS; else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) type = ACL_TYPE_DEFAULT; else goto out; err = hsi_nfs3_setxattr(hi, value, type, size); fuse_reply_err(req, err); out: DEBUG_OUT("out,err: %d\n",err); fuse_reply_err(req, err); return; }
static int zfsfuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { if(strlen(name) >= MAXNAMELEN) return ENAMETOOLONG; vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); znode_t *znode; int error = zfs_zget(zfsvfs, parent, &znode, B_TRUE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vnode_t *dvp = ZTOV(znode); ASSERT(dvp != NULL); vnode_t *vp = NULL; cred_t cred; zfsfuse_getcred(req, &cred); error = VOP_LOOKUP(dvp, (char *) name, &vp, NULL, 0, NULL, &cred, NULL, NULL, NULL); if(error) goto out; struct fuse_entry_param e = { 0 }; e.attr_timeout = 0.0; e.entry_timeout = 0.0; if(vp == NULL) goto out; e.ino = VTOZ(vp)->z_id; if(e.ino == 3) e.ino = 1; e.generation = VTOZ(vp)->z_phys->zp_gen; error = zfsfuse_stat(vp, &e.attr, &cred); out: if(vp != NULL) VN_RELE(vp); VN_RELE(dvp); ZFS_EXIT(zfsvfs); if(!error) fuse_reply_entry(req, &e); return error; }
static int zfsfuse_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); file_info_t *info = (file_info_t *)(uintptr_t) fi->fh; ASSERT(info->vp != NULL); ASSERT(VTOZ(info->vp) != NULL); ASSERT(VTOZ(info->vp)->z_id == ino); cred_t cred; zfsfuse_getcred(req, &cred); int error = VOP_CLOSE(info->vp, info->flags, 1, (offset_t) 0, &cred, NULL); VERIFY(error == 0); VN_RELE(info->vp); kmem_cache_free(file_info_cache, info); ZFS_EXIT(zfsvfs); return error; }
static void sqfs_ll_op_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { sqfs_inode *inode; sqfs_ll *ll; if (fi->flags & (O_WRONLY | O_RDWR)) { fuse_reply_err(req, EROFS); return; } inode = malloc(sizeof(sqfs_inode)); if (!inode) { fuse_reply_err(req, ENOMEM); return; } ll = fuse_req_userdata(req); if (sqfs_ll_inode(ll, inode, ino)) { fuse_reply_err(req, ENOENT); } else if (!S_ISREG(inode->base.mode)) { fuse_reply_err(req, EISDIR); } else { fi->fh = (intptr_t)inode; fuse_reply_open(req, fi); return; } free(inode); }
static int zfsfuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) { if(strlen(name) >= MAXNAMELEN) return ENAMETOOLONG; vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); znode_t *znode; int error = zfs_zget(zfsvfs, parent, &znode, B_FALSE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vnode_t *dvp = ZTOV(znode); ASSERT(dvp != NULL); cred_t cred; zfsfuse_getcred(req, &cred); error = VOP_REMOVE(dvp, (char *) name, &cred, NULL, 0); VN_RELE(dvp); ZFS_EXIT(zfsvfs); return error; }
static void compiz_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { CompDisplay *d = (CompDisplay *)fuse_req_userdata(req); FuseInode *inode, *c; struct dirbuf b; inode = fuseFindInode(inodes, ino, DIR_MASK); if (!inode) { fuse_reply_err(req, ENOTDIR); return; } memset(&b, 0, sizeof (b)); dirbuf_add(req, &b, ".", ino); dirbuf_add(req, &b, "..", inode->parent ? inode->parent->ino : ino); if (!inode->child || !(inode->type & CONST_DIR_MASK)) fuseUpdateInode(d, inode); for (c = inode->child; c; c = c->sibling) dirbuf_add(req, &b, c->name, c->ino); reply_buf_limited(req, b.p, b.size, off, size); free(b.p); }
// Return the fuse_ino_t corresponding to the given request's inode_t static fuse_ino_t cfsfuseino(fuse_req_t req, inode_t cfs_ino) { inode_t root_cfs_ino = ((mount_t *) fuse_req_userdata(req))->root_ino; if (cfs_ino == root_cfs_ino) return FUSE_ROOT_ID; else if (cfs_ino == FUSE_ROOT_ID) return (fuse_ino_t) root_cfs_ino; else return (fuse_ino_t) cfs_ino; }
// Return the request's inode_t corresponding to the fuse_ino_t static inode_t fusecfsino(fuse_req_t req, fuse_ino_t fuse_ino) { inode_t root_cfs_ino = ((mount_t *) fuse_req_userdata(req))->root_ino; if (fuse_ino == root_cfs_ino) return FUSE_ROOT_ID; if (fuse_ino == FUSE_ROOT_ID) return root_cfs_ino; else return (inode_t) fuse_ino; }
void hsx_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { struct hsfs_rw_info winfo; struct hsfs_super * sb = (struct hsfs_super *)fuse_req_userdata(req); size_t cnt = 0; int err = 0; char * buffer = NULL; DEBUG_IN("offset 0x%x size 0x%x", (unsigned int)off, (unsigned int)size); buffer = (char *) malloc(sb->wsize); if( NULL == buffer){ err = ENOMEM; fuse_reply_err(req, err); goto out; } memset(&winfo, 0, sizeof(struct hsfs_rw_info)); if(fi->direct_io) winfo.stable = HSFS_FILE_SYNC; else winfo.stable = HSFS_UNSTABLE; if(NULL == (winfo.inode = hsfs_ilookup(sb, ino))){ err = ENOENT; fuse_reply_err(req, err); goto out; } DEBUG("ino %lu", winfo.inode->ino); while(cnt < size){ size_t tmp_size = min(size - cnt, sb->wsize); winfo.rw_size = tmp_size; winfo.rw_off = off + cnt; memcpy(buffer, buf + cnt, tmp_size); winfo.data.data_len = tmp_size; winfo.data.data_val = buffer; err = hsi_nfs3_write(&winfo); if(err){ fuse_reply_err(req, err); goto out; } cnt += winfo.ret_count; } fuse_reply_write(req, cnt); out: if(NULL != buffer) free(buffer); DEBUG_OUT("err %d", err); return; }
void hsx_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { struct hsfs_readdir_ctx *saved_ctx, *ctx = NULL; struct hsfs_inode *parent; struct hsfs_super *sb; size_t res, len = 0; char * buf; int err, count = 0; DEBUG_IN("P_I(%lu), Size(%lld), Off(0x%llx)", ino, size, off); (void)fi; sb = fuse_req_userdata(req); FUSE_ASSERT(sb != NULL); parent = hsfs_ilookup(sb, ino); FUSE_ASSERT(parent != NULL); err = hsi_nfs3_readdir(parent, size, off, &ctx); if(err) goto out1; saved_ctx = ctx; buf = (char *) malloc(size); if( NULL == buf){ err = ENOMEM; goto out2; } while(ctx != NULL){ res = fuse_add_direntry(req, buf + len, size - len, ctx->name, &ctx->stbuf, ctx->off); /* From fuse doc, buf is not copied if res larger than * requested */ if(res >= size - len) break; len += res; ctx = ctx->next; count++; } /* If EOF, we will return an empty buffer here. */ if (!err) fuse_reply_buf(req, buf, len); free(buf); out2: __free_ctx(saved_ctx, 0); out1: if(err) fuse_reply_err(req, err); DEBUG_OUT("with %d, %d entries returned.", err, count); }
static int zfsfuse_readlink(fuse_req_t req, fuse_ino_t ino) { vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); znode_t *znode; int error = zfs_zget(zfsvfs, ino, &znode, B_FALSE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vnode_t *vp = ZTOV(znode); ASSERT(vp != NULL); char buffer[PATH_MAX + 1]; iovec_t iovec; uio_t uio; uio.uio_iov = &iovec; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_fmode = 0; uio.uio_llimit = RLIM64_INFINITY; iovec.iov_base = buffer; iovec.iov_len = sizeof(buffer) - 1; uio.uio_resid = iovec.iov_len; uio.uio_loffset = 0; cred_t cred; zfsfuse_getcred(req, &cred); error = VOP_READLINK(vp, &uio, &cred, NULL); VN_RELE(vp); ZFS_EXIT(zfsvfs); if(!error) { VERIFY(uio.uio_loffset < sizeof(buffer)); buffer[uio.uio_loffset] = '\0'; fuse_reply_readlink(req, buffer); } return error; }
static int zfsfuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { file_info_t *info = (file_info_t *)(uintptr_t) fi->fh; vnode_t *vp = info->vp; ASSERT(vp != NULL); ASSERT(VTOZ(vp) != NULL); ASSERT(VTOZ(vp)->z_id == ino); vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; char *outbuf = kmem_alloc(size, KM_NOSLEEP); if(outbuf == NULL) return ENOMEM; ZFS_ENTER(zfsvfs); iovec_t iovec; uio_t uio; uio.uio_iov = &iovec; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_fmode = 0; uio.uio_llimit = RLIM64_INFINITY; iovec.iov_base = outbuf; iovec.iov_len = size; uio.uio_resid = iovec.iov_len; uio.uio_loffset = off; cred_t cred; zfsfuse_getcred(req, &cred); int error = VOP_READ(vp, &uio, info->flags, &cred, NULL); ZFS_EXIT(zfsvfs); if(!error) fuse_reply_buf(req, outbuf, uio.uio_loffset - off); kmem_free(outbuf, size); return error; }
static int zfsfuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { file_info_t *info = (file_info_t *)(uintptr_t) fi->fh; vnode_t *vp = info->vp; ASSERT(vp != NULL); ASSERT(VTOZ(vp) != NULL); ASSERT(VTOZ(vp)->z_id == ino); vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); iovec_t iovec; uio_t uio; uio.uio_iov = &iovec; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_fmode = 0; uio.uio_llimit = RLIM64_INFINITY; iovec.iov_base = (void *) buf; iovec.iov_len = size; uio.uio_resid = iovec.iov_len; uio.uio_loffset = off; cred_t cred; zfsfuse_getcred(req, &cred); int error = VOP_WRITE(vp, &uio, info->flags, &cred, NULL); ZFS_EXIT(zfsvfs); if(!error) { /* When not using direct_io, we must always write 'size' bytes */ VERIFY(uio.uio_resid == 0); fuse_reply_write(req, size - uio.uio_resid); } return error; }
static int zfsfuse_access(fuse_req_t req, fuse_ino_t ino, int mask) { vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); znode_t *znode; int error = zfs_zget(zfsvfs, ino, &znode, B_TRUE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vnode_t *vp = ZTOV(znode); ASSERT(vp != NULL); cred_t cred; zfsfuse_getcred(req, &cred); int mode = 0; if(mask & R_OK) mode |= VREAD; if(mask & W_OK) mode |= VWRITE; if(mask & X_OK) mode |= VEXEC; error = VOP_ACCESS(vp, mode, 0, &cred, NULL); VN_RELE(vp); ZFS_EXIT(zfsvfs); return error; }
static int zfsfuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { if(strlen(name) >= MAXNAMELEN) return ENAMETOOLONG; vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); znode_t *znode; int error = zfs_zget(zfsvfs, parent, &znode, B_FALSE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vnode_t *dvp = ZTOV(znode); ASSERT(dvp != NULL); cred_t cred; zfsfuse_getcred(req, &cred); /* FUSE doesn't care if we remove the current working directory so we just pass NULL as the cwd parameter (no problem for ZFS) */ error = VOP_RMDIR(dvp, (char *) name, NULL, &cred, NULL, 0); /* Linux uses ENOTEMPTY when trying to remove a non-empty directory */ if(error == EEXIST) error = ENOTEMPTY; VN_RELE(dvp); ZFS_EXIT(zfsvfs); return error; }
static void compiz_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { CompDisplay *d = (CompDisplay *)fuse_req_userdata(req); FuseInode *inode; inode = fuseFindInode(inodes, ino, WRITE_MASK); if (inode) { struct stat stbuf; if ((to_set & FUSE_SET_ATTR_SIZE) != FUSE_SET_ATTR_SIZE) { fuse_reply_err(req, EACCES); return; } if (attr->st_size != 0) { fuse_reply_err(req, EACCES); return; } inode->flags |= FUSE_INODE_FLAG_TRUNC; memset(&stbuf, 0, sizeof (stbuf)); fuseInodeStat(d, inode, &stbuf); fuse_reply_attr(req, &stbuf, 1.0); } else { fuse_reply_err(req, ENOENT); } }
void hsx_fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { int err = 0; struct hsfs_inode *hi_parent = NULL; struct hsfs_inode *new = NULL; struct fuse_entry_param e; struct hsfs_super *sb = NULL; const char *dirname = name; DEBUG_IN("ino:%lu.\n", parent); memset(&e, 0, sizeof(struct fuse_entry_param)); sb = fuse_req_userdata(req); hi_parent = hsx_fuse_iget(sb, parent); if(NULL == sb) { ERR("ERR in fuse_req_userdata"); goto out; } if(NULL == hi_parent) { ERR("ERR in hsx_fuse_iget"); goto out; } err = hsi_nfs3_mkdir(hi_parent, &new, dirname, mode); if(0 != err ) { fuse_reply_err(req, err); goto out; }else { hsx_fuse_fill_reply(new, &e); fuse_reply_entry(req, &e); goto out; } out: DEBUG_OUT(" out errno is: %d\n", err); return; };
void hsx_fuse_readlink(fuse_req_t req, fuse_ino_t ino) { int st = 0; int err = 0; struct hsfs_inode *hi = NULL; struct hsfs_super *hi_sb = NULL; char *link = NULL; DEBUG_IN("%s\n","THE HSX_FUSE_READLINK."); hi_sb = fuse_req_userdata(req); if(!hi_sb){ ERR("%s gets inode->sb fails \n", progname); err = ENOENT; goto out; } hi = hsfs_ilookup(hi_sb, ino); if(!hi){ ERR("%s gets inode fails \n", progname); err = ENOENT; goto out; } st = hsi_nfs3_readlink(hi,&link); if(st != 0){ err = st; goto out; } fuse_reply_readlink(req, link); out: if(link != NULL){ free(link); } if(st != 0){ fuse_reply_err(req, err); } DEBUG_OUT(" WITH ERRNO %d\n", err); return; }
static int zfsfuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); file_info_t *info = (file_info_t *)(uintptr_t) fi->fh; ASSERT(info->vp != NULL); ASSERT(VTOZ(info->vp) != NULL); ASSERT(VTOZ(info->vp)->z_id == ino); vnode_t *vp = info->vp; cred_t cred; zfsfuse_getcred(req, &cred); int error = VOP_FSYNC(vp, datasync ? FDSYNC : FSYNC, &cred, NULL); ZFS_EXIT(zfsvfs); return error; }
static void sqfs_ll_op_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { sqfs_ll *ll = fuse_req_userdata(req); sqfs_inode *inode = (sqfs_inode*)(intptr_t)fi->fh; sqfs_err err = SQFS_OK; off_t osize; char *buf = malloc(size); if (!buf) { fuse_reply_err(req, ENOMEM); return; } osize = size; err = sqfs_read_range(&ll->fs, inode, off, &osize, buf); if (err) { fuse_reply_err(req, EIO); } else if (osize == 0) { /* EOF */ fuse_reply_buf(req, NULL, 0); } else { fuse_reply_buf(req, buf, osize); } free(buf); }
static void compiz_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { CompDisplay *d = (CompDisplay *)fuse_req_userdata(req); FuseInode *inode; inode = fuseFindInode(inodes, ino, ~0); if (inode) { struct stat stbuf; memset(&stbuf, 0, sizeof (stbuf)); fuseInodeStat(d, inode, &stbuf); fuse_reply_attr(req, &stbuf, 1.0); } else { fuse_reply_err(req, ENOENT); } }
static void compiz_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { CompDisplay *d = (CompDisplay *)fuse_req_userdata(req); FuseInode *inode; struct fuse_entry_param e; inode = fuseFindInode(inodes, parent, DIR_MASK); if (!inode) { fuse_reply_err(req, ENOENT); return; } if (!inode->child || !(inode->type & CONST_DIR_MASK)) fuseUpdateInode(d, inode); inode = fuseLookupChild(inode, name); if (!inode) { fuse_reply_err(req, ENOENT); return; } memset(&e, 0, sizeof (e)); e.attr_timeout = 1.0; e.entry_timeout = 1.0; e.ino = inode->ino; fuseInodeStat(d, inode, &e.attr); fuse_reply_entry(req, &e); }
static int zfsfuse_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); znode_t *znode; int error = zfs_zget(zfsvfs, ino, &znode, B_TRUE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vnode_t *vp = ZTOV(znode); ASSERT(vp != NULL); if(vp->v_type != VDIR) { error = ENOTDIR; goto out; } cred_t cred; zfsfuse_getcred(req, &cred); /* * Check permissions. */ if (error = VOP_ACCESS(vp, VREAD | VEXEC, 0, &cred, NULL)) goto out; vnode_t *old_vp = vp; /* XXX: not sure about flags */ error = VOP_OPEN(&vp, FREAD, &cred, NULL); ASSERT(old_vp == vp); if(!error) { file_info_t *info = kmem_cache_alloc(file_info_cache, KM_NOSLEEP); if(info == NULL) { error = ENOMEM; goto out; } info->vp = vp; info->flags = FREAD; fi->fh = (uint64_t) (uintptr_t) info; } out: if(error) VN_RELE(vp); ZFS_EXIT(zfsvfs); if(!error) fuse_reply_open(req, fi); return error; }
static struct lo_data *lo_data(fuse_req_t req) { return (struct lo_data *) fuse_req_userdata(req); }
void hsx_fuse_rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname) { int err = 0; struct hsfs_super *sb = NULL; struct hsfs_inode *hi = NULL, *newhi = NULL; DEBUG_IN(" %s to %s", name, newname); if (name == NULL) { ERR("Source name is NULL\n"); err = EINVAL; goto out; } else if (newname == NULL) { ERR("Target name is NULL\n"); err = EINVAL; goto out; } else if (!(strcmp(name, ""))) { ERR("Source name is empty\n"); err = EINVAL; goto out; } else if (!(strcmp(newname, ""))) { ERR("Target name is empty\n"); err = EINVAL; goto out; } else if (strlen(name) > NAME_MAX) { ERR("Source name is too long\n"); err = ENAMETOOLONG; goto out; } else if (strlen(newname) > NAME_MAX) { ERR("Target name is too long\n"); err = ENAMETOOLONG; goto out; } if (!(sb = fuse_req_userdata(req))) { ERR("Get user data failed\n"); err = EIO; goto out; } if (!(hi = hsx_fuse_iget(sb, parent))) { ERR("Get hsfs inode failed\n"); err = ENOENT; goto out; } if (!(newhi = hsx_fuse_iget(sb, newparent))) { ERR("Get hsfs inode failed\n"); err = ENOENT; goto out; } if ((err = hsi_nfs3_rename(hi, name, newhi, newname))) { goto out; } out: fuse_reply_err(req, err); DEBUG_OUT(" %s to %s errno:%d", name, newname, err); }
static int zfsfuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); vnode_t *vp; boolean_t release; int error; cred_t cred; zfsfuse_getcred(req, &cred); if(fi == NULL) { znode_t *znode; error = zfs_zget(zfsvfs, ino, &znode, B_TRUE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vp = ZTOV(znode); release = B_TRUE; } else { file_info_t *info = (file_info_t *)(uintptr_t) fi->fh; vp = info->vp; release = B_FALSE; /* * Special treatment for ftruncate(). * This is needed because otherwise ftruncate() would * fail with permission denied on read-only files. * (Solaris calls VOP_SPACE instead of VOP_SETATTR on * ftruncate). */ if(to_set & FUSE_SET_ATTR_SIZE) { /* Check if file is opened for writing */ if((info->flags & FWRITE) == 0) { error = EBADF; goto out; } /* Sanity check */ if(vp->v_type != VREG) { error = EINVAL; goto out; } flock64_t bf; bf.l_whence = 0; /* beginning of file */ bf.l_start = attr->st_size; bf.l_type = F_WRLCK; bf.l_len = (off_t) 0; /* FIXME: check locks */ error = VOP_SPACE(vp, F_FREESP, &bf, info->flags, 0, &cred, NULL); if(error) goto out; to_set &= ~FUSE_SET_ATTR_SIZE; if(to_set == 0) goto out; } } ASSERT(vp != NULL); vattr_t vattr = { 0 }; if(to_set & FUSE_SET_ATTR_MODE) { vattr.va_mask |= AT_MODE; vattr.va_mode = attr->st_mode; } if(to_set & FUSE_SET_ATTR_UID) { vattr.va_mask |= AT_UID; vattr.va_uid = attr->st_uid; } if(to_set & FUSE_SET_ATTR_GID) { vattr.va_mask |= AT_GID; vattr.va_gid = attr->st_gid; } if(to_set & FUSE_SET_ATTR_SIZE) { vattr.va_mask |= AT_SIZE; vattr.va_size = attr->st_size; } if(to_set & FUSE_SET_ATTR_ATIME) { vattr.va_mask |= AT_ATIME; TIME_TO_TIMESTRUC(attr->st_atime, &vattr.va_atime); } if(to_set & FUSE_SET_ATTR_MTIME) { vattr.va_mask |= AT_MTIME; TIME_TO_TIMESTRUC(attr->st_mtime, &vattr.va_mtime); } int flags = (to_set & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ? ATTR_UTIME : 0; error = VOP_SETATTR(vp, &vattr, flags, &cred, NULL); out: ; struct stat stat_reply; if(!error) error = zfsfuse_stat(vp, &stat_reply, &cred); /* Do not release if vp was an opened inode */ if(release) VN_RELE(vp); ZFS_EXIT(zfsvfs); if(!error) fuse_reply_attr(req, &stat_reply, 0.0); return error; }
static int zfsfuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { vnode_t *vp = ((file_info_t *)(uintptr_t) fi->fh)->vp; ASSERT(vp != NULL); ASSERT(VTOZ(vp) != NULL); ASSERT(VTOZ(vp)->z_id == ino); if(vp->v_type != VDIR) return ENOTDIR; vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; char *outbuf = kmem_alloc(size, KM_NOSLEEP); if(outbuf == NULL) return ENOMEM; ZFS_ENTER(zfsvfs); cred_t cred; zfsfuse_getcred(req, &cred); union { char buf[DIRENT64_RECLEN(MAXNAMELEN)]; struct dirent64 dirent; } entry; struct stat fstat = { 0 }; iovec_t iovec; uio_t uio; uio.uio_iov = &iovec; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_fmode = 0; uio.uio_llimit = RLIM64_INFINITY; int eofp = 0; int outbuf_off = 0; int outbuf_resid = size; off_t next = off; int error; for(;;) { iovec.iov_base = entry.buf; iovec.iov_len = sizeof(entry.buf); uio.uio_resid = iovec.iov_len; uio.uio_loffset = next; error = VOP_READDIR(vp, &uio, &cred, &eofp, NULL, 0); if(error) goto out; /* No more directory entries */ if(iovec.iov_base == entry.buf) break; fstat.st_ino = entry.dirent.d_ino; fstat.st_mode = 0; int dsize = fuse_dirent_size(strlen(entry.dirent.d_name)); if(dsize > outbuf_resid) break; fuse_add_dirent(outbuf + outbuf_off, entry.dirent.d_name, &fstat, entry.dirent.d_off); outbuf_off += dsize; outbuf_resid -= dsize; next = entry.dirent.d_off; } out: ZFS_EXIT(zfsvfs); if(!error) fuse_reply_buf(req, outbuf, outbuf_off); kmem_free(outbuf, size); return error; }
static int zfsfuse_opencreate(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int fflags, mode_t createmode, const char *name) { if(name && strlen(name) >= MAXNAMELEN) return ENAMETOOLONG; vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; ZFS_ENTER(zfsvfs); cred_t cred; zfsfuse_getcred(req, &cred); /* Map flags */ int mode, flags; if(fflags & O_WRONLY) { mode = VWRITE; flags = FWRITE; } else if(fflags & O_RDWR) { mode = VREAD | VWRITE; flags = FREAD | FWRITE; } else { mode = VREAD; flags = FREAD; } if(fflags & O_CREAT) flags |= FCREAT; if(fflags & O_SYNC) flags |= FSYNC; if(fflags & O_DSYNC) flags |= FDSYNC; if(fflags & O_RSYNC) flags |= FRSYNC; if(fflags & O_APPEND) flags |= FAPPEND; if(fflags & O_LARGEFILE) flags |= FOFFMAX; if(fflags & O_NOFOLLOW) flags |= FNOFOLLOW; if(fflags & O_TRUNC) flags |= FTRUNC; if(fflags & O_EXCL) flags |= FEXCL; znode_t *znode; int error = zfs_zget(zfsvfs, ino, &znode, B_FALSE); if(error) { ZFS_EXIT(zfsvfs); /* If the inode we are trying to get was recently deleted dnode_hold_impl will return EEXIST instead of ENOENT */ return error == EEXIST ? ENOENT : error; } ASSERT(znode != NULL); vnode_t *vp = ZTOV(znode); ASSERT(vp != NULL); if (flags & FCREAT) { enum vcexcl excl; /* * Wish to create a file. */ vattr_t vattr; vattr.va_type = VREG; vattr.va_mode = createmode; vattr.va_mask = AT_TYPE|AT_MODE; if (flags & FTRUNC) { vattr.va_size = 0; vattr.va_mask |= AT_SIZE; } if (flags & FEXCL) excl = EXCL; else excl = NONEXCL; vnode_t *new_vp; /* FIXME: check filesystem boundaries */ error = VOP_CREATE(vp, (char *) name, &vattr, excl, mode, &new_vp, &cred, 0, NULL, NULL); if(error) goto out; VN_RELE(vp); vp = new_vp; } else { /* * Get the attributes to check whether file is large. * We do this only if the O_LARGEFILE flag is not set and * only for regular files. */ if (!(flags & FOFFMAX) && (vp->v_type == VREG)) { vattr_t vattr; vattr.va_mask = AT_SIZE; if ((error = VOP_GETATTR(vp, &vattr, 0, &cred, NULL))) goto out; if (vattr.va_size > (u_offset_t) MAXOFF32_T) { /* * Large File API - regular open fails * if FOFFMAX flag is set in file mode */ error = EOVERFLOW; goto out; } } /* * Check permissions. */ if (error = VOP_ACCESS(vp, mode, 0, &cred, NULL)) goto out; } if ((flags & FNOFOLLOW) && vp->v_type == VLNK) { error = ELOOP; goto out; } vnode_t *old_vp = vp; error = VOP_OPEN(&vp, flags, &cred, NULL); ASSERT(old_vp == vp); if(error) goto out; struct fuse_entry_param e = { 0 }; if(flags & FCREAT) { error = zfsfuse_stat(vp, &e.attr, &cred); if(error) goto out; } file_info_t *info = kmem_cache_alloc(file_info_cache, KM_NOSLEEP); if(info == NULL) { error = ENOMEM; goto out; } info->vp = vp; info->flags = flags; fi->fh = (uint64_t) (uintptr_t) info; fi->keep_cache = 1; if(flags & FCREAT) { e.attr_timeout = 0.0; e.entry_timeout = 0.0; e.ino = VTOZ(vp)->z_id; if(e.ino == 3) e.ino = 1; e.generation = VTOZ(vp)->z_phys->zp_gen; } out: if(error) { ASSERT(vp->v_count > 0); VN_RELE(vp); } ZFS_EXIT(zfsvfs); if(!error) { if(!(flags & FCREAT)) fuse_reply_open(req, fi); else fuse_reply_create(req, &e, fi); } return error; }