Ejemplo n.º 1
0
static void
smb_put_inode(struct inode *inode)
{
        struct smb_dirent *finfo = SMB_FINFO(inode);

        if (finfo->opened != 0) {

                /* smb_proc_close wants mtime in finfo */
                finfo->mtime = inode->i_mtime;
                
                if (smb_proc_close(SMB_SERVER(inode), finfo)) {
                        /* We can't do anything but complain. */
                        printk("smb_put_inode: could not close\n");
                }
        }
        
        smb_free_inode_info(SMB_INOP(inode));

        if (S_ISDIR(inode->i_mode)) {
                DDPRINTK("smb_put_inode: put directory %ld\n",
                         inode->i_ino);
                smb_invalid_dir_cache(inode->i_ino);
        }                

	clear_inode(inode);
}
Ejemplo n.º 2
0
/* We will search the inode that belongs to this name, currently by a
   complete linear search through the inodes belonging to this
   filesystem. This has to be fixed. */
static struct smb_inode_info *
smb_find_dir_inode(struct inode *parent, const char *name, int len)
{
	struct smb_server *server = SMB_SERVER(parent);
	struct smb_inode_info *dir = SMB_INOP(parent);
	struct smb_inode_info *result = &(server->root);

	if (name == NULL)
	{
		return NULL;
	}
	if ((len == 1) && (name[0] == '.'))
	{
		return dir;
	}
	if ((len == 2) && (name[0] == '.') && (name[1] == '.'))
	{
		return dir->dir;
	}
	do
	{
		if (result->dir == dir)
		{
			if (compare_filename(server, name, len,
					     &(result->finfo)) == 0)
			{
				return result;
			}
		}
		result = result->next;
	}
	while (result != &(server->root));

	return NULL;
}
Ejemplo n.º 3
0
int
smb_ioctl(struct inode *inode, struct file *filp,
	  unsigned int cmd, unsigned long arg)
{
	struct smb_sb_info *server = SMB_SERVER(inode);
	struct smb_conn_opt opt;
	int result = -EINVAL;

	switch (cmd) {
	case SMB_IOC_GETMOUNTUID:
		result = put_user(NEW_TO_OLD_UID(server->mnt->mounted_uid),
				  (uid16_t *) arg);
		break;
	case SMB_IOC_GETMOUNTUID32:
		result = put_user(server->mnt->mounted_uid, (uid_t *) arg);
		break;

	case SMB_IOC_NEWCONN:
		/* require an argument == the mount data, else it is EINVAL */
		if (!arg)
			break;

		result = -EFAULT;
		if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
			result = smb_newconn(server, &opt);
		break;
	default:
	}

	return result;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
static struct inode *
smb_iget(struct inode *dir, struct smb_inode_info *new_inode_info)
{
	struct inode *inode;
	struct smb_inode_info *root;

	if ((dir == NULL) || (new_inode_info == NULL))
	{
		printk("smb_iget: parameter is NULL\n");
		return NULL;
	}
	new_inode_info->state = SMB_INODE_LOOKED_UP;
	new_inode_info->nused = 0;
	new_inode_info->dir = SMB_INOP(dir);

	SMB_INOP(dir)->nused += 1;

	/*
	 * We have to link the new inode_info into the doubly linked
	 * list of inode_infos to make a complete linear search possible.
	 */
	root = &(SMB_SERVER(dir)->root);

	new_inode_info->prev = root;
	new_inode_info->next = root->next;
	root->next->prev = new_inode_info;
	root->next = new_inode_info;

	if (!(inode = iget(dir->i_sb, smb_info_ino(new_inode_info))))
	{
		printk("smb_iget: iget failed!");
		/*
		 * If we blocked in iget(), another task may have referenced
		 * the info structure ... clean up with smb_free_inode_info.
		 */
		smb_free_inode_info(new_inode_info);
		return NULL;
	}

	return inode;
}
Ejemplo n.º 6
0
int
smb_ioctl(struct inode *inode, struct file *filp,
	  unsigned int cmd, unsigned long arg)
{
	struct smb_sb_info *server = SMB_SERVER(inode);
	int result = -EINVAL;

	switch (cmd)
	{
	case SMB_IOC_GETMOUNTUID:
		result = put_user(server->mnt->mounted_uid, (uid_t *) arg);
		break;

	case SMB_IOC_NEWCONN:
	{
		struct smb_conn_opt opt;

		if (arg)
		{
			result = -EFAULT;
			if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
				result = smb_newconn(server, &opt);
		}
		else
		{
#if 0
			/* obsolete option ... print a warning */
			printk("SMBFS: ioctl deprecated, please upgrade "
				"smbfs package\n");
#endif
			result = 0;
		}
		break;
	}
	default:
	}
	return result;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
static int
smb_readdir(struct inode *dir, struct file *filp,
	    void *dirent, filldir_t filldir)
{
	int result, i = 0;
	struct smb_dirent *entry = NULL;
	struct smb_server *server = SMB_SERVER(dir);

	DPRINTK("smb_readdir: filp->f_pos = %d\n", (int) filp->f_pos);
	DDPRINTK("smb_readdir: dir->i_ino = %ld, c_ino = %ld\n",
		 dir->i_ino, c_ino);

	if ((dir == NULL) || !S_ISDIR(dir->i_mode))
	{
		printk("smb_readdir: dir is NULL or not a directory\n");
		return -EBADF;
	}
	if (c_entry == NULL)
	{
		i = sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
		c_entry = (struct smb_dirent *) smb_vmalloc(i);
		if (c_entry == NULL)
		{
			printk("smb_readdir: no MEMORY for cache\n");
			return -ENOMEM;
		}
	}
	if (filp->f_pos == 0)
	{
		c_ino = 0;
		c_dev = 0;
		c_seen_eof = 0;

		if (filldir(dirent, ".", 1, filp->f_pos,
			    smb_info_ino(SMB_INOP(dir))) < 0)
		{
			return 0;
		}
		filp->f_pos += 1;
	}
	if (filp->f_pos == 1)
	{
		if (filldir(dirent, "..", 2, filp->f_pos,
			    smb_info_ino(SMB_INOP(dir)->dir)) < 0)
		{
			return 0;
		}
		filp->f_pos += 1;
	}
	entry = smb_search_in_cache(dir, filp->f_pos);

	if (entry == NULL)
	{
		if (c_seen_eof)
		{
			/* End of directory */
			return 0;
		}
		result = smb_refill_dir_cache(server, dir, filp->f_pos);
		if (result <= 0)
		{
			return result;
		}
		entry = c_entry;
	}
	while (entry < &(c_entry[c_size]))
	{
		/* We found it.  For getwd(), we have to return the
		   correct inode in d_ino if the inode is currently in
		   use. Otherwise the inode number does not
		   matter. (You can argue a lot about this..) */

		struct smb_inode_info *ino_info
		= smb_find_dir_inode(dir, entry->name, entry->len);

		ino_t ino = entry->f_ino;

		if (ino_info != NULL)
		{
			ino = smb_info_ino(ino_info);
		}
		DDPRINTK("smb_readdir: entry->name = %s\n", entry->name);
		DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);

		if (filldir(dirent, entry->name, strlen(entry->name),
			    entry->f_pos, ino) < 0)
		{
			break;
		}
		if ((dir->i_dev != c_dev) || (dir->i_ino != c_ino)
		    || (entry->f_pos != filp->f_pos))
		{
			/* Someone has destroyed the cache while we slept
			   in filldir */
			break;
		}
		filp->f_pos += 1;
		entry += 1;
	}
	return 0;
}
Ejemplo n.º 9
0
static void
smb_read_inode(struct inode *inode)
{
        /* Our task should be extremely simple here. We only have to
           look up the information somebody else (smb_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 smb_inode_info *inode_info
                = (struct smb_inode_info *)(inode->i_ino);

#if 1
        struct smb_inode_info *root = &(SMB_SERVER(inode)->root);
        struct smb_inode_info *check_info = root;

        do {
                if (inode_info == check_info) {
                        if (check_info->state == SMB_INODE_LOOKED_UP) {
                                DDPRINTK("smb_read_inode: found it!\n");
                                goto good;
                        }
                        else {
                                printk("smb_read_inode: "
                                       "state != SMB_INODE_LOOKED_UP\n");
                                return;
                        }
                }
                check_info = check_info->next;
        } while (check_info != root);

        /* Ok, now we're in trouble. The inode info is not there. What
           should we do now??? */
        printk("smb_read_inode: inode info not found\n");
        return;

 good:
#endif
        inode_info->state = SMB_INODE_VALID;

        SMB_INOP(inode) = inode_info;

        if (SMB_INOP(inode)->finfo.attr & aDIR)
                inode->i_mode = SMB_SERVER(inode)->m.dir_mode;
        else
                inode->i_mode = SMB_SERVER(inode)->m.file_mode;

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

        inode->i_nlink   = 1;
        inode->i_uid     = SMB_SERVER(inode)->m.uid;
        inode->i_gid     = SMB_SERVER(inode)->m.gid;
        inode->i_size    = SMB_INOP(inode)->finfo.size;
        inode->i_blksize = 1024;
        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 = SMB_INOP(inode)->finfo.mtime;
        inode->i_ctime = SMB_INOP(inode)->finfo.ctime;
        inode->i_atime = SMB_INOP(inode)->finfo.atime;

        if (S_ISREG(inode->i_mode))
                inode->i_op = &smb_file_inode_operations;
        else if (S_ISDIR(inode->i_mode))
                inode->i_op = &smb_dir_inode_operations;
        else
                inode->i_op = NULL;

}
Ejemplo n.º 10
0
/* DO MORE */
int
smb_notify_change(struct inode *inode, struct iattr *attr)
{
	int error = 0;

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

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

	if (((attr->ia_valid & ATTR_GID) && 
	     (attr->ia_uid != SMB_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;

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

                if ((error = smb_make_open(inode, O_WRONLY)) < 0)
                        goto fail;

                if ((error = smb_proc_trunc(SMB_SERVER(inode),
                                            SMB_FINFO(inode)->fileid,
                                            attr->ia_size)) < 0)
                        goto fail;

        }

        if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0) {

                struct smb_dirent finfo;

                finfo.attr  = 0;

                if ((attr->ia_valid & ATTR_CTIME) != 0)
                        finfo.ctime = attr->ia_ctime;
                else
                        finfo.ctime = inode->i_ctime;

                if ((attr->ia_valid & ATTR_MTIME) != 0)
                        finfo.mtime = attr->ia_mtime;
                else
                        finfo.mtime = inode->i_mtime;

                if ((attr->ia_valid & ATTR_ATIME) != 0)
                        finfo.atime = attr->ia_atime;
                else
                        finfo.atime = inode->i_atime;

                if ((error = smb_proc_setattr(SMB_SERVER(inode),
                                              inode, &finfo)) >= 0) {
                        inode->i_ctime = finfo.ctime;
                        inode->i_mtime = finfo.mtime;
                        inode->i_atime = finfo.atime;
                }
        }

 fail:
        smb_invalid_dir_cache((unsigned long)(SMB_INOP(inode)->dir));

	return error;
}
Ejemplo n.º 11
0
/*
 * Fill in the supplied page for mmap
 */
static unsigned long
smb_file_mmap_nopage(struct vm_area_struct *area,
		     unsigned long address, int no_share)
{
	struct inode *inode = area->vm_inode;
	unsigned long page;
	unsigned int clear;
	unsigned long tmp;
	int n;
	int i;
	int pos;

	page = __get_free_page(GFP_KERNEL);
	if (!page)
		return 0;
	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 */
	n = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 3 - 10;

	if (smb_make_open(inode, O_RDONLY) < 0)
	{
		clear = PAGE_SIZE;
	} else
	{

		for (i = 0; i < (PAGE_SIZE - clear); i += n)
		{
			int hunk, result;

			hunk = PAGE_SIZE - i;
			if (hunk > n)
				hunk = n;

			DDPRINTK("smb_file_mmap_nopage: reading\n");
			DDPRINTK("smb_file_mmap_nopage: pos = %d\n", pos);
			result = smb_proc_read(SMB_SERVER(inode),
					       SMB_FINFO(inode), pos, hunk,
					       (char *) (page + i), 0);
			DDPRINTK("smb_file_mmap_nopage: result= %d\n", result);
			if (result < 0)
				break;
			pos += result;
			if (result < n)
			{
				i += result;
				break;
			}
		}
	}

	tmp = page + PAGE_SIZE;
	while (clear--)
	{
		*(char *) --tmp = 0;
	}
	return page;
}