提交 939cbe5a 编写于 作者: A Arnd Bergmann 提交者: Greg Kroah-Hartman

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: NArnd Bergmann <arnd@arndb.de>
Cc: linux-cifs@vger.kernel.org
Cc: Jeff Layton <jlayton@redhat.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 561c5cf9
......@@ -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/
......
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.
#
# 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
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.
/*
* 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);
}
/*
* 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;
}
/*
* 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,
};
/*
* 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;
}
#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 */
此差异已折叠。
/*
* 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;
}
此差异已折叠。
/*
* 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;
此差异已折叠。
#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 */
/*
* 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
/*
* 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
/*
* 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 */
/*
* 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
/*
* 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
/*
* 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
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.
/*
* 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);
}
#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_ */
此差异已折叠。
/*
* 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,
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册