STATIC int linvfs_symlink( struct inode *dir, struct dentry *dentry, const char *symname) { struct inode *ip; vattr_t va; vnode_t *dvp; /* directory containing name of symlink */ vnode_t *cvp; /* used to lookup symlink to put in dentry */ int error; dvp = LINVFS_GET_VP(dir); cvp = NULL; memset(&va, 0, sizeof(va)); va.va_type = VLNK; va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO; va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; error = 0; VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error); if (!error && cvp) { ASSERT(cvp->v_type == VLNK); ip = LINVFS_GET_IP(cvp); d_instantiate(dentry, ip); validate_fields(dir); validate_fields(ip); /* size needs update */ } return -error; }
STATIC int linvfs_symlink( struct inode *dir, struct dentry *dentry, const char *symname) { struct inode *ip; vattr_t va; vnode_t *dvp; /* directory containing name of symlink */ vnode_t *cvp; /* used to lookup symlink to put in dentry */ int error; dvp = LINVFS_GET_VP(dir); cvp = NULL; memset(&va, 0, sizeof(va)); va.va_mode = S_IFLNK | (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO); va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; error = 0; VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error); if (likely(!error && cvp)) { error = linvfs_init_security(cvp, dir); if (likely(!error)) { ip = LINVFS_GET_IP(cvp); d_instantiate(dentry, ip); validate_fields(dir); validate_fields(ip); } } return -error; }
static int unionfs_symlink(void *v) { struct vop_symlink_args *ap = v; int error; struct unionfs_node *dunp; struct componentname *cnp; struct vnode *udvp; struct vnode *uvp; UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n"); error = EROFS; dunp = VTOUNIONFS(ap->a_dvp); cnp = ap->a_cnp; udvp = dunp->un_uppervp; if (udvp != NULLVP) { error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target); if (error == 0) { error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, ap->a_dvp, ap->a_vpp, cnp); if (error) { vput(uvp); } else { vrele(uvp); } } } UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error); return (error); }
int RUMP_VOP_SYMLINK(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap, char *target) { int error; rump_schedule(); error = VOP_SYMLINK(dvp, vpp, cnp, vap, target); rump_unschedule(); return error; }
/* * union_symlink: * * dvp is locked on entry and remains locked on return. a_vpp is garbage * (unused). * * union_symlink(struct vnode *a_dvp, struct vnode **a_vpp, * struct componentname *a_cnp, struct vattr *a_vap, * char *a_target) */ static int union_symlink(struct vop_old_symlink_args *ap) { struct union_node *dun = VTOUNION(ap->a_dvp); struct componentname *cnp = ap->a_cnp; struct thread *td = cnp->cn_td; struct vnode *dvp; int error = EROFS; if ((dvp = union_lock_upper(dun, td)) != NULLVP) { error = VOP_SYMLINK(dvp, ap->a_vpp, cnp, ap->a_vap, ap->a_target); union_unlock_upper(dvp, td); } return (error); }
/* * Does most of the work for symlink(). * * Note, however, if you're implementing symlinks, that various * other parts of the VFS layer are missing crucial elements of * support for symlinks. */ int vfs_symlink(const char *contents, char *path) { struct vnode *newdir; char newname[NAME_MAX+1]; int result; result = vfs_lookparent(path, &newdir, newname, sizeof(newname)); if (result) { return result; } result = VOP_SYMLINK(newdir, newname, contents); VOP_DECREF(newdir); return result; }
STATIC int linvfs_symlink( struct inode *dir, struct dentry *dentry, const char *symname) { int error; vnode_t *dvp; /* directory containing name to remove */ vnode_t *cvp; /* used to lookup symlink to put in dentry */ vattr_t va; struct inode *ip = NULL; dvp = LINVFS_GET_VP(dir); bzero(&va, sizeof(va)); va.va_type = VLNK; va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO; va.va_mask = AT_TYPE|AT_MODE; error = 0; VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error); if (!error) { ASSERT(cvp); ASSERT(cvp->v_type == VLNK); ip = LINVFS_GET_IP(cvp); if (!ip) { error = ENOMEM; VN_RELE(cvp); } else { /* linvfs_revalidate_core returns (-) errors */ error = -linvfs_revalidate_core(ip, ATTR_COMM); d_instantiate(dentry, ip); validate_fields(dir); validate_fields(ip); /* size needs update */ mark_inode_dirty_sync(ip); mark_inode_dirty_sync(dir); } } return -error; }
static int auto_symlink( vnode_t *dvp, char *lnknm, /* new entry */ vattr_t *tva, char *tnm, /* existing entry */ cred_t *cred, caller_context_t *ct, int flags) { vnode_t *newvp; int error; AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n", (void *)dvp, lnknm, tnm)); if (error = auto_trigger_mount(dvp, cred, &newvp)) goto done; if (newvp != NULL) { /* * Node is mounted on. */ if (vn_is_readonly(newvp)) error = EROFS; else error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred, ct, flags); VN_RELE(newvp); } else error = ENOSYS; done: AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error)); return (error); }
static int zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap) { char *name = NULL; /* location determined later */ char *link; /* symlink content follows name */ znode_t *dzp; vnode_t *vp = NULL; xvattr_t xva; int vflg = 0; size_t lrsize = sizeof (lr_create_t); lr_attr_t *lrattr; void *start; size_t xvatlen; uint64_t txtype; struct componentname cn; int error; txtype = (lr->lr_common.lrc_txtype & ~TX_CI); if (byteswap) { byteswap_uint64_array(lr, sizeof (*lr)); if (txtype == TX_CREATE_ATTR || txtype == TX_MKDIR_ATTR) zfs_replay_swap_attrs((lr_attr_t *)(lr + 1)); } if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0) return (error); xva_init(&xva); zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID, lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid); /* * All forms of zfs create (create, mkdir, mkxattrdir, symlink) * eventually end up in zfs_mknode(), which assigns the object's * creation time and generation number. The generic VOP_CREATE() * doesn't have either concept, so we smuggle the values inside * the vattr's otherwise unused va_ctime and va_nblocks fields. */ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime); xva.xva_vattr.va_nblocks = lr->lr_gen; error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL); if (error != ENOENT) goto out; if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; /* * Symlinks don't have fuid info, and CIFS never creates * symlinks. * * The _ATTR versions will grab the fuid info in their subcases. */ if ((int)lr->lr_common.lrc_txtype != TX_SYMLINK && (int)lr->lr_common.lrc_txtype != TX_MKDIR_ATTR && (int)lr->lr_common.lrc_txtype != TX_CREATE_ATTR) { start = (lr + 1); zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); } cn.cn_cred = kcred; cn.cn_thread = curthread; cn.cn_flags = SAVENAME; vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY); switch (txtype) { case TX_CREATE_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva); start = (caddr_t)(lr + 1) + xvatlen; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); name = (char *)start; /*FALLTHROUGH*/ case TX_CREATE: if (name == NULL) name = (char *)start; cn.cn_nameptr = name; error = VOP_CREATE(ZTOV(dzp), &vp, &cn, &xva.xva_vattr /*,vflg*/); break; case TX_MKDIR_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize); zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva); start = (caddr_t)(lr + 1) + xvatlen; zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); name = (char *)start; /*FALLTHROUGH*/ case TX_MKDIR: if (name == NULL) name = (char *)(lr + 1); cn.cn_nameptr = name; error = VOP_MKDIR(ZTOV(dzp), &vp, &cn, &xva.xva_vattr /*,vflg*/); break; case TX_MKXATTR: error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &vp, kcred); break; case TX_SYMLINK: name = (char *)(lr + 1); link = name + strlen(name) + 1; cn.cn_nameptr = name; error = VOP_SYMLINK(ZTOV(dzp), &vp, &cn, &xva.xva_vattr, link /*,vflg*/); break; default: error = ENOTSUP; } VOP_UNLOCK(ZTOV(dzp), 0); out: if (error == 0 && vp != NULL) VN_URELE(vp); VN_RELE(ZTOV(dzp)); if (zfsvfs->z_fuid_replay) zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; return (error); }
static int zfsfuse_symlink(fuse_req_t req, const char *link, 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); vattr_t vattr; vattr.va_type = VLNK; vattr.va_mode = 0777; vattr.va_mask = AT_TYPE | AT_MODE; error = VOP_SYMLINK(dvp, (char *) name, &vattr, (char *) link, &cred, NULL, 0); vnode_t *vp = NULL; if(error) goto out; error = VOP_LOOKUP(dvp, (char *) name, &vp, NULL, 0, NULL, &cred, NULL, NULL, NULL); if(error) goto out; ASSERT(vp != NULL); struct fuse_entry_param e = { 0 }; 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; 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; }
/* * Creates the fs cache directory. * The directory name is the ascii version of the fsid. * Also makes a symlink to the directory using the specified name. */ int fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp) { int error; vnode_t *fscdirvp = NULL; vnode_t *infovp = NULL; vnode_t *attrvp = NULL; struct vattr *attrp = (struct vattr *)NULL; char name[CFS_FRONTFILE_NAME_SIZE]; int files; int blocks = 0; cfs_cid_t cid; ino64_t fsid; ASSERT(MUTEX_HELD(&cachep->c_fslistlock)); ASSERT(fscp->fs_infovp == NULL); ASSERT(fscp->fs_fscdirvp == NULL); ASSERT(fscp->fs_fsattrdir == NULL); /* directory, symlink and options file + attrcache dir */ files = 0; while (files < 4) { error = cachefs_allocfile(cachep); if (error) goto out; files++; } error = cachefs_allocblocks(cachep, 4, CACHEFS_RL_NONE); if (error) goto out; blocks = 4; attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP); attrp->va_mode = S_IFDIR | 0777; attrp->va_uid = 0; attrp->va_gid = 0; attrp->va_type = VDIR; attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred, NULL, 0, NULL); if (error) { cmn_err(CE_WARN, "Can't create fs cache directory"); goto out; } /* * Created the directory. Get the fileno. That'll be the cachefs_fsid. */ attrp->va_mask = AT_NODEID; error = VOP_GETATTR(fscdirvp, attrp, 0, kcred, NULL); if (error) { goto out; } fsid = attrp->va_nodeid; attrp->va_mode = S_IFREG | 0666; attrp->va_uid = 0; attrp->va_gid = 0; attrp->va_type = VREG; attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; error = VOP_CREATE(fscdirvp, CACHEFS_FSINFO, attrp, EXCL, 0600, &infovp, kcred, 0, NULL, NULL); if (error) { cmn_err(CE_WARN, "Can't create fs option file"); goto out; } attrp->va_size = MAXBSIZE; attrp->va_mask = AT_SIZE; error = VOP_SETATTR(infovp, attrp, 0, kcred, NULL); if (error) { cmn_err(CE_WARN, "Can't set size of fsinfo file"); goto out; } /* write out the info file */ fscp->fs_flags |= CFS_FS_DIRTYINFO; error = fscache_info_sync(fscp); if (error) goto out; /* * Install the symlink from cachefs_fsid -> directory. */ cid.cid_flags = 0; cid.cid_fileno = fsid; make_ascii_name(&cid, name); error = VOP_RENAME(cachep->c_dirvp, namep, cachep->c_dirvp, name, kcred, NULL, 0); if (error) { cmn_err(CE_WARN, "Can't rename cache directory"); goto out; } attrp->va_mask = AT_MODE | AT_TYPE; attrp->va_mode = 0777; attrp->va_type = VLNK; error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred, NULL, 0); if (error) { cmn_err(CE_WARN, "Can't create cache directory symlink"); goto out; } /* * Finally, make the attrcache directory */ attrp->va_mode = S_IFDIR | 0777; attrp->va_uid = 0; attrp->va_gid = 0; attrp->va_type = VDIR; attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred, NULL, 0, NULL); if (error) { cmn_err(CE_WARN, "Can't create attrcache dir for fscache"); goto out; } mutex_enter(&fscp->fs_fslock); fscp->fs_cfsid = fsid; fscp->fs_fscdirvp = fscdirvp; fscp->fs_fsattrdir = attrvp; fscp->fs_infovp = infovp; mutex_exit(&fscp->fs_fslock); out: if (error) { while (files-- > 0) cachefs_freefile(cachep); if (fscdirvp) VN_RELE(fscdirvp); if (blocks) cachefs_freeblocks(cachep, blocks, CACHEFS_RL_NONE); if (attrvp) VN_RELE(attrvp); if (infovp) VN_RELE(infovp); } if (attrp) cachefs_kmem_free(attrp, sizeof (struct vattr)); return (error); }