mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 20:32:22 +00:00
staging: remove smbfs
smbfs got moved to staging in 2.6.37, so we can finally remove it in the 2.6.39 merge window. All users should by now have migrated to cifs. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Cc: linux-cifs@vger.kernel.org Cc: Jeff Layton <jlayton@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
561c5cf923
commit
939cbe5af5
@ -149,8 +149,6 @@ source "drivers/staging/msm/Kconfig"
|
||||
|
||||
source "drivers/staging/lirc/Kconfig"
|
||||
|
||||
source "drivers/staging/smbfs/Kconfig"
|
||||
|
||||
source "drivers/staging/easycap/Kconfig"
|
||||
|
||||
source "drivers/staging/solo6x10/Kconfig"
|
||||
|
@ -34,7 +34,6 @@ obj-$(CONFIG_POHMELFS) += pohmelfs/
|
||||
obj-$(CONFIG_IDE_PHISON) += phison/
|
||||
obj-$(CONFIG_LINE6_USB) += line6/
|
||||
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
|
||||
obj-$(CONFIG_SMB_FS) += smbfs/
|
||||
obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/
|
||||
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
|
||||
obj-$(CONFIG_VT6655) += vt6655/
|
||||
|
@ -1,56 +0,0 @@
|
||||
config SMB_FS
|
||||
tristate "SMB file system support (OBSOLETE, please use CIFS)"
|
||||
depends on BKL # probably unfixable
|
||||
depends on INET
|
||||
select NLS
|
||||
help
|
||||
SMB (Server Message Block) is the protocol Windows for Workgroups
|
||||
(WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share
|
||||
files and printers over local networks. Saying Y here allows you to
|
||||
mount their file systems (often called "shares" in this context) and
|
||||
access them just like any other Unix directory. Currently, this
|
||||
works only if the Windows machines use TCP/IP as the underlying
|
||||
transport protocol, and not NetBEUI. For details, read
|
||||
<file:Documentation/filesystems/smbfs.txt> and the SMB-HOWTO,
|
||||
available from <http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
Note: if you just want your box to act as an SMB *server* and make
|
||||
files and printing services available to Windows clients (which need
|
||||
to have a TCP/IP stack), you don't need to say Y here; you can use
|
||||
the program SAMBA (available from <ftp://ftp.samba.org/pub/samba/>)
|
||||
for that.
|
||||
|
||||
General information about how to connect Linux, Windows machines and
|
||||
Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
|
||||
|
||||
To compile the SMB support as a module, choose M here:
|
||||
the module will be called smbfs. Most people say N, however.
|
||||
|
||||
config SMB_NLS_DEFAULT
|
||||
bool "Use a default NLS"
|
||||
depends on SMB_FS
|
||||
help
|
||||
Enabling this will make smbfs use nls translations by default. You
|
||||
need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls
|
||||
settings and you need to give the default nls for the SMB server as
|
||||
CONFIG_SMB_NLS_REMOTE.
|
||||
|
||||
The nls settings can be changed at mount time, if your smbmount
|
||||
supports that, using the codepage and iocharset parameters.
|
||||
|
||||
smbmount from samba 2.2.0 or later supports this.
|
||||
|
||||
config SMB_NLS_REMOTE
|
||||
string "Default Remote NLS Option"
|
||||
depends on SMB_NLS_DEFAULT
|
||||
default "cp437"
|
||||
help
|
||||
This setting allows you to specify a default value for which
|
||||
codepage the server uses. If this field is left blank no
|
||||
translations will be done by default. The local codepage/charset
|
||||
default to CONFIG_NLS_DEFAULT.
|
||||
|
||||
The nls settings can be changed at mount time, if your smbmount
|
||||
supports that, using the codepage and iocharset parameters.
|
||||
|
||||
smbmount from samba 2.2.0 or later supports this.
|
@ -1,18 +0,0 @@
|
||||
#
|
||||
# Makefile for the linux smb-filesystem routines.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SMB_FS) += smbfs.o
|
||||
|
||||
smbfs-y := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o \
|
||||
symlink.o smbiod.o request.o
|
||||
|
||||
# If you want debugging output, you may add these flags to the EXTRA_CFLAGS
|
||||
# SMBFS_PARANOIA should normally be enabled.
|
||||
|
||||
ccflags-y := -DSMBFS_PARANOIA
|
||||
#ccflags-y += -DSMBFS_DEBUG
|
||||
#ccflags-y += -DSMBFS_DEBUG_VERBOSE
|
||||
#ccflags-y += -DDEBUG_SMB_TIMESTAMP
|
||||
#ccflags-y += -Werror
|
||||
|
@ -1,8 +0,0 @@
|
||||
smbfs is on its way out of the kernel, it has been replaced
|
||||
by cifs several years ago.
|
||||
|
||||
The smbfs code uses the big kernel lock which
|
||||
is getting deprecated.
|
||||
|
||||
Users that find smbfs to work but not cifs should contact
|
||||
the CIFS developers on linux-cifs@vger.kernel.org.
|
@ -1,208 +0,0 @@
|
||||
/*
|
||||
* cache.c
|
||||
*
|
||||
* Copyright (C) 1997 by Bill Hawes
|
||||
*
|
||||
* Routines to support directory cacheing using the page cache.
|
||||
* This cache code is almost directly taken from ncpfs.
|
||||
*
|
||||
* Please add a note about your changes to smbfs in the ChangeLog file.
|
||||
*/
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/net.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
#include "smb_fs.h"
|
||||
#include "smb_debug.h"
|
||||
#include "proto.h"
|
||||
|
||||
/*
|
||||
* Force the next attempt to use the cache to be a timeout.
|
||||
* If we can't find the page that's fine, it will cause a refresh.
|
||||
*/
|
||||
void
|
||||
smb_invalid_dir_cache(struct inode * dir)
|
||||
{
|
||||
struct smb_sb_info *server = server_from_inode(dir);
|
||||
union smb_dir_cache *cache = NULL;
|
||||
struct page *page = NULL;
|
||||
|
||||
page = grab_cache_page(&dir->i_data, 0);
|
||||
if (!page)
|
||||
goto out;
|
||||
|
||||
if (!PageUptodate(page))
|
||||
goto out_unlock;
|
||||
|
||||
cache = kmap(page);
|
||||
cache->head.time = jiffies - SMB_MAX_AGE(server);
|
||||
|
||||
kunmap(page);
|
||||
SetPageUptodate(page);
|
||||
out_unlock:
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark all dentries for 'parent' as invalid, forcing them to be re-read
|
||||
*/
|
||||
void
|
||||
smb_invalidate_dircache_entries(struct dentry *parent)
|
||||
{
|
||||
struct smb_sb_info *server = server_from_dentry(parent);
|
||||
struct list_head *next;
|
||||
struct dentry *dentry;
|
||||
|
||||
spin_lock(&parent->d_lock);
|
||||
next = parent->d_subdirs.next;
|
||||
while (next != &parent->d_subdirs) {
|
||||
dentry = list_entry(next, struct dentry, d_u.d_child);
|
||||
dentry->d_fsdata = NULL;
|
||||
smb_age_dentry(server, dentry);
|
||||
next = next->next;
|
||||
}
|
||||
spin_unlock(&parent->d_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* dget, but require that fpos and parent matches what the dentry contains.
|
||||
* dentry is not known to be a valid pointer at entry.
|
||||
*/
|
||||
struct dentry *
|
||||
smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
|
||||
{
|
||||
struct dentry *dent = dentry;
|
||||
struct list_head *next;
|
||||
|
||||
if (d_validate(dent, parent)) {
|
||||
if (dent->d_name.len <= SMB_MAXNAMELEN &&
|
||||
(unsigned long)dent->d_fsdata == fpos) {
|
||||
if (!dent->d_inode) {
|
||||
dput(dent);
|
||||
dent = NULL;
|
||||
}
|
||||
return dent;
|
||||
}
|
||||
dput(dent);
|
||||
}
|
||||
|
||||
/* If a pointer is invalid, we search the dentry. */
|
||||
spin_lock(&parent->d_lock);
|
||||
next = parent->d_subdirs.next;
|
||||
while (next != &parent->d_subdirs) {
|
||||
dent = list_entry(next, struct dentry, d_u.d_child);
|
||||
if ((unsigned long)dent->d_fsdata == fpos) {
|
||||
if (dent->d_inode)
|
||||
dget(dent);
|
||||
else
|
||||
dent = NULL;
|
||||
goto out_unlock;
|
||||
}
|
||||
next = next->next;
|
||||
}
|
||||
dent = NULL;
|
||||
out_unlock:
|
||||
spin_unlock(&parent->d_lock);
|
||||
return dent;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create dentry/inode for this file and add it to the dircache.
|
||||
*/
|
||||
int
|
||||
smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
|
||||
struct smb_cache_control *ctrl, struct qstr *qname,
|
||||
struct smb_fattr *entry)
|
||||
{
|
||||
struct dentry *newdent, *dentry = filp->f_path.dentry;
|
||||
struct inode *newino, *inode = dentry->d_inode;
|
||||
struct smb_cache_control ctl = *ctrl;
|
||||
int valid = 0;
|
||||
int hashed = 0;
|
||||
ino_t ino = 0;
|
||||
|
||||
qname->hash = full_name_hash(qname->name, qname->len);
|
||||
|
||||
if (dentry->d_op && dentry->d_op->d_hash)
|
||||
if (dentry->d_op->d_hash(dentry, inode, qname) != 0)
|
||||
goto end_advance;
|
||||
|
||||
newdent = d_lookup(dentry, qname);
|
||||
|
||||
if (!newdent) {
|
||||
newdent = d_alloc(dentry, qname);
|
||||
if (!newdent)
|
||||
goto end_advance;
|
||||
} else {
|
||||
hashed = 1;
|
||||
/* dir i_mutex is locked because we're in readdir */
|
||||
dentry_update_name_case(newdent, qname);
|
||||
}
|
||||
|
||||
if (!newdent->d_inode) {
|
||||
smb_renew_times(newdent);
|
||||
entry->f_ino = iunique(inode->i_sb, 2);
|
||||
newino = smb_iget(inode->i_sb, entry);
|
||||
if (newino) {
|
||||
smb_new_dentry(newdent);
|
||||
d_instantiate(newdent, newino);
|
||||
if (!hashed)
|
||||
d_rehash(newdent);
|
||||
}
|
||||
} else
|
||||
smb_set_inode_attr(newdent->d_inode, entry);
|
||||
|
||||
if (newdent->d_inode) {
|
||||
ino = newdent->d_inode->i_ino;
|
||||
newdent->d_fsdata = (void *) ctl.fpos;
|
||||
smb_new_dentry(newdent);
|
||||
}
|
||||
|
||||
if (ctl.idx >= SMB_DIRCACHE_SIZE) {
|
||||
if (ctl.page) {
|
||||
kunmap(ctl.page);
|
||||
SetPageUptodate(ctl.page);
|
||||
unlock_page(ctl.page);
|
||||
page_cache_release(ctl.page);
|
||||
}
|
||||
ctl.cache = NULL;
|
||||
ctl.idx -= SMB_DIRCACHE_SIZE;
|
||||
ctl.ofs += 1;
|
||||
ctl.page = grab_cache_page(&inode->i_data, ctl.ofs);
|
||||
if (ctl.page)
|
||||
ctl.cache = kmap(ctl.page);
|
||||
}
|
||||
if (ctl.cache) {
|
||||
ctl.cache->dentry[ctl.idx] = newdent;
|
||||
valid = 1;
|
||||
}
|
||||
dput(newdent);
|
||||
|
||||
end_advance:
|
||||
if (!valid)
|
||||
ctl.valid = 0;
|
||||
if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
|
||||
if (!ino)
|
||||
ino = find_inode_number(dentry, qname);
|
||||
if (!ino)
|
||||
ino = iunique(inode->i_sb, 2);
|
||||
ctl.filled = filldir(dirent, qname->name, qname->len,
|
||||
filp->f_pos, ino, DT_UNKNOWN);
|
||||
if (!ctl.filled)
|
||||
filp->f_pos += 1;
|
||||
}
|
||||
ctl.fpos += 1;
|
||||
ctl.idx += 1;
|
||||
*ctrl = ctl;
|
||||
return (ctl.valid || !ctl.filled);
|
||||
}
|
@ -1,699 +0,0 @@
|
||||
/*
|
||||
* dir.c
|
||||
*
|
||||
* Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
* Please add a note about your changes to smbfs in the ChangeLog file.
|
||||
*/
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include "smb_fs.h"
|
||||
#include "smb_mount.h"
|
||||
#include "smbno.h"
|
||||
|
||||
#include "smb_debug.h"
|
||||
#include "proto.h"
|
||||
|
||||
static int smb_readdir(struct file *, void *, filldir_t);
|
||||
static int smb_dir_open(struct inode *, struct file *);
|
||||
|
||||
static struct dentry *smb_lookup(struct inode *, struct dentry *, struct nameidata *);
|
||||
static int smb_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
static int smb_mkdir(struct inode *, struct dentry *, int);
|
||||
static int smb_rmdir(struct inode *, struct dentry *);
|
||||
static int smb_unlink(struct inode *, struct dentry *);
|
||||
static int smb_rename(struct inode *, struct dentry *,
|
||||
struct inode *, struct dentry *);
|
||||
static int smb_make_node(struct inode *,struct dentry *,int,dev_t);
|
||||
static int smb_link(struct dentry *, struct inode *, struct dentry *);
|
||||
|
||||
const struct file_operations smb_dir_operations =
|
||||
{
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.readdir = smb_readdir,
|
||||
.unlocked_ioctl = smb_ioctl,
|
||||
.open = smb_dir_open,
|
||||
};
|
||||
|
||||
const struct inode_operations smb_dir_inode_operations =
|
||||
{
|
||||
.create = smb_create,
|
||||
.lookup = smb_lookup,
|
||||
.unlink = smb_unlink,
|
||||
.mkdir = smb_mkdir,
|
||||
.rmdir = smb_rmdir,
|
||||
.rename = smb_rename,
|
||||
.getattr = smb_getattr,
|
||||
.setattr = smb_notify_change,
|
||||
};
|
||||
|
||||
const struct inode_operations smb_dir_inode_operations_unix =
|
||||
{
|
||||
.create = smb_create,
|
||||
.lookup = smb_lookup,
|
||||
.unlink = smb_unlink,
|
||||
.mkdir = smb_mkdir,
|
||||
.rmdir = smb_rmdir,
|
||||
.rename = smb_rename,
|
||||
.getattr = smb_getattr,
|
||||
.setattr = smb_notify_change,
|
||||
.symlink = smb_symlink,
|
||||
.mknod = smb_make_node,
|
||||
.link = smb_link,
|
||||
};
|
||||
|
||||
/*
|
||||
* Read a directory, using filldir to fill the dirent memory.
|
||||
* smb_proc_readdir does the actual reading from the smb server.
|
||||
*
|
||||
* The cache code is almost directly taken from ncpfs
|
||||
*/
|
||||
static int
|
||||
smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
{
|
||||
struct dentry *dentry = filp->f_path.dentry;
|
||||
struct inode *dir = dentry->d_inode;
|
||||
struct smb_sb_info *server = server_from_dentry(dentry);
|
||||
union smb_dir_cache *cache = NULL;
|
||||
struct smb_cache_control ctl;
|
||||
struct page *page = NULL;
|
||||
int result;
|
||||
|
||||
ctl.page = NULL;
|
||||
ctl.cache = NULL;
|
||||
|
||||
VERBOSE("reading %s/%s, f_pos=%d\n",
|
||||
DENTRY_PATH(dentry), (int) filp->f_pos);
|
||||
|
||||
result = 0;
|
||||
|
||||
lock_kernel();
|
||||
|
||||
switch ((unsigned int) filp->f_pos) {
|
||||
case 0:
|
||||
if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
|
||||
goto out;
|
||||
filp->f_pos = 1;
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR) < 0)
|
||||
goto out;
|
||||
filp->f_pos = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure our inode is up-to-date.
|
||||
*/
|
||||
result = smb_revalidate_inode(dentry);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
|
||||
page = grab_cache_page(&dir->i_data, 0);
|
||||
if (!page)
|
||||
goto read_really;
|
||||
|
||||
ctl.cache = cache = kmap(page);
|
||||
ctl.head = cache->head;
|
||||
|
||||
if (!PageUptodate(page) || !ctl.head.eof) {
|
||||
VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",
|
||||
DENTRY_PATH(dentry), PageUptodate(page),ctl.head.eof);
|
||||
goto init_cache;
|
||||
}
|
||||
|
||||
if (filp->f_pos == 2) {
|
||||
if (jiffies - ctl.head.time >= SMB_MAX_AGE(server))
|
||||
goto init_cache;
|
||||
|
||||
/*
|
||||
* N.B. ncpfs checks mtime of dentry too here, we don't.
|
||||
* 1. common smb servers do not update mtime on dir changes
|
||||
* 2. it requires an extra smb request
|
||||
* (revalidate has the same timeout as ctl.head.time)
|
||||
*
|
||||
* Instead smbfs invalidates its own cache on local changes
|
||||
* and remote changes are not seen until timeout.
|
||||
*/
|
||||
}
|
||||
|
||||
if (filp->f_pos > ctl.head.end)
|
||||
goto finished;
|
||||
|
||||
ctl.fpos = filp->f_pos + (SMB_DIRCACHE_START - 2);
|
||||
ctl.ofs = ctl.fpos / SMB_DIRCACHE_SIZE;
|
||||
ctl.idx = ctl.fpos % SMB_DIRCACHE_SIZE;
|
||||
|
||||
for (;;) {
|
||||
if (ctl.ofs != 0) {
|
||||
ctl.page = find_lock_page(&dir->i_data, ctl.ofs);
|
||||
if (!ctl.page)
|
||||
goto invalid_cache;
|
||||
ctl.cache = kmap(ctl.page);
|
||||
if (!PageUptodate(ctl.page))
|
||||
goto invalid_cache;
|
||||
}
|
||||
while (ctl.idx < SMB_DIRCACHE_SIZE) {
|
||||
struct dentry *dent;
|
||||
int res;
|
||||
|
||||
dent = smb_dget_fpos(ctl.cache->dentry[ctl.idx],
|
||||
dentry, filp->f_pos);
|
||||
if (!dent)
|
||||
goto invalid_cache;
|
||||
|
||||
res = filldir(dirent, dent->d_name.name,
|
||||
dent->d_name.len, filp->f_pos,
|
||||
dent->d_inode->i_ino, DT_UNKNOWN);
|
||||
dput(dent);
|
||||
if (res)
|
||||
goto finished;
|
||||
filp->f_pos += 1;
|
||||
ctl.idx += 1;
|
||||
if (filp->f_pos > ctl.head.end)
|
||||
goto finished;
|
||||
}
|
||||
if (ctl.page) {
|
||||
kunmap(ctl.page);
|
||||
SetPageUptodate(ctl.page);
|
||||
unlock_page(ctl.page);
|
||||
page_cache_release(ctl.page);
|
||||
ctl.page = NULL;
|
||||
}
|
||||
ctl.idx = 0;
|
||||
ctl.ofs += 1;
|
||||
}
|
||||
invalid_cache:
|
||||
if (ctl.page) {
|
||||
kunmap(ctl.page);
|
||||
unlock_page(ctl.page);
|
||||
page_cache_release(ctl.page);
|
||||
ctl.page = NULL;
|
||||
}
|
||||
ctl.cache = cache;
|
||||
init_cache:
|
||||
smb_invalidate_dircache_entries(dentry);
|
||||
ctl.head.time = jiffies;
|
||||
ctl.head.eof = 0;
|
||||
ctl.fpos = 2;
|
||||
ctl.ofs = 0;
|
||||
ctl.idx = SMB_DIRCACHE_START;
|
||||
ctl.filled = 0;
|
||||
ctl.valid = 1;
|
||||
read_really:
|
||||
result = server->ops->readdir(filp, dirent, filldir, &ctl);
|
||||
if (result == -ERESTARTSYS && page)
|
||||
ClearPageUptodate(page);
|
||||
if (ctl.idx == -1)
|
||||
goto invalid_cache; /* retry */
|
||||
ctl.head.end = ctl.fpos - 1;
|
||||
ctl.head.eof = ctl.valid;
|
||||
finished:
|
||||
if (page) {
|
||||
cache->head = ctl.head;
|
||||
kunmap(page);
|
||||
if (result != -ERESTARTSYS)
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
if (ctl.page) {
|
||||
kunmap(ctl.page);
|
||||
SetPageUptodate(ctl.page);
|
||||
unlock_page(ctl.page);
|
||||
page_cache_release(ctl.page);
|
||||
}
|
||||
out:
|
||||
unlock_kernel();
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_dir_open(struct inode *dir, struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct smb_sb_info *server;
|
||||
int error = 0;
|
||||
|
||||
VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,
|
||||
file->f_path.dentry->d_name.name);
|
||||
|
||||
/*
|
||||
* Directory timestamps in the core protocol aren't updated
|
||||
* when a file is added, so we give them a very short TTL.
|
||||
*/
|
||||
lock_kernel();
|
||||
server = server_from_dentry(dentry);
|
||||
if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) {
|
||||
unsigned long age = jiffies - SMB_I(dir)->oldmtime;
|
||||
if (age > 2*HZ)
|
||||
smb_invalid_dir_cache(dir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: in order to allow the smbmount process to open the
|
||||
* mount point, we only revalidate if the connection is valid or
|
||||
* if the process is trying to access something other than the root.
|
||||
*/
|
||||
if (server->state == CONN_VALID || !IS_ROOT(dentry))
|
||||
error = smb_revalidate_inode(dentry);
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dentry operations routines
|
||||
*/
|
||||
static int smb_lookup_validate(struct dentry *, struct nameidata *);
|
||||
static int smb_hash_dentry(const struct dentry *, const struct inode *,
|
||||
struct qstr *);
|
||||
static int smb_compare_dentry(const struct dentry *,
|
||||
const struct inode *,
|
||||
const struct dentry *, const struct inode *,
|
||||
unsigned int, const char *, const struct qstr *);
|
||||
static int smb_delete_dentry(const struct dentry *);
|
||||
|
||||
const struct dentry_operations smbfs_dentry_operations =
|
||||
{
|
||||
.d_revalidate = smb_lookup_validate,
|
||||
.d_hash = smb_hash_dentry,
|
||||
.d_compare = smb_compare_dentry,
|
||||
.d_delete = smb_delete_dentry,
|
||||
};
|
||||
|
||||
const struct dentry_operations smbfs_dentry_operations_case =
|
||||
{
|
||||
.d_revalidate = smb_lookup_validate,
|
||||
.d_delete = smb_delete_dentry,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This is the callback when the dcache has a lookup hit.
|
||||
*/
|
||||
static int
|
||||
smb_lookup_validate(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct smb_sb_info *server;
|
||||
struct inode *inode;
|
||||
unsigned long age;
|
||||
int valid;
|
||||
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
server = server_from_dentry(dentry);
|
||||
inode = dentry->d_inode;
|
||||
age = jiffies - dentry->d_time;
|
||||
|
||||
/*
|
||||
* The default validation is based on dentry age:
|
||||
* we believe in dentries for a few seconds. (But each
|
||||
* successful server lookup renews the timestamp.)
|
||||
*/
|
||||
valid = (age <= SMB_MAX_AGE(server));
|
||||
#ifdef SMBFS_DEBUG_VERBOSE
|
||||
if (!valid)
|
||||
VERBOSE("%s/%s not valid, age=%lu\n",
|
||||
DENTRY_PATH(dentry), age);
|
||||
#endif
|
||||
|
||||
if (inode) {
|
||||
lock_kernel();
|
||||
if (is_bad_inode(inode)) {
|
||||
PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));
|
||||
valid = 0;
|
||||
} else if (!valid)
|
||||
valid = (smb_revalidate_inode(dentry) == 0);
|
||||
unlock_kernel();
|
||||
} else {
|
||||
/*
|
||||
* What should we do for negative dentries?
|
||||
*/
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_hash_dentry(const struct dentry *dir, const struct inode *inode,
|
||||
struct qstr *this)
|
||||
{
|
||||
unsigned long hash;
|
||||
int i;
|
||||
|
||||
hash = init_name_hash();
|
||||
for (i=0; i < this->len ; i++)
|
||||
hash = partial_name_hash(tolower(this->name[i]), hash);
|
||||
this->hash = end_name_hash(hash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_compare_dentry(const struct dentry *parent,
|
||||
const struct inode *pinode,
|
||||
const struct dentry *dentry, const struct inode *inode,
|
||||
unsigned int len, const char *str, const struct qstr *name)
|
||||
{
|
||||
int i, result = 1;
|
||||
|
||||
if (len != name->len)
|
||||
goto out;
|
||||
for (i=0; i < len; i++) {
|
||||
if (tolower(str[i]) != tolower(name->name[i]))
|
||||
goto out;
|
||||
}
|
||||
result = 0;
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the callback from dput() when d_count is going to 0.
|
||||
* We use this to unhash dentries with bad inodes.
|
||||
*/
|
||||
static int
|
||||
smb_delete_dentry(const struct dentry *dentry)
|
||||
{
|
||||
if (dentry->d_inode) {
|
||||
if (is_bad_inode(dentry->d_inode)) {
|
||||
PARANOIA("bad inode, unhashing %s/%s\n",
|
||||
DENTRY_PATH(dentry));
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* N.B. Unhash negative dentries? */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a new dentry
|
||||
*/
|
||||
void
|
||||
smb_new_dentry(struct dentry *dentry)
|
||||
{
|
||||
dentry->d_time = jiffies;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Whenever a lookup succeeds, we know the parent directories
|
||||
* are all valid, so we want to update the dentry timestamps.
|
||||
* N.B. Move this to dcache?
|
||||
*/
|
||||
void
|
||||
smb_renew_times(struct dentry * dentry)
|
||||
{
|
||||
dget(dentry);
|
||||
dentry->d_time = jiffies;
|
||||
|
||||
while (!IS_ROOT(dentry)) {
|
||||
struct dentry *parent = dget_parent(dentry);
|
||||
dput(dentry);
|
||||
dentry = parent;
|
||||
|
||||
dentry->d_time = jiffies;
|
||||
}
|
||||
dput(dentry);
|
||||
}
|
||||
|
||||
static struct dentry *
|
||||
smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct smb_fattr finfo;
|
||||
struct inode *inode;
|
||||
int error;
|
||||
|
||||
error = -ENAMETOOLONG;
|
||||
if (dentry->d_name.len > SMB_MAXNAMELEN)
|
||||
goto out;
|
||||
|
||||
/* Do not allow lookup of names with backslashes in */
|
||||
error = -EINVAL;
|
||||
if (memchr(dentry->d_name.name, '\\', dentry->d_name.len))
|
||||
goto out;
|
||||
|
||||
lock_kernel();
|
||||
error = smb_proc_getattr(dentry, &finfo);
|
||||
#ifdef SMBFS_PARANOIA
|
||||
if (error && error != -ENOENT)
|
||||
PARANOIA("find %s/%s failed, error=%d\n",
|
||||
DENTRY_PATH(dentry), error);
|
||||
#endif
|
||||
|
||||
inode = NULL;
|
||||
if (error == -ENOENT)
|
||||
goto add_entry;
|
||||
if (!error) {
|
||||
error = -EACCES;
|
||||
finfo.f_ino = iunique(dentry->d_sb, 2);
|
||||
inode = smb_iget(dir->i_sb, &finfo);
|
||||
if (inode) {
|
||||
add_entry:
|
||||
d_add(dentry, inode);
|
||||
smb_renew_times(dentry);
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
unlock_kernel();
|
||||
out:
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
/*
|
||||
* This code is common to all routines creating a new inode.
|
||||
*/
|
||||
static int
|
||||
smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
|
||||
{
|
||||
struct smb_sb_info *server = server_from_dentry(dentry);
|
||||
struct inode *inode;
|
||||
int error;
|
||||
struct smb_fattr fattr;
|
||||
|
||||
VERBOSE("file %s/%s, fileid=%u\n", DENTRY_PATH(dentry), fileid);
|
||||
|
||||
error = smb_proc_getattr(dentry, &fattr);
|
||||
if (error)
|
||||
goto out_close;
|
||||
|
||||
smb_renew_times(dentry);
|
||||
fattr.f_ino = iunique(dentry->d_sb, 2);
|
||||
inode = smb_iget(dentry->d_sb, &fattr);
|
||||
if (!inode)
|
||||
goto out_no_inode;
|
||||
|
||||
if (have_id) {
|
||||
struct smb_inode_info *ei = SMB_I(inode);
|
||||
ei->fileid = fileid;
|
||||
ei->access = SMB_O_RDWR;
|
||||
ei->open = server->generation;
|
||||
}
|
||||
d_instantiate(dentry, inode);
|
||||
out:
|
||||
return error;
|
||||
|
||||
out_no_inode:
|
||||
error = -EACCES;
|
||||
out_close:
|
||||
if (have_id) {
|
||||
PARANOIA("%s/%s failed, error=%d, closing %u\n",
|
||||
DENTRY_PATH(dentry), error, fileid);
|
||||
smb_close_fileid(dentry, fileid);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* N.B. How should the mode argument be used? */
|
||||
static int
|
||||
smb_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
struct nameidata *nd)
|
||||
{
|
||||
struct smb_sb_info *server = server_from_dentry(dentry);
|
||||
__u16 fileid;
|
||||
int error;
|
||||
struct iattr attr;
|
||||
|
||||
VERBOSE("creating %s/%s, mode=%d\n", DENTRY_PATH(dentry), mode);
|
||||
|
||||
lock_kernel();
|
||||
smb_invalid_dir_cache(dir);
|
||||
error = smb_proc_create(dentry, 0, get_seconds(), &fileid);
|
||||
if (!error) {
|
||||
if (server->opt.capabilities & SMB_CAP_UNIX) {
|
||||
/* Set attributes for new file */
|
||||
attr.ia_valid = ATTR_MODE;
|
||||
attr.ia_mode = mode;
|
||||
error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
|
||||
}
|
||||
error = smb_instantiate(dentry, fileid, 1);
|
||||
} else {
|
||||
PARANOIA("%s/%s failed, error=%d\n",
|
||||
DENTRY_PATH(dentry), error);
|
||||
}
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
/* N.B. How should the mode argument be used? */
|
||||
static int
|
||||
smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
{
|
||||
struct smb_sb_info *server = server_from_dentry(dentry);
|
||||
int error;
|
||||
struct iattr attr;
|
||||
|
||||
lock_kernel();
|
||||
smb_invalid_dir_cache(dir);
|
||||
error = smb_proc_mkdir(dentry);
|
||||
if (!error) {
|
||||
if (server->opt.capabilities & SMB_CAP_UNIX) {
|
||||
/* Set attributes for new directory */
|
||||
attr.ia_valid = ATTR_MODE;
|
||||
attr.ia_mode = mode;
|
||||
error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
|
||||
}
|
||||
error = smb_instantiate(dentry, 0, 0);
|
||||
}
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Close the directory if it's open.
|
||||
*/
|
||||
lock_kernel();
|
||||
smb_close(inode);
|
||||
|
||||
/*
|
||||
* Check that nobody else is using the directory..
|
||||
*/
|
||||
error = -EBUSY;
|
||||
if (!d_unhashed(dentry))
|
||||
goto out;
|
||||
|
||||
smb_invalid_dir_cache(dir);
|
||||
error = smb_proc_rmdir(dentry);
|
||||
|
||||
out:
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_unlink(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Close the file if it's open.
|
||||
*/
|
||||
lock_kernel();
|
||||
smb_close(dentry->d_inode);
|
||||
|
||||
smb_invalid_dir_cache(dir);
|
||||
error = smb_proc_unlink(dentry);
|
||||
if (!error)
|
||||
smb_renew_times(dentry);
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry)
|
||||
{
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Close any open files, and check whether to delete the
|
||||
* target before attempting the rename.
|
||||
*/
|
||||
lock_kernel();
|
||||
if (old_dentry->d_inode)
|
||||
smb_close(old_dentry->d_inode);
|
||||
if (new_dentry->d_inode) {
|
||||
smb_close(new_dentry->d_inode);
|
||||
error = smb_proc_unlink(new_dentry);
|
||||
if (error) {
|
||||
VERBOSE("unlink %s/%s, error=%d\n",
|
||||
DENTRY_PATH(new_dentry), error);
|
||||
goto out;
|
||||
}
|
||||
/* FIXME */
|
||||
d_delete(new_dentry);
|
||||
}
|
||||
|
||||
smb_invalid_dir_cache(old_dir);
|
||||
smb_invalid_dir_cache(new_dir);
|
||||
error = smb_proc_mv(old_dentry, new_dentry);
|
||||
if (!error) {
|
||||
smb_renew_times(old_dentry);
|
||||
smb_renew_times(new_dentry);
|
||||
}
|
||||
out:
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: samba servers won't let you create device nodes unless uid/gid
|
||||
* matches the connection credentials (and we don't know which those are ...)
|
||||
*/
|
||||
static int
|
||||
smb_make_node(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
{
|
||||
int error;
|
||||
struct iattr attr;
|
||||
|
||||
attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
|
||||
attr.ia_mode = mode;
|
||||
current_euid_egid(&attr.ia_uid, &attr.ia_gid);
|
||||
|
||||
if (!new_valid_dev(dev))
|
||||
return -EINVAL;
|
||||
|
||||
smb_invalid_dir_cache(dir);
|
||||
error = smb_proc_setattr_unix(dentry, &attr, MAJOR(dev), MINOR(dev));
|
||||
if (!error) {
|
||||
error = smb_instantiate(dentry, 0, 0);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* dentry = existing file
|
||||
* new_dentry = new file
|
||||
*/
|
||||
static int
|
||||
smb_link(struct dentry *dentry, struct inode *dir, struct dentry *new_dentry)
|
||||
{
|
||||
int error;
|
||||
|
||||
DEBUG1("smb_link old=%s/%s new=%s/%s\n",
|
||||
DENTRY_PATH(dentry), DENTRY_PATH(new_dentry));
|
||||
smb_invalid_dir_cache(dir);
|
||||
error = smb_proc_link(server_from_dentry(dentry), dentry, new_dentry);
|
||||
if (!error) {
|
||||
smb_renew_times(dentry);
|
||||
error = smb_instantiate(new_dentry, 0, 0);
|
||||
}
|
||||
return error;
|
||||
}
|
@ -1,456 +0,0 @@
|
||||
/*
|
||||
* file.c
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
* Please add a note about your changes to smbfs in the ChangeLog file.
|
||||
*/
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/aio.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include "smbno.h"
|
||||
#include "smb_fs.h"
|
||||
#include "smb_debug.h"
|
||||
#include "proto.h"
|
||||
|
||||
static int
|
||||
smb_fsync(struct file *file, int datasync)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct smb_sb_info *server = server_from_dentry(dentry);
|
||||
int result;
|
||||
|
||||
VERBOSE("sync file %s/%s\n", DENTRY_PATH(dentry));
|
||||
|
||||
/*
|
||||
* The VFS will writepage() all dirty pages for us, but we
|
||||
* should send a SMBflush to the server, letting it know that
|
||||
* we want things synchronized with actual storage.
|
||||
*
|
||||
* Note: this function requires all pages to have been written already
|
||||
* (should be ok with writepage_sync)
|
||||
*/
|
||||
result = smb_proc_flush(server, SMB_I(dentry->d_inode)->fileid);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a page synchronously.
|
||||
*/
|
||||
static int
|
||||
smb_readpage_sync(struct dentry *dentry, struct page *page)
|
||||
{
|
||||
char *buffer = kmap(page);
|
||||
loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
|
||||
struct smb_sb_info *server = server_from_dentry(dentry);
|
||||
unsigned int rsize = smb_get_rsize(server);
|
||||
int count = PAGE_SIZE;
|
||||
int result;
|
||||
|
||||
VERBOSE("file %s/%s, count=%d@%Ld, rsize=%d\n",
|
||||
DENTRY_PATH(dentry), count, offset, rsize);
|
||||
|
||||
result = smb_open(dentry, SMB_O_RDONLY);
|
||||
if (result < 0)
|
||||
goto io_error;
|
||||
|
||||
do {
|
||||
if (count < rsize)
|
||||
rsize = count;
|
||||
|
||||
result = server->ops->read(dentry->d_inode,offset,rsize,buffer);
|
||||
if (result < 0)
|
||||
goto io_error;
|
||||
|
||||
count -= result;
|
||||
offset += result;
|
||||
buffer += result;
|
||||
dentry->d_inode->i_atime =
|
||||
current_fs_time(dentry->d_inode->i_sb);
|
||||
if (result < rsize)
|
||||
break;
|
||||
} while (count);
|
||||
|
||||
memset(buffer, 0, count);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
result = 0;
|
||||
|
||||
io_error:
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are called with the page locked and we unlock it when done.
|
||||
*/
|
||||
static int
|
||||
smb_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
int error;
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
|
||||
page_cache_get(page);
|
||||
error = smb_readpage_sync(dentry, page);
|
||||
page_cache_release(page);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a page synchronously.
|
||||
* Offset is the data offset within the page.
|
||||
*/
|
||||
static int
|
||||
smb_writepage_sync(struct inode *inode, struct page *page,
|
||||
unsigned long pageoffset, unsigned int count)
|
||||
{
|
||||
loff_t offset;
|
||||
char *buffer = kmap(page) + pageoffset;
|
||||
struct smb_sb_info *server = server_from_inode(inode);
|
||||
unsigned int wsize = smb_get_wsize(server);
|
||||
int ret = 0;
|
||||
|
||||
offset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageoffset;
|
||||
VERBOSE("file ino=%ld, fileid=%d, count=%d@%Ld, wsize=%d\n",
|
||||
inode->i_ino, SMB_I(inode)->fileid, count, offset, wsize);
|
||||
|
||||
do {
|
||||
int write_ret;
|
||||
|
||||
if (count < wsize)
|
||||
wsize = count;
|
||||
|
||||
write_ret = server->ops->write(inode, offset, wsize, buffer);
|
||||
if (write_ret < 0) {
|
||||
PARANOIA("failed write, wsize=%d, write_ret=%d\n",
|
||||
wsize, write_ret);
|
||||
ret = write_ret;
|
||||
break;
|
||||
}
|
||||
/* N.B. what if result < wsize?? */
|
||||
#ifdef SMBFS_PARANOIA
|
||||
if (write_ret < wsize)
|
||||
PARANOIA("short write, wsize=%d, write_ret=%d\n",
|
||||
wsize, write_ret);
|
||||
#endif
|
||||
buffer += wsize;
|
||||
offset += wsize;
|
||||
count -= wsize;
|
||||
/*
|
||||
* Update the inode now rather than waiting for a refresh.
|
||||
*/
|
||||
inode->i_mtime = inode->i_atime = current_fs_time(inode->i_sb);
|
||||
SMB_I(inode)->flags |= SMB_F_LOCALWRITE;
|
||||
if (offset > inode->i_size)
|
||||
inode->i_size = offset;
|
||||
} while (count);
|
||||
|
||||
kunmap(page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a page to the server. This will be used for NFS swapping only
|
||||
* (for now), and we currently do this synchronously only.
|
||||
*
|
||||
* We are called with the page locked and we unlock it when done.
|
||||
*/
|
||||
static int
|
||||
smb_writepage(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
struct address_space *mapping = page->mapping;
|
||||
struct inode *inode;
|
||||
unsigned long end_index;
|
||||
unsigned offset = PAGE_CACHE_SIZE;
|
||||
int err;
|
||||
|
||||
BUG_ON(!mapping);
|
||||
inode = mapping->host;
|
||||
BUG_ON(!inode);
|
||||
|
||||
end_index = inode->i_size >> PAGE_CACHE_SHIFT;
|
||||
|
||||
/* easy case */
|
||||
if (page->index < end_index)
|
||||
goto do_it;
|
||||
/* things got complicated... */
|
||||
offset = inode->i_size & (PAGE_CACHE_SIZE-1);
|
||||
/* OK, are we completely out? */
|
||||
if (page->index >= end_index+1 || !offset)
|
||||
return 0; /* truncated - don't care */
|
||||
do_it:
|
||||
page_cache_get(page);
|
||||
err = smb_writepage_sync(inode, page, 0, offset);
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_updatepage(struct file *file, struct page *page, unsigned long offset,
|
||||
unsigned int count)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
|
||||
DEBUG1("(%s/%s %d@%lld)\n", DENTRY_PATH(dentry), count,
|
||||
((unsigned long long)page->index << PAGE_CACHE_SHIFT) + offset);
|
||||
|
||||
return smb_writepage_sync(dentry->d_inode, page, offset, count);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
smb_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
struct file * file = iocb->ki_filp;
|
||||
struct dentry * dentry = file->f_path.dentry;
|
||||
ssize_t status;
|
||||
|
||||
VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
|
||||
(unsigned long) iocb->ki_left, (unsigned long) pos);
|
||||
|
||||
status = smb_revalidate_inode(dentry);
|
||||
if (status) {
|
||||
PARANOIA("%s/%s validation failed, error=%Zd\n",
|
||||
DENTRY_PATH(dentry), status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
VERBOSE("before read, size=%ld, flags=%x, atime=%ld\n",
|
||||
(long)dentry->d_inode->i_size,
|
||||
dentry->d_inode->i_flags, dentry->d_inode->i_atime.tv_sec);
|
||||
|
||||
status = generic_file_aio_read(iocb, iov, nr_segs, pos);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_file_mmap(struct file * file, struct vm_area_struct * vma)
|
||||
{
|
||||
struct dentry * dentry = file->f_path.dentry;
|
||||
int status;
|
||||
|
||||
VERBOSE("file %s/%s, address %lu - %lu\n",
|
||||
DENTRY_PATH(dentry), vma->vm_start, vma->vm_end);
|
||||
|
||||
status = smb_revalidate_inode(dentry);
|
||||
if (status) {
|
||||
PARANOIA("%s/%s validation failed, error=%d\n",
|
||||
DENTRY_PATH(dentry), status);
|
||||
goto out;
|
||||
}
|
||||
status = generic_file_mmap(file, vma);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
smb_file_splice_read(struct file *file, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe, size_t count,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
ssize_t status;
|
||||
|
||||
VERBOSE("file %s/%s, pos=%Ld, count=%lu\n",
|
||||
DENTRY_PATH(dentry), *ppos, count);
|
||||
|
||||
status = smb_revalidate_inode(dentry);
|
||||
if (status) {
|
||||
PARANOIA("%s/%s validation failed, error=%Zd\n",
|
||||
DENTRY_PATH(dentry), status);
|
||||
goto out;
|
||||
}
|
||||
status = generic_file_splice_read(file, ppos, pipe, count, flags);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* This does the "real" work of the write. The generic routine has
|
||||
* allocated the page, locked it, done all the page alignment stuff
|
||||
* calculations etc. Now we should just copy the data from user
|
||||
* space and write it back to the real medium..
|
||||
*
|
||||
* If the writer ends up delaying the write, the writer needs to
|
||||
* increment the page use counts until he is done with the page.
|
||||
*/
|
||||
static int smb_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
|
||||
*pagep = grab_cache_page_write_begin(mapping, index, flags);
|
||||
if (!*pagep)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smb_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned copied,
|
||||
struct page *page, void *fsdata)
|
||||
{
|
||||
int status;
|
||||
unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
|
||||
|
||||
lock_kernel();
|
||||
status = smb_updatepage(file, page, offset, copied);
|
||||
unlock_kernel();
|
||||
|
||||
if (!status) {
|
||||
if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
|
||||
SetPageUptodate(page);
|
||||
status = copied;
|
||||
}
|
||||
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
const struct address_space_operations smb_file_aops = {
|
||||
.readpage = smb_readpage,
|
||||
.writepage = smb_writepage,
|
||||
.write_begin = smb_write_begin,
|
||||
.write_end = smb_write_end,
|
||||
};
|
||||
|
||||
/*
|
||||
* Write to a file (through the page cache).
|
||||
*/
|
||||
static ssize_t
|
||||
smb_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t pos)
|
||||
{
|
||||
struct file * file = iocb->ki_filp;
|
||||
struct dentry * dentry = file->f_path.dentry;
|
||||
ssize_t result;
|
||||
|
||||
VERBOSE("file %s/%s, count=%lu@%lu\n",
|
||||
DENTRY_PATH(dentry),
|
||||
(unsigned long) iocb->ki_left, (unsigned long) pos);
|
||||
|
||||
result = smb_revalidate_inode(dentry);
|
||||
if (result) {
|
||||
PARANOIA("%s/%s validation failed, error=%Zd\n",
|
||||
DENTRY_PATH(dentry), result);
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = smb_open(dentry, SMB_O_WRONLY);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
if (iocb->ki_left > 0) {
|
||||
result = generic_file_aio_write(iocb, iov, nr_segs, pos);
|
||||
VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
|
||||
(long) file->f_pos, (long) dentry->d_inode->i_size,
|
||||
dentry->d_inode->i_mtime.tv_sec,
|
||||
dentry->d_inode->i_atime.tv_sec);
|
||||
}
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_file_open(struct inode *inode, struct file * file)
|
||||
{
|
||||
int result;
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
int smb_mode = (file->f_mode & O_ACCMODE) - 1;
|
||||
|
||||
lock_kernel();
|
||||
result = smb_open(dentry, smb_mode);
|
||||
if (result)
|
||||
goto out;
|
||||
SMB_I(inode)->openers++;
|
||||
out:
|
||||
unlock_kernel();
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_file_release(struct inode *inode, struct file * file)
|
||||
{
|
||||
lock_kernel();
|
||||
if (!--SMB_I(inode)->openers) {
|
||||
/* We must flush any dirty pages now as we won't be able to
|
||||
write anything after close. mmap can trigger this.
|
||||
"openers" should perhaps include mmap'ers ... */
|
||||
filemap_write_and_wait(inode->i_mapping);
|
||||
smb_close(inode);
|
||||
}
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the required access is compatible with
|
||||
* an inode's permission. SMB doesn't recognize superuser
|
||||
* privileges, so we need our own check for this.
|
||||
*/
|
||||
static int
|
||||
smb_file_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
int mode = inode->i_mode;
|
||||
int error = 0;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
VERBOSE("mode=%x, mask=%x\n", mode, mask);
|
||||
|
||||
/* Look at user permissions */
|
||||
mode >>= 6;
|
||||
if (mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC))
|
||||
error = -EACCES;
|
||||
return error;
|
||||
}
|
||||
|
||||
static loff_t smb_remote_llseek(struct file *file, loff_t offset, int origin)
|
||||
{
|
||||
loff_t ret;
|
||||
lock_kernel();
|
||||
ret = generic_file_llseek_unlocked(file, offset, origin);
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct file_operations smb_file_operations =
|
||||
{
|
||||
.llseek = smb_remote_llseek,
|
||||
.read = do_sync_read,
|
||||
.aio_read = smb_file_aio_read,
|
||||
.write = do_sync_write,
|
||||
.aio_write = smb_file_aio_write,
|
||||
.unlocked_ioctl = smb_ioctl,
|
||||
.mmap = smb_file_mmap,
|
||||
.open = smb_file_open,
|
||||
.release = smb_file_release,
|
||||
.fsync = smb_fsync,
|
||||
.splice_read = smb_file_splice_read,
|
||||
};
|
||||
|
||||
const struct inode_operations smb_file_inode_operations =
|
||||
{
|
||||
.permission = smb_file_permission,
|
||||
.getattr = smb_getattr,
|
||||
.setattr = smb_notify_change,
|
||||
};
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* getopt.c
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/net.h>
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
/**
|
||||
* smb_getopt - option parser
|
||||
* @caller: name of the caller, for error messages
|
||||
* @options: the options string
|
||||
* @opts: an array of &struct option entries controlling parser operations
|
||||
* @optopt: output; will contain the current option
|
||||
* @optarg: output; will contain the value (if one exists)
|
||||
* @flag: output; may be NULL; should point to a long for or'ing flags
|
||||
* @value: output; may be NULL; will be overwritten with the integer value
|
||||
* of the current argument.
|
||||
*
|
||||
* Helper to parse options on the format used by mount ("a=b,c=d,e,f").
|
||||
* Returns opts->val if a matching entry in the 'opts' array is found,
|
||||
* 0 when no more tokens are found, -1 if an error is encountered.
|
||||
*/
|
||||
int smb_getopt(char *caller, char **options, struct option *opts,
|
||||
char **optopt, char **optarg, unsigned long *flag,
|
||||
unsigned long *value)
|
||||
{
|
||||
char *token;
|
||||
char *val;
|
||||
int i;
|
||||
|
||||
do {
|
||||
if ((token = strsep(options, ",")) == NULL)
|
||||
return 0;
|
||||
} while (*token == '\0');
|
||||
*optopt = token;
|
||||
|
||||
*optarg = NULL;
|
||||
if ((val = strchr (token, '=')) != NULL) {
|
||||
*val++ = 0;
|
||||
if (value)
|
||||
*value = simple_strtoul(val, NULL, 0);
|
||||
*optarg = val;
|
||||
}
|
||||
|
||||
for (i = 0; opts[i].name != NULL; i++) {
|
||||
if (!strcmp(opts[i].name, token)) {
|
||||
if (!opts[i].flag && (!val || !*val)) {
|
||||
printk("%s: the %s option requires an argument\n",
|
||||
caller, token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flag && opts[i].flag)
|
||||
*flag |= opts[i].flag;
|
||||
|
||||
return opts[i].val;
|
||||
}
|
||||
}
|
||||
printk("%s: Unrecognized mount option %s\n", caller, token);
|
||||
return -1;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#ifndef _LINUX_GETOPT_H
|
||||
#define _LINUX_GETOPT_H
|
||||
|
||||
struct option {
|
||||
const char *name;
|
||||
unsigned long flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
extern int smb_getopt(char *caller, char **options, struct option *opts,
|
||||
char **optopt, char **optarg, unsigned long *flag,
|
||||
unsigned long *value);
|
||||
|
||||
#endif /* _LINUX_GETOPT_H */
|
@ -1,854 +0,0 @@
|
||||
/*
|
||||
* inode.c
|
||||
*
|
||||
* Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
* Please add a note about your changes to smbfs in the ChangeLog file.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/highuid.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "smb_fs.h"
|
||||
#include "smbno.h"
|
||||
#include "smb_mount.h"
|
||||
#include "smb_debug.h"
|
||||
#include "getopt.h"
|
||||
#include "proto.h"
|
||||
|
||||
/* Always pick a default string */
|
||||
#ifdef CONFIG_SMB_NLS_REMOTE
|
||||
#define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE
|
||||
#else
|
||||
#define SMB_NLS_REMOTE ""
|
||||
#endif
|
||||
|
||||
#define SMB_TTL_DEFAULT 1000
|
||||
|
||||
static void smb_evict_inode(struct inode *);
|
||||
static void smb_put_super(struct super_block *);
|
||||
static int smb_statfs(struct dentry *, struct kstatfs *);
|
||||
static int smb_show_options(struct seq_file *, struct vfsmount *);
|
||||
|
||||
static struct kmem_cache *smb_inode_cachep;
|
||||
|
||||
static struct inode *smb_alloc_inode(struct super_block *sb)
|
||||
{
|
||||
struct smb_inode_info *ei;
|
||||
ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, GFP_KERNEL);
|
||||
if (!ei)
|
||||
return NULL;
|
||||
return &ei->vfs_inode;
|
||||
}
|
||||
|
||||
static void smb_i_callback(struct rcu_head *head)
|
||||
{
|
||||
struct inode *inode = container_of(head, struct inode, i_rcu);
|
||||
INIT_LIST_HEAD(&inode->i_dentry);
|
||||
kmem_cache_free(smb_inode_cachep, SMB_I(inode));
|
||||
}
|
||||
|
||||
static void smb_destroy_inode(struct inode *inode)
|
||||
{
|
||||
call_rcu(&inode->i_rcu, smb_i_callback);
|
||||
}
|
||||
|
||||
static void init_once(void *foo)
|
||||
{
|
||||
struct smb_inode_info *ei = (struct smb_inode_info *) foo;
|
||||
|
||||
inode_init_once(&ei->vfs_inode);
|
||||
}
|
||||
|
||||
static int init_inodecache(void)
|
||||
{
|
||||
smb_inode_cachep = kmem_cache_create("smb_inode_cache",
|
||||
sizeof(struct smb_inode_info),
|
||||
0, (SLAB_RECLAIM_ACCOUNT|
|
||||
SLAB_MEM_SPREAD),
|
||||
init_once);
|
||||
if (smb_inode_cachep == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void destroy_inodecache(void)
|
||||
{
|
||||
kmem_cache_destroy(smb_inode_cachep);
|
||||
}
|
||||
|
||||
static int smb_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
*flags |= MS_NODIRATIME;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct super_operations smb_sops =
|
||||
{
|
||||
.alloc_inode = smb_alloc_inode,
|
||||
.destroy_inode = smb_destroy_inode,
|
||||
.drop_inode = generic_delete_inode,
|
||||
.evict_inode = smb_evict_inode,
|
||||
.put_super = smb_put_super,
|
||||
.statfs = smb_statfs,
|
||||
.show_options = smb_show_options,
|
||||
.remount_fs = smb_remount,
|
||||
};
|
||||
|
||||
|
||||
/* We are always generating a new inode here */
|
||||
struct inode *
|
||||
smb_iget(struct super_block *sb, struct smb_fattr *fattr)
|
||||
{
|
||||
struct smb_sb_info *server = SMB_SB(sb);
|
||||
struct inode *result;
|
||||
|
||||
DEBUG1("smb_iget: %p\n", fattr);
|
||||
|
||||
result = new_inode(sb);
|
||||
if (!result)
|
||||
return result;
|
||||
result->i_ino = fattr->f_ino;
|
||||
SMB_I(result)->open = 0;
|
||||
SMB_I(result)->fileid = 0;
|
||||
SMB_I(result)->access = 0;
|
||||
SMB_I(result)->flags = 0;
|
||||
SMB_I(result)->closed = 0;
|
||||
SMB_I(result)->openers = 0;
|
||||
smb_set_inode_attr(result, fattr);
|
||||
if (S_ISREG(result->i_mode)) {
|
||||
result->i_op = &smb_file_inode_operations;
|
||||
result->i_fop = &smb_file_operations;
|
||||
result->i_data.a_ops = &smb_file_aops;
|
||||
} else if (S_ISDIR(result->i_mode)) {
|
||||
if (server->opt.capabilities & SMB_CAP_UNIX)
|
||||
result->i_op = &smb_dir_inode_operations_unix;
|
||||
else
|
||||
result->i_op = &smb_dir_inode_operations;
|
||||
result->i_fop = &smb_dir_operations;
|
||||
} else if (S_ISLNK(result->i_mode)) {
|
||||
result->i_op = &smb_link_inode_operations;
|
||||
} else {
|
||||
init_special_inode(result, result->i_mode, fattr->f_rdev);
|
||||
}
|
||||
insert_inode_hash(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the inode data to a smb_fattr structure.
|
||||
*/
|
||||
void
|
||||
smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
|
||||
{
|
||||
memset(fattr, 0, sizeof(struct smb_fattr));
|
||||
fattr->f_mode = inode->i_mode;
|
||||
fattr->f_nlink = inode->i_nlink;
|
||||
fattr->f_ino = inode->i_ino;
|
||||
fattr->f_uid = inode->i_uid;
|
||||
fattr->f_gid = inode->i_gid;
|
||||
fattr->f_size = inode->i_size;
|
||||
fattr->f_mtime = inode->i_mtime;
|
||||
fattr->f_ctime = inode->i_ctime;
|
||||
fattr->f_atime = inode->i_atime;
|
||||
fattr->f_blocks = inode->i_blocks;
|
||||
|
||||
fattr->attr = SMB_I(inode)->attr;
|
||||
/*
|
||||
* Keep the attributes in sync with the inode permissions.
|
||||
*/
|
||||
if (fattr->f_mode & S_IWUSR)
|
||||
fattr->attr &= ~aRONLY;
|
||||
else
|
||||
fattr->attr |= aRONLY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the inode, possibly causing it to invalidate its pages if mtime/size
|
||||
* is different from last time.
|
||||
*/
|
||||
void
|
||||
smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
|
||||
{
|
||||
struct smb_inode_info *ei = SMB_I(inode);
|
||||
|
||||
/*
|
||||
* A size change should have a different mtime, or same mtime
|
||||
* but different size.
|
||||
*/
|
||||
time_t last_time = inode->i_mtime.tv_sec;
|
||||
loff_t last_sz = inode->i_size;
|
||||
|
||||
inode->i_mode = fattr->f_mode;
|
||||
inode->i_nlink = fattr->f_nlink;
|
||||
inode->i_uid = fattr->f_uid;
|
||||
inode->i_gid = fattr->f_gid;
|
||||
inode->i_ctime = fattr->f_ctime;
|
||||
inode->i_blocks = fattr->f_blocks;
|
||||
inode->i_size = fattr->f_size;
|
||||
inode->i_mtime = fattr->f_mtime;
|
||||
inode->i_atime = fattr->f_atime;
|
||||
ei->attr = fattr->attr;
|
||||
|
||||
/*
|
||||
* Update the "last time refreshed" field for revalidation.
|
||||
*/
|
||||
ei->oldmtime = jiffies;
|
||||
|
||||
if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) {
|
||||
VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
|
||||
inode->i_ino,
|
||||
(long) last_time, (long) inode->i_mtime.tv_sec,
|
||||
(long) last_sz, (long) inode->i_size);
|
||||
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
invalidate_remote_inode(inode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called if the connection has gone bad ...
|
||||
* try to kill off all the current inodes.
|
||||
*/
|
||||
void
|
||||
smb_invalidate_inodes(struct smb_sb_info *server)
|
||||
{
|
||||
VERBOSE("\n");
|
||||
shrink_dcache_sb(SB_of(server));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called when we want to check whether the inode
|
||||
* has changed on the server. If it has changed, we must
|
||||
* invalidate our local caches.
|
||||
*/
|
||||
int
|
||||
smb_revalidate_inode(struct dentry *dentry)
|
||||
{
|
||||
struct smb_sb_info *s = server_from_dentry(dentry);
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error = 0;
|
||||
|
||||
DEBUG1("smb_revalidate_inode\n");
|
||||
lock_kernel();
|
||||
|
||||
/*
|
||||
* Check whether we've recently refreshed the inode.
|
||||
*/
|
||||
if (time_before(jiffies, SMB_I(inode)->oldmtime + SMB_MAX_AGE(s))) {
|
||||
VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n",
|
||||
inode->i_ino, jiffies, SMB_I(inode)->oldmtime);
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = smb_refresh_inode(dentry);
|
||||
out:
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called when i_nlink == 0 and i_count goes to 0.
|
||||
* All blocking cleanup operations need to go here to avoid races.
|
||||
*/
|
||||
static void
|
||||
smb_evict_inode(struct inode *ino)
|
||||
{
|
||||
DEBUG1("ino=%ld\n", ino->i_ino);
|
||||
truncate_inode_pages(&ino->i_data, 0);
|
||||
end_writeback(ino);
|
||||
lock_kernel();
|
||||
if (smb_close(ino))
|
||||
PARANOIA("could not close inode %ld\n", ino->i_ino);
|
||||
unlock_kernel();
|
||||
}
|
||||
|
||||
static struct option opts[] = {
|
||||
{ "version", 0, 'v' },
|
||||
{ "win95", SMB_MOUNT_WIN95, 1 },
|
||||
{ "oldattr", SMB_MOUNT_OLDATTR, 1 },
|
||||
{ "dirattr", SMB_MOUNT_DIRATTR, 1 },
|
||||
{ "case", SMB_MOUNT_CASE, 1 },
|
||||
{ "uid", 0, 'u' },
|
||||
{ "gid", 0, 'g' },
|
||||
{ "file_mode", 0, 'f' },
|
||||
{ "dir_mode", 0, 'd' },
|
||||
{ "iocharset", 0, 'i' },
|
||||
{ "codepage", 0, 'c' },
|
||||
{ "ttl", 0, 't' },
|
||||
{ NULL, 0, 0}
|
||||
};
|
||||
|
||||
static int
|
||||
parse_options(struct smb_mount_data_kernel *mnt, char *options)
|
||||
{
|
||||
int c;
|
||||
unsigned long flags;
|
||||
unsigned long value;
|
||||
char *optarg;
|
||||
char *optopt;
|
||||
|
||||
flags = 0;
|
||||
while ( (c = smb_getopt("smbfs", &options, opts,
|
||||
&optopt, &optarg, &flags, &value)) > 0) {
|
||||
|
||||
VERBOSE("'%s' -> '%s'\n", optopt, optarg ? optarg : "<none>");
|
||||
switch (c) {
|
||||
case 1:
|
||||
/* got a "flag" option */
|
||||
break;
|
||||
case 'v':
|
||||
if (value != SMB_MOUNT_VERSION) {
|
||||
printk ("smbfs: Bad mount version %ld, expected %d\n",
|
||||
value, SMB_MOUNT_VERSION);
|
||||
return 0;
|
||||
}
|
||||
mnt->version = value;
|
||||
break;
|
||||
case 'u':
|
||||
mnt->uid = value;
|
||||
flags |= SMB_MOUNT_UID;
|
||||
break;
|
||||
case 'g':
|
||||
mnt->gid = value;
|
||||
flags |= SMB_MOUNT_GID;
|
||||
break;
|
||||
case 'f':
|
||||
mnt->file_mode = (value & S_IRWXUGO) | S_IFREG;
|
||||
flags |= SMB_MOUNT_FMODE;
|
||||
break;
|
||||
case 'd':
|
||||
mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR;
|
||||
flags |= SMB_MOUNT_DMODE;
|
||||
break;
|
||||
case 'i':
|
||||
strlcpy(mnt->codepage.local_name, optarg,
|
||||
SMB_NLS_MAXNAMELEN);
|
||||
break;
|
||||
case 'c':
|
||||
strlcpy(mnt->codepage.remote_name, optarg,
|
||||
SMB_NLS_MAXNAMELEN);
|
||||
break;
|
||||
case 't':
|
||||
mnt->ttl = value;
|
||||
break;
|
||||
default:
|
||||
printk ("smbfs: Unrecognized mount option %s\n",
|
||||
optopt);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
mnt->flags = flags;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* smb_show_options() is for displaying mount options in /proc/mounts.
|
||||
* It tries to avoid showing settings that were not changed from their
|
||||
* defaults.
|
||||
*/
|
||||
static int
|
||||
smb_show_options(struct seq_file *s, struct vfsmount *m)
|
||||
{
|
||||
struct smb_mount_data_kernel *mnt = SMB_SB(m->mnt_sb)->mnt;
|
||||
int i;
|
||||
|
||||
for (i = 0; opts[i].name != NULL; i++)
|
||||
if (mnt->flags & opts[i].flag)
|
||||
seq_printf(s, ",%s", opts[i].name);
|
||||
|
||||
if (mnt->flags & SMB_MOUNT_UID)
|
||||
seq_printf(s, ",uid=%d", mnt->uid);
|
||||
if (mnt->flags & SMB_MOUNT_GID)
|
||||
seq_printf(s, ",gid=%d", mnt->gid);
|
||||
if (mnt->mounted_uid != 0)
|
||||
seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid);
|
||||
|
||||
/*
|
||||
* Defaults for file_mode and dir_mode are unknown to us; they
|
||||
* depend on the current umask of the user doing the mount.
|
||||
*/
|
||||
if (mnt->flags & SMB_MOUNT_FMODE)
|
||||
seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO);
|
||||
if (mnt->flags & SMB_MOUNT_DMODE)
|
||||
seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO);
|
||||
|
||||
if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT))
|
||||
seq_printf(s, ",iocharset=%s", mnt->codepage.local_name);
|
||||
if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE))
|
||||
seq_printf(s, ",codepage=%s", mnt->codepage.remote_name);
|
||||
|
||||
if (mnt->ttl != SMB_TTL_DEFAULT)
|
||||
seq_printf(s, ",ttl=%d", mnt->ttl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
smb_unload_nls(struct smb_sb_info *server)
|
||||
{
|
||||
unload_nls(server->remote_nls);
|
||||
unload_nls(server->local_nls);
|
||||
}
|
||||
|
||||
static void
|
||||
smb_put_super(struct super_block *sb)
|
||||
{
|
||||
struct smb_sb_info *server = SMB_SB(sb);
|
||||
|
||||
lock_kernel();
|
||||
|
||||
smb_lock_server(server);
|
||||
server->state = CONN_INVALID;
|
||||
smbiod_unregister_server(server);
|
||||
|
||||
smb_close_socket(server);
|
||||
|
||||
if (server->conn_pid)
|
||||
kill_pid(server->conn_pid, SIGTERM, 1);
|
||||
|
||||
bdi_destroy(&server->bdi);
|
||||
kfree(server->ops);
|
||||
smb_unload_nls(server);
|
||||
sb->s_fs_info = NULL;
|
||||
smb_unlock_server(server);
|
||||
put_pid(server->conn_pid);
|
||||
kfree(server);
|
||||
|
||||
unlock_kernel();
|
||||
}
|
||||
|
||||
static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
|
||||
{
|
||||
struct smb_sb_info *server;
|
||||
struct smb_mount_data_kernel *mnt;
|
||||
struct smb_mount_data *oldmnt;
|
||||
struct inode *root_inode;
|
||||
struct smb_fattr root;
|
||||
int ver;
|
||||
void *mem;
|
||||
static int warn_count;
|
||||
|
||||
lock_kernel();
|
||||
|
||||
if (warn_count < 5) {
|
||||
warn_count++;
|
||||
printk(KERN_EMERG "smbfs is deprecated and will be removed"
|
||||
" from the 2.6.37 kernel. Please migrate to cifs\n");
|
||||
}
|
||||
|
||||
if (!raw_data)
|
||||
goto out_no_data;
|
||||
|
||||
oldmnt = (struct smb_mount_data *) raw_data;
|
||||
ver = oldmnt->version;
|
||||
if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII)
|
||||
goto out_wrong_data;
|
||||
|
||||
sb->s_flags |= MS_NODIRATIME;
|
||||
sb->s_blocksize = 1024; /* Eh... Is this correct? */
|
||||
sb->s_blocksize_bits = 10;
|
||||
sb->s_magic = SMB_SUPER_MAGIC;
|
||||
sb->s_op = &smb_sops;
|
||||
sb->s_time_gran = 100;
|
||||
|
||||
server = kzalloc(sizeof(struct smb_sb_info), GFP_KERNEL);
|
||||
if (!server)
|
||||
goto out_no_server;
|
||||
sb->s_fs_info = server;
|
||||
|
||||
if (bdi_setup_and_register(&server->bdi, "smbfs", BDI_CAP_MAP_COPY))
|
||||
goto out_bdi;
|
||||
|
||||
sb->s_bdi = &server->bdi;
|
||||
|
||||
server->super_block = sb;
|
||||
server->mnt = NULL;
|
||||
server->sock_file = NULL;
|
||||
init_waitqueue_head(&server->conn_wq);
|
||||
sema_init(&server->sem, 1);
|
||||
INIT_LIST_HEAD(&server->entry);
|
||||
INIT_LIST_HEAD(&server->xmitq);
|
||||
INIT_LIST_HEAD(&server->recvq);
|
||||
server->conn_error = 0;
|
||||
server->conn_pid = NULL;
|
||||
server->state = CONN_INVALID; /* no connection yet */
|
||||
server->generation = 0;
|
||||
|
||||
/* Allocate the global temp buffer and some superblock helper structs */
|
||||
/* FIXME: move these to the smb_sb_info struct */
|
||||
VERBOSE("alloc chunk = %lu\n", sizeof(struct smb_ops) +
|
||||
sizeof(struct smb_mount_data_kernel));
|
||||
mem = kmalloc(sizeof(struct smb_ops) +
|
||||
sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
|
||||
if (!mem)
|
||||
goto out_no_mem;
|
||||
|
||||
server->ops = mem;
|
||||
smb_install_null_ops(server->ops);
|
||||
server->mnt = mem + sizeof(struct smb_ops);
|
||||
|
||||
/* Setup NLS stuff */
|
||||
server->remote_nls = NULL;
|
||||
server->local_nls = NULL;
|
||||
|
||||
mnt = server->mnt;
|
||||
|
||||
memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
|
||||
strlcpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
|
||||
SMB_NLS_MAXNAMELEN);
|
||||
strlcpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
|
||||
SMB_NLS_MAXNAMELEN);
|
||||
|
||||
mnt->ttl = SMB_TTL_DEFAULT;
|
||||
if (ver == SMB_MOUNT_OLDVERSION) {
|
||||
mnt->version = oldmnt->version;
|
||||
|
||||
SET_UID(mnt->uid, oldmnt->uid);
|
||||
SET_GID(mnt->gid, oldmnt->gid);
|
||||
|
||||
mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG;
|
||||
mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR;
|
||||
|
||||
mnt->flags = (oldmnt->file_mode >> 9) | SMB_MOUNT_UID |
|
||||
SMB_MOUNT_GID | SMB_MOUNT_FMODE | SMB_MOUNT_DMODE;
|
||||
} else {
|
||||
mnt->file_mode = S_IRWXU | S_IRGRP | S_IXGRP |
|
||||
S_IROTH | S_IXOTH | S_IFREG;
|
||||
mnt->dir_mode = S_IRWXU | S_IRGRP | S_IXGRP |
|
||||
S_IROTH | S_IXOTH | S_IFDIR;
|
||||
if (parse_options(mnt, raw_data))
|
||||
goto out_bad_option;
|
||||
}
|
||||
mnt->mounted_uid = current_uid();
|
||||
smb_setcodepage(server, &mnt->codepage);
|
||||
|
||||
/*
|
||||
* Display the enabled options
|
||||
* Note: smb_proc_getattr uses these in 2.4 (but was changed in 2.2)
|
||||
*/
|
||||
if (mnt->flags & SMB_MOUNT_OLDATTR)
|
||||
printk("SMBFS: Using core getattr (Win 95 speedup)\n");
|
||||
else if (mnt->flags & SMB_MOUNT_DIRATTR)
|
||||
printk("SMBFS: Using dir ff getattr\n");
|
||||
|
||||
if (smbiod_register_server(server) < 0) {
|
||||
printk(KERN_ERR "smbfs: failed to start smbiod\n");
|
||||
goto out_no_smbiod;
|
||||
}
|
||||
if (server->mnt->flags & SMB_MOUNT_CASE)
|
||||
sb->s_d_op = &smbfs_dentry_operations_case;
|
||||
else
|
||||
sb->s_d_op = &smbfs_dentry_operations;
|
||||
|
||||
/*
|
||||
* Keep the super block locked while we get the root inode.
|
||||
*/
|
||||
smb_init_root_dirent(server, &root, sb);
|
||||
root_inode = smb_iget(sb, &root);
|
||||
if (!root_inode)
|
||||
goto out_no_root;
|
||||
|
||||
sb->s_root = d_alloc_root(root_inode);
|
||||
if (!sb->s_root)
|
||||
goto out_no_root;
|
||||
|
||||
smb_new_dentry(sb->s_root);
|
||||
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
|
||||
out_no_root:
|
||||
iput(root_inode);
|
||||
out_no_smbiod:
|
||||
smb_unload_nls(server);
|
||||
out_bad_option:
|
||||
kfree(mem);
|
||||
out_no_mem:
|
||||
bdi_destroy(&server->bdi);
|
||||
out_bdi:
|
||||
if (!server->mnt)
|
||||
printk(KERN_ERR "smb_fill_super: allocation failure\n");
|
||||
sb->s_fs_info = NULL;
|
||||
kfree(server);
|
||||
goto out_fail;
|
||||
out_wrong_data:
|
||||
printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver);
|
||||
goto out_fail;
|
||||
out_no_data:
|
||||
printk(KERN_ERR "smb_fill_super: missing data argument\n");
|
||||
out_fail:
|
||||
unlock_kernel();
|
||||
return -EINVAL;
|
||||
out_no_server:
|
||||
printk(KERN_ERR "smb_fill_super: cannot allocate struct smb_sb_info\n");
|
||||
unlock_kernel();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int
|
||||
smb_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
int result;
|
||||
|
||||
lock_kernel();
|
||||
|
||||
result = smb_proc_dskattr(dentry, buf);
|
||||
|
||||
unlock_kernel();
|
||||
|
||||
buf->f_type = SMB_SUPER_MAGIC;
|
||||
buf->f_namelen = SMB_MAXPATHLEN;
|
||||
return result;
|
||||
}
|
||||
|
||||
int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
||||
{
|
||||
int err = smb_revalidate_inode(dentry);
|
||||
if (!err)
|
||||
generic_fillattr(dentry->d_inode, stat);
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
smb_notify_change(struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct smb_sb_info *server = server_from_dentry(dentry);
|
||||
unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO);
|
||||
int error, changed, refresh = 0;
|
||||
struct smb_fattr fattr;
|
||||
|
||||
lock_kernel();
|
||||
|
||||
error = smb_revalidate_inode(dentry);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if ((error = inode_change_ok(inode, attr)) < 0)
|
||||
goto out;
|
||||
|
||||
error = -EPERM;
|
||||
if ((attr->ia_valid & ATTR_UID) && (attr->ia_uid != server->mnt->uid))
|
||||
goto out;
|
||||
|
||||
if ((attr->ia_valid & ATTR_GID) && (attr->ia_uid != server->mnt->gid))
|
||||
goto out;
|
||||
|
||||
if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask))
|
||||
goto out;
|
||||
|
||||
if ((attr->ia_valid & ATTR_SIZE) != 0) {
|
||||
VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n",
|
||||
DENTRY_PATH(dentry),
|
||||
(long) inode->i_size, (long) attr->ia_size);
|
||||
|
||||
filemap_write_and_wait(inode->i_mapping);
|
||||
|
||||
error = smb_open(dentry, O_WRONLY);
|
||||
if (error)
|
||||
goto out;
|
||||
error = server->ops->truncate(inode, attr->ia_size);
|
||||
if (error)
|
||||
goto out;
|
||||
truncate_setsize(inode, attr->ia_size);
|
||||
refresh = 1;
|
||||
}
|
||||
|
||||
if (server->opt.capabilities & SMB_CAP_UNIX) {
|
||||
/* For now we don't want to set the size with setattr_unix */
|
||||
attr->ia_valid &= ~ATTR_SIZE;
|
||||
/* FIXME: only call if we actually want to set something? */
|
||||
error = smb_proc_setattr_unix(dentry, attr, 0, 0);
|
||||
if (!error)
|
||||
refresh = 1;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the fattr and check for changed fields.
|
||||
* Note: CTIME under SMB is creation time rather than
|
||||
* change time, so we don't attempt to change it.
|
||||
*/
|
||||
smb_get_inode_attr(inode, &fattr);
|
||||
|
||||
changed = 0;
|
||||
if ((attr->ia_valid & ATTR_MTIME) != 0) {
|
||||
fattr.f_mtime = attr->ia_mtime;
|
||||
changed = 1;
|
||||
}
|
||||
if ((attr->ia_valid & ATTR_ATIME) != 0) {
|
||||
fattr.f_atime = attr->ia_atime;
|
||||
/* Earlier protocols don't have an access time */
|
||||
if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
|
||||
changed = 1;
|
||||
}
|
||||
if (changed) {
|
||||
error = smb_proc_settime(dentry, &fattr);
|
||||
if (error)
|
||||
goto out;
|
||||
refresh = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for mode changes ... we're extremely limited in
|
||||
* what can be set for SMB servers: just the read-only bit.
|
||||
*/
|
||||
if ((attr->ia_valid & ATTR_MODE) != 0) {
|
||||
VERBOSE("%s/%s mode change, old=%x, new=%x\n",
|
||||
DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode);
|
||||
changed = 0;
|
||||
if (attr->ia_mode & S_IWUSR) {
|
||||
if (fattr.attr & aRONLY) {
|
||||
fattr.attr &= ~aRONLY;
|
||||
changed = 1;
|
||||
}
|
||||
} else {
|
||||
if (!(fattr.attr & aRONLY)) {
|
||||
fattr.attr |= aRONLY;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
error = smb_proc_setattr(dentry, &fattr);
|
||||
if (error)
|
||||
goto out;
|
||||
refresh = 1;
|
||||
}
|
||||
}
|
||||
error = 0;
|
||||
|
||||
out:
|
||||
if (refresh)
|
||||
smb_refresh_inode(dentry);
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct dentry *smb_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data)
|
||||
{
|
||||
return mount_nodev(fs_type, flags, data, smb_fill_super);
|
||||
}
|
||||
|
||||
static struct file_system_type smb_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "smbfs",
|
||||
.mount = smb_mount,
|
||||
.kill_sb = kill_anon_super,
|
||||
.fs_flags = FS_BINARY_MOUNTDATA,
|
||||
};
|
||||
|
||||
static int __init init_smb_fs(void)
|
||||
{
|
||||
int err;
|
||||
DEBUG1("registering ...\n");
|
||||
|
||||
err = init_inodecache();
|
||||
if (err)
|
||||
goto out_inode;
|
||||
err = smb_init_request_cache();
|
||||
if (err)
|
||||
goto out_request;
|
||||
err = register_filesystem(&smb_fs_type);
|
||||
if (err)
|
||||
goto out;
|
||||
return 0;
|
||||
out:
|
||||
smb_destroy_request_cache();
|
||||
out_request:
|
||||
destroy_inodecache();
|
||||
out_inode:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit exit_smb_fs(void)
|
||||
{
|
||||
DEBUG1("unregistering ...\n");
|
||||
unregister_filesystem(&smb_fs_type);
|
||||
smb_destroy_request_cache();
|
||||
destroy_inodecache();
|
||||
}
|
||||
|
||||
module_init(init_smb_fs)
|
||||
module_exit(exit_smb_fs)
|
||||
MODULE_LICENSE("GPL");
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* ioctl.c
|
||||
*
|
||||
* Copyright (C) 1995, 1996 by Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
* Please add a note about your changes to smbfs in the ChangeLog file.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/highuid.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/net.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "smb_fs.h"
|
||||
#include "smb_mount.h"
|
||||
#include "proto.h"
|
||||
|
||||
long
|
||||
smb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct smb_sb_info *server = server_from_inode(filp->f_path.dentry->d_inode);
|
||||
struct smb_conn_opt opt;
|
||||
int result = -EINVAL;
|
||||
|
||||
lock_kernel();
|
||||
switch (cmd) {
|
||||
uid16_t uid16;
|
||||
uid_t uid32;
|
||||
case SMB_IOC_GETMOUNTUID:
|
||||
SET_UID(uid16, server->mnt->mounted_uid);
|
||||
result = put_user(uid16, (uid16_t __user *) arg);
|
||||
break;
|
||||
case SMB_IOC_GETMOUNTUID32:
|
||||
SET_UID(uid32, server->mnt->mounted_uid);
|
||||
result = put_user(uid32, (uid_t __user *) arg);
|
||||
break;
|
||||
|
||||
case SMB_IOC_NEWCONN:
|
||||
/* arg is smb_conn_opt, or NULL if no connection was made */
|
||||
if (!arg) {
|
||||
result = 0;
|
||||
smb_lock_server(server);
|
||||
server->state = CONN_RETRIED;
|
||||
printk(KERN_ERR "Connection attempt failed! [%d]\n",
|
||||
server->conn_error);
|
||||
smbiod_flush(server);
|
||||
smb_unlock_server(server);
|
||||
break;
|
||||
}
|
||||
|
||||
result = -EFAULT;
|
||||
if (!copy_from_user(&opt, (void __user *)arg, sizeof(opt)))
|
||||
result = smb_newconn(server, &opt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
unlock_kernel();
|
||||
|
||||
return result;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Autogenerated with cproto on: Sat Sep 13 17:18:51 CEST 2003
|
||||
*/
|
||||
|
||||
struct smb_request;
|
||||
struct sock;
|
||||
struct statfs;
|
||||
|
||||
/* proc.c */
|
||||
extern int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp);
|
||||
extern __u32 smb_len(__u8 *p);
|
||||
extern int smb_get_rsize(struct smb_sb_info *server);
|
||||
extern int smb_get_wsize(struct smb_sb_info *server);
|
||||
extern int smb_errno(struct smb_request *req);
|
||||
extern int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt);
|
||||
extern __u8 *smb_setup_header(struct smb_request *req, __u8 command, __u16 wct, __u16 bcc);
|
||||
extern int smb_open(struct dentry *dentry, int wish);
|
||||
extern int smb_close(struct inode *ino);
|
||||
extern int smb_close_fileid(struct dentry *dentry, __u16 fileid);
|
||||
extern int smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid);
|
||||
extern int smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry);
|
||||
extern int smb_proc_mkdir(struct dentry *dentry);
|
||||
extern int smb_proc_rmdir(struct dentry *dentry);
|
||||
extern int smb_proc_unlink(struct dentry *dentry);
|
||||
extern int smb_proc_flush(struct smb_sb_info *server, __u16 fileid);
|
||||
extern void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr,
|
||||
struct super_block *sb);
|
||||
extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr);
|
||||
extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr);
|
||||
extern int smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, unsigned int major, unsigned int minor);
|
||||
extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr);
|
||||
extern int smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr);
|
||||
extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *d, char *buffer, int len);
|
||||
extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, const char *oldpath);
|
||||
extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry);
|
||||
extern void smb_install_null_ops(struct smb_ops *ops);
|
||||
/* dir.c */
|
||||
extern const struct file_operations smb_dir_operations;
|
||||
extern const struct inode_operations smb_dir_inode_operations;
|
||||
extern const struct inode_operations smb_dir_inode_operations_unix;
|
||||
extern const struct dentry_operations smbfs_dentry_operations_case;
|
||||
extern const struct dentry_operations smbfs_dentry_operations;
|
||||
extern void smb_new_dentry(struct dentry *dentry);
|
||||
extern void smb_renew_times(struct dentry *dentry);
|
||||
/* cache.c */
|
||||
extern void smb_invalid_dir_cache(struct inode *dir);
|
||||
extern void smb_invalidate_dircache_entries(struct dentry *parent);
|
||||
extern struct dentry *smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos);
|
||||
extern int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctrl, struct qstr *qname, struct smb_fattr *entry);
|
||||
/* sock.c */
|
||||
extern void smb_data_ready(struct sock *sk, int len);
|
||||
extern int smb_valid_socket(struct inode *inode);
|
||||
extern void smb_close_socket(struct smb_sb_info *server);
|
||||
extern int smb_recv_available(struct smb_sb_info *server);
|
||||
extern int smb_receive_header(struct smb_sb_info *server);
|
||||
extern int smb_receive_drop(struct smb_sb_info *server);
|
||||
extern int smb_receive(struct smb_sb_info *server, struct smb_request *req);
|
||||
extern int smb_send_request(struct smb_request *req);
|
||||
/* inode.c */
|
||||
extern struct inode *smb_iget(struct super_block *sb, struct smb_fattr *fattr);
|
||||
extern void smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr);
|
||||
extern void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr);
|
||||
extern void smb_invalidate_inodes(struct smb_sb_info *server);
|
||||
extern int smb_revalidate_inode(struct dentry *dentry);
|
||||
extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
|
||||
extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
|
||||
/* file.c */
|
||||
extern const struct address_space_operations smb_file_aops;
|
||||
extern const struct file_operations smb_file_operations;
|
||||
extern const struct inode_operations smb_file_inode_operations;
|
||||
/* ioctl.c */
|
||||
extern long smb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
|
||||
/* smbiod.c */
|
||||
extern void smbiod_wake_up(void);
|
||||
extern int smbiod_register_server(struct smb_sb_info *server);
|
||||
extern void smbiod_unregister_server(struct smb_sb_info *server);
|
||||
extern void smbiod_flush(struct smb_sb_info *server);
|
||||
extern int smbiod_retry(struct smb_sb_info *server);
|
||||
/* request.c */
|
||||
extern int smb_init_request_cache(void);
|
||||
extern void smb_destroy_request_cache(void);
|
||||
extern struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize);
|
||||
extern void smb_rput(struct smb_request *req);
|
||||
extern int smb_add_request(struct smb_request *req);
|
||||
extern int smb_request_send_server(struct smb_sb_info *server);
|
||||
extern int smb_request_recv(struct smb_sb_info *server);
|
||||
/* symlink.c */
|
||||
extern int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname);
|
||||
extern const struct inode_operations smb_link_inode_operations;
|
@ -1,817 +0,0 @@
|
||||
/*
|
||||
* request.c
|
||||
*
|
||||
* Copyright (C) 2001 by Urban Widmark
|
||||
*
|
||||
* Please add a note about your changes to smbfs in the ChangeLog file.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "smb_fs.h"
|
||||
#include "smbno.h"
|
||||
#include "smb_mount.h"
|
||||
#include "smb_debug.h"
|
||||
#include "request.h"
|
||||
#include "proto.h"
|
||||
|
||||
/* #define SMB_SLAB_DEBUG (SLAB_RED_ZONE | SLAB_POISON) */
|
||||
#define SMB_SLAB_DEBUG 0
|
||||
|
||||
/* cache for request structures */
|
||||
static struct kmem_cache *req_cachep;
|
||||
|
||||
static int smb_request_send_req(struct smb_request *req);
|
||||
|
||||
/*
|
||||
/proc/slabinfo:
|
||||
name, active, num, objsize, active_slabs, num_slaps, #pages
|
||||
*/
|
||||
|
||||
|
||||
int smb_init_request_cache(void)
|
||||
{
|
||||
req_cachep = kmem_cache_create("smb_request",
|
||||
sizeof(struct smb_request), 0,
|
||||
SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN,
|
||||
NULL);
|
||||
if (req_cachep == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void smb_destroy_request_cache(void)
|
||||
{
|
||||
kmem_cache_destroy(req_cachep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and initialise a request structure
|
||||
*/
|
||||
static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server,
|
||||
int bufsize)
|
||||
{
|
||||
struct smb_request *req;
|
||||
unsigned char *buf = NULL;
|
||||
|
||||
req = kmem_cache_zalloc(req_cachep, GFP_KERNEL);
|
||||
VERBOSE("allocating request: %p\n", req);
|
||||
if (!req)
|
||||
goto out;
|
||||
|
||||
if (bufsize > 0) {
|
||||
buf = kmalloc(bufsize, GFP_NOFS);
|
||||
if (!buf) {
|
||||
kmem_cache_free(req_cachep, req);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
req->rq_buffer = buf;
|
||||
req->rq_bufsize = bufsize;
|
||||
req->rq_server = server;
|
||||
init_waitqueue_head(&req->rq_wait);
|
||||
INIT_LIST_HEAD(&req->rq_queue);
|
||||
atomic_set(&req->rq_count, 1);
|
||||
|
||||
out:
|
||||
return req;
|
||||
}
|
||||
|
||||
struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize)
|
||||
{
|
||||
struct smb_request *req = NULL;
|
||||
|
||||
for (;;) {
|
||||
atomic_inc(&server->nr_requests);
|
||||
if (atomic_read(&server->nr_requests) <= MAX_REQUEST_HARD) {
|
||||
req = smb_do_alloc_request(server, bufsize);
|
||||
if (req != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Try to free up at least one request in order to stay
|
||||
* below the hard limit
|
||||
*/
|
||||
if (nfs_try_to_free_pages(server))
|
||||
continue;
|
||||
|
||||
if (fatal_signal_pending(current))
|
||||
return ERR_PTR(-ERESTARTSYS);
|
||||
current->policy = SCHED_YIELD;
|
||||
schedule();
|
||||
#else
|
||||
/* FIXME: we want something like nfs does above, but that
|
||||
requires changes to all callers and can wait. */
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
static void smb_free_request(struct smb_request *req)
|
||||
{
|
||||
atomic_dec(&req->rq_server->nr_requests);
|
||||
if (req->rq_buffer && !(req->rq_flags & SMB_REQ_STATIC))
|
||||
kfree(req->rq_buffer);
|
||||
kfree(req->rq_trans2buffer);
|
||||
kmem_cache_free(req_cachep, req);
|
||||
}
|
||||
|
||||
/*
|
||||
* What prevents a rget to race with a rput? The count must never drop to zero
|
||||
* while it is in use. Only rput if it is ok that it is free'd.
|
||||
*/
|
||||
static void smb_rget(struct smb_request *req)
|
||||
{
|
||||
atomic_inc(&req->rq_count);
|
||||
}
|
||||
void smb_rput(struct smb_request *req)
|
||||
{
|
||||
if (atomic_dec_and_test(&req->rq_count)) {
|
||||
list_del_init(&req->rq_queue);
|
||||
smb_free_request(req);
|
||||
}
|
||||
}
|
||||
|
||||
/* setup to receive the data part of the SMB */
|
||||
static int smb_setup_bcc(struct smb_request *req)
|
||||
{
|
||||
int result = 0;
|
||||
req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;
|
||||
|
||||
if (req->rq_rlen > req->rq_bufsize) {
|
||||
PARANOIA("Packet too large %d > %d\n",
|
||||
req->rq_rlen, req->rq_bufsize);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
req->rq_iov[0].iov_base = req->rq_buffer;
|
||||
req->rq_iov[0].iov_len = req->rq_rlen;
|
||||
req->rq_iovlen = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare a "normal" request structure.
|
||||
*/
|
||||
static int smb_setup_request(struct smb_request *req)
|
||||
{
|
||||
int len = smb_len(req->rq_header) + 4;
|
||||
req->rq_slen = len;
|
||||
|
||||
/* if we expect a data part in the reply we set the iov's to read it */
|
||||
if (req->rq_resp_bcc)
|
||||
req->rq_setup_read = smb_setup_bcc;
|
||||
|
||||
/* This tries to support re-using the same request */
|
||||
req->rq_bytes_sent = 0;
|
||||
req->rq_rcls = 0;
|
||||
req->rq_err = 0;
|
||||
req->rq_errno = 0;
|
||||
req->rq_fragment = 0;
|
||||
kfree(req->rq_trans2buffer);
|
||||
req->rq_trans2buffer = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare a transaction2 request structure
|
||||
*/
|
||||
static int smb_setup_trans2request(struct smb_request *req)
|
||||
{
|
||||
struct smb_sb_info *server = req->rq_server;
|
||||
int mparam, mdata;
|
||||
static unsigned char padding[4];
|
||||
|
||||
/* I know the following is very ugly, but I want to build the
|
||||
smb packet as efficiently as possible. */
|
||||
|
||||
const int smb_parameters = 15;
|
||||
const int header = SMB_HEADER_LEN + 2 * smb_parameters + 2;
|
||||
const int oparam = ALIGN(header + 3, sizeof(u32));
|
||||
const int odata = ALIGN(oparam + req->rq_lparm, sizeof(u32));
|
||||
const int bcc = (req->rq_data ? odata + req->rq_ldata :
|
||||
oparam + req->rq_lparm) - header;
|
||||
|
||||
if ((bcc + oparam) > server->opt.max_xmit)
|
||||
return -ENOMEM;
|
||||
smb_setup_header(req, SMBtrans2, smb_parameters, bcc);
|
||||
|
||||
/*
|
||||
* max parameters + max data + max setup == bufsize to make NT4 happy
|
||||
* and not abort the transfer or split into multiple responses. It also
|
||||
* makes smbfs happy as handling packets larger than the buffer size
|
||||
* is extra work.
|
||||
*
|
||||
* OS/2 is probably going to hate me for this ...
|
||||
*/
|
||||
mparam = SMB_TRANS2_MAX_PARAM;
|
||||
mdata = req->rq_bufsize - mparam;
|
||||
|
||||
mdata = server->opt.max_xmit - mparam - 100;
|
||||
if (mdata < 1024) {
|
||||
mdata = 1024;
|
||||
mparam = 20;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* NT/win2k has ~4k max_xmit, so with this we request more than it wants
|
||||
to return as one SMB. Useful for testing the fragmented trans2
|
||||
handling. */
|
||||
mdata = 8192;
|
||||
#endif
|
||||
|
||||
WSET(req->rq_header, smb_tpscnt, req->rq_lparm);
|
||||
WSET(req->rq_header, smb_tdscnt, req->rq_ldata);
|
||||
WSET(req->rq_header, smb_mprcnt, mparam);
|
||||
WSET(req->rq_header, smb_mdrcnt, mdata);
|
||||
WSET(req->rq_header, smb_msrcnt, 0); /* max setup always 0 ? */
|
||||
WSET(req->rq_header, smb_flags, 0);
|
||||
DSET(req->rq_header, smb_timeout, 0);
|
||||
WSET(req->rq_header, smb_pscnt, req->rq_lparm);
|
||||
WSET(req->rq_header, smb_psoff, oparam - 4);
|
||||
WSET(req->rq_header, smb_dscnt, req->rq_ldata);
|
||||
WSET(req->rq_header, smb_dsoff, req->rq_data ? odata - 4 : 0);
|
||||
*(req->rq_header + smb_suwcnt) = 0x01; /* setup count */
|
||||
*(req->rq_header + smb_suwcnt + 1) = 0x00; /* reserved */
|
||||
WSET(req->rq_header, smb_setup0, req->rq_trans2_command);
|
||||
|
||||
req->rq_iovlen = 2;
|
||||
req->rq_iov[0].iov_base = (void *) req->rq_header;
|
||||
req->rq_iov[0].iov_len = oparam;
|
||||
req->rq_iov[1].iov_base = (req->rq_parm==NULL) ? padding : req->rq_parm;
|
||||
req->rq_iov[1].iov_len = req->rq_lparm;
|
||||
req->rq_slen = oparam + req->rq_lparm;
|
||||
|
||||
if (req->rq_data) {
|
||||
req->rq_iovlen += 2;
|
||||
req->rq_iov[2].iov_base = padding;
|
||||
req->rq_iov[2].iov_len = odata - oparam - req->rq_lparm;
|
||||
req->rq_iov[3].iov_base = req->rq_data;
|
||||
req->rq_iov[3].iov_len = req->rq_ldata;
|
||||
req->rq_slen = odata + req->rq_ldata;
|
||||
}
|
||||
|
||||
/* always a data part for trans2 replies */
|
||||
req->rq_setup_read = smb_setup_bcc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a request and tell smbiod to process it
|
||||
*/
|
||||
int smb_add_request(struct smb_request *req)
|
||||
{
|
||||
long timeleft;
|
||||
struct smb_sb_info *server = req->rq_server;
|
||||
int result = 0;
|
||||
|
||||
smb_setup_request(req);
|
||||
if (req->rq_trans2_command) {
|
||||
if (req->rq_buffer == NULL) {
|
||||
PARANOIA("trans2 attempted without response buffer!\n");
|
||||
return -EIO;
|
||||
}
|
||||
result = smb_setup_trans2request(req);
|
||||
}
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
#ifdef SMB_DEBUG_PACKET_SIZE
|
||||
add_xmit_stats(req);
|
||||
#endif
|
||||
|
||||
/* add 'req' to the queue of requests */
|
||||
if (smb_lock_server_interruptible(server))
|
||||
return -EINTR;
|
||||
|
||||
/*
|
||||
* Try to send the request as the process. If that fails we queue the
|
||||
* request and let smbiod send it later.
|
||||
*/
|
||||
|
||||
/* FIXME: each server has a number on the maximum number of parallel
|
||||
requests. 10, 50 or so. We should not allow more requests to be
|
||||
active. */
|
||||
if (server->mid > 0xf000)
|
||||
server->mid = 0;
|
||||
req->rq_mid = server->mid++;
|
||||
WSET(req->rq_header, smb_mid, req->rq_mid);
|
||||
|
||||
result = 0;
|
||||
if (server->state == CONN_VALID) {
|
||||
if (list_empty(&server->xmitq))
|
||||
result = smb_request_send_req(req);
|
||||
if (result < 0) {
|
||||
/* Connection lost? */
|
||||
server->conn_error = result;
|
||||
server->state = CONN_INVALID;
|
||||
}
|
||||
}
|
||||
if (result != 1)
|
||||
list_add_tail(&req->rq_queue, &server->xmitq);
|
||||
smb_rget(req);
|
||||
|
||||
if (server->state != CONN_VALID)
|
||||
smbiod_retry(server);
|
||||
|
||||
smb_unlock_server(server);
|
||||
|
||||
smbiod_wake_up();
|
||||
|
||||
timeleft = wait_event_interruptible_timeout(req->rq_wait,
|
||||
req->rq_flags & SMB_REQ_RECEIVED, 30*HZ);
|
||||
if (!timeleft || signal_pending(current)) {
|
||||
/*
|
||||
* On timeout or on interrupt we want to try and remove the
|
||||
* request from the recvq/xmitq.
|
||||
* First check if the request is still part of a queue. (May
|
||||
* have been removed by some error condition)
|
||||
*/
|
||||
smb_lock_server(server);
|
||||
if (!list_empty(&req->rq_queue)) {
|
||||
list_del_init(&req->rq_queue);
|
||||
smb_rput(req);
|
||||
}
|
||||
smb_unlock_server(server);
|
||||
}
|
||||
|
||||
if (!timeleft) {
|
||||
PARANOIA("request [%p, mid=%d] timed out!\n",
|
||||
req, req->rq_mid);
|
||||
VERBOSE("smb_com: %02x\n", *(req->rq_header + smb_com));
|
||||
VERBOSE("smb_rcls: %02x\n", *(req->rq_header + smb_rcls));
|
||||
VERBOSE("smb_flg: %02x\n", *(req->rq_header + smb_flg));
|
||||
VERBOSE("smb_tid: %04x\n", WVAL(req->rq_header, smb_tid));
|
||||
VERBOSE("smb_pid: %04x\n", WVAL(req->rq_header, smb_pid));
|
||||
VERBOSE("smb_uid: %04x\n", WVAL(req->rq_header, smb_uid));
|
||||
VERBOSE("smb_mid: %04x\n", WVAL(req->rq_header, smb_mid));
|
||||
VERBOSE("smb_wct: %02x\n", *(req->rq_header + smb_wct));
|
||||
|
||||
req->rq_rcls = ERRSRV;
|
||||
req->rq_err = ERRtimeout;
|
||||
|
||||
/* Just in case it was "stuck" */
|
||||
smbiod_wake_up();
|
||||
}
|
||||
VERBOSE("woke up, rcls=%d\n", req->rq_rcls);
|
||||
|
||||
if (req->rq_rcls != 0)
|
||||
req->rq_errno = smb_errno(req);
|
||||
if (signal_pending(current))
|
||||
req->rq_errno = -ERESTARTSYS;
|
||||
return req->rq_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a request and place it on the recvq if successfully sent.
|
||||
* Must be called with the server lock held.
|
||||
*/
|
||||
static int smb_request_send_req(struct smb_request *req)
|
||||
{
|
||||
struct smb_sb_info *server = req->rq_server;
|
||||
int result;
|
||||
|
||||
if (req->rq_bytes_sent == 0) {
|
||||
WSET(req->rq_header, smb_tid, server->opt.tid);
|
||||
WSET(req->rq_header, smb_pid, 1);
|
||||
WSET(req->rq_header, smb_uid, server->opt.server_uid);
|
||||
}
|
||||
|
||||
result = smb_send_request(req);
|
||||
if (result < 0 && result != -EAGAIN)
|
||||
goto out;
|
||||
|
||||
result = 0;
|
||||
if (!(req->rq_flags & SMB_REQ_TRANSMITTED))
|
||||
goto out;
|
||||
|
||||
list_move_tail(&req->rq_queue, &server->recvq);
|
||||
result = 1;
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends one request for this server. (smbiod)
|
||||
* Must be called with the server lock held.
|
||||
* Returns: <0 on error
|
||||
* 0 if no request could be completely sent
|
||||
* 1 if all data for one request was sent
|
||||
*/
|
||||
int smb_request_send_server(struct smb_sb_info *server)
|
||||
{
|
||||
struct list_head *head;
|
||||
struct smb_request *req;
|
||||
int result;
|
||||
|
||||
if (server->state != CONN_VALID)
|
||||
return 0;
|
||||
|
||||
/* dequeue first request, if any */
|
||||
req = NULL;
|
||||
head = server->xmitq.next;
|
||||
if (head != &server->xmitq) {
|
||||
req = list_entry(head, struct smb_request, rq_queue);
|
||||
}
|
||||
if (!req)
|
||||
return 0;
|
||||
|
||||
result = smb_request_send_req(req);
|
||||
if (result < 0) {
|
||||
server->conn_error = result;
|
||||
list_move(&req->rq_queue, &server->xmitq);
|
||||
result = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find a request matching this "mid". Typically the first entry will
|
||||
* be the matching one.
|
||||
*/
|
||||
static struct smb_request *find_request(struct smb_sb_info *server, int mid)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct smb_request *req = NULL;
|
||||
|
||||
list_for_each(tmp, &server->recvq) {
|
||||
req = list_entry(tmp, struct smb_request, rq_queue);
|
||||
if (req->rq_mid == mid) {
|
||||
break;
|
||||
}
|
||||
req = NULL;
|
||||
}
|
||||
|
||||
if (!req) {
|
||||
VERBOSE("received reply with mid %d but no request!\n",
|
||||
WVAL(server->header, smb_mid));
|
||||
server->rstate = SMB_RECV_DROP;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when we have read the smb header and believe this is a response.
|
||||
*/
|
||||
static int smb_init_request(struct smb_sb_info *server, struct smb_request *req)
|
||||
{
|
||||
int hdrlen, wct;
|
||||
|
||||
memcpy(req->rq_header, server->header, SMB_HEADER_LEN);
|
||||
|
||||
wct = *(req->rq_header + smb_wct);
|
||||
if (wct > 20) {
|
||||
PARANOIA("wct too large, %d > 20\n", wct);
|
||||
server->rstate = SMB_RECV_DROP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->rq_resp_wct = wct;
|
||||
hdrlen = SMB_HEADER_LEN + wct*2 + 2;
|
||||
VERBOSE("header length: %d smb_wct: %2d\n", hdrlen, wct);
|
||||
|
||||
req->rq_bytes_recvd = SMB_HEADER_LEN;
|
||||
req->rq_rlen = hdrlen;
|
||||
req->rq_iov[0].iov_base = req->rq_header;
|
||||
req->rq_iov[0].iov_len = hdrlen;
|
||||
req->rq_iovlen = 1;
|
||||
server->rstate = SMB_RECV_PARAM;
|
||||
|
||||
#ifdef SMB_DEBUG_PACKET_SIZE
|
||||
add_recv_stats(smb_len(server->header));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the SMB parameters
|
||||
*/
|
||||
static int smb_recv_param(struct smb_sb_info *server, struct smb_request *req)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = smb_receive(server, req);
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (req->rq_bytes_recvd < req->rq_rlen)
|
||||
return 0;
|
||||
|
||||
VERBOSE("result: %d smb_bcc: %04x\n", result,
|
||||
WVAL(req->rq_header, SMB_HEADER_LEN +
|
||||
(*(req->rq_header + smb_wct) * 2)));
|
||||
|
||||
result = 0;
|
||||
req->rq_iov[0].iov_base = NULL;
|
||||
req->rq_rlen = 0;
|
||||
if (req->rq_callback)
|
||||
req->rq_callback(req);
|
||||
else if (req->rq_setup_read)
|
||||
result = req->rq_setup_read(req);
|
||||
if (result < 0) {
|
||||
server->rstate = SMB_RECV_DROP;
|
||||
return result;
|
||||
}
|
||||
|
||||
server->rstate = req->rq_rlen > 0 ? SMB_RECV_DATA : SMB_RECV_END;
|
||||
|
||||
req->rq_bytes_recvd = 0; // recvd out of the iov
|
||||
|
||||
VERBOSE("rlen: %d\n", req->rq_rlen);
|
||||
if (req->rq_rlen < 0) {
|
||||
PARANOIA("Parameters read beyond end of packet!\n");
|
||||
server->rstate = SMB_RECV_END;
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the SMB data
|
||||
*/
|
||||
static int smb_recv_data(struct smb_sb_info *server, struct smb_request *req)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = smb_receive(server, req);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
if (req->rq_bytes_recvd < req->rq_rlen)
|
||||
goto out;
|
||||
server->rstate = SMB_RECV_END;
|
||||
out:
|
||||
VERBOSE("result: %d\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a transaction2 response
|
||||
* Return: 0 if the response has been fully read
|
||||
* 1 if there are further "fragments" to read
|
||||
* <0 if there is an error
|
||||
*/
|
||||
static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
|
||||
{
|
||||
unsigned char *inbuf;
|
||||
unsigned int parm_disp, parm_offset, parm_count, parm_tot;
|
||||
unsigned int data_disp, data_offset, data_count, data_tot;
|
||||
int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2;
|
||||
|
||||
VERBOSE("handling trans2\n");
|
||||
|
||||
inbuf = req->rq_header;
|
||||
data_tot = WVAL(inbuf, smb_tdrcnt);
|
||||
parm_tot = WVAL(inbuf, smb_tprcnt);
|
||||
parm_disp = WVAL(inbuf, smb_prdisp);
|
||||
parm_offset = WVAL(inbuf, smb_proff);
|
||||
parm_count = WVAL(inbuf, smb_prcnt);
|
||||
data_disp = WVAL(inbuf, smb_drdisp);
|
||||
data_offset = WVAL(inbuf, smb_droff);
|
||||
data_count = WVAL(inbuf, smb_drcnt);
|
||||
|
||||
/* Modify offset for the split header/buffer we use */
|
||||
if (data_count || data_offset) {
|
||||
if (unlikely(data_offset < hdrlen))
|
||||
goto out_bad_data;
|
||||
else
|
||||
data_offset -= hdrlen;
|
||||
}
|
||||
if (parm_count || parm_offset) {
|
||||
if (unlikely(parm_offset < hdrlen))
|
||||
goto out_bad_parm;
|
||||
else
|
||||
parm_offset -= hdrlen;
|
||||
}
|
||||
|
||||
if (parm_count == parm_tot && data_count == data_tot) {
|
||||
/*
|
||||
* This packet has all the trans2 data.
|
||||
*
|
||||
* We setup the request so that this will be the common
|
||||
* case. It may be a server error to not return a
|
||||
* response that fits.
|
||||
*/
|
||||
VERBOSE("single trans2 response "
|
||||
"dcnt=%u, pcnt=%u, doff=%u, poff=%u\n",
|
||||
data_count, parm_count,
|
||||
data_offset, parm_offset);
|
||||
req->rq_ldata = data_count;
|
||||
req->rq_lparm = parm_count;
|
||||
req->rq_data = req->rq_buffer + data_offset;
|
||||
req->rq_parm = req->rq_buffer + parm_offset;
|
||||
if (unlikely(parm_offset + parm_count > req->rq_rlen))
|
||||
goto out_bad_parm;
|
||||
if (unlikely(data_offset + data_count > req->rq_rlen))
|
||||
goto out_bad_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
VERBOSE("multi trans2 response "
|
||||
"frag=%d, dcnt=%u, pcnt=%u, doff=%u, poff=%u\n",
|
||||
req->rq_fragment,
|
||||
data_count, parm_count,
|
||||
data_offset, parm_offset);
|
||||
|
||||
if (!req->rq_fragment) {
|
||||
int buf_len;
|
||||
|
||||
/* We got the first trans2 fragment */
|
||||
req->rq_fragment = 1;
|
||||
req->rq_total_data = data_tot;
|
||||
req->rq_total_parm = parm_tot;
|
||||
req->rq_ldata = 0;
|
||||
req->rq_lparm = 0;
|
||||
|
||||
buf_len = data_tot + parm_tot;
|
||||
if (buf_len > SMB_MAX_PACKET_SIZE)
|
||||
goto out_too_long;
|
||||
|
||||
req->rq_trans2bufsize = buf_len;
|
||||
req->rq_trans2buffer = kzalloc(buf_len, GFP_NOFS);
|
||||
if (!req->rq_trans2buffer)
|
||||
goto out_no_mem;
|
||||
|
||||
req->rq_parm = req->rq_trans2buffer;
|
||||
req->rq_data = req->rq_trans2buffer + parm_tot;
|
||||
} else if (unlikely(req->rq_total_data < data_tot ||
|
||||
req->rq_total_parm < parm_tot))
|
||||
goto out_data_grew;
|
||||
|
||||
if (unlikely(parm_disp + parm_count > req->rq_total_parm ||
|
||||
parm_offset + parm_count > req->rq_rlen))
|
||||
goto out_bad_parm;
|
||||
if (unlikely(data_disp + data_count > req->rq_total_data ||
|
||||
data_offset + data_count > req->rq_rlen))
|
||||
goto out_bad_data;
|
||||
|
||||
inbuf = req->rq_buffer;
|
||||
memcpy(req->rq_parm + parm_disp, inbuf + parm_offset, parm_count);
|
||||
memcpy(req->rq_data + data_disp, inbuf + data_offset, data_count);
|
||||
|
||||
req->rq_ldata += data_count;
|
||||
req->rq_lparm += parm_count;
|
||||
|
||||
/*
|
||||
* Check whether we've received all of the data. Note that
|
||||
* we use the packet totals -- total lengths might shrink!
|
||||
*/
|
||||
if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot) {
|
||||
req->rq_ldata = data_tot;
|
||||
req->rq_lparm = parm_tot;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
out_too_long:
|
||||
printk(KERN_ERR "smb_trans2: data/param too long, data=%u, parm=%u\n",
|
||||
data_tot, parm_tot);
|
||||
goto out_EIO;
|
||||
out_no_mem:
|
||||
printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n",
|
||||
req->rq_trans2bufsize);
|
||||
req->rq_errno = -ENOMEM;
|
||||
goto out;
|
||||
out_data_grew:
|
||||
printk(KERN_ERR "smb_trans2: data/params grew!\n");
|
||||
goto out_EIO;
|
||||
out_bad_parm:
|
||||
printk(KERN_ERR "smb_trans2: invalid parms, disp=%u, cnt=%u, tot=%u, ofs=%u\n",
|
||||
parm_disp, parm_count, parm_tot, parm_offset);
|
||||
goto out_EIO;
|
||||
out_bad_data:
|
||||
printk(KERN_ERR "smb_trans2: invalid data, disp=%u, cnt=%u, tot=%u, ofs=%u\n",
|
||||
data_disp, data_count, data_tot, data_offset);
|
||||
out_EIO:
|
||||
req->rq_errno = -EIO;
|
||||
out:
|
||||
return req->rq_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* State machine for receiving responses. We handle the fact that we can't
|
||||
* read the full response in one try by having states telling us how much we
|
||||
* have read.
|
||||
*
|
||||
* Must be called with the server lock held (only called from smbiod).
|
||||
*
|
||||
* Return: <0 on error
|
||||
*/
|
||||
int smb_request_recv(struct smb_sb_info *server)
|
||||
{
|
||||
struct smb_request *req = NULL;
|
||||
int result = 0;
|
||||
|
||||
if (smb_recv_available(server) <= 0)
|
||||
return 0;
|
||||
|
||||
VERBOSE("state: %d\n", server->rstate);
|
||||
switch (server->rstate) {
|
||||
case SMB_RECV_DROP:
|
||||
result = smb_receive_drop(server);
|
||||
if (result < 0)
|
||||
break;
|
||||
if (server->rstate == SMB_RECV_DROP)
|
||||
break;
|
||||
server->rstate = SMB_RECV_START;
|
||||
/* fallthrough */
|
||||
case SMB_RECV_START:
|
||||
server->smb_read = 0;
|
||||
server->rstate = SMB_RECV_HEADER;
|
||||
/* fallthrough */
|
||||
case SMB_RECV_HEADER:
|
||||
result = smb_receive_header(server);
|
||||
if (result < 0)
|
||||
break;
|
||||
if (server->rstate == SMB_RECV_HEADER)
|
||||
break;
|
||||
if (! (*(server->header + smb_flg) & SMB_FLAGS_REPLY) ) {
|
||||
server->rstate = SMB_RECV_REQUEST;
|
||||
break;
|
||||
}
|
||||
if (server->rstate != SMB_RECV_HCOMPLETE)
|
||||
break;
|
||||
/* fallthrough */
|
||||
case SMB_RECV_HCOMPLETE:
|
||||
req = find_request(server, WVAL(server->header, smb_mid));
|
||||
if (!req)
|
||||
break;
|
||||
smb_init_request(server, req);
|
||||
req->rq_rcls = *(req->rq_header + smb_rcls);
|
||||
req->rq_err = WVAL(req->rq_header, smb_err);
|
||||
if (server->rstate != SMB_RECV_PARAM)
|
||||
break;
|
||||
/* fallthrough */
|
||||
case SMB_RECV_PARAM:
|
||||
if (!req)
|
||||
req = find_request(server,WVAL(server->header,smb_mid));
|
||||
if (!req)
|
||||
break;
|
||||
result = smb_recv_param(server, req);
|
||||
if (result < 0)
|
||||
break;
|
||||
if (server->rstate != SMB_RECV_DATA)
|
||||
break;
|
||||
/* fallthrough */
|
||||
case SMB_RECV_DATA:
|
||||
if (!req)
|
||||
req = find_request(server,WVAL(server->header,smb_mid));
|
||||
if (!req)
|
||||
break;
|
||||
result = smb_recv_data(server, req);
|
||||
if (result < 0)
|
||||
break;
|
||||
break;
|
||||
|
||||
/* We should never be called with any of these states */
|
||||
case SMB_RECV_END:
|
||||
case SMB_RECV_REQUEST:
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
/* We saw an error */
|
||||
return result;
|
||||
}
|
||||
|
||||
if (server->rstate != SMB_RECV_END)
|
||||
return 0;
|
||||
|
||||
result = 0;
|
||||
if (req->rq_trans2_command && req->rq_rcls == SUCCESS)
|
||||
result = smb_recv_trans2(server, req);
|
||||
|
||||
/*
|
||||
* Response completely read. Drop any extra bytes sent by the server.
|
||||
* (Yes, servers sometimes add extra bytes to responses)
|
||||
*/
|
||||
VERBOSE("smb_len: %d smb_read: %d\n",
|
||||
server->smb_len, server->smb_read);
|
||||
if (server->smb_read < server->smb_len)
|
||||
smb_receive_drop(server);
|
||||
|
||||
server->rstate = SMB_RECV_START;
|
||||
|
||||
if (!result) {
|
||||
list_del_init(&req->rq_queue);
|
||||
req->rq_flags |= SMB_REQ_RECEIVED;
|
||||
smb_rput(req);
|
||||
wake_up_interruptible(&req->rq_wait);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
struct smb_request {
|
||||
struct list_head rq_queue; /* recvq or xmitq for the server */
|
||||
|
||||
atomic_t rq_count;
|
||||
|
||||
wait_queue_head_t rq_wait;
|
||||
int rq_flags;
|
||||
int rq_mid; /* multiplex ID, set by request.c */
|
||||
|
||||
struct smb_sb_info *rq_server;
|
||||
|
||||
/* header + word count + parameter words + byte count */
|
||||
unsigned char rq_header[SMB_HEADER_LEN + 20*2 + 2];
|
||||
|
||||
int rq_bufsize;
|
||||
unsigned char *rq_buffer;
|
||||
|
||||
/* FIXME: this is not good enough for merging IO requests. */
|
||||
unsigned char *rq_page;
|
||||
int rq_rsize;
|
||||
|
||||
int rq_resp_wct;
|
||||
int rq_resp_bcc;
|
||||
|
||||
int rq_rlen;
|
||||
int rq_bytes_recvd;
|
||||
|
||||
int rq_slen;
|
||||
int rq_bytes_sent;
|
||||
|
||||
int rq_iovlen;
|
||||
struct kvec rq_iov[4];
|
||||
|
||||
int (*rq_setup_read) (struct smb_request *);
|
||||
void (*rq_callback) (struct smb_request *);
|
||||
|
||||
/* ------ trans2 stuff ------ */
|
||||
|
||||
u16 rq_trans2_command; /* 0 if not a trans2 request */
|
||||
unsigned int rq_ldata;
|
||||
unsigned char *rq_data;
|
||||
unsigned int rq_lparm;
|
||||
unsigned char *rq_parm;
|
||||
|
||||
int rq_fragment;
|
||||
u32 rq_total_data;
|
||||
u32 rq_total_parm;
|
||||
int rq_trans2bufsize;
|
||||
unsigned char *rq_trans2buffer;
|
||||
|
||||
/* ------ response ------ */
|
||||
|
||||
unsigned short rq_rcls;
|
||||
unsigned short rq_err;
|
||||
int rq_errno;
|
||||
};
|
||||
|
||||
#define SMB_REQ_STATIC 0x0001 /* rq_buffer is static */
|
||||
#define SMB_REQ_NORETRY 0x0002 /* request is invalid after retry */
|
||||
|
||||
#define SMB_REQ_TRANSMITTED 0x4000 /* all data has been sent */
|
||||
#define SMB_REQ_RECEIVED 0x8000 /* reply received, smbiod is done */
|
||||
|
||||
#define xSMB_REQ_NOREPLY 0x0004 /* we don't want the reply (if any) */
|
||||
#define xSMB_REQ_NORECEIVER 0x0008 /* caller doesn't wait for response */
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* smb.h
|
||||
*
|
||||
* Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SMB_H
|
||||
#define _LINUX_SMB_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/magic.h>
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/time.h>
|
||||
#endif
|
||||
|
||||
enum smb_protocol {
|
||||
SMB_PROTOCOL_NONE,
|
||||
SMB_PROTOCOL_CORE,
|
||||
SMB_PROTOCOL_COREPLUS,
|
||||
SMB_PROTOCOL_LANMAN1,
|
||||
SMB_PROTOCOL_LANMAN2,
|
||||
SMB_PROTOCOL_NT1
|
||||
};
|
||||
|
||||
enum smb_case_hndl {
|
||||
SMB_CASE_DEFAULT,
|
||||
SMB_CASE_LOWER,
|
||||
SMB_CASE_UPPER
|
||||
};
|
||||
|
||||
struct smb_dskattr {
|
||||
__u16 total;
|
||||
__u16 allocblocks;
|
||||
__u16 blocksize;
|
||||
__u16 free;
|
||||
};
|
||||
|
||||
struct smb_conn_opt {
|
||||
|
||||
/* The socket */
|
||||
unsigned int fd;
|
||||
|
||||
enum smb_protocol protocol;
|
||||
enum smb_case_hndl case_handling;
|
||||
|
||||
/* Connection-Options */
|
||||
|
||||
__u32 max_xmit;
|
||||
__u16 server_uid;
|
||||
__u16 tid;
|
||||
|
||||
/* The following are LANMAN 1.0 options */
|
||||
__u16 secmode;
|
||||
__u16 maxmux;
|
||||
__u16 maxvcs;
|
||||
__u16 rawmode;
|
||||
__u32 sesskey;
|
||||
|
||||
/* The following are NT LM 0.12 options */
|
||||
__u32 maxraw;
|
||||
__u32 capabilities;
|
||||
__s16 serverzone;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define SMB_NLS_MAXNAMELEN 20
|
||||
struct smb_nls_codepage {
|
||||
char local_name[SMB_NLS_MAXNAMELEN];
|
||||
char remote_name[SMB_NLS_MAXNAMELEN];
|
||||
};
|
||||
|
||||
|
||||
#define SMB_MAXNAMELEN 255
|
||||
#define SMB_MAXPATHLEN 1024
|
||||
|
||||
/*
|
||||
* Contains all relevant data on a SMB networked file.
|
||||
*/
|
||||
struct smb_fattr {
|
||||
__u16 attr;
|
||||
|
||||
unsigned long f_ino;
|
||||
umode_t f_mode;
|
||||
nlink_t f_nlink;
|
||||
uid_t f_uid;
|
||||
gid_t f_gid;
|
||||
dev_t f_rdev;
|
||||
loff_t f_size;
|
||||
struct timespec f_atime;
|
||||
struct timespec f_mtime;
|
||||
struct timespec f_ctime;
|
||||
unsigned long f_blocks;
|
||||
int f_unix;
|
||||
};
|
||||
|
||||
enum smb_conn_state {
|
||||
CONN_VALID, /* everything's fine */
|
||||
CONN_INVALID, /* Something went wrong, but did not
|
||||
try to reconnect yet. */
|
||||
CONN_RETRIED, /* Tried a reconnection, but was refused */
|
||||
CONN_RETRYING /* Currently trying to reconnect */
|
||||
};
|
||||
|
||||
#define SMB_HEADER_LEN 37 /* includes everything up to, but not
|
||||
* including smb_bcc */
|
||||
|
||||
#define SMB_INITIAL_PACKET_SIZE 4000
|
||||
#define SMB_MAX_PACKET_SIZE 32768
|
||||
|
||||
/* reserve this much space for trans2 parameters. Shouldn't have to be more
|
||||
than 10 or so, but OS/2 seems happier like this. */
|
||||
#define SMB_TRANS2_MAX_PARAM 64
|
||||
|
||||
#endif
|
||||
#endif
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Defines some debug macros for smbfs.
|
||||
*/
|
||||
|
||||
/* This makes a dentry parent/child name pair. Useful for debugging printk's */
|
||||
#define DENTRY_PATH(dentry) \
|
||||
(dentry)->d_parent->d_name.name,(dentry)->d_name.name
|
||||
|
||||
/*
|
||||
* safety checks that should never happen ???
|
||||
* these are normally enabled.
|
||||
*/
|
||||
#ifdef SMBFS_PARANOIA
|
||||
# define PARANOIA(f, a...) printk(KERN_NOTICE "%s: " f, __func__ , ## a)
|
||||
#else
|
||||
# define PARANOIA(f, a...) do { ; } while(0)
|
||||
#endif
|
||||
|
||||
/* lots of debug messages */
|
||||
#ifdef SMBFS_DEBUG_VERBOSE
|
||||
# define VERBOSE(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
|
||||
#else
|
||||
# define VERBOSE(f, a...) do { ; } while(0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "normal" debug messages, but not with a normal DEBUG define ... way
|
||||
* too common name.
|
||||
*/
|
||||
#ifdef SMBFS_DEBUG
|
||||
#define DEBUG1(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
|
||||
#else
|
||||
#define DEBUG1(f, a...) do { ; } while(0)
|
||||
#endif
|
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* smb_fs.h
|
||||
*
|
||||
* Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SMB_FS_H
|
||||
#define _LINUX_SMB_FS_H
|
||||
|
||||
#include "smb.h"
|
||||
|
||||
/*
|
||||
* ioctl commands
|
||||
*/
|
||||
#define SMB_IOC_GETMOUNTUID _IOR('u', 1, __kernel_old_uid_t)
|
||||
#define SMB_IOC_NEWCONN _IOW('u', 2, struct smb_conn_opt)
|
||||
|
||||
/* __kernel_uid_t can never change, so we have to use __kernel_uid32_t */
|
||||
#define SMB_IOC_GETMOUNTUID32 _IOR('u', 3, __kernel_uid32_t)
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include "smb_fs_i.h"
|
||||
#include "smb_fs_sb.h"
|
||||
#include "smb_mount.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
static inline struct smb_sb_info *SMB_SB(struct super_block *sb)
|
||||
{
|
||||
return sb->s_fs_info;
|
||||
}
|
||||
|
||||
static inline struct smb_inode_info *SMB_I(struct inode *inode)
|
||||
{
|
||||
return container_of(inode, struct smb_inode_info, vfs_inode);
|
||||
}
|
||||
|
||||
/* macro names are short for word, double-word, long value (?) */
|
||||
#define WVAL(buf, pos) (get_unaligned_le16((u8 *)(buf) + (pos)))
|
||||
#define DVAL(buf, pos) (get_unaligned_le32((u8 *)(buf) + (pos)))
|
||||
#define LVAL(buf, pos) (get_unaligned_le64((u8 *)(buf) + (pos)))
|
||||
|
||||
#define WSET(buf, pos, val) put_unaligned_le16((val), (u8 *)(buf) + (pos))
|
||||
#define DSET(buf, pos, val) put_unaligned_le32((val), (u8 *)(buf) + (pos))
|
||||
#define LSET(buf, pos, val) put_unaligned_le64((val), (u8 *)(buf) + (pos))
|
||||
|
||||
/* where to find the base of the SMB packet proper */
|
||||
#define smb_base(buf) ((u8 *)(((u8 *)(buf))+4))
|
||||
|
||||
/*
|
||||
* Flags for the in-memory inode
|
||||
*/
|
||||
#define SMB_F_LOCALWRITE 0x02 /* file modified locally */
|
||||
|
||||
|
||||
/* NT1 protocol capability bits */
|
||||
#define SMB_CAP_RAW_MODE 0x00000001
|
||||
#define SMB_CAP_MPX_MODE 0x00000002
|
||||
#define SMB_CAP_UNICODE 0x00000004
|
||||
#define SMB_CAP_LARGE_FILES 0x00000008
|
||||
#define SMB_CAP_NT_SMBS 0x00000010
|
||||
#define SMB_CAP_RPC_REMOTE_APIS 0x00000020
|
||||
#define SMB_CAP_STATUS32 0x00000040
|
||||
#define SMB_CAP_LEVEL_II_OPLOCKS 0x00000080
|
||||
#define SMB_CAP_LOCK_AND_READ 0x00000100
|
||||
#define SMB_CAP_NT_FIND 0x00000200
|
||||
#define SMB_CAP_DFS 0x00001000
|
||||
#define SMB_CAP_LARGE_READX 0x00004000
|
||||
#define SMB_CAP_LARGE_WRITEX 0x00008000
|
||||
#define SMB_CAP_UNIX 0x00800000 /* unofficial ... */
|
||||
|
||||
|
||||
/*
|
||||
* This is the time we allow an inode, dentry or dir cache to live. It is bad
|
||||
* for performance to have shorter ttl on an inode than on the cache. It can
|
||||
* cause refresh on each inode for a dir listing ... one-by-one
|
||||
*/
|
||||
#define SMB_MAX_AGE(server) (((server)->mnt->ttl * HZ) / 1000)
|
||||
|
||||
static inline void
|
||||
smb_age_dentry(struct smb_sb_info *server, struct dentry *dentry)
|
||||
{
|
||||
dentry->d_time = jiffies - SMB_MAX_AGE(server);
|
||||
}
|
||||
|
||||
struct smb_cache_head {
|
||||
time_t mtime; /* unused */
|
||||
unsigned long time; /* cache age */
|
||||
unsigned long end; /* last valid fpos in cache */
|
||||
int eof;
|
||||
};
|
||||
|
||||
#define SMB_DIRCACHE_SIZE ((int)(PAGE_CACHE_SIZE/sizeof(struct dentry *)))
|
||||
union smb_dir_cache {
|
||||
struct smb_cache_head head;
|
||||
struct dentry *dentry[SMB_DIRCACHE_SIZE];
|
||||
};
|
||||
|
||||
#define SMB_FIRSTCACHE_SIZE ((int)((SMB_DIRCACHE_SIZE * \
|
||||
sizeof(struct dentry *) - sizeof(struct smb_cache_head)) / \
|
||||
sizeof(struct dentry *)))
|
||||
|
||||
#define SMB_DIRCACHE_START (SMB_DIRCACHE_SIZE - SMB_FIRSTCACHE_SIZE)
|
||||
|
||||
struct smb_cache_control {
|
||||
struct smb_cache_head head;
|
||||
struct page *page;
|
||||
union smb_dir_cache *cache;
|
||||
unsigned long fpos, ofs;
|
||||
int filled, valid, idx;
|
||||
};
|
||||
|
||||
#define SMB_OPS_NUM_STATIC 5
|
||||
struct smb_ops {
|
||||
int (*read)(struct inode *inode, loff_t offset, int count,
|
||||
char *data);
|
||||
int (*write)(struct inode *inode, loff_t offset, int count, const
|
||||
char *data);
|
||||
int (*readdir)(struct file *filp, void *dirent, filldir_t filldir,
|
||||
struct smb_cache_control *ctl);
|
||||
|
||||
int (*getattr)(struct smb_sb_info *server, struct dentry *dir,
|
||||
struct smb_fattr *fattr);
|
||||
/* int (*setattr)(...); */ /* setattr is really icky! */
|
||||
|
||||
int (*truncate)(struct inode *inode, loff_t length);
|
||||
|
||||
|
||||
/* --- --- --- end of "static" entries --- --- --- */
|
||||
|
||||
int (*convert)(unsigned char *output, int olen,
|
||||
const unsigned char *input, int ilen,
|
||||
struct nls_table *nls_from,
|
||||
struct nls_table *nls_to);
|
||||
};
|
||||
|
||||
static inline int
|
||||
smb_is_open(struct inode *i)
|
||||
{
|
||||
return (SMB_I(i)->open == server_from_inode(i)->generation);
|
||||
}
|
||||
|
||||
extern void smb_install_null_ops(struct smb_ops *);
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _LINUX_SMB_FS_H */
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* smb_fs_i.h
|
||||
*
|
||||
* Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SMB_FS_I
|
||||
#define _LINUX_SMB_FS_I
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
/*
|
||||
* smb fs inode data (in memory only)
|
||||
*/
|
||||
struct smb_inode_info {
|
||||
|
||||
/*
|
||||
* file handles are local to a connection. A file is open if
|
||||
* (open == generation).
|
||||
*/
|
||||
unsigned int open; /* open generation */
|
||||
__u16 fileid; /* What id to handle a file with? */
|
||||
__u16 attr; /* Attribute fields, DOS value */
|
||||
|
||||
__u16 access; /* Access mode */
|
||||
__u16 flags;
|
||||
unsigned long oldmtime; /* last time refreshed */
|
||||
unsigned long closed; /* timestamp when closed */
|
||||
unsigned openers; /* number of fileid users */
|
||||
|
||||
struct inode vfs_inode; /* must be at the end */
|
||||
};
|
||||
|
||||
#endif
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* smb_fs_sb.h
|
||||
*
|
||||
* Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SMB_FS_SB
|
||||
#define _SMB_FS_SB
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include "smb.h"
|
||||
|
||||
/*
|
||||
* Upper limit on the total number of active smb_request structs.
|
||||
*/
|
||||
#define MAX_REQUEST_HARD 256
|
||||
|
||||
enum smb_receive_state {
|
||||
SMB_RECV_START, /* No data read, looking for length + sig */
|
||||
SMB_RECV_HEADER, /* Reading the header data */
|
||||
SMB_RECV_HCOMPLETE, /* Done with the header */
|
||||
SMB_RECV_PARAM, /* Reading parameter words */
|
||||
SMB_RECV_DATA, /* Reading data bytes */
|
||||
SMB_RECV_END, /* End of request */
|
||||
SMB_RECV_DROP, /* Dropping this SMB */
|
||||
SMB_RECV_REQUEST, /* Received a request and not a reply */
|
||||
};
|
||||
|
||||
/* structure access macros */
|
||||
#define server_from_inode(inode) SMB_SB((inode)->i_sb)
|
||||
#define server_from_dentry(dentry) SMB_SB((dentry)->d_sb)
|
||||
#define SB_of(server) ((server)->super_block)
|
||||
|
||||
struct smb_sb_info {
|
||||
/* List of all smbfs superblocks */
|
||||
struct list_head entry;
|
||||
|
||||
enum smb_conn_state state;
|
||||
struct file * sock_file;
|
||||
int conn_error;
|
||||
enum smb_receive_state rstate;
|
||||
|
||||
atomic_t nr_requests;
|
||||
struct list_head xmitq;
|
||||
struct list_head recvq;
|
||||
u16 mid;
|
||||
|
||||
struct smb_mount_data_kernel *mnt;
|
||||
|
||||
/* Connections are counted. Each time a new socket arrives,
|
||||
* generation is incremented.
|
||||
*/
|
||||
unsigned int generation;
|
||||
struct pid *conn_pid;
|
||||
struct smb_conn_opt opt;
|
||||
wait_queue_head_t conn_wq;
|
||||
int conn_complete;
|
||||
struct semaphore sem;
|
||||
|
||||
unsigned char header[SMB_HEADER_LEN + 20*2 + 2];
|
||||
u32 header_len;
|
||||
u32 smb_len;
|
||||
u32 smb_read;
|
||||
|
||||
/* We use our own data_ready callback, but need the original one */
|
||||
void *data_ready;
|
||||
|
||||
/* nls pointers for codepage conversions */
|
||||
struct nls_table *remote_nls;
|
||||
struct nls_table *local_nls;
|
||||
|
||||
struct smb_ops *ops;
|
||||
|
||||
struct super_block *super_block;
|
||||
|
||||
struct backing_dev_info bdi;
|
||||
};
|
||||
|
||||
static inline int
|
||||
smb_lock_server_interruptible(struct smb_sb_info *server)
|
||||
{
|
||||
return down_interruptible(&(server->sem));
|
||||
}
|
||||
|
||||
static inline void
|
||||
smb_lock_server(struct smb_sb_info *server)
|
||||
{
|
||||
down(&(server->sem));
|
||||
}
|
||||
|
||||
static inline void
|
||||
smb_unlock_server(struct smb_sb_info *server)
|
||||
{
|
||||
up(&(server->sem));
|
||||
}
|
||||
|
||||
#endif
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* smb_mount.h
|
||||
*
|
||||
* Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SMB_MOUNT_H
|
||||
#define _LINUX_SMB_MOUNT_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define SMB_MOUNT_VERSION 6
|
||||
|
||||
struct smb_mount_data {
|
||||
int version;
|
||||
__kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */
|
||||
__kernel_uid_t uid;
|
||||
__kernel_gid_t gid;
|
||||
__kernel_mode_t file_mode;
|
||||
__kernel_mode_t dir_mode;
|
||||
};
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* "vers" in big-endian */
|
||||
#define SMB_MOUNT_ASCII 0x76657273
|
||||
|
||||
#define SMB_MOUNT_OLDVERSION 6
|
||||
#undef SMB_MOUNT_VERSION
|
||||
#define SMB_MOUNT_VERSION 7
|
||||
|
||||
/* flags */
|
||||
#define SMB_MOUNT_WIN95 0x0001 /* Win 95 server */
|
||||
#define SMB_MOUNT_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */
|
||||
#define SMB_MOUNT_DIRATTR 0x0004 /* Use find_first for getattr */
|
||||
#define SMB_MOUNT_CASE 0x0008 /* Be case sensitive */
|
||||
#define SMB_MOUNT_UNICODE 0x0010 /* Server talks unicode */
|
||||
#define SMB_MOUNT_UID 0x0020 /* Use user specified uid */
|
||||
#define SMB_MOUNT_GID 0x0040 /* Use user specified gid */
|
||||
#define SMB_MOUNT_FMODE 0x0080 /* Use user specified file mode */
|
||||
#define SMB_MOUNT_DMODE 0x0100 /* Use user specified dir mode */
|
||||
|
||||
struct smb_mount_data_kernel {
|
||||
int version;
|
||||
|
||||
uid_t mounted_uid; /* Who may umount() this filesystem? */
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
mode_t file_mode;
|
||||
mode_t dir_mode;
|
||||
|
||||
u32 flags;
|
||||
|
||||
/* maximum age in jiffies (inode, dentry and dircache) */
|
||||
int ttl;
|
||||
|
||||
struct smb_nls_codepage codepage;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,8 +0,0 @@
|
||||
Smbfs is a filesystem that implements the SMB protocol, which is the
|
||||
protocol used by Windows for Workgroups, Windows 95 and Windows NT.
|
||||
Smbfs was inspired by Samba, the program written by Andrew Tridgell
|
||||
that turns any Unix host into a file server for DOS or Windows clients.
|
||||
|
||||
Smbfs is a SMB client, but uses parts of samba for its operation. For
|
||||
more info on samba, including documentation, please go to
|
||||
http://www.samba.org/ and then on to your nearest mirror.
|
@ -1,343 +0,0 @@
|
||||
/*
|
||||
* smbiod.c
|
||||
*
|
||||
* Copyright (C) 2000, Charles Loep / Corel Corp.
|
||||
* Copyright (C) 2001, Urban Widmark
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "smb_fs.h"
|
||||
#include "smbno.h"
|
||||
#include "smb_mount.h"
|
||||
#include "smb_debug.h"
|
||||
#include "request.h"
|
||||
#include "proto.h"
|
||||
|
||||
enum smbiod_state {
|
||||
SMBIOD_DEAD,
|
||||
SMBIOD_STARTING,
|
||||
SMBIOD_RUNNING,
|
||||
};
|
||||
|
||||
static enum smbiod_state smbiod_state = SMBIOD_DEAD;
|
||||
static struct task_struct *smbiod_thread;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait);
|
||||
static LIST_HEAD(smb_servers);
|
||||
static DEFINE_SPINLOCK(servers_lock);
|
||||
|
||||
#define SMBIOD_DATA_READY (1<<0)
|
||||
static unsigned long smbiod_flags;
|
||||
|
||||
static int smbiod(void *);
|
||||
static int smbiod_start(void);
|
||||
|
||||
/*
|
||||
* called when there's work for us to do
|
||||
*/
|
||||
void smbiod_wake_up(void)
|
||||
{
|
||||
if (smbiod_state == SMBIOD_DEAD)
|
||||
return;
|
||||
set_bit(SMBIOD_DATA_READY, &smbiod_flags);
|
||||
wake_up_interruptible(&smbiod_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* start smbiod if none is running
|
||||
*/
|
||||
static int smbiod_start(void)
|
||||
{
|
||||
struct task_struct *tsk;
|
||||
int err = 0;
|
||||
|
||||
if (smbiod_state != SMBIOD_DEAD)
|
||||
return 0;
|
||||
smbiod_state = SMBIOD_STARTING;
|
||||
__module_get(THIS_MODULE);
|
||||
spin_unlock(&servers_lock);
|
||||
tsk = kthread_run(smbiod, NULL, "smbiod");
|
||||
if (IS_ERR(tsk)) {
|
||||
err = PTR_ERR(tsk);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
spin_lock(&servers_lock);
|
||||
if (err < 0) {
|
||||
smbiod_state = SMBIOD_DEAD;
|
||||
smbiod_thread = NULL;
|
||||
} else {
|
||||
smbiod_state = SMBIOD_RUNNING;
|
||||
smbiod_thread = tsk;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* register a server & start smbiod if necessary
|
||||
*/
|
||||
int smbiod_register_server(struct smb_sb_info *server)
|
||||
{
|
||||
int ret;
|
||||
spin_lock(&servers_lock);
|
||||
list_add(&server->entry, &smb_servers);
|
||||
VERBOSE("%p\n", server);
|
||||
ret = smbiod_start();
|
||||
spin_unlock(&servers_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unregister a server
|
||||
* Must be called with the server lock held.
|
||||
*/
|
||||
void smbiod_unregister_server(struct smb_sb_info *server)
|
||||
{
|
||||
spin_lock(&servers_lock);
|
||||
list_del_init(&server->entry);
|
||||
VERBOSE("%p\n", server);
|
||||
spin_unlock(&servers_lock);
|
||||
|
||||
smbiod_wake_up();
|
||||
smbiod_flush(server);
|
||||
}
|
||||
|
||||
void smbiod_flush(struct smb_sb_info *server)
|
||||
{
|
||||
struct list_head *tmp, *n;
|
||||
struct smb_request *req;
|
||||
|
||||
list_for_each_safe(tmp, n, &server->xmitq) {
|
||||
req = list_entry(tmp, struct smb_request, rq_queue);
|
||||
req->rq_errno = -EIO;
|
||||
list_del_init(&req->rq_queue);
|
||||
smb_rput(req);
|
||||
wake_up_interruptible(&req->rq_wait);
|
||||
}
|
||||
list_for_each_safe(tmp, n, &server->recvq) {
|
||||
req = list_entry(tmp, struct smb_request, rq_queue);
|
||||
req->rq_errno = -EIO;
|
||||
list_del_init(&req->rq_queue);
|
||||
smb_rput(req);
|
||||
wake_up_interruptible(&req->rq_wait);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wake up smbmount and make it reconnect to the server.
|
||||
* This must be called with the server locked.
|
||||
*
|
||||
* FIXME: add smbconnect version to this
|
||||
*/
|
||||
int smbiod_retry(struct smb_sb_info *server)
|
||||
{
|
||||
struct list_head *head;
|
||||
struct smb_request *req;
|
||||
struct pid *pid = get_pid(server->conn_pid);
|
||||
int result = 0;
|
||||
|
||||
VERBOSE("state: %d\n", server->state);
|
||||
if (server->state == CONN_VALID || server->state == CONN_RETRYING)
|
||||
goto out;
|
||||
|
||||
smb_invalidate_inodes(server);
|
||||
|
||||
/*
|
||||
* Some requests are meaningless after a retry, so we abort them.
|
||||
* One example are all requests using 'fileid' since the files are
|
||||
* closed on retry.
|
||||
*/
|
||||
head = server->xmitq.next;
|
||||
while (head != &server->xmitq) {
|
||||
req = list_entry(head, struct smb_request, rq_queue);
|
||||
head = head->next;
|
||||
|
||||
req->rq_bytes_sent = 0;
|
||||
if (req->rq_flags & SMB_REQ_NORETRY) {
|
||||
VERBOSE("aborting request %p on xmitq\n", req);
|
||||
req->rq_errno = -EIO;
|
||||
list_del_init(&req->rq_queue);
|
||||
smb_rput(req);
|
||||
wake_up_interruptible(&req->rq_wait);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: test the code for retrying request we already sent
|
||||
*/
|
||||
head = server->recvq.next;
|
||||
while (head != &server->recvq) {
|
||||
req = list_entry(head, struct smb_request, rq_queue);
|
||||
head = head->next;
|
||||
#if 0
|
||||
if (req->rq_flags & SMB_REQ_RETRY) {
|
||||
/* must move the request to the xmitq */
|
||||
VERBOSE("retrying request %p on recvq\n", req);
|
||||
list_move(&req->rq_queue, &server->xmitq);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
VERBOSE("aborting request %p on recvq\n", req);
|
||||
/* req->rq_rcls = ???; */ /* FIXME: set smb error code too? */
|
||||
req->rq_errno = -EIO;
|
||||
list_del_init(&req->rq_queue);
|
||||
smb_rput(req);
|
||||
wake_up_interruptible(&req->rq_wait);
|
||||
}
|
||||
|
||||
smb_close_socket(server);
|
||||
|
||||
if (!pid) {
|
||||
/* FIXME: this is fatal, umount? */
|
||||
printk(KERN_ERR "smb_retry: no connection process\n");
|
||||
server->state = CONN_RETRIED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change state so that only one retry per server will be started.
|
||||
*/
|
||||
server->state = CONN_RETRYING;
|
||||
|
||||
/*
|
||||
* Note: use the "priv" flag, as a user process may need to reconnect.
|
||||
*/
|
||||
result = kill_pid(pid, SIGUSR1, 1);
|
||||
if (result) {
|
||||
/* FIXME: this is most likely fatal, umount? */
|
||||
printk(KERN_ERR "smb_retry: signal failed [%d]\n", result);
|
||||
goto out;
|
||||
}
|
||||
VERBOSE("signalled pid %d\n", pid_nr(pid));
|
||||
|
||||
/* FIXME: The retried requests should perhaps get a "time boost". */
|
||||
|
||||
out:
|
||||
put_pid(pid);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently handles lockingX packets.
|
||||
*/
|
||||
static void smbiod_handle_request(struct smb_sb_info *server)
|
||||
{
|
||||
PARANOIA("smbiod got a request ... and we don't implement oplocks!\n");
|
||||
server->rstate = SMB_RECV_DROP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do some IO for one server.
|
||||
*/
|
||||
static void smbiod_doio(struct smb_sb_info *server)
|
||||
{
|
||||
int result;
|
||||
int maxwork = 7;
|
||||
|
||||
if (server->state != CONN_VALID)
|
||||
goto out;
|
||||
|
||||
do {
|
||||
result = smb_request_recv(server);
|
||||
if (result < 0) {
|
||||
server->state = CONN_INVALID;
|
||||
smbiod_retry(server);
|
||||
goto out; /* reconnecting is slow */
|
||||
} else if (server->rstate == SMB_RECV_REQUEST)
|
||||
smbiod_handle_request(server);
|
||||
} while (result > 0 && maxwork-- > 0);
|
||||
|
||||
/*
|
||||
* If there is more to read then we want to be sure to wake up again.
|
||||
*/
|
||||
if (server->state != CONN_VALID)
|
||||
goto out;
|
||||
if (smb_recv_available(server) > 0)
|
||||
set_bit(SMBIOD_DATA_READY, &smbiod_flags);
|
||||
|
||||
do {
|
||||
result = smb_request_send_server(server);
|
||||
if (result < 0) {
|
||||
server->state = CONN_INVALID;
|
||||
smbiod_retry(server);
|
||||
goto out; /* reconnecting is slow */
|
||||
}
|
||||
} while (result > 0);
|
||||
|
||||
/*
|
||||
* If the last request was not sent out we want to wake up again.
|
||||
*/
|
||||
if (!list_empty(&server->xmitq))
|
||||
set_bit(SMBIOD_DATA_READY, &smbiod_flags);
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* smbiod kernel thread
|
||||
*/
|
||||
static int smbiod(void *unused)
|
||||
{
|
||||
VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);
|
||||
|
||||
for (;;) {
|
||||
struct smb_sb_info *server;
|
||||
struct list_head *pos, *n;
|
||||
|
||||
/* FIXME: Use poll? */
|
||||
wait_event_interruptible(smbiod_wait,
|
||||
test_bit(SMBIOD_DATA_READY, &smbiod_flags));
|
||||
if (signal_pending(current)) {
|
||||
spin_lock(&servers_lock);
|
||||
smbiod_state = SMBIOD_DEAD;
|
||||
spin_unlock(&servers_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
clear_bit(SMBIOD_DATA_READY, &smbiod_flags);
|
||||
|
||||
spin_lock(&servers_lock);
|
||||
if (list_empty(&smb_servers)) {
|
||||
smbiod_state = SMBIOD_DEAD;
|
||||
spin_unlock(&servers_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
list_for_each_safe(pos, n, &smb_servers) {
|
||||
server = list_entry(pos, struct smb_sb_info, entry);
|
||||
VERBOSE("checking server %p\n", server);
|
||||
|
||||
if (server->state == CONN_VALID) {
|
||||
spin_unlock(&servers_lock);
|
||||
|
||||
smb_lock_server(server);
|
||||
smbiod_doio(server);
|
||||
smb_unlock_server(server);
|
||||
|
||||
spin_lock(&servers_lock);
|
||||
}
|
||||
}
|
||||
spin_unlock(&servers_lock);
|
||||
}
|
||||
|
||||
VERBOSE("SMB Kernel thread exiting (%d) ...\n", current->pid);
|
||||
module_put_and_exit(0);
|
||||
}
|
@ -1,363 +0,0 @@
|
||||
#ifndef _SMBNO_H_
|
||||
#define _SMBNO_H_
|
||||
|
||||
/* these define the attribute byte as seen by DOS */
|
||||
#define aRONLY (1L<<0)
|
||||
#define aHIDDEN (1L<<1)
|
||||
#define aSYSTEM (1L<<2)
|
||||
#define aVOLID (1L<<3)
|
||||
#define aDIR (1L<<4)
|
||||
#define aARCH (1L<<5)
|
||||
|
||||
/* error classes */
|
||||
#define SUCCESS 0 /* The request was successful. */
|
||||
#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */
|
||||
#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/
|
||||
#define ERRHRD 0x03 /* Error is an hardware error. */
|
||||
#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
|
||||
|
||||
/* SMB X/Open error codes for the ERRdos error class */
|
||||
|
||||
#define ERRbadfunc 1 /* Invalid function (or system call) */
|
||||
#define ERRbadfile 2 /* File not found (pathname error) */
|
||||
#define ERRbadpath 3 /* Directory not found */
|
||||
#define ERRnofids 4 /* Too many open files */
|
||||
#define ERRnoaccess 5 /* Access denied */
|
||||
#define ERRbadfid 6 /* Invalid fid */
|
||||
#define ERRbadmcb 7 /* Memory control blocks destroyed */
|
||||
#define ERRnomem 8 /* Out of memory */
|
||||
#define ERRbadmem 9 /* Invalid memory block address */
|
||||
#define ERRbadenv 10 /* Invalid environment */
|
||||
#define ERRbadformat 11 /* Invalid format */
|
||||
#define ERRbadaccess 12 /* Invalid open mode */
|
||||
#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
|
||||
#define ERRres 14 /* reserved */
|
||||
#define ERRbaddrive 15 /* Invalid drive */
|
||||
#define ERRremcd 16 /* Attempt to delete current directory */
|
||||
#define ERRdiffdevice 17 /* rename/move across different filesystems */
|
||||
#define ERRnofiles 18 /* no more files found in file search */
|
||||
#define ERRbadshare 32 /* Share mode on file conflict with open mode */
|
||||
#define ERRlock 33 /* Lock request conflicts with existing lock */
|
||||
#define ERRfilexists 80 /* File in operation already exists */
|
||||
#define ERRbadpipe 230 /* Named pipe invalid */
|
||||
#define ERRpipebusy 231 /* All instances of pipe are busy */
|
||||
#define ERRpipeclosing 232 /* named pipe close in progress */
|
||||
#define ERRnotconnected 233 /* No process on other end of named pipe */
|
||||
#define ERRmoredata 234 /* More data to be returned */
|
||||
|
||||
#define ERROR_INVALID_PARAMETER 87
|
||||
#define ERROR_DISK_FULL 112
|
||||
#define ERROR_INVALID_NAME 123
|
||||
#define ERROR_DIR_NOT_EMPTY 145
|
||||
#define ERROR_NOT_LOCKED 158
|
||||
#define ERROR_ALREADY_EXISTS 183 /* see also 80 ? */
|
||||
#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */
|
||||
#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not supported */
|
||||
|
||||
/* Error codes for the ERRSRV class */
|
||||
|
||||
#define ERRerror 1 /* Non specific error code */
|
||||
#define ERRbadpw 2 /* Bad password */
|
||||
#define ERRbadtype 3 /* reserved */
|
||||
#define ERRaccess 4 /* No permissions to do the requested operation */
|
||||
#define ERRinvnid 5 /* tid invalid */
|
||||
#define ERRinvnetname 6 /* Invalid servername */
|
||||
#define ERRinvdevice 7 /* Invalid device */
|
||||
#define ERRqfull 49 /* Print queue full */
|
||||
#define ERRqtoobig 50 /* Queued item too big */
|
||||
#define ERRinvpfid 52 /* Invalid print file in smb_fid */
|
||||
#define ERRsmbcmd 64 /* Unrecognised command */
|
||||
#define ERRsrverror 65 /* smb server internal error */
|
||||
#define ERRfilespecs 67 /* fid and pathname invalid combination */
|
||||
#define ERRbadlink 68 /* reserved */
|
||||
#define ERRbadpermits 69 /* Access specified for a file is not valid */
|
||||
#define ERRbadpid 70 /* reserved */
|
||||
#define ERRsetattrmode 71 /* attribute mode invalid */
|
||||
#define ERRpaused 81 /* Message server paused */
|
||||
#define ERRmsgoff 82 /* Not receiving messages */
|
||||
#define ERRnoroom 83 /* No room for message */
|
||||
#define ERRrmuns 87 /* too many remote usernames */
|
||||
#define ERRtimeout 88 /* operation timed out */
|
||||
#define ERRnoresource 89 /* No resources currently available for request. */
|
||||
#define ERRtoomanyuids 90 /* too many userids */
|
||||
#define ERRbaduid 91 /* bad userid */
|
||||
#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */
|
||||
#define ERRuseSTD 251 /* temporarily unable to use raw mode, use std.mode */
|
||||
#define ERRcontMPX 252 /* resume MPX mode */
|
||||
#define ERRbadPW /* reserved */
|
||||
#define ERRnosupport 0xFFFF
|
||||
|
||||
/* Error codes for the ERRHRD class */
|
||||
|
||||
#define ERRnowrite 19 /* read only media */
|
||||
#define ERRbadunit 20 /* Unknown device */
|
||||
#define ERRnotready 21 /* Drive not ready */
|
||||
#define ERRbadcmd 22 /* Unknown command */
|
||||
#define ERRdata 23 /* Data (CRC) error */
|
||||
#define ERRbadreq 24 /* Bad request structure length */
|
||||
#define ERRseek 25
|
||||
#define ERRbadmedia 26
|
||||
#define ERRbadsector 27
|
||||
#define ERRnopaper 28
|
||||
#define ERRwrite 29 /* write fault */
|
||||
#define ERRread 30 /* read fault */
|
||||
#define ERRgeneral 31 /* General hardware failure */
|
||||
#define ERRwrongdisk 34
|
||||
#define ERRFCBunavail 35
|
||||
#define ERRsharebufexc 36 /* share buffer exceeded */
|
||||
#define ERRdiskfull 39
|
||||
|
||||
/*
|
||||
* Access modes when opening a file
|
||||
*/
|
||||
#define SMB_ACCMASK 0x0003
|
||||
#define SMB_O_RDONLY 0x0000
|
||||
#define SMB_O_WRONLY 0x0001
|
||||
#define SMB_O_RDWR 0x0002
|
||||
|
||||
/* offsets into message for common items */
|
||||
#define smb_com 8
|
||||
#define smb_rcls 9
|
||||
#define smb_reh 10
|
||||
#define smb_err 11
|
||||
#define smb_flg 13
|
||||
#define smb_flg2 14
|
||||
#define smb_reb 13
|
||||
#define smb_tid 28
|
||||
#define smb_pid 30
|
||||
#define smb_uid 32
|
||||
#define smb_mid 34
|
||||
#define smb_wct 36
|
||||
#define smb_vwv 37
|
||||
#define smb_vwv0 37
|
||||
#define smb_vwv1 39
|
||||
#define smb_vwv2 41
|
||||
#define smb_vwv3 43
|
||||
#define smb_vwv4 45
|
||||
#define smb_vwv5 47
|
||||
#define smb_vwv6 49
|
||||
#define smb_vwv7 51
|
||||
#define smb_vwv8 53
|
||||
#define smb_vwv9 55
|
||||
#define smb_vwv10 57
|
||||
#define smb_vwv11 59
|
||||
#define smb_vwv12 61
|
||||
#define smb_vwv13 63
|
||||
#define smb_vwv14 65
|
||||
|
||||
/* these are the trans2 sub fields for primary requests */
|
||||
#define smb_tpscnt smb_vwv0
|
||||
#define smb_tdscnt smb_vwv1
|
||||
#define smb_mprcnt smb_vwv2
|
||||
#define smb_mdrcnt smb_vwv3
|
||||
#define smb_msrcnt smb_vwv4
|
||||
#define smb_flags smb_vwv5
|
||||
#define smb_timeout smb_vwv6
|
||||
#define smb_pscnt smb_vwv9
|
||||
#define smb_psoff smb_vwv10
|
||||
#define smb_dscnt smb_vwv11
|
||||
#define smb_dsoff smb_vwv12
|
||||
#define smb_suwcnt smb_vwv13
|
||||
#define smb_setup smb_vwv14
|
||||
#define smb_setup0 smb_setup
|
||||
#define smb_setup1 (smb_setup+2)
|
||||
#define smb_setup2 (smb_setup+4)
|
||||
|
||||
/* these are for the secondary requests */
|
||||
#define smb_spscnt smb_vwv2
|
||||
#define smb_spsoff smb_vwv3
|
||||
#define smb_spsdisp smb_vwv4
|
||||
#define smb_sdscnt smb_vwv5
|
||||
#define smb_sdsoff smb_vwv6
|
||||
#define smb_sdsdisp smb_vwv7
|
||||
#define smb_sfid smb_vwv8
|
||||
|
||||
/* and these for responses */
|
||||
#define smb_tprcnt smb_vwv0
|
||||
#define smb_tdrcnt smb_vwv1
|
||||
#define smb_prcnt smb_vwv3
|
||||
#define smb_proff smb_vwv4
|
||||
#define smb_prdisp smb_vwv5
|
||||
#define smb_drcnt smb_vwv6
|
||||
#define smb_droff smb_vwv7
|
||||
#define smb_drdisp smb_vwv8
|
||||
|
||||
/* the complete */
|
||||
#define SMBmkdir 0x00 /* create directory */
|
||||
#define SMBrmdir 0x01 /* delete directory */
|
||||
#define SMBopen 0x02 /* open file */
|
||||
#define SMBcreate 0x03 /* create file */
|
||||
#define SMBclose 0x04 /* close file */
|
||||
#define SMBflush 0x05 /* flush file */
|
||||
#define SMBunlink 0x06 /* delete file */
|
||||
#define SMBmv 0x07 /* rename file */
|
||||
#define SMBgetatr 0x08 /* get file attributes */
|
||||
#define SMBsetatr 0x09 /* set file attributes */
|
||||
#define SMBread 0x0A /* read from file */
|
||||
#define SMBwrite 0x0B /* write to file */
|
||||
#define SMBlock 0x0C /* lock byte range */
|
||||
#define SMBunlock 0x0D /* unlock byte range */
|
||||
#define SMBctemp 0x0E /* create temporary file */
|
||||
#define SMBmknew 0x0F /* make new file */
|
||||
#define SMBchkpth 0x10 /* check directory path */
|
||||
#define SMBexit 0x11 /* process exit */
|
||||
#define SMBlseek 0x12 /* seek */
|
||||
#define SMBtcon 0x70 /* tree connect */
|
||||
#define SMBtconX 0x75 /* tree connect and X*/
|
||||
#define SMBtdis 0x71 /* tree disconnect */
|
||||
#define SMBnegprot 0x72 /* negotiate protocol */
|
||||
#define SMBdskattr 0x80 /* get disk attributes */
|
||||
#define SMBsearch 0x81 /* search directory */
|
||||
#define SMBsplopen 0xC0 /* open print spool file */
|
||||
#define SMBsplwr 0xC1 /* write to print spool file */
|
||||
#define SMBsplclose 0xC2 /* close print spool file */
|
||||
#define SMBsplretq 0xC3 /* return print queue */
|
||||
#define SMBsends 0xD0 /* send single block message */
|
||||
#define SMBsendb 0xD1 /* send broadcast message */
|
||||
#define SMBfwdname 0xD2 /* forward user name */
|
||||
#define SMBcancelf 0xD3 /* cancel forward */
|
||||
#define SMBgetmac 0xD4 /* get machine name */
|
||||
#define SMBsendstrt 0xD5 /* send start of multi-block message */
|
||||
#define SMBsendend 0xD6 /* send end of multi-block message */
|
||||
#define SMBsendtxt 0xD7 /* send text of multi-block message */
|
||||
|
||||
/* Core+ protocol */
|
||||
#define SMBlockread 0x13 /* Lock a range and read */
|
||||
#define SMBwriteunlock 0x14 /* Unlock a range then write */
|
||||
#define SMBreadbraw 0x1a /* read a block of data with no smb header */
|
||||
#define SMBwritebraw 0x1d /* write a block of data with no smb header */
|
||||
#define SMBwritec 0x20 /* secondary write request */
|
||||
#define SMBwriteclose 0x2c /* write a file then close it */
|
||||
|
||||
/* dos extended protocol */
|
||||
#define SMBreadBraw 0x1A /* read block raw */
|
||||
#define SMBreadBmpx 0x1B /* read block multiplexed */
|
||||
#define SMBreadBs 0x1C /* read block (secondary response) */
|
||||
#define SMBwriteBraw 0x1D /* write block raw */
|
||||
#define SMBwriteBmpx 0x1E /* write block multiplexed */
|
||||
#define SMBwriteBs 0x1F /* write block (secondary request) */
|
||||
#define SMBwriteC 0x20 /* write complete response */
|
||||
#define SMBsetattrE 0x22 /* set file attributes expanded */
|
||||
#define SMBgetattrE 0x23 /* get file attributes expanded */
|
||||
#define SMBlockingX 0x24 /* lock/unlock byte ranges and X */
|
||||
#define SMBtrans 0x25 /* transaction - name, bytes in/out */
|
||||
#define SMBtranss 0x26 /* transaction (secondary request/response) */
|
||||
#define SMBioctl 0x27 /* IOCTL */
|
||||
#define SMBioctls 0x28 /* IOCTL (secondary request/response) */
|
||||
#define SMBcopy 0x29 /* copy */
|
||||
#define SMBmove 0x2A /* move */
|
||||
#define SMBecho 0x2B /* echo */
|
||||
#define SMBopenX 0x2D /* open and X */
|
||||
#define SMBreadX 0x2E /* read and X */
|
||||
#define SMBwriteX 0x2F /* write and X */
|
||||
#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */
|
||||
#define SMBtconX 0x75 /* tree connect and X */
|
||||
#define SMBffirst 0x82 /* find first */
|
||||
#define SMBfunique 0x83 /* find unique */
|
||||
#define SMBfclose 0x84 /* find close */
|
||||
#define SMBinvalid 0xFE /* invalid command */
|
||||
|
||||
|
||||
/* Extended 2.0 protocol */
|
||||
#define SMBtrans2 0x32 /* TRANS2 protocol set */
|
||||
#define SMBtranss2 0x33 /* TRANS2 protocol set, secondary command */
|
||||
#define SMBfindclose 0x34 /* Terminate a TRANSACT2_FINDFIRST */
|
||||
#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
|
||||
#define SMBulogoffX 0x74 /* user logoff */
|
||||
|
||||
/* these are the TRANS2 sub commands */
|
||||
#define TRANSACT2_OPEN 0
|
||||
#define TRANSACT2_FINDFIRST 1
|
||||
#define TRANSACT2_FINDNEXT 2
|
||||
#define TRANSACT2_QFSINFO 3
|
||||
#define TRANSACT2_SETFSINFO 4
|
||||
#define TRANSACT2_QPATHINFO 5
|
||||
#define TRANSACT2_SETPATHINFO 6
|
||||
#define TRANSACT2_QFILEINFO 7
|
||||
#define TRANSACT2_SETFILEINFO 8
|
||||
#define TRANSACT2_FSCTL 9
|
||||
#define TRANSACT2_IOCTL 10
|
||||
#define TRANSACT2_FINDNOTIFYFIRST 11
|
||||
#define TRANSACT2_FINDNOTIFYNEXT 12
|
||||
#define TRANSACT2_MKDIR 13
|
||||
|
||||
/* Information Levels - Shared? */
|
||||
#define SMB_INFO_STANDARD 1
|
||||
#define SMB_INFO_QUERY_EA_SIZE 2
|
||||
#define SMB_INFO_QUERY_EAS_FROM_LIST 3
|
||||
#define SMB_INFO_QUERY_ALL_EAS 4
|
||||
#define SMB_INFO_IS_NAME_VALID 6
|
||||
|
||||
/* Information Levels - TRANSACT2_FINDFIRST */
|
||||
#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
|
||||
#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
|
||||
#define SMB_FIND_FILE_NAMES_INFO 0x103
|
||||
#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
|
||||
|
||||
/* Information Levels - TRANSACT2_QPATHINFO */
|
||||
#define SMB_QUERY_FILE_BASIC_INFO 0x101
|
||||
#define SMB_QUERY_FILE_STANDARD_INFO 0x102
|
||||
#define SMB_QUERY_FILE_EA_INFO 0x103
|
||||
#define SMB_QUERY_FILE_NAME_INFO 0x104
|
||||
#define SMB_QUERY_FILE_ALL_INFO 0x107
|
||||
#define SMB_QUERY_FILE_ALT_NAME_INFO 0x108
|
||||
#define SMB_QUERY_FILE_STREAM_INFO 0x109
|
||||
#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10b
|
||||
|
||||
/* Information Levels - TRANSACT2_SETFILEINFO */
|
||||
#define SMB_SET_FILE_BASIC_INFO 0x101
|
||||
#define SMB_SET_FILE_DISPOSITION_INFO 0x102
|
||||
#define SMB_SET_FILE_ALLOCATION_INFO 0x103
|
||||
#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
|
||||
|
||||
/* smb_flg field flags */
|
||||
#define SMB_FLAGS_SUPPORT_LOCKREAD 0x01
|
||||
#define SMB_FLAGS_CLIENT_BUF_AVAIL 0x02
|
||||
#define SMB_FLAGS_RESERVED 0x04
|
||||
#define SMB_FLAGS_CASELESS_PATHNAMES 0x08
|
||||
#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10
|
||||
#define SMB_FLAGS_REQUEST_OPLOCK 0x20
|
||||
#define SMB_FLAGS_REQUEST_BATCH_OPLOCK 0x40
|
||||
#define SMB_FLAGS_REPLY 0x80
|
||||
|
||||
/* smb_flg2 field flags (samba-2.2.0/source/include/smb.h) */
|
||||
#define SMB_FLAGS2_LONG_PATH_COMPONENTS 0x0001
|
||||
#define SMB_FLAGS2_EXTENDED_ATTRIBUTES 0x0002
|
||||
#define SMB_FLAGS2_DFS_PATHNAMES 0x1000
|
||||
#define SMB_FLAGS2_READ_PERMIT_NO_EXECUTE 0x2000
|
||||
#define SMB_FLAGS2_32_BIT_ERROR_CODES 0x4000
|
||||
#define SMB_FLAGS2_UNICODE_STRINGS 0x8000
|
||||
|
||||
|
||||
/*
|
||||
* UNIX stuff (from samba trans2.h)
|
||||
*/
|
||||
#define MIN_UNIX_INFO_LEVEL 0x200
|
||||
#define MAX_UNIX_INFO_LEVEL 0x2FF
|
||||
#define SMB_FIND_FILE_UNIX 0x202
|
||||
#define SMB_QUERY_FILE_UNIX_BASIC 0x200
|
||||
#define SMB_QUERY_FILE_UNIX_LINK 0x201
|
||||
#define SMB_QUERY_FILE_UNIX_HLINK 0x202
|
||||
#define SMB_SET_FILE_UNIX_BASIC 0x200
|
||||
#define SMB_SET_FILE_UNIX_LINK 0x201
|
||||
#define SMB_SET_FILE_UNIX_HLINK 0x203
|
||||
#define SMB_QUERY_CIFS_UNIX_INFO 0x200
|
||||
|
||||
/* values which means "don't change it" */
|
||||
#define SMB_MODE_NO_CHANGE 0xFFFFFFFF
|
||||
#define SMB_UID_NO_CHANGE 0xFFFFFFFF
|
||||
#define SMB_GID_NO_CHANGE 0xFFFFFFFF
|
||||
#define SMB_TIME_NO_CHANGE 0xFFFFFFFFFFFFFFFFULL
|
||||
#define SMB_SIZE_NO_CHANGE 0xFFFFFFFFFFFFFFFFULL
|
||||
|
||||
/* UNIX filetype mappings. */
|
||||
#define UNIX_TYPE_FILE 0
|
||||
#define UNIX_TYPE_DIR 1
|
||||
#define UNIX_TYPE_SYMLINK 2
|
||||
#define UNIX_TYPE_CHARDEV 3
|
||||
#define UNIX_TYPE_BLKDEV 4
|
||||
#define UNIX_TYPE_FIFO 5
|
||||
#define UNIX_TYPE_SOCKET 6
|
||||
#define UNIX_TYPE_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
#endif /* _SMBNO_H_ */
|
@ -1,385 +0,0 @@
|
||||
/*
|
||||
* sock.c
|
||||
*
|
||||
* Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
|
||||
* Copyright (C) 1997 by Volker Lendecke
|
||||
*
|
||||
* Please add a note about your changes to smbfs in the ChangeLog file.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/scm.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/ioctls.h>
|
||||
|
||||
#include "smb_fs.h"
|
||||
#include "smb.h"
|
||||
#include "smbno.h"
|
||||
#include "smb_debug.h"
|
||||
#include "proto.h"
|
||||
#include "request.h"
|
||||
|
||||
|
||||
static int
|
||||
_recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags)
|
||||
{
|
||||
struct kvec iov = {ubuf, size};
|
||||
struct msghdr msg = {.msg_flags = flags};
|
||||
msg.msg_flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
|
||||
return kernel_recvmsg(socket, &msg, &iov, 1, size, msg.msg_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the server this socket belongs to
|
||||
*/
|
||||
static struct smb_sb_info *
|
||||
server_from_socket(struct socket *socket)
|
||||
{
|
||||
return socket->sk->sk_user_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when there is data on the socket.
|
||||
*/
|
||||
void
|
||||
smb_data_ready(struct sock *sk, int len)
|
||||
{
|
||||
struct smb_sb_info *server = server_from_socket(sk->sk_socket);
|
||||
void (*data_ready)(struct sock *, int) = server->data_ready;
|
||||
|
||||
data_ready(sk, len);
|
||||
VERBOSE("(%p, %d)\n", sk, len);
|
||||
smbiod_wake_up();
|
||||
}
|
||||
|
||||
int
|
||||
smb_valid_socket(struct inode * inode)
|
||||
{
|
||||
return (inode && S_ISSOCK(inode->i_mode) &&
|
||||
SOCKET_I(inode)->type == SOCK_STREAM);
|
||||
}
|
||||
|
||||
static struct socket *
|
||||
server_sock(struct smb_sb_info *server)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
if (server && (file = server->sock_file))
|
||||
{
|
||||
#ifdef SMBFS_PARANOIA
|
||||
if (!smb_valid_socket(file->f_path.dentry->d_inode))
|
||||
PARANOIA("bad socket!\n");
|
||||
#endif
|
||||
return SOCKET_I(file->f_path.dentry->d_inode);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
smb_close_socket(struct smb_sb_info *server)
|
||||
{
|
||||
struct file * file = server->sock_file;
|
||||
|
||||
if (file) {
|
||||
struct socket *sock = server_sock(server);
|
||||
|
||||
VERBOSE("closing socket %p\n", sock);
|
||||
sock->sk->sk_data_ready = server->data_ready;
|
||||
server->sock_file = NULL;
|
||||
fput(file);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
smb_get_length(struct socket *socket, unsigned char *header)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = _recvfrom(socket, header, 4, MSG_PEEK);
|
||||
if (result == -EAGAIN)
|
||||
return -ENODATA;
|
||||
if (result < 0) {
|
||||
PARANOIA("recv error = %d\n", -result);
|
||||
return result;
|
||||
}
|
||||
if (result < 4)
|
||||
return -ENODATA;
|
||||
|
||||
switch (header[0]) {
|
||||
case 0x00:
|
||||
case 0x82:
|
||||
break;
|
||||
|
||||
case 0x85:
|
||||
DEBUG1("Got SESSION KEEP ALIVE\n");
|
||||
_recvfrom(socket, header, 4, 0); /* read away */
|
||||
return -ENODATA;
|
||||
|
||||
default:
|
||||
PARANOIA("Invalid NBT packet, code=%x\n", header[0]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* The length in the RFC NB header is the raw data length */
|
||||
return smb_len(header);
|
||||
}
|
||||
|
||||
int
|
||||
smb_recv_available(struct smb_sb_info *server)
|
||||
{
|
||||
mm_segment_t oldfs;
|
||||
int avail, err;
|
||||
struct socket *sock = server_sock(server);
|
||||
|
||||
oldfs = get_fs();
|
||||
set_fs(get_ds());
|
||||
err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
|
||||
set_fs(oldfs);
|
||||
return (err >= 0) ? avail : err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the kvec to move on 'n' bytes (from nfs/sunrpc)
|
||||
*/
|
||||
static int
|
||||
smb_move_iov(struct kvec **data, size_t *num, struct kvec *vec, unsigned amount)
|
||||
{
|
||||
struct kvec *iv = *data;
|
||||
int i;
|
||||
int len;
|
||||
|
||||
/*
|
||||
* Eat any sent kvecs
|
||||
*/
|
||||
while (iv->iov_len <= amount) {
|
||||
amount -= iv->iov_len;
|
||||
iv++;
|
||||
(*num)--;
|
||||
}
|
||||
|
||||
/*
|
||||
* And chew down the partial one
|
||||
*/
|
||||
vec[0].iov_len = iv->iov_len-amount;
|
||||
vec[0].iov_base =((unsigned char *)iv->iov_base)+amount;
|
||||
iv++;
|
||||
|
||||
len = vec[0].iov_len;
|
||||
|
||||
/*
|
||||
* And copy any others
|
||||
*/
|
||||
for (i = 1; i < *num; i++) {
|
||||
vec[i] = *iv++;
|
||||
len += vec[i].iov_len;
|
||||
}
|
||||
|
||||
*data = vec;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* smb_receive_header
|
||||
* Only called by the smbiod thread.
|
||||
*/
|
||||
int
|
||||
smb_receive_header(struct smb_sb_info *server)
|
||||
{
|
||||
struct socket *sock;
|
||||
int result = 0;
|
||||
unsigned char peek_buf[4];
|
||||
|
||||
result = -EIO;
|
||||
sock = server_sock(server);
|
||||
if (!sock)
|
||||
goto out;
|
||||
if (sock->sk->sk_state != TCP_ESTABLISHED)
|
||||
goto out;
|
||||
|
||||
if (!server->smb_read) {
|
||||
result = smb_get_length(sock, peek_buf);
|
||||
if (result < 0) {
|
||||
if (result == -ENODATA)
|
||||
result = 0;
|
||||
goto out;
|
||||
}
|
||||
server->smb_len = result + 4;
|
||||
|
||||
if (server->smb_len < SMB_HEADER_LEN) {
|
||||
PARANOIA("short packet: %d\n", result);
|
||||
server->rstate = SMB_RECV_DROP;
|
||||
result = -EIO;
|
||||
goto out;
|
||||
}
|
||||
if (server->smb_len > SMB_MAX_PACKET_SIZE) {
|
||||
PARANOIA("long packet: %d\n", result);
|
||||
server->rstate = SMB_RECV_DROP;
|
||||
result = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
result = _recvfrom(sock, server->header + server->smb_read,
|
||||
SMB_HEADER_LEN - server->smb_read, 0);
|
||||
VERBOSE("_recvfrom: %d\n", result);
|
||||
if (result < 0) {
|
||||
VERBOSE("receive error: %d\n", result);
|
||||
goto out;
|
||||
}
|
||||
server->smb_read += result;
|
||||
|
||||
if (server->smb_read == SMB_HEADER_LEN)
|
||||
server->rstate = SMB_RECV_HCOMPLETE;
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static char drop_buffer[PAGE_SIZE];
|
||||
|
||||
/*
|
||||
* smb_receive_drop - read and throw away the data
|
||||
* Only called by the smbiod thread.
|
||||
*
|
||||
* FIXME: we are in the kernel, could we just tell the socket that we want
|
||||
* to drop stuff from the buffer?
|
||||
*/
|
||||
int
|
||||
smb_receive_drop(struct smb_sb_info *server)
|
||||
{
|
||||
struct socket *sock;
|
||||
unsigned int flags;
|
||||
struct kvec iov;
|
||||
struct msghdr msg;
|
||||
int rlen = smb_len(server->header) - server->smb_read + 4;
|
||||
int result = -EIO;
|
||||
|
||||
if (rlen > PAGE_SIZE)
|
||||
rlen = PAGE_SIZE;
|
||||
|
||||
sock = server_sock(server);
|
||||
if (!sock)
|
||||
goto out;
|
||||
if (sock->sk->sk_state != TCP_ESTABLISHED)
|
||||
goto out;
|
||||
|
||||
flags = MSG_DONTWAIT | MSG_NOSIGNAL;
|
||||
iov.iov_base = drop_buffer;
|
||||
iov.iov_len = PAGE_SIZE;
|
||||
msg.msg_flags = flags;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = NULL;
|
||||
|
||||
result = kernel_recvmsg(sock, &msg, &iov, 1, rlen, flags);
|
||||
|
||||
VERBOSE("read: %d\n", result);
|
||||
if (result < 0) {
|
||||
VERBOSE("receive error: %d\n", result);
|
||||
goto out;
|
||||
}
|
||||
server->smb_read += result;
|
||||
|
||||
if (server->smb_read >= server->smb_len)
|
||||
server->rstate = SMB_RECV_END;
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* smb_receive
|
||||
* Only called by the smbiod thread.
|
||||
*/
|
||||
int
|
||||
smb_receive(struct smb_sb_info *server, struct smb_request *req)
|
||||
{
|
||||
struct socket *sock;
|
||||
unsigned int flags;
|
||||
struct kvec iov[4];
|
||||
struct kvec *p = req->rq_iov;
|
||||
size_t num = req->rq_iovlen;
|
||||
struct msghdr msg;
|
||||
int rlen;
|
||||
int result = -EIO;
|
||||
|
||||
sock = server_sock(server);
|
||||
if (!sock)
|
||||
goto out;
|
||||
if (sock->sk->sk_state != TCP_ESTABLISHED)
|
||||
goto out;
|
||||
|
||||
flags = MSG_DONTWAIT | MSG_NOSIGNAL;
|
||||
msg.msg_flags = flags;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = NULL;
|
||||
|
||||
/* Dont repeat bytes and count available bufferspace */
|
||||
rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd),
|
||||
(req->rq_rlen - req->rq_bytes_recvd));
|
||||
|
||||
result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);
|
||||
|
||||
VERBOSE("read: %d\n", result);
|
||||
if (result < 0) {
|
||||
VERBOSE("receive error: %d\n", result);
|
||||
goto out;
|
||||
}
|
||||
req->rq_bytes_recvd += result;
|
||||
server->smb_read += result;
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to send a SMB request. This may return after sending only parts of the
|
||||
* request. SMB_REQ_TRANSMITTED will be set if a request was fully sent.
|
||||
*
|
||||
* Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
|
||||
*/
|
||||
int
|
||||
smb_send_request(struct smb_request *req)
|
||||
{
|
||||
struct smb_sb_info *server = req->rq_server;
|
||||
struct socket *sock;
|
||||
struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
|
||||
int slen = req->rq_slen - req->rq_bytes_sent;
|
||||
int result = -EIO;
|
||||
struct kvec iov[4];
|
||||
struct kvec *p = req->rq_iov;
|
||||
size_t num = req->rq_iovlen;
|
||||
|
||||
sock = server_sock(server);
|
||||
if (!sock)
|
||||
goto out;
|
||||
if (sock->sk->sk_state != TCP_ESTABLISHED)
|
||||
goto out;
|
||||
|
||||
/* Dont repeat bytes */
|
||||
if (req->rq_bytes_sent)
|
||||
smb_move_iov(&p, &num, iov, req->rq_bytes_sent);
|
||||
|
||||
result = kernel_sendmsg(sock, &msg, p, num, slen);
|
||||
|
||||
if (result >= 0) {
|
||||
req->rq_bytes_sent += result;
|
||||
if (req->rq_bytes_sent >= req->rq_slen)
|
||||
req->rq_flags |= SMB_REQ_TRANSMITTED;
|
||||
}
|
||||
out:
|
||||
return result;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* symlink.c
|
||||
*
|
||||
* Copyright (C) 2002 by John Newbigin
|
||||
*
|
||||
* Please add a note about your changes to smbfs in the ChangeLog file.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include "smbno.h"
|
||||
#include "smb_fs.h"
|
||||
#include "smb_debug.h"
|
||||
#include "proto.h"
|
||||
|
||||
int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname)
|
||||
{
|
||||
DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry));
|
||||
|
||||
return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname);
|
||||
}
|
||||
|
||||
static void *smb_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
char *link = __getname();
|
||||
DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry));
|
||||
|
||||
if (!link) {
|
||||
link = ERR_PTR(-ENOMEM);
|
||||
} else {
|
||||
int len = smb_proc_read_link(server_from_dentry(dentry),
|
||||
dentry, link, PATH_MAX - 1);
|
||||
if (len < 0) {
|
||||
__putname(link);
|
||||
link = ERR_PTR(len);
|
||||
} else {
|
||||
link[len] = 0;
|
||||
}
|
||||
}
|
||||
nd_set_link(nd, link);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void smb_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
|
||||
{
|
||||
char *s = nd_get_link(nd);
|
||||
if (!IS_ERR(s))
|
||||
__putname(s);
|
||||
}
|
||||
|
||||
const struct inode_operations smb_link_inode_operations =
|
||||
{
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = smb_follow_link,
|
||||
.put_link = smb_put_link,
|
||||
};
|
Loading…
Reference in New Issue
Block a user