Esempio 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);
}
Esempio n. 2
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;
}
Esempio n. 3
0
static void
ncp_read_inode(struct inode *inode)
{
        /* Our task should be extremely simple here. We only have to
           look up the information somebody else (ncp_iget) put into
           the inode tree. The address of this information is the
           inode->i_ino. Just to make sure everything went well, we
           check it's there. */

        struct ncp_inode_info *inode_info = ncp_find_inode(inode);

	if (inode_info == NULL)
	{
		/* Ok, now we're in trouble. The inode info is not there. What
		   should we do now??? */
		printk("ncp_read_inode: inode info not found\n");
		return;
	}

        inode_info->state = NCP_INODE_VALID;

        NCP_INOP(inode) = inode_info;
	inode_info->inode = inode;

        if (NCP_ISTRUCT(inode)->attributes & aDIR)
	{
                inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
		/* for directories dataStreamSize seems to be some
		   Object ID ??? */
		inode->i_size = 512;
	}
	else
	{
                inode->i_mode = NCP_SERVER(inode)->m.file_mode;
		inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize;
	}

        DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);

        inode->i_nlink   = 1;
        inode->i_uid     = NCP_SERVER(inode)->m.uid;
        inode->i_gid     = NCP_SERVER(inode)->m.gid;
        inode->i_blksize = 512;
        inode->i_rdev    = 0;

        if ((inode->i_blksize != 0) && (inode->i_size != 0))
	{
                inode->i_blocks =
                        (inode->i_size - 1) / inode->i_blksize + 1;
	}
        else
	{
                inode->i_blocks = 0;
	}

	inode->i_mtime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->modifyTime,
					   NCP_ISTRUCT(inode)->modifyDate);
	inode->i_ctime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->creationTime,
					   NCP_ISTRUCT(inode)->creationDate);
	inode->i_atime = ncp_date_dos2unix(0,
					   NCP_ISTRUCT(inode)->lastAccessDate);

        if (S_ISREG(inode->i_mode))
	{
                inode->i_op = &ncp_file_inode_operations;
	}
        else if (S_ISDIR(inode->i_mode))
	{
                inode->i_op = &ncp_dir_inode_operations;
	}
        else
	{
                inode->i_op = NULL;
	}
}
Esempio 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;
}