Skip to content
Snippets Groups Projects
vfs_inode.c 27.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		goto FreeFcall;
    	}
    
    	if (!fcall)
    		return -EIO;
    
    
    	if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) {
    
    		retval = -EINVAL;
    		goto FreeFcall;
    	}
    
    	/* copy extension buffer into buffer */
    
    	if (fcall->params.rstat.stat.extension.len < buflen)
    		buflen = fcall->params.rstat.stat.extension.len;
    
    	memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
    	buffer[buflen-1] = 0;
    
    
    	retval = buflen;
    
          FreeFcall:
    	kfree(fcall);
    
    	return retval;
    }
    
    /**
     * v9fs_vfs_readlink - read a symlink's location
     * @dentry: dentry for symlink
     * @buf: buffer to load symlink location into
     * @buflen: length of buffer
     *
     */
    
    static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
    			     int buflen)
    {
    	int retval;
    	int ret;
    	char *link = __getname();
    
    
    
    	dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
    
    	retval = v9fs_readlink(dentry, link, buflen);
    
    	if (retval > 0) {
    		if ((ret = copy_to_user(buffer, link, retval)) != 0) {
    			dprintk(DEBUG_ERROR, "problem copying to user: %d\n",
    				ret);
    			retval = ret;
    		}
    	}
    
    
    	__putname(link);
    
    	return retval;
    }
    
    /**
     * v9fs_vfs_follow_link - follow a symlink path
     * @dentry: dentry for symlink
     * @nd: nameidata
     *
     */
    
    static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
    {
    	int len = 0;
    	char *link = __getname();
    
    	dprintk(DEBUG_VFS, "%s n", dentry->d_name.name);
    
    	if (!link)
    		link = ERR_PTR(-ENOMEM);
    	else {
    
    		len = v9fs_readlink(dentry, link, strlen(link));
    
    			__putname(link);
    
    			link = ERR_PTR(len);
    		} else
    			link[len] = 0;
    	}
    	nd_set_link(nd, link);
    
    	return NULL;
    }
    
    /**
     * v9fs_vfs_put_link - release a symlink path
     * @dentry: dentry for symlink
     * @nd: nameidata
     *
     */
    
    static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
    {
    	char *s = nd_get_link(nd);
    
    	dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s);
    	if (!IS_ERR(s))
    
    		__putname(s);
    
    static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
    	int mode, const char *extension)
    
    	int err;
    	u32 fid, perm;
    
    	struct v9fs_session_info *v9ses;
    
    	struct v9fs_fid *dfid, *vfid;
    	struct inode *inode;
    
    	struct v9fs_fcall *fcall;
    	struct v9fs_wstat wstat;
    
    	inode = NULL;
    	vfid = NULL;
    	v9ses = v9fs_inode2v9ses(dir);
    	dfid = v9fs_fid_lookup(dentry->d_parent);
    	perm = unixmode2p9mode(v9ses, mode);
    
    
    	if (!v9ses->extended) {
    		dprintk(DEBUG_ERROR, "not extended\n");
    
    		return -EPERM;
    
    	err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
    		perm, V9FS_OREAD, &fid, NULL, NULL);
    
    	if (err)
    		goto error;
    
    	err = v9fs_t_clunk(v9ses, fid);
    	if (err)
    		goto error;
    
    	vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
    	if (IS_ERR(vfid)) {
    		err = PTR_ERR(vfid);
    		vfid = NULL;
    		goto error;
    	}
    
    	inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
    	if (IS_ERR(inode)) {
    		err = PTR_ERR(inode);
    		inode = NULL;
    		goto error;
    
    	/* issue a Twstat */
    	v9fs_blank_wstat(&wstat);
    	wstat.muid = v9ses->name;
    	wstat.extension = (char *) extension;
    
    	err = v9fs_t_wstat(v9ses, vfid->fid, &wstat, &fcall);
    
    		PRINT_FCALL_ERROR("wstat error", fcall);
    		goto error;
    
    	kfree(fcall);
    	dentry->d_op = &v9fs_dentry_operations;
    	d_instantiate(dentry, inode);
    	return 0;
    
    	if (vfid)
    		v9fs_fid_destroy(vfid);
    
    	if (inode)
    		iput(inode);
    
    	return err;
    
    
    }
    
    /**
     * v9fs_vfs_symlink - helper function to create symlinks
     * @dir: directory inode containing symlink
     * @dentry: dentry for symlink
     * @symname: symlink data
     *
     * See 9P2000.u RFC for more information
     *
     */
    
    static int
    v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
    {
    	dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
    		symname);
    
    	return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);
    }
    
    /**
     * v9fs_vfs_link - create a hardlink
     * @old_dentry: dentry for file to link to
     * @dir: inode destination for new link
     * @dentry: dentry for link
     *
     */
    
    /* XXX - lots of code dup'd from symlink and creates,
     * figure out a better reuse strategy
     */
    
    static int
    v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
    	      struct dentry *dentry)
    {
    	int retval;
    	struct v9fs_fid *oldfid;
    	char *name;
    
    	dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
    		old_dentry->d_name.name);
    
    	oldfid = v9fs_fid_lookup(old_dentry);
    	if (!oldfid) {
    		dprintk(DEBUG_ERROR, "can't find oldfid\n");
    		return -EPERM;
    	}
    
    	name = __getname();
    	sprintf(name, "hardlink(%d)\n", oldfid->fid);
    	retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
    	__putname(name);
    
    
    	return retval;
    }
    
    /**
     * v9fs_vfs_mknod - create a special file
     * @dir: inode destination for new link
     * @dentry: dentry for file
     * @mode: mode for creation
     * @dev_t: device associated with special file
     *
     */
    
    static int
    v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
    {
    
    	int retval;
    	char *name;
    
    
    	dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
    		dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
    
    
    	if (!new_valid_dev(rdev))
    		return -EINVAL;
    
    	name = __getname();
    
    	/* build extension */
    	if (S_ISBLK(mode))
    
    		sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
    
    	else if (S_ISCHR(mode))
    
    		sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
    
    		__putname(name);
    		return -EINVAL;
    
    	retval = v9fs_vfs_mkspecial(dir, dentry, mode, name);
    	__putname(name);
    
    static struct inode_operations v9fs_dir_inode_operations_ext = {
    
    	.create = v9fs_vfs_create,
    	.lookup = v9fs_vfs_lookup,
    	.symlink = v9fs_vfs_symlink,
    	.link = v9fs_vfs_link,
    	.unlink = v9fs_vfs_unlink,
    	.mkdir = v9fs_vfs_mkdir,
    	.rmdir = v9fs_vfs_rmdir,
    	.mknod = v9fs_vfs_mknod,
    	.rename = v9fs_vfs_rename,
    	.readlink = v9fs_vfs_readlink,
    	.getattr = v9fs_vfs_getattr,
    	.setattr = v9fs_vfs_setattr,
    };
    
    
    static struct inode_operations v9fs_dir_inode_operations = {
    	.create = v9fs_vfs_create,
    	.lookup = v9fs_vfs_lookup,
    	.unlink = v9fs_vfs_unlink,
    	.mkdir = v9fs_vfs_mkdir,
    	.rmdir = v9fs_vfs_rmdir,
    	.mknod = v9fs_vfs_mknod,
    	.rename = v9fs_vfs_rename,
    	.getattr = v9fs_vfs_getattr,
    	.setattr = v9fs_vfs_setattr,
    };
    
    
    static struct inode_operations v9fs_file_inode_operations = {
    	.getattr = v9fs_vfs_getattr,
    	.setattr = v9fs_vfs_setattr,
    };
    
    static struct inode_operations v9fs_symlink_inode_operations = {
    	.readlink = v9fs_vfs_readlink,
    	.follow_link = v9fs_vfs_follow_link,
    	.put_link = v9fs_vfs_put_link,
    	.getattr = v9fs_vfs_getattr,
    	.setattr = v9fs_vfs_setattr,
    };