Beispiel #1
0
/* This is used for a general mmap of a ncp file */
int ncp_mmap(struct file *file, struct vm_area_struct *vma)
{
    struct inode *inode = file_inode(file);

    ncp_dbg(1, "called\n");

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

    /* only PAGE_COW or read-only supported now */
    if (vma->vm_flags & VM_SHARED)
        return -EINVAL;
    /* we do not support files bigger than 4GB... We eventually
       supports just 4GB... */
    if (vma_pages(vma) + vma->vm_pgoff
            > (1U << (32 - PAGE_SHIFT)))
        return -EFBIG;

    vma->vm_ops = &ncp_file_mmap;
    file_accessed(file);
    return 0;
}
Beispiel #2
0
/*
 * Fill in the inode based on the nw_file_info structure.
 */
static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
{
	struct nw_info_struct *nwi = &nwinfo->i;
	struct ncp_server *server = NCP_SERVER(inode);

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

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

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

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

	inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
			  		   le16_to_cpu(nwi->modifyDate));
	inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
			    		   le16_to_cpu(nwi->creationDate));
	inode->i_atime = ncp_date_dos2unix(0,
					   le16_to_cpu(nwi->lastAccessDate));
	ncp_update_inode(inode, nwinfo);
}
Beispiel #3
0
/* This is used for a general mmap of a ncp file */
int ncp_mmap(struct file *file, struct vm_area_struct *vma)
{
	struct inode *inode = file->f_dentry->d_inode;
	
	DPRINTK(KERN_DEBUG "ncp_mmap: called\n");

	if (!ncp_conn_valid(NCP_SERVER(inode))) {
		return -EIO;
	}
	/* only PAGE_COW or read-only supported now */
	if (vma->vm_flags & VM_SHARED)
		return -EINVAL;
	if (!inode->i_sb || !S_ISREG(inode->i_mode))
		return -EACCES;
	if (!IS_RDONLY(inode)) {
		inode->i_atime = CURRENT_TIME;
	}

	vma->vm_file = file;
	file->f_count++;
	vma->vm_ops = &ncp_file_mmap;
	return 0;
}
Beispiel #4
0
void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
{
	struct nw_info_struct *nwi = &nwinfo->i;
	struct ncp_server *server = NCP_SERVER(inode);

	if (!NCP_FINFO(inode)->opened) {
		if (nwi->attributes & aDIR) {
			inode->i_mode = server->m.dir_mode;
			inode->i_size = 512;
		} else {
			inode->i_mode = server->m.file_mode;
			inode->i_size = le32_to_cpu(nwi->dataStreamSize);
		}
		if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
	}
	inode->i_blocks = 0;
	if ((inode->i_size)&&(inode->i_blksize)) {
		inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1;
	}
	/* TODO: times? I'm not sure... */
	NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
	NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
	NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
}
Beispiel #5
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;
}
Beispiel #6
0
static ssize_t
ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
	struct dentry *dentry = file->f_dentry;
	struct inode *inode = dentry->d_inode;
	size_t already_written = 0;
	off_t pos;
	size_t bufsize;
	int errno;
	void* bouncebuffer;

	DPRINTK("ncp_file_write: enter %s/%s\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);
	errno = -EIO;
	if (!ncp_conn_valid(NCP_SERVER(inode)))
		goto out;
	if (!S_ISREG(inode->i_mode)) {
		DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
			inode->i_mode);
		return -EINVAL;
	}

	errno = 0;
	if (!count)
		goto out;
	errno = ncp_make_open(inode, O_WRONLY);
	if (errno) {
		DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
		return errno;
	}
	pos = *ppos;

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

	already_written = 0;

	bouncebuffer = vmalloc(bufsize);
	if (!bouncebuffer) {
		errno = -EIO;	/* -ENOMEM */
		goto outrel;
	}
	while (already_written < count) {
		int written_this_time;
		size_t to_write = min_t(unsigned int,
				      bufsize - (pos % bufsize),
				      count - already_written);

		if (copy_from_user(bouncebuffer, buf, to_write)) {
			errno = -EFAULT;
			break;
		}
		if (ncp_write_kernel(NCP_SERVER(inode), 
		    NCP_FINFO(inode)->file_handle,
		    pos, to_write, bouncebuffer, &written_this_time) != 0) {
			errno = -EIO;
			break;
		}
		pos += written_this_time;
		buf += written_this_time;
		already_written += written_this_time;

		if (written_this_time != to_write) {
			break;
		}
	}
	vfree(bouncebuffer);
	inode->i_mtime = inode->i_atime = CURRENT_TIME;
	
	*ppos = pos;

	if (pos > inode->i_size) {
		inode->i_size = pos;
	}
	DPRINTK("ncp_file_write: exit %s/%s\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);
outrel:
	ncp_inode_close(inode);		
out:
	return already_written ? already_written : errno;
}
Beispiel #7
0
static ssize_t
ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
	struct dentry *dentry = file->f_dentry;
	struct inode *inode = dentry->d_inode;
	size_t already_read = 0;
	off_t pos;
	size_t bufsize;
	int error;
	void* freepage;
	size_t freelen;

	DPRINTK("ncp_file_read: enter %s/%s\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);

	error = -EIO;
	if (!ncp_conn_valid(NCP_SERVER(inode)))
		goto out;
	error = -EINVAL;
	if (!S_ISREG(inode->i_mode)) {
		DPRINTK("ncp_file_read: read from non-file, mode %07o\n",
			inode->i_mode);
		goto out;
	}

	pos = *ppos;
/* leave it out on server ...
	if (pos + count > inode->i_size) {
		count = inode->i_size - pos;
	}
*/
	error = 0;
	if (!count)	/* size_t is never < 0 */
		goto out;

	error = ncp_make_open(inode, O_RDONLY);
	if (error) {
		DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
		goto out;
	}

	bufsize = NCP_SERVER(inode)->buffer_size;

	error = -EIO;
	freelen = ncp_read_bounce_size(bufsize);
	freepage = vmalloc(freelen);
	if (!freepage)
		goto outrel;
	error = 0;
	/* First read in as much as possible for each bufsize. */
	while (already_read < count) {
		int read_this_time;
		size_t to_read = min_t(unsigned int,
				     bufsize - (pos % bufsize),
				     count - already_read);

		error = ncp_read_bounce(NCP_SERVER(inode),
			 	NCP_FINFO(inode)->file_handle,
				pos, to_read, buf, &read_this_time, 
				freepage, freelen);
		if (error) {
			error = -EIO;	/* NW errno -> Linux errno */
			break;
		}
		pos += read_this_time;
		buf += read_this_time;
		already_read += read_this_time;

		if (read_this_time != to_read) {
			break;
		}
	}
	vfree(freepage);

	*ppos = pos;

	if (!IS_RDONLY(inode)) {
		inode->i_atime = CURRENT_TIME;
	}
	
	DPRINTK("ncp_file_read: exit %s/%s\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);
outrel:
	ncp_inode_close(inode);		
out:
	return already_read ? already_read : error;
}
Beispiel #8
0
static ssize_t
ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	size_t already_read = 0;
	off_t pos;
	size_t bufsize;
	int error;
	void* freepage;
	size_t freelen;

	DPRINTK("ncp_file_read: enter %s/%s\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);

	pos = *ppos;

	if ((ssize_t) count < 0) {
		return -EINVAL;
	}
	if (!count)
		return 0;
	if (pos > inode->i_sb->s_maxbytes)
		return 0;
	if (pos + count > inode->i_sb->s_maxbytes) {
		count = inode->i_sb->s_maxbytes - pos;
	}

	error = ncp_make_open(inode, O_RDONLY);
	if (error) {
		DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
		return error;
	}

	bufsize = NCP_SERVER(inode)->buffer_size;

	error = -EIO;
	freelen = ncp_read_bounce_size(bufsize);
	freepage = vmalloc(freelen);
	if (!freepage)
		goto outrel;
	error = 0;
	/* First read in as much as possible for each bufsize. */
	while (already_read < count) {
		int read_this_time;
		size_t to_read = min_t(unsigned int,
				     bufsize - (pos % bufsize),
				     count - already_read);

		error = ncp_read_bounce(NCP_SERVER(inode),
			 	NCP_FINFO(inode)->file_handle,
				pos, to_read, buf, &read_this_time, 
				freepage, freelen);
		if (error) {
			error = -EIO;	/* NW errno -> Linux errno */
			break;
		}
		pos += read_this_time;
		buf += read_this_time;
		already_read += read_this_time;

		if (read_this_time != to_read) {
			break;
		}
	}
	vfree(freepage);

	*ppos = pos;

	file_accessed(file);

	DPRINTK("ncp_file_read: exit %s/%s\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);
outrel:
	ncp_inode_close(inode);		
	return already_read ? already_read : error;
}
Beispiel #9
0
static ssize_t
ncp_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
	struct file *file = iocb->ki_filp;
	struct inode *inode = file_inode(file);
	size_t already_read = 0;
	off_t pos = iocb->ki_pos;
	size_t bufsize;
	int error;
	void *freepage;
	size_t freelen;

	ncp_dbg(1, "enter %pD2\n", file);

	if (!iov_iter_count(to))
		return 0;
	if (pos > inode->i_sb->s_maxbytes)
		return 0;
	iov_iter_truncate(to, inode->i_sb->s_maxbytes - pos);

	error = ncp_make_open(inode, O_RDONLY);
	if (error) {
		ncp_dbg(1, "open failed, error=%d\n", error);
		return error;
	}

	bufsize = NCP_SERVER(inode)->buffer_size;

	error = -EIO;
	freelen = ncp_read_bounce_size(bufsize);
	freepage = vmalloc(freelen);
	if (!freepage)
		goto outrel;
	error = 0;
	/* First read in as much as possible for each bufsize. */
	while (iov_iter_count(to)) {
		int read_this_time;
		size_t to_read = min_t(size_t,
				     bufsize - (pos % bufsize),
				     iov_iter_count(to));

		error = ncp_read_bounce(NCP_SERVER(inode),
			 	NCP_FINFO(inode)->file_handle,
				pos, to_read, to, &read_this_time, 
				freepage, freelen);
		if (error) {
			error = -EIO;	/* NW errno -> Linux errno */
			break;
		}
		pos += read_this_time;
		already_read += read_this_time;

		if (read_this_time != to_read)
			break;
	}
	vfree(freepage);

	iocb->ki_pos = pos;

	file_accessed(file);

	ncp_dbg(1, "exit %pD2\n", file);
outrel:
	ncp_inode_close(inode);		
	return already_read ? already_read : error;
}
Beispiel #10
0
static ssize_t
ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
	struct file *file = iocb->ki_filp;
	struct inode *inode = file_inode(file);
	size_t already_written = 0;
	size_t bufsize;
	int errno;
	void *bouncebuffer;
	off_t pos;

	ncp_dbg(1, "enter %pD2\n", file);
	errno = generic_write_checks(iocb, from);
	if (errno <= 0)
		return errno;

	errno = ncp_make_open(inode, O_WRONLY);
	if (errno) {
		ncp_dbg(1, "open failed, error=%d\n", errno);
		return errno;
	}
	bufsize = NCP_SERVER(inode)->buffer_size;

	errno = file_update_time(file);
	if (errno)
		goto outrel;

	bouncebuffer = vmalloc(bufsize);
	if (!bouncebuffer) {
		errno = -EIO;	/* -ENOMEM */
		goto outrel;
	}
	pos = iocb->ki_pos;
	while (iov_iter_count(from)) {
		int written_this_time;
		size_t to_write = min_t(size_t,
				      bufsize - (pos % bufsize),
				      iov_iter_count(from));

		if (copy_from_iter(bouncebuffer, to_write, from) != to_write) {
			errno = -EFAULT;
			break;
		}
		if (ncp_write_kernel(NCP_SERVER(inode), 
		    NCP_FINFO(inode)->file_handle,
		    pos, to_write, bouncebuffer, &written_this_time) != 0) {
			errno = -EIO;
			break;
		}
		pos += written_this_time;
		already_written += written_this_time;

		if (written_this_time != to_write)
			break;
	}
	vfree(bouncebuffer);

	iocb->ki_pos = pos;

	if (pos > i_size_read(inode)) {
		mutex_lock(&inode->i_mutex);
		if (pos > i_size_read(inode))
			i_size_write(inode, pos);
		mutex_unlock(&inode->i_mutex);
	}
	ncp_dbg(1, "exit %pD2\n", file);
outrel:
	ncp_inode_close(inode);		
	return already_written ? already_written : errno;
}
Beispiel #11
0
int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
	struct inode *inode;
	char *rawlink;
	int length, err, i, outlen;
	int kludge;
	int mode;
	__le32 attr;
	unsigned int hdr;

	DPRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);

	if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber))
		kludge = 0;
	else
#ifdef CONFIG_NCPFS_EXTRAS
	if (NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS)
		kludge = 1;
	else
#endif
	/* EPERM is returned by VFS if symlink procedure does not exist */
		return -EPERM;
  
	rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
	if (!rawlink)
		return -ENOMEM;

	if (kludge) {
		mode = 0;
		attr = aSHARED | aHIDDEN;
		((__le32 *)rawlink)[0]=NCP_SYMLINK_MAGIC0;
		((__le32 *)rawlink)[1]=NCP_SYMLINK_MAGIC1;
		hdr = 8;
	} else {
		mode = S_IFLNK | S_IRWXUGO;
		attr = 0;
		hdr = 0;
	}			

	length = strlen(symname);
	/* map to/from server charset, do not touch upper/lower case as
	   symlink can point out of ncp filesystem */
	outlen = NCP_MAX_SYMLINK_SIZE - hdr;
	err = ncp_io2vol(NCP_SERVER(dir), rawlink + hdr, &outlen, symname, length, 0);
	if (err)
		goto failfree;

	outlen += hdr;

	err = -EIO;
	if (ncp_create_new(dir,dentry,mode,0,attr)) {
		goto failfree;
	}

	inode=dentry->d_inode;

	if (ncp_make_open(inode, O_WRONLY))
		goto failfree;

	if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, 
			     0, outlen, rawlink, &i) || i!=outlen) {
		goto fail;
	}

	ncp_inode_close(inode);
	ncp_make_closed(inode);
	kfree(rawlink);
	return 0;
fail:;
	ncp_inode_close(inode);
	ncp_make_closed(inode);
failfree:;
	kfree(rawlink);
	return err;
}
Beispiel #12
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;
}
Beispiel #13
0
int ncp_make_open(struct inode *inode, int right)
{
	int error;
	int access;

	error = -EINVAL;
	if (!inode) {
		printk(KERN_ERR "ncp_make_open: got NULL inode\n");
		goto out;
	}

	DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %u\n",
		atomic_read(&NCP_FINFO(inode)->opened), 
		NCP_FINFO(inode)->volNumber, 
		NCP_FINFO(inode)->dirEntNum);
	error = -EACCES;
	mutex_lock(&NCP_FINFO(inode)->open_mutex);
	if (!atomic_read(&NCP_FINFO(inode)->opened)) {
		struct ncp_entry_info finfo;
		int result;

		/*                   */
		finfo.access = O_RDWR;
		result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
					inode, NULL, OC_MODE_OPEN,
					0, AR_READ | AR_WRITE, &finfo);
		if (!result)
			goto update;
		/*                                                                */
		switch (right) {
			case O_RDONLY:
				finfo.access = O_RDONLY;
				result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
					inode, NULL, OC_MODE_OPEN,
					0, AR_READ, &finfo);
				break;
			case O_WRONLY:
				finfo.access = O_WRONLY;
				result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
					inode, NULL, OC_MODE_OPEN,
					0, AR_WRITE, &finfo);
				break;
		}
		if (result) {
			PPRINTK("ncp_make_open: failed, result=%d\n", result);
			goto out_unlock;
		}
		/*
                                  
   */
	update:
		ncp_update_inode(inode, &finfo);
		atomic_set(&NCP_FINFO(inode)->opened, 1);
	}

	access = NCP_FINFO(inode)->access;
	PPRINTK("ncp_make_open: file open, access=%x\n", access);
	if (access == right || access == O_RDWR) {
		atomic_inc(&NCP_FINFO(inode)->opened);
		error = 0;
	}

out_unlock:
	mutex_unlock(&NCP_FINFO(inode)->open_mutex);
out:
	return error;
}
Beispiel #14
0
/*
 * Fill in the supplied page for mmap
 */
static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
				     unsigned long address, int no_share)
{
	struct file *file = area->vm_file;
	struct dentry *dentry = file->f_dentry;
	struct inode *inode = dentry->d_inode;
	unsigned long page;
	unsigned int clear;
	unsigned long tmp;
	int bufsize;
	int pos;
	mm_segment_t fs;

	page = __get_free_page(GFP_KERNEL);
	if (!page)
		return page;
	address &= PAGE_MASK;
	pos = address - area->vm_start + area->vm_offset;

	clear = 0;
	if (address + PAGE_SIZE > area->vm_end) {
		clear = address + PAGE_SIZE - area->vm_end;
	}
	/* what we can read in one go */
	bufsize = NCP_SERVER(inode)->buffer_size;

	fs = get_fs();
	set_fs(get_ds());

	if (ncp_make_open(inode, O_RDONLY) < 0) {
		clear = PAGE_SIZE;
	} else {
		int already_read = 0;
		int count = PAGE_SIZE - clear;
		int to_read;

		while (already_read < count) {
			int read_this_time;

			if ((pos % bufsize) != 0) {
				to_read = bufsize - (pos % bufsize);
			} else {
				to_read = bufsize;
			}

			to_read = min(to_read, count - already_read);

			if (ncp_read(NCP_SERVER(inode),
				     NCP_FINFO(inode)->file_handle,
				     pos, to_read,
				     (char *) (page + already_read),
				     &read_this_time) != 0) {
				read_this_time = 0;
			}
			pos += read_this_time;
			already_read += read_this_time;

			if (read_this_time < to_read) {
				break;
			}
		}

	}

	set_fs(fs);

	tmp = page + PAGE_SIZE;
	while (clear--) {
		*(char *) --tmp = 0;
	}
	return page;
}
Beispiel #15
0
static int
ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
{
    int bufsize, already_read;
    off_t pos;
    int errno;

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

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

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

    pos = file->f_pos;

    if (pos + count > inode->i_size)
    {
        count = inode->i_size - pos;
    }

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

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

    bufsize = NCP_SERVER(inode)->buffer_size;

    already_read = 0;

    /* First read in as much as possible for each bufsize. */
    while (already_read < count)
    {
        int read_this_time;
        int to_read = min(bufsize - (pos % bufsize),
                          count - already_read);

        if (ncp_read(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
                     pos, to_read, buf, &read_this_time) != 0)
        {
            return -EIO; /* This is not exact, i know.. */
        }

        pos += read_this_time;
        buf += read_this_time;
        already_read += read_this_time;

        if (read_this_time < to_read)
        {
            break;
        }
    }

    file->f_pos = pos;

    if (!IS_RDONLY(inode))
    {
        inode->i_atime = CURRENT_TIME;
    }

    inode->i_dirt = 1;

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

    return already_read;
}
/*
 * Fill in the supplied page for mmap
 * XXX: how are we excluding truncate/invalidate here? Maybe need to lock
 * page?
 */
static int ncp_file_mmap_fault(struct vm_area_struct *area,
					struct vm_fault *vmf)
{
	struct file *file = area->vm_file;
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	char *pg_addr;
	unsigned int already_read;
	unsigned int count;
	int bufsize;
	int pos; /* XXX: loff_t ? */

	/*
	 * ncpfs has nothing against high pages as long
	 * as recvmsg and memset works on it
	 */
	vmf->page = alloc_page(GFP_HIGHUSER);
	if (!vmf->page)
		return VM_FAULT_OOM;
	pg_addr = kmap(vmf->page);
	pos = vmf->pgoff << PAGE_SHIFT;

	count = PAGE_SIZE;
	/* what we can read in one go */
	bufsize = NCP_SERVER(inode)->buffer_size;

	already_read = 0;
	if (ncp_make_open(inode, O_RDONLY) >= 0) {
		while (already_read < count) {
			int read_this_time;
			int to_read;

			to_read = bufsize - (pos % bufsize);

			to_read = min_t(unsigned int, to_read, count - already_read);

			if (ncp_read_kernel(NCP_SERVER(inode),
				     NCP_FINFO(inode)->file_handle,
				     pos, to_read,
				     pg_addr + already_read,
				     &read_this_time) != 0) {
				read_this_time = 0;
			}
			pos += read_this_time;
			already_read += read_this_time;

			if (read_this_time < to_read) {
				break;
			}
		}
		ncp_inode_close(inode);

	}

	if (already_read < PAGE_SIZE)
		memset(pg_addr + already_read, 0, PAGE_SIZE - already_read);
	flush_dcache_page(vmf->page);
	kunmap(vmf->page);

	/*
	 * If I understand ncp_read_kernel() properly, the above always
	 * fetches from the network, here the analogue of disk.
	 * -- nyc
	 */
	count_vm_event(PGMAJFAULT);
	mem_cgroup_count_vm_event(area->vm_mm, PGMAJFAULT);
	return VM_FAULT_MAJOR;
}
Beispiel #17
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;
}
Beispiel #18
0
/*
 * Open a file with the specified read/write mode.
 */
int ncp_make_open(struct inode *inode, int right)
{
	int error;
	int access;

	error = -EINVAL;
	if (!inode) {
		pr_err("%s: got NULL inode\n", __func__);
		goto out;
	}

	ncp_dbg(1, "opened=%d, volume # %u, dir entry # %u\n",
		atomic_read(&NCP_FINFO(inode)->opened), 
		NCP_FINFO(inode)->volNumber, 
		NCP_FINFO(inode)->dirEntNum);
	error = -EACCES;
	mutex_lock(&NCP_FINFO(inode)->open_mutex);
	if (!atomic_read(&NCP_FINFO(inode)->opened)) {
		struct ncp_entry_info finfo;
		int result;

		/* tries max. rights */
		finfo.access = O_RDWR;
		result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
					inode, NULL, OC_MODE_OPEN,
					0, AR_READ | AR_WRITE, &finfo);
		if (!result)
			goto update;
		/* RDWR did not succeeded, try readonly or writeonly as requested */
		switch (right) {
			case O_RDONLY:
				finfo.access = O_RDONLY;
				result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
					inode, NULL, OC_MODE_OPEN,
					0, AR_READ, &finfo);
				break;
			case O_WRONLY:
				finfo.access = O_WRONLY;
				result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
					inode, NULL, OC_MODE_OPEN,
					0, AR_WRITE, &finfo);
				break;
		}
		if (result) {
			ncp_vdbg("failed, result=%d\n", result);
			goto out_unlock;
		}
		/*
		 * Update the inode information.
		 */
	update:
		ncp_update_inode(inode, &finfo);
		atomic_set(&NCP_FINFO(inode)->opened, 1);
	}

	access = NCP_FINFO(inode)->access;
	ncp_vdbg("file open, access=%x\n", access);
	if (access == right || access == O_RDWR) {
		atomic_inc(&NCP_FINFO(inode)->opened);
		error = 0;
	}

out_unlock:
	mutex_unlock(&NCP_FINFO(inode)->open_mutex);
out:
	return error;
}
Beispiel #19
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;
	}
}
Beispiel #20
0
int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
{
	struct inode *inode = dentry->d_inode;
	int result = 0;
	__le32 info_mask;
	struct nw_modify_dos_info info;
	struct ncp_server *server;

	result = -EIO;

	lock_kernel();	

	server = NCP_SERVER(inode);
	if ((!server) || !ncp_conn_valid(server))
		goto out;

	/* ageing the dentry to force validation */
	ncp_age_dentry(server, dentry);

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

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

	if (((attr->ia_valid & ATTR_GID) &&
	     (attr->ia_gid != server->m.gid)))
		goto out;

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

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

#if 1 
        if ((attr->ia_valid & ATTR_MODE) != 0)
        {
		umode_t newmode = attr->ia_mode;

		info_mask |= DM_ATTRIBUTES;

                if (S_ISDIR(inode->i_mode)) {
                	newmode &= server->m.dir_mode;
		} else {
#ifdef CONFIG_NCPFS_EXTRAS			
			if (server->m.flags & NCP_MOUNT_EXTRAS) {
				/* any non-default execute bit set */
				if (newmode & ~server->m.file_mode & S_IXUGO)
					info.attributes |= aSHARED | aSYSTEM;
				/* read for group/world and not in default file_mode */
				else if (newmode & ~server->m.file_mode & S_IRUGO)
					info.attributes |= aSHARED;
			} else
#endif
				newmode &= server->m.file_mode;			
                }
                if (newmode & S_IWUGO)
                	info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
                else
			info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);

#ifdef CONFIG_NCPFS_NFS_NS
		if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
			result = ncp_modify_nfs_info(server,
						     NCP_FINFO(inode)->volNumber,
						     NCP_FINFO(inode)->dirEntNum,
						     attr->ia_mode, 0);
			if (result != 0)
				goto out;
			info.attributes &= ~(aSHARED | aSYSTEM);
			{
				/* mark partial success */
				struct iattr tmpattr;
				
				tmpattr.ia_valid = ATTR_MODE;
				tmpattr.ia_mode = attr->ia_mode;

				result = inode_setattr(inode, &tmpattr);
				if (result)
					goto out;
			}
		}
#endif
        }
#endif

	/* Do SIZE before attributes, otherwise mtime together with size does not work...
	 */
	if ((attr->ia_valid & ATTR_SIZE) != 0) {
		int written;

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

		if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
			result = -EACCES;
			goto out;
		}
		ncp_write_kernel(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_inode_close(inode);
		result = ncp_make_closed(inode);
		if (result)
			goto out;
		{
			struct iattr tmpattr;
			
			tmpattr.ia_valid = ATTR_SIZE;
			tmpattr.ia_size = attr->ia_size;
			
			result = inode_setattr(inode, &tmpattr);
			if (result)
				goto out;
		}
	}
	if ((attr->ia_valid & ATTR_CTIME) != 0) {
		info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
		ncp_date_unix2dos(attr->ia_ctime.tv_sec,
			     &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.tv_sec,
				  &info.modifyTime, &info.modifyDate);
	}
	if ((attr->ia_valid & ATTR_ATIME) != 0) {
		__le16 dummy;
		info_mask |= (DM_LAST_ACCESS_DATE);
		ncp_date_unix2dos(attr->ia_atime.tv_sec,
				  &dummy, &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;
			} else
				goto out;
		}
#ifdef CONFIG_NCPFS_STRONG		
		if ((!result) && (info_mask & DM_ATTRIBUTES))
			NCP_FINFO(inode)->nwattr = info.attributes;
#endif
	}
	if (!result)
		result = inode_setattr(inode, attr);
out:
	unlock_kernel();
	return result;
}
Beispiel #21
0
static ssize_t
ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	size_t already_written = 0;
	off_t pos;
	size_t bufsize;
	int errno;
	void* bouncebuffer;

	DPRINTK("ncp_file_write: enter %s/%s\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);
	if ((ssize_t) count < 0)
		return -EINVAL;
	pos = *ppos;
	if (file->f_flags & O_APPEND) {
		pos = i_size_read(inode);
	}

	if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
		if (pos >= MAX_NON_LFS) {
			return -EFBIG;
		}
		if (count > MAX_NON_LFS - (u32)pos) {
			count = MAX_NON_LFS - (u32)pos;
		}
	}
	if (pos >= inode->i_sb->s_maxbytes) {
		if (count || pos > inode->i_sb->s_maxbytes) {
			return -EFBIG;
		}
	}
	if (pos + count > inode->i_sb->s_maxbytes) {
		count = inode->i_sb->s_maxbytes - pos;
	}
	
	if (!count)
		return 0;
	errno = ncp_make_open(inode, O_WRONLY);
	if (errno) {
		DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
		return errno;
	}
	bufsize = NCP_SERVER(inode)->buffer_size;

	already_written = 0;

	bouncebuffer = vmalloc(bufsize);
	if (!bouncebuffer) {
		errno = -EIO;	/* -ENOMEM */
		goto outrel;
	}
	while (already_written < count) {
		int written_this_time;
		size_t to_write = min_t(unsigned int,
				      bufsize - (pos % bufsize),
				      count - already_written);

		if (copy_from_user(bouncebuffer, buf, to_write)) {
			errno = -EFAULT;
			break;
		}
		if (ncp_write_kernel(NCP_SERVER(inode), 
		    NCP_FINFO(inode)->file_handle,
		    pos, to_write, bouncebuffer, &written_this_time) != 0) {
			errno = -EIO;
			break;
		}
		pos += written_this_time;
		buf += written_this_time;
		already_written += written_this_time;

		if (written_this_time != to_write) {
			break;
		}
	}
	vfree(bouncebuffer);

	file_update_time(file);

	*ppos = pos;

	if (pos > i_size_read(inode)) {
		mutex_lock(&inode->i_mutex);
		if (pos > i_size_read(inode))
			i_size_write(inode, pos);
		mutex_unlock(&inode->i_mutex);
	}
	DPRINTK("ncp_file_write: exit %s/%s\n",
		dentry->d_parent->d_name.name, dentry->d_name.name);
outrel:
	ncp_inode_close(inode);		
	return already_written ? already_written : errno;
}