static void serve_create(fuse_req_t req, fuse_ino_t parent, const char * local_name, mode_t mode, struct fuse_file_info * fi) { Dprintf("%s(parent = %lu, local_name = \"%s\")\n", __FUNCTION__, parent, local_name); fdesc_t * fdesc; int r; struct fuse_entry_param e; r = create(req, parent, local_name, mode, &e, &fdesc); if (r < 0) { r = fuse_reply_err(req, -r); fuse_reply_assert(!r); return; } fi_set_fdesc(fi, fdesc); r = fuse_reply_create(req, &e, fi); fuse_reply_assert(!r); }
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; }
static void workspace_nfs_create(fuse_req_t req, struct inode_struct *pinode, struct name_struct *xname, struct workspace_fh_struct *fh, mode_t mode) { struct resource_struct *resource=fh->object->resource; struct net_nfs_export_struct *nfs_export=(struct net_nfs_export_struct *) resource->data; struct nfs_context *nfs_ctx=(struct nfs_context *) nfs_export->data; char *path=fh->pathinfo.path + fh->relpath; struct entry_struct *entry=NULL, *parent=pinode->alias; struct inode_struct *inode; struct nfsfh *nfsfh=NULL; logoutput("workspace_nfs_create, path %s", path); entry=create_entry(parent, xname); inode=create_inode(); if (entry && inode) { int result=0; inode->alias=entry; entry->inode=inode; pthread_mutex_lock(&nfs_export->mutex); result=nfs_creat(nfs_ctx, path, mode, &nfsfh); pthread_mutex_unlock(&nfs_export->mutex); if (result==0) { struct fuse_entry_param e; unsigned int error=0; struct stat st; memset(&st, 0, sizeof(struct stat)); add_inode_hashtable(inode, increase_inodes_workspace, (void *) fh->object->workspace_mount); insert_entry(entry, &error, 0); adjust_pathmax(fh->pathinfo.len); nfs_fstat(nfs_ctx, nfsfh, &st); inode->nlookup=1; inode->mode=st.st_mode; inode->nlink=st.st_nlink; inode->uid=st.st_uid; inode->gid=st.st_gid; inode->rdev=st.st_rdev; inode->size=st.st_size; inode->mtim.tv_sec=st.st_mtim.tv_sec; inode->mtim.tv_nsec=st.st_mtim.tv_nsec; inode->ctim.tv_sec=st.st_ctim.tv_sec; inode->ctim.tv_nsec=st.st_ctim.tv_nsec; e.ino = inode->ino; e.generation = 1; e.attr_timeout = fs_options.attr_timeout; e.entry_timeout = fs_options.entry_timeout; e.attr.st_ino = e.ino; e.attr.st_mode = st.st_mode; e.attr.st_nlink = st.st_nlink; e.attr.st_uid = st.st_uid; e.attr.st_gid = st.st_gid; e.attr.st_rdev = st.st_rdev; e.attr.st_atim.tv_sec = st.st_atim.tv_sec; e.attr.st_atim.tv_nsec = st.st_atim.tv_nsec; e.attr.st_mtim.tv_sec = st.st_mtim.tv_sec; e.attr.st_mtim.tv_nsec = st.st_mtim.tv_nsec; e.attr.st_ctim.tv_sec = st.st_ctim.tv_sec; e.attr.st_ctim.tv_nsec = st.st_ctim.tv_nsec; e.attr.st_blksize=_DEFAULT_BLOCKSIZE; if (inode->size % e.attr.st_blksize == 0) { e.attr.st_blocks=inode->size / e.attr.st_blksize; } else { e.attr.st_blocks=1 + inode->size / e.attr.st_blksize; } fh->handle.data=(void *) nfsfh; fuse_reply_create(req, &e, fh->fi); } else { /* error nfs create */ destroy_entry(entry); free(inode); fuse_reply_err(req, abs(result)); } } else { /* not enough memory to allocate entry and/or inode */ if (entry) { destroy_entry(entry); entry=NULL; } if (inode) { free(inode); inode=NULL; } fuse_reply_err(req, ENOMEM); } free_path_pathinfo(&fh->pathinfo); }