コード例 #1
0
ファイル: inode.c プロジェクト: Antonio-Zhou/Linux-2.6.11
/*
 * This is called to update the inode attributes after
 * we've made changes to a file or directory.
 */
static int
smb_refresh_inode(struct dentry *dentry)
{
	struct inode *inode = dentry->d_inode;
	int error;
	struct smb_fattr fattr;

	error = smb_proc_getattr(dentry, &fattr);
	if (!error) {
		smb_renew_times(dentry);
		/*
		 * Check whether the type part of the mode changed,
		 * and don't update the attributes if it did.
		 *
		 * And don't dick with the root inode
		 */
		if (inode->i_ino == 2)
			return error;
		if (S_ISLNK(inode->i_mode))
			return error;	/* VFS will deal with it */

		if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
			smb_set_inode_attr(inode, &fattr);
		} else {
			/*
			 * Big trouble! The inode has become a new object,
			 * so any operations attempted on it are invalid.
			 *
			 * To limit damage, mark the inode as bad so that
			 * subsequent lookup validations will fail.
			 */
			PARANOIA("%s/%s changed mode, %07o to %07o\n",
				 DENTRY_PATH(dentry),
				 inode->i_mode, fattr.f_mode);

			fattr.f_mode = inode->i_mode; /* save mode */
			make_bad_inode(inode);
			inode->i_mode = fattr.f_mode; /* restore mode */
			/*
			 * No need to worry about unhashing the dentry: the
			 * lookup validation will see that the inode is bad.
			 * But we do want to invalidate the caches ...
			 */
			if (!S_ISDIR(inode->i_mode))
				invalidate_remote_inode(inode);
			else
				smb_invalid_dir_cache(inode);
			error = -EIO;
		}
	}
	return error;
}
コード例 #2
0
ファイル: dir.c プロジェクト: rohsaini/mkunity
static int
smb_create(struct inode *dir, const char *name, int len, int mode,
	   struct inode **result)
{
	int error;
	struct smb_dirent entry;
	struct smb_inode_info *new_inode_info;

	*result = NULL;

	if (!dir || !S_ISDIR(dir->i_mode))
	{
		printk("smb_create: inode is NULL or not a directory\n");
		iput(dir);
		return -ENOENT;
	}
	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
				     GFP_KERNEL);
	if (new_inode_info == NULL)
	{
		iput(dir);
		return -ENOMEM;
	}
	error = smb_proc_create(dir, name, len, 0, CURRENT_TIME);
	if (error < 0)
	{
		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
		iput(dir);
		return error;
	}
	smb_invalid_dir_cache(dir->i_ino);

	if ((error = smb_proc_getattr(dir, name, len, &entry)) < 0)
	{
		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
		iput(dir);
		return error;
	}
	entry.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1);

	new_inode_info->finfo = entry;

	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
	{
		iput(dir);
		return error;
	}
	iput(dir);
	return 0;
}
コード例 #3
0
ファイル: dir.c プロジェクト: rohsaini/mkunity
static int
smb_lookup(struct inode *dir, const char *name, int len,
	   struct inode **result)
{
	struct smb_dirent finfo;
	struct smb_inode_info *result_info;
	int error;
	int found_in_cache;

	struct smb_inode_info *new_inode_info = NULL;

	*result = NULL;

	if (!dir || !S_ISDIR(dir->i_mode))
	{
		printk("smb_lookup: inode is NULL or not a directory.\n");
		iput(dir);
		return -ENOENT;
	}
	DDPRINTK("smb_lookup: %s\n", name);

	/* Fast cheat for . */
	if (len == 0 || (len == 1 && name[0] == '.'))
	{
		*result = dir;
		return 0;
	}
	/* ..and for .. */
	if (len == 2 && name[0] == '.' && name[1] == '.')
	{
		struct smb_inode_info *parent = SMB_INOP(dir)->dir;

		if (parent->state == SMB_INODE_CACHED)
		{
			parent->state = SMB_INODE_LOOKED_UP;
		}
		*result = iget(dir->i_sb, smb_info_ino(parent));
		iput(dir);
		if (*result == 0)
		{
			return -EACCES;
		}
		return 0;
	}
	result_info = smb_find_dir_inode(dir, name, len);

      in_tree:
	if (result_info != NULL)
	{
		if (result_info->state == SMB_INODE_CACHED)
		{
			result_info->state = SMB_INODE_LOOKED_UP;
		}
		*result = iget(dir->i_sb, smb_info_ino(result_info));
		iput(dir);

		if (new_inode_info != NULL)
		{
			smb_kfree_s(new_inode_info,
				    sizeof(struct smb_inode_info));
		}
		if (*result == NULL)
		{
			return -EACCES;
		}
		return 0;
	}
	/* If the file is in the dir cache, we do not have to ask the
	   server. */
	found_in_cache = 0;

	if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino) && (c_size != 0))
	{
		int first = c_last_returned_index;
		int i;

		i = first;
		do
		{
			if (compare_filename(SMB_SERVER(dir), name, len,
					     &(c_entry[i])) == 0)
			{
				finfo = c_entry[i];
				found_in_cache = 1;
				break;
			}
			i = (i + 1) % c_size;
		}
		while (i != first);
	}
	if (found_in_cache == 0)
	{
		DPRINTK("smb_lookup: not found in cache: %s\n", name);
		if (len > SMB_MAXNAMELEN)
		{
			iput(dir);
			return -ENAMETOOLONG;
		}
		error = smb_proc_getattr(dir, name, len, &finfo);
		if (error < 0)
		{
			iput(dir);
			return error;
		}
		finfo.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1);
	}
	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
				     GFP_KERNEL);

	/* Here somebody else might have inserted the inode */

	result_info = smb_find_dir_inode(dir, name, len);
	if (result_info != NULL)
	{
		goto in_tree;
	}

	if (new_inode_info == NULL)
	{
		iput(dir);
		return -ENOMEM;
	}
	new_inode_info->finfo = finfo;

	DPRINTK("attr: %x\n", finfo.attr);

	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
	{
		iput(dir);
		return -EACCES;
	}
	DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long) result_info);
	iput(dir);
	return 0;
}