Exemplo n.º 1
0
/*
 * Defer release of inode_info and file_info structures until the inode
 * has been cleared.  This avoids a race condition allowing the inode to 
 * be put back in use before being cleared. Also, temporarily increment
 * i_count after clear_inode() so that the inode can't be reused.
 */
static void
ncp_put_inode(struct inode *inode)
{
	struct super_block	*sb	= inode->i_sb;
	struct ncp_server	*server	= NCP_SERVER(inode);
	struct ncp_inode_info	*iinfo	= NCP_INOP(inode);
        struct nw_file_info	*finfo	= NCP_FINFO(inode);

	/*
	 * This operation may block, so we lock before checking the count.
	 */
	lock_super(sb);

	if (inode->i_count > 1) {
printk("ncp_put_inode: inode in use device %s, inode %ld, count=%ld\n", 
kdevname(inode->i_dev), inode->i_ino, inode->i_count);
		goto unlock;
	}
	
	DDPRINTK("ncp_put_inode: put %s\n",
		 finfo->i.entryName);
	/*
	 * This operation should never block.
	 */
        if (S_ISDIR(inode->i_mode))
	{
                DDPRINTK("ncp_put_inode: put directory %ld\n",
			 inode->i_ino);
                ncp_invalid_dir_cache(inode);
        }                

	clear_inode(inode);

	/*
	 * After clearing the inode i_count will be 0 in 2.0.xx kernels.
	 * To keep the inode from being reused as free if we block while
	 * closing the file, increment i_count temporarily.
	 */
	inode->i_count++;

	if (finfo->opened != 0)
	{
		if (ncp_close_file(server, finfo->file_handle) != 0)
		{
			/* We can't do anything but complain. */
			printk("ncp_put_inode: could not close %s\n",
		 		finfo->i.entryName);
		}
	}

	ncp_free_inode_info(iinfo);
	inode->i_count--;
		
unlock:
	unlock_super(sb);
}
Exemplo n.º 2
0
static void
ncp_delete_inode(struct inode *inode)
{
	if (S_ISDIR(inode->i_mode)) {
		DDPRINTK(KERN_DEBUG "ncp_delete_inode: put directory %ld\n", inode->i_ino);
		ncp_invalid_dir_cache(inode);
	}

	if (NCP_FINFO(inode)->opened && ncp_make_closed(inode) != 0) {
		/* We can't do anything but complain. */
		printk(KERN_ERR "ncp_delete_inode: could not close\n");
	}
	clear_inode(inode);
}
Exemplo n.º 3
0
static int
ncp_file_write(struct inode *inode, struct file *file, const char *buf,
               int count)
{
    int bufsize, already_written;
    off_t pos;
    int errno;

    if (inode == NULL)
    {
        DPRINTK("ncp_file_write: inode = NULL\n");
        return -EINVAL;
    }
    if (!ncp_conn_valid(NCP_SERVER(inode)))
    {
        return -EIO;
    }

    if (!S_ISREG(inode->i_mode))
    {
        DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
                inode->i_mode);
        return -EINVAL;
    }

    DPRINTK("ncp_file_write: enter %s\n", NCP_ISTRUCT(inode)->entryName);

    if (count <= 0)
    {
        return 0;
    }

    if ((errno = ncp_make_open(inode, O_RDWR)) != 0)
    {
        return errno;
    }

    pos = file->f_pos;

    if (file->f_flags & O_APPEND)
    {
        pos = inode->i_size;
    }

    bufsize = NCP_SERVER(inode)->buffer_size;

    already_written = 0;

    while (already_written < count)
    {
        int written_this_time;
        int to_write = min(bufsize - (pos % bufsize),
                           count - already_written);

        if (ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
                      pos, to_write, buf, &written_this_time) != 0)
        {
            return -EIO;
        }

        pos += written_this_time;
        buf += written_this_time;
        already_written += written_this_time;

        if (written_this_time < to_write)
        {
            break;
        }
    }

    inode->i_mtime = inode->i_ctime = CURRENT_TIME;
    inode->i_dirt = 1;

    file->f_pos = pos;

    if (pos > inode->i_size)
    {
        inode->i_size = pos;
        ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
    }

    DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName);

    return already_written;
}
Exemplo n.º 4
0
static int
ncp_notify_change(struct inode *inode, struct iattr *attr)
{
	int result = 0;
	int info_mask;
	struct nw_modify_dos_info info;

	if (!ncp_conn_valid(NCP_SERVER(inode)))
	{
		return -EIO;
	}

	if ((result = inode_change_ok(inode, attr)) < 0)
		return result;

	if (((attr->ia_valid & ATTR_UID) && 
	     (attr->ia_uid != NCP_SERVER(inode)->m.uid)))
		return -EPERM;

	if (((attr->ia_valid & ATTR_GID) && 
	     (attr->ia_uid != NCP_SERVER(inode)->m.gid)))
                return -EPERM;

	if (((attr->ia_valid & ATTR_MODE) &&
	     (attr->ia_mode &
	      ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
		return -EPERM;

	info_mask = 0;
	memset(&info, 0, sizeof(info));

	if ((attr->ia_valid & ATTR_CTIME) != 0)
	{
		info_mask |= (DM_CREATE_TIME|DM_CREATE_DATE);
		ncp_date_unix2dos(attr->ia_ctime,
				  &(info.creationTime), &(info.creationDate));
	}
	
	if ((attr->ia_valid & ATTR_MTIME) != 0)
	{
		info_mask |= (DM_MODIFY_TIME|DM_MODIFY_DATE);
		ncp_date_unix2dos(attr->ia_mtime,
				  &(info.modifyTime), &(info.modifyDate));
	}
	
	if ((attr->ia_valid & ATTR_ATIME) != 0)
	{
		__u16 dummy;
		info_mask |= (DM_LAST_ACCESS_DATE);
		ncp_date_unix2dos(attr->ia_ctime,
				  &(dummy), &(info.lastAccessDate));
	}

	if (info_mask != 0)
	{
		if ((result =
		     ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
							NCP_ISTRUCT(inode),
							info_mask,
							&info)) != 0)
		{
			result = -EACCES;

			if (info_mask == (DM_CREATE_TIME|DM_CREATE_DATE))
			{
				/* NetWare seems not to allow this. I
                                   do not know why. So, just tell the
                                   user everything went fine. This is
                                   a terrible hack, but I do not know
                                   how to do this correctly. */
				result = 0;
			}
		}
	}

        if ((attr->ia_valid & ATTR_SIZE) != 0)
	{
		int written;

		DPRINTK("ncpfs: trying to change size of %s to %ld\n",
			NCP_ISTRUCT(inode)->entryName, attr->ia_size);

		if ((result = ncp_make_open(inode, O_RDWR)) < 0)
		{
			return -EACCES;
		}

		ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
			  attr->ia_size, 0, "", &written);

		/* According to ndir, the changes only take effect after
		   closing the file */
		ncp_close_file(NCP_SERVER(inode),
			       NCP_FINFO(inode)->file_handle);
		NCP_FINFO(inode)->opened = 0;

		result = 0;
	}

        ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);

	return result;
}
Exemplo n.º 5
0
int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
{
	struct inode *inode = dentry->d_inode;
	int result = 0;
	int info_mask;
	struct nw_modify_dos_info info;

	result = -EIO;
	if (!ncp_conn_valid(NCP_SERVER(inode)))
		goto out;

	result = inode_change_ok(inode, attr);
	if (result < 0)
		goto out;

	result = -EPERM;
	if (((attr->ia_valid & ATTR_UID) &&
	     (attr->ia_uid != NCP_SERVER(inode)->m.uid)))
		goto out;

	if (((attr->ia_valid & ATTR_GID) &&
	     (attr->ia_uid != NCP_SERVER(inode)->m.gid)))
		goto out;

	if (((attr->ia_valid & ATTR_MODE) &&
	     (attr->ia_mode &
	      ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
		goto out;

	info_mask = 0;
	memset(&info, 0, sizeof(info));

#if 1 
        if ((attr->ia_valid & ATTR_MODE) != 0)
        {
                if (!S_ISREG(inode->i_mode))
                {
                        return -EPERM;
                }
                else
                {
			umode_t newmode;

                        info_mask |= DM_ATTRIBUTES;
                        newmode=attr->ia_mode;
                        newmode &= NCP_SERVER(inode)->m.file_mode;

                        if (newmode & 0222) /* any write bit set */
                        {
                                info.attributes &= ~0x60001;
                        }
                        else
                        {
                                info.attributes |= 0x60001;
                        }
                }
        }
#endif

	if ((attr->ia_valid & ATTR_CTIME) != 0) {
		info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
		ncp_date_unix2dos(attr->ia_ctime,
			     &(info.creationTime), &(info.creationDate));
		info.creationTime = le16_to_cpu(info.creationTime);
		info.creationDate = le16_to_cpu(info.creationDate);
	}
	if ((attr->ia_valid & ATTR_MTIME) != 0) {
		info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
		ncp_date_unix2dos(attr->ia_mtime,
				  &(info.modifyTime), &(info.modifyDate));
		info.modifyTime = le16_to_cpu(info.modifyTime);
		info.modifyDate = le16_to_cpu(info.modifyDate);
	}
	if ((attr->ia_valid & ATTR_ATIME) != 0) {
		__u16 dummy;
		info_mask |= (DM_LAST_ACCESS_DATE);
		ncp_date_unix2dos(attr->ia_ctime,
				  &(dummy), &(info.lastAccessDate));
		info.lastAccessDate = le16_to_cpu(info.lastAccessDate);
	}
	if (info_mask != 0) {
		result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
				      inode, info_mask, &info);
		if (result != 0) {
			result = -EACCES;

			if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
				/* NetWare seems not to allow this. I
				   do not know why. So, just tell the
				   user everything went fine. This is
				   a terrible hack, but I do not know
				   how to do this correctly. */
				result = 0;
			}
		}
	}
	if ((attr->ia_valid & ATTR_SIZE) != 0) {
		int written;

		DPRINTK(KERN_DEBUG "ncpfs: trying to change size to %ld\n",
			attr->ia_size);

		if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
			return -EACCES;
		}
		ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
			  attr->ia_size, 0, "", &written);

		/* According to ndir, the changes only take effect after
		   closing the file */
		result = ncp_make_closed(inode);
	}
	ncp_invalid_dir_cache(dentry->d_parent->d_inode);
out:
	return result;
}