/* * The inode of symbolic link is different to data stream. * The data stream become link name. Unless the LONG_SYMLINK * flag is set. */ static int befs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct super_block *sb = dentry->d_sb; befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); char *link; int res; if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t linklen = data->size; befs_debug(sb, "Follow long symlink"); link = kmalloc(linklen, GFP_NOFS); if (link == NULL) return -ENOMEM; if (befs_read_lsymlink(sb, data, link, linklen) != linklen) { kfree(link); befs_error(sb, "Failed to read entire long symlink"); return -EIO; } res = vfs_follow_link(nd, link); kfree(link); } else { link = befs_ino->i_data.symlink; res = vfs_follow_link(nd, link); } return res; }
static int #endif InodeOpFollowlink(struct dentry *dentry, // IN : dentry of symlink struct nameidata *nd) // OUT: stores result { int ret; VMBlockInodeInfo *iinfo; if (!dentry) { Warning("InodeOpReadlink: invalid args from kernel\n"); ret = -EINVAL; goto out; } iinfo = INODE_TO_IINFO(dentry->d_inode); if (!iinfo) { ret = -EINVAL; goto out; } ret = vfs_follow_link(nd, iinfo->name); out: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) return ERR_PTR(ret); #else return ret; #endif }
int smb_follow_link(struct dentry *dentry, struct nameidata *nd) { char *link; int result; DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry)); result = -ENOMEM; link = kmalloc(SMB_MAXNAMELEN + 1, GFP_KERNEL); if (!link) goto out; result = smb_proc_read_link(server_from_dentry(dentry), dentry, link, SMB_MAXNAMELEN); if (result < 0 || result >= SMB_MAXNAMELEN) goto out_free; link[result] = 0; result = vfs_follow_link(nd, link); out_free: kfree(link); out: return result; }
static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) #endif { unsigned char *alias; int ret; yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; yaffs_GrossLock(dev); alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); yaffs_GrossUnlock(dev); if (!alias) { ret = -ENOMEM; goto out; } ret = vfs_follow_link(nd, alias); kfree(alias); out: #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) return ERR_PTR (ret); #else return ret; #endif }
/** * vxfs_immed_follow_link - follow immed symlink * @dp: dentry for the link * @np: pathname lookup data for the current path walk * * Description: * vxfs_immed_follow_link restarts the pathname lookup with * the data obtained from @dp. * * Returns: * Zero on success, else a negative error code. */ static int vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np) { struct vxfs_inode_info *vip = VXFS_INO(dp->d_inode); return (vfs_follow_link(np, vip->vii_immed.vi_immed)); }
static void *ocfs2_follow_link(struct dentry *dentry, struct nameidata *nd) { int status; char *link; struct inode *inode = dentry->d_inode; struct page *page = NULL; struct buffer_head *bh = NULL; if (ocfs2_inode_is_fast_symlink(inode)) link = ocfs2_fast_symlink_getlink(inode, &bh); else link = ocfs2_page_getlink(dentry, &page); if (IS_ERR(link)) { status = PTR_ERR(link); mlog_errno(status); goto bail; } status = vfs_follow_link(nd, link); bail: if (page) { kunmap(page); page_cache_release(page); } brelse(bh); return ERR_PTR(status); }
static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd) { int ret; char *link; link = read_link(dentry); ret = vfs_follow_link(nd, link); free_link(link); return ret; }
int #endif vnode_iop_follow_link( DENT_T *dentry, /* link */ struct nameidata *nd /* link resolution */ ) { INODE_T *ip; struct uio uio; iovec_t iov; int err = 0; char *buf = KMEM_ALLOC(PATH_MAX, KM_SLEEP); CALL_DATA_T cd; if (buf == NULL) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) return ERR_PTR(-ENOMEM); #else return -ENOMEM; #endif uio.uio_iov = &iov; mfs_uioset(&uio, buf, PATH_MAX-1, 0, UIO_SYSSPACE); mdki_linux_init_call_data(&cd); ip = dentry->d_inode; ASSERT_KERNEL_UNLOCKED(); ASSERT_I_SEM_NOT_MINE(ip); err = VOP_READLINK(ITOV(ip), &uio, &cd); err = mdki_errno_unix_to_linux(err); mdki_linux_destroy_call_data(&cd); if (err == 0) { if (uio.uio_resid == 0) err = -ENAMETOOLONG; else { /* readlink doesn't copy a NUL at the end, we must do it */ buf[uio.uio_offset] = '\0'; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) /* follow the link */ err = vfs_follow_link(nd, buf); #else nd_set_link(nd, buf); return(buf); /* vnop_iop_put_link() will free this buf. */ #endif } } KMEM_FREE(buf, PATH_MAX); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) return ERR_PTR(err); #else return(err); #endif }
int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { unsigned char *buf; int ret; buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); if (IS_ERR(buf)) return PTR_ERR(buf); ret = vfs_follow_link(nd, buf); kfree(buf); return ret; }
int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { unsigned char *buf; int ret; buf = jffs2_getlink(dentry); if (IS_ERR(buf)) return PTR_ERR(buf); ret = vfs_follow_link(nd, buf); kfree(buf); return ret; }
/* * careful here - this function can get called recursively, so * we need to be very careful about how much stack we use. * uio is kmalloced for this reason... */ STATIC int linvfs_follow_link( struct dentry *dentry, struct nameidata *nd) { vnode_t *vp; uio_t *uio; iovec_t iov; int error; char *link; ASSERT(dentry); ASSERT(nd); link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL); if (!link) return -ENOMEM; uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL); if (!uio) { kfree(link); return -ENOMEM; } vp = LINVFS_GET_VP(dentry->d_inode); iov.iov_base = link; iov.iov_len = MAXNAMELEN; uio->uio_iov = &iov; uio->uio_offset = 0; uio->uio_segflg = UIO_SYSSPACE; uio->uio_resid = MAXNAMELEN; uio->uio_iovcnt = 1; VOP_READLINK(vp, uio, 0, NULL, error); if (error) { kfree(uio); kfree(link); return -error; } link[MAXNAMELEN - uio->uio_resid] = '\0'; kfree(uio); /* vfs_follow_link returns (-) errors */ error = vfs_follow_link(nd, link); kfree(link); return error; }
static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; error = gfs2_readlinki(ip, &buf, &len); if (!error) { error = vfs_follow_link(nd, buf); if (buf != array) kfree(buf); } return ERR_PTR(error); }
int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) { int error = 0; unsigned long page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; error = sysfs_getlink(dentry, (char *) page); if (!error) error = vfs_follow_link(nd, (char *) page); free_page(page); return error; }
static int HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link struct nameidata *nd) // OUT: Contains target dentry #endif { HgfsAttrInfo attr; char *fileName = NULL; int error; ASSERT(dentry); ASSERT(nd); if (!dentry) { LOG(4, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: null input\n")); error = -EINVAL; goto out; } LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: calling " "HgfsPrivateGetattr\n")); error = HgfsPrivateGetattr(dentry, &attr, &fileName); if (!error) { /* Let's make sure we got called on a symlink. */ if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) { LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: got called " "on something that wasn't a symlink\n")); error = -EINVAL; } else { LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: calling " "vfs_follow_link\n")); error = vfs_follow_link(nd, fileName); } kfree(fileName); } out: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) return ERR_PTR(error); #else return error; #endif }
int cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = direntry->d_inode; int rc = -EACCES; int xid; char *full_path = NULL; char * target_path; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; xid = GetXid(); down(&direntry->d_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) { FreeXid(xid); return -ENOMEM; } cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; target_path = kmalloc(PATH_MAX, GFP_KERNEL); if(target_path == NULL) { if (full_path) kfree(full_path); FreeXid(xid); return -ENOMEM; } /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */ /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */ /* BB add read reparse point symlink code and Unix extensions symlink code here BB */ if (pTcon->ses->capabilities & CAP_UNIX) rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, target_path, PATH_MAX-1, cifs_sb->local_nls); else { /* rc = CIFSSMBQueryReparseLinkInfo */ /* BB Add code to Query ReparsePoint info */ } /* BB Anything else to do to handle recursive links? */ /* BB Should we be using page symlink ops here? */ if (rc == 0) { /* BB Add special case check for Samba DFS symlinks */ target_path[PATH_MAX-1] = 0; rc = vfs_follow_link(nd, target_path); } /* else EACCESS */ if (target_path) kfree(target_path); if (full_path) kfree(full_path); FreeXid(xid); return rc; }
static int ufs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *s = (char *)dentry->d_inode->u.ufs_i.i_u1.i_symlink; return vfs_follow_link(nd, s); }
static int snd_info_card_followlink(struct dentry *dentry, struct nameidata *nd) { char *s = ((struct proc_dir_entry *) dentry->d_inode->u.generic_ip)->data; return vfs_follow_link(nd, s); }
static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd) { char *s = (char *)SYSV_I(dentry->d_inode)->i_data; return vfs_follow_link(nd, s); }
/* * The follow_link operation is special: it must behave as a no-op * so that a bad root inode can at least be unmounted. To do this * we must dput() the base and return the dentry with a dget(). */ static int bad_follow_link(struct dentry *dent, struct nameidata *nd) { return vfs_follow_link(nd, ERR_PTR(-EIO)); }
static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *s = JFS_IP(dentry->d_inode)->i_inline; return vfs_follow_link(nd, s); }
int #endif vnode_shadow_iop_follow_link( DENT_T *dentry, /* entry we are trying to resolve */ struct nameidata *nd /* Contains parent dentry */ ) { int err = 0; int len = PATH_MAX; char *buff; mm_segment_t old_fs; /* Because we provide a kernel buffer. */ INODE_T *real_inode; DENT_T *real_dentry; VNODE_T *cvp; /* this function must consume a reference on base */ /* We only path_release on error. */ err = 0; real_dentry = REALDENTRY_LOCKED(dentry, &cvp); if (real_dentry == NULL) { err = -ENOENT; MDKI_PATH_RELEASE(nd); goto out_nolock; } VNODE_DGET(real_dentry); /* protect inode */ if (real_dentry->d_inode == NULL) { /* delete race */ err = -ENOENT; MDKI_PATH_RELEASE(nd); goto out; } real_inode = real_dentry->d_inode; /* If there are no underlying symlink functions, we are done */ if (real_inode->i_op && real_inode->i_op->readlink && real_inode->i_op->follow_link) { buff = KMEM_ALLOC(len, KM_SLEEP); if (!buff) { MDKI_PATH_RELEASE(nd); err = -ENOMEM; goto out; } /* We're providing a kernel buffer to copy into, so let everyone know. */ old_fs = get_fs(); set_fs(KERNEL_DS); err = vnode_shadow_iop_readlink(dentry, buff, len); set_fs(old_fs); if (err < 0) { KMEM_FREE(buff, len); MDKI_PATH_RELEASE(nd); goto out; } /* done with dentry */ /* Make sure string is null terminated */ buff[err] = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) err = vfs_follow_link(nd, buff); KMEM_FREE(buff,len); #else VNODE_DPUT(real_dentry); REALDENTRY_UNLOCK(dentry, cvp); nd_set_link(nd, buff); return(buff); /* vnop_iop_put_link() will free this buf. */ #endif } out: VNODE_DPUT(real_dentry); REALDENTRY_UNLOCK(dentry, cvp); out_nolock: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) return ERR_PTR(err); #else return(err); #endif }