[patch] smbfs update for 2.4.0-test7-pre4

From: Urban Widmark (urban@svenskatest.se)
Date: Mon Aug 14 2000 - 15:17:31 EST


Hello

See beginning of patch for ChangeLog summary.

It containts the following maybe-not-really-just-a-bugfix changes:
* nls support
  Well tested, patches have been around >1 year. Is reportedly working
  fine with 16 bit nls and is doing utf8 just fine in my tests. It could
  perhaps been seen as a bug to get files with names shown as
  'r?ksm?rg?s'. Unless enabled it works like before.
* ascii mount options
  Adds to the interface vs smbmount so that future smbmounts can handle
  future extensions to smbfs without modification. Does not break existing
  userspace.

(To me) less obvious changes in detail:
* smb_retry:
  Doing interruptible_sleep_on_timeout will return immediately if current
  has a pending signal (no reason why it can't have one at that
  point). That in turn makes smbmount fail to access the mountpoint, it
  terminates and the mount stops working.

  This change makes smbfs survive a crashing mozilla.

* smb_data_callback:
  I believe the existing code could end up looping indefinitly while
  holding the BKL. This too is signal related. If peek_buf[0] == 0x85 and
  you have a pending signal the loop will never terminate. I have a report
  of lockup trouble, don't know yet if this fixes that.
  lock_kernel(); while(1) {} seems like a risky combination anyway.

Note that the patch adds an export of strsep too. Someone cared ... :)

Please apply.

/Urban

diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog
--- linux-2.4.0-test7-pre4-orig/fs/smbfs/ChangeLog Sat Aug 12 21:04:17 2000
+++ linux/fs/smbfs/ChangeLog Mon Aug 14 21:27:16 2000
@@ -1,5 +1,16 @@
 ChangeLog for smbfs.
 
+2000-08-14 Urban Widmark <urban@svenskatest.se>
+
+ * dir.c: support case sensitive shares
+ * inode.c: ascii mount options
+ * proc.c: check length of paths to avoid buffer overflow
+ * proc.c: don't do interruptable_sleep in smb_retry to avoid signal
+ problem/race.
+ * proc.c: O_RDONLY & smb_revalidate_inode fix (tail -f)
+ * proc.c: add nls support
+ * sock.c: attempt to fix smb_data_callback (avoid infinite loop)
+
 2000-07-25 Urban Widmark <urban@svenskatest.se>
 
         * proc.c: fix 3 places where bad server responses could cause an Oops.
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/smbfs/Makefile linux/fs/smbfs/Makefile
--- linux-2.4.0-test7-pre4-orig/fs/smbfs/Makefile Sat Aug 12 21:04:17 2000
+++ linux/fs/smbfs/Makefile Mon Aug 14 21:27:16 2000
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := smbfs.o
-O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o
+O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o
 M_OBJS := $(O_TARGET)
 
 # If you want debugging output, you may add these flags to the EXTRA_CFLAGS
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- linux-2.4.0-test7-pre4-orig/fs/smbfs/dir.c Mon Aug 14 20:15:25 2000
+++ linux/fs/smbfs/dir.c Mon Aug 14 21:27:16 2000
@@ -14,6 +14,7 @@
 #include <linux/ctype.h>
 
 #include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
 #include <linux/smbno.h>
 
 #include "smb_debug.h"
@@ -142,7 +143,7 @@
 }
 
 /*
- * Note: in order to allow the smbclient process to open the
+ * Note: in order to allow the smbmount process to open the
  * mount point, we don't revalidate if conn_pid is NULL.
  */
 static int
@@ -190,6 +191,13 @@
         d_delete: smb_delete_dentry,
 };
 
+static 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.
  */
@@ -249,8 +257,7 @@
 
         if (a->len != b->len)
                 goto out;
- for (i=0; i < a->len; i++)
- {
+ for (i=0; i < a->len; i++) {
                 if (tolower(a->name[i]) != tolower(b->name[i]))
                         goto out;
         }
@@ -300,6 +307,7 @@
         struct smb_fattr finfo;
         struct inode *inode;
         int error;
+ struct smb_sb_info *server;
 
         error = -ENAMETOOLONG;
         if (dentry->d_name.len > SMB_MAXNAMELEN)
@@ -315,15 +323,18 @@
         inode = NULL;
         if (error == -ENOENT)
                 goto add_entry;
- if (!error)
- {
+ if (!error) {
                 error = -EACCES;
                 finfo.f_ino = smb_invent_inos(1);
                 inode = smb_iget(dir->i_sb, &finfo);
- if (inode)
- {
+ if (inode) {
         add_entry:
- dentry->d_op = &smbfs_dentry_operations;
+ server = server_from_dentry(dentry);
+ if (server->mnt->flags & SMB_MOUNT_CASE)
+ dentry->d_op = &smbfs_dentry_operations_case;
+ else
+ dentry->d_op = &smbfs_dentry_operations;
+
                         d_add(dentry, inode);
                         smb_renew_times(dentry);
                         error = 0;
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/smbfs/getopt.c linux/fs/smbfs/getopt.c
--- linux-2.4.0-test7-pre4-orig/fs/smbfs/getopt.c Thu Jan 1 01:00:00 1970
+++ linux/fs/smbfs/getopt.c Mon Aug 14 21:27:16 2000
@@ -0,0 +1,61 @@
+/*
+ * getopt.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.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;
+
+ if ( (token = strsep(options, ",")) == NULL)
+ return 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].has_arg && (!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;
+}
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/smbfs/getopt.h linux/fs/smbfs/getopt.h
--- linux-2.4.0-test7-pre4-orig/fs/smbfs/getopt.h Thu Jan 1 01:00:00 1970
+++ linux/fs/smbfs/getopt.h Mon Aug 14 21:27:16 2000
@@ -0,0 +1,15 @@
+#ifndef _LINUX_GETOPT_H
+#define _LINUX_GETOPT_H
+
+struct option {
+ const char *name;
+ int has_arg;
+ 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 */
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- linux-2.4.0-test7-pre4-orig/fs/smbfs/inode.c Sat Aug 12 21:04:17 2000
+++ linux/fs/smbfs/inode.c Mon Aug 14 21:29:16 2000
@@ -20,6 +20,7 @@
 #include <linux/file.h>
 #include <linux/dcache.h>
 #include <linux/smp_lock.h>
+#include <linux/nls.h>
 
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
@@ -29,6 +30,7 @@
 #include <asm/uaccess.h>
 
 #include "smb_debug.h"
+#include "getopt.h"
 
 static void smb_delete_inode(struct inode *);
 static void smb_put_super(struct super_block *);
@@ -282,6 +284,82 @@
         clear_inode(ino);
 }
 
+/* FIXME: flags and has_arg could probably be merged. */
+struct option opts[] = {
+ { "version", 1, 0, 'v' },
+ { "win95", 0, SMB_MOUNT_WIN95, 1 },
+ { "oldattr", 0, SMB_MOUNT_OLDATTR, 1 },
+ { "dirattr", 0, SMB_MOUNT_DIRATTR, 1 },
+ { "case", 0, SMB_MOUNT_CASE, 1 },
+ { "uid", 1, 0, 'u' },
+ { "gid", 1, 0, 'g' },
+ { "file_mode", 1, 0, 'f' },
+ { "dir_mode", 1, 0, 'd' },
+ { "iocharset", 1, 0, 'i' },
+ { "codepage", 1, 0, 'c' },
+ { NULL, 0, 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;
+ break;
+ case 'g':
+ mnt->gid = value;
+ break;
+ case 'f':
+ mnt->file_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->file_mode |= S_IFREG;
+ break;
+ case 'd':
+ mnt->dir_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->dir_mode |= S_IFDIR;
+ break;
+ case 'i':
+ strncpy(mnt->codepage.local_name, optarg,
+ SMB_NLS_MAXNAMELEN);
+ break;
+ case 'c':
+ strncpy(mnt->codepage.remote_name, optarg,
+ SMB_NLS_MAXNAMELEN);
+ break;
+ default:
+ printk ("smbfs: Unrecognized mount option %s\n",
+ optopt);
+ return -1;
+ }
+ }
+ mnt->flags = flags;
+ return c;
+}
+
+
 static void
 smb_put_super(struct super_block *sb)
 {
@@ -300,18 +378,32 @@
         kfree(sb->u.smbfs_sb.temp_buf);
         if (server->packet)
                 smb_vfree(server->packet);
+
+ if(sb->u.smbfs_sb.remote_nls) {
+ unload_nls(sb->u.smbfs_sb.remote_nls);
+ sb->u.smbfs_sb.remote_nls = NULL;
+ }
+ if(sb->u.smbfs_sb.local_nls) {
+ unload_nls(sb->u.smbfs_sb.local_nls);
+ sb->u.smbfs_sb.local_nls = NULL;
+ }
 }
 
 struct super_block *
 smb_read_super(struct super_block *sb, void *raw_data, int silent)
 {
- struct smb_mount_data *mnt;
+ struct smb_mount_data_kernel *mnt;
+ struct smb_mount_data *oldmnt;
         struct inode *root_inode;
         struct smb_fattr root;
+ int ver;
 
         if (!raw_data)
                 goto out_no_data;
- if (((struct smb_mount_data *) raw_data)->version != SMB_MOUNT_VERSION)
+
+ 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_blocksize = 1024; /* Eh... Is this correct? */
@@ -320,6 +412,7 @@
         sb->s_flags = 0;
         sb->s_op = &smb_sops;
 
+ sb->u.smbfs_sb.mnt = NULL;
         sb->u.smbfs_sb.sock_file = NULL;
         init_MUTEX(&sb->u.smbfs_sb.sem);
         init_waitqueue_head(&sb->u.smbfs_sb.wait);
@@ -332,30 +425,61 @@
                 goto out_no_mem;
 
         /* Allocate the global temp buffer */
- sb->u.smbfs_sb.temp_buf = kmalloc(SMB_MAXPATHLEN + 20, GFP_KERNEL);
+ sb->u.smbfs_sb.temp_buf = kmalloc(2*SMB_MAXPATHLEN + 20, GFP_KERNEL);
         if (!sb->u.smbfs_sb.temp_buf)
                 goto out_no_temp;
 
+ /* Setup NLS stuff */
+ sb->u.smbfs_sb.remote_nls = NULL;
+ sb->u.smbfs_sb.local_nls = NULL;
+ sb->u.smbfs_sb.name_buf = sb->u.smbfs_sb.temp_buf + SMB_MAXPATHLEN + 20;
+
         /* Allocate the mount data structure */
- mnt = kmalloc(sizeof(struct smb_mount_data), GFP_KERNEL);
+ /* FIXME: merge this with the other malloc and get a whole page? */
+ mnt = kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
         if (!mnt)
                 goto out_no_mount;
- *mnt = *((struct smb_mount_data *) raw_data);
- /* FIXME: passes config flags in high bits of file mode. Should be a
- separate flags field. (but smbmount includes kernel headers ...) */
- mnt->version = (mnt->file_mode >> 9);
- mnt->file_mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
- mnt->file_mode |= S_IFREG;
- mnt->dir_mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
- mnt->dir_mode |= S_IFDIR;
         sb->u.smbfs_sb.mnt = mnt;
+
+ memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
+ strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
+ SMB_NLS_MAXNAMELEN);
+ strncpy(mnt->codepage.local_name, CONFIG_SMB_NLS_REMOTE,
+ SMB_NLS_MAXNAMELEN);
+
+ if (ver == SMB_MOUNT_OLDVERSION) {
+ mnt->version = oldmnt->version;
+
+ /* FIXME: is this enough to convert uid/gid's ? */
+ mnt->mounted_uid = oldmnt->mounted_uid;
+ mnt->uid = oldmnt->uid;
+ mnt->gid = oldmnt->gid;
+
+ mnt->file_mode =
+ oldmnt->file_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->dir_mode =
+ oldmnt->dir_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->file_mode |= S_IFREG;
+ mnt->dir_mode |= S_IFDIR;
+
+ mnt->flags = (oldmnt->file_mode >> 9);
+ } else {
+ if (parse_options(mnt, raw_data))
+ goto out_bad_option;
+
+ mnt->mounted_uid = current->uid;
+ }
+ smb_setcodepage(&sb->u.smbfs_sb, &mnt->codepage);
+ if (!sb->u.smbfs_sb.convert)
+ PARANOIA("convert funcptr was NULL!\n");
+
         /*
          * Display the enabled options
          * Note: smb_proc_getattr uses these in 2.4 (but was changed in 2.2)
          */
- if (mnt->version & SMB_FIX_OLDATTR)
+ if (mnt->flags & SMB_MOUNT_OLDATTR)
                 printk("SMBFS: Using core getattr (Win 95 speedup)\n");
- else if (mnt->version & SMB_FIX_DIRATTR)
+ else if (mnt->flags & SMB_MOUNT_DIRATTR)
                 printk("SMBFS: Using dir ff getattr\n");
 
         /*
@@ -374,16 +498,18 @@
 
 out_no_root:
         iput(root_inode);
+out_bad_option:
         kfree(sb->u.smbfs_sb.mnt);
 out_no_mount:
         kfree(sb->u.smbfs_sb.temp_buf);
 out_no_temp:
         smb_vfree(sb->u.smbfs_sb.packet);
 out_no_mem:
- printk(KERN_ERR "smb_read_super: allocation failure\n");
+ if (!sb->u.smbfs_sb.mnt)
+ printk(KERN_ERR "smb_read_super: allocation failure\n");
         goto out_fail;
 out_wrong_data:
- printk(KERN_ERR "SMBFS: need mount version %d\n", SMB_MOUNT_VERSION);
+ printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver);
         goto out_fail;
 out_no_data:
         printk(KERN_ERR "smb_read_super: missing data argument\n");
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- linux-2.4.0-test7-pre4-orig/fs/smbfs/proc.c Sat Aug 12 21:04:17 2000
+++ linux/fs/smbfs/proc.c Mon Aug 14 21:27:16 2000
@@ -16,6 +16,7 @@
 #include <linux/fcntl.h>
 #include <linux/dcache.h>
 #include <linux/dirent.h>
+#include <linux/nls.h>
 
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
@@ -25,10 +26,14 @@
 
 #include "smb_debug.h"
 
+
 /* Features. Undefine if they cause problems, this should perhaps be a
    config option. */
 #define SMBFS_POSIX_UNLINK 1
 
+/* Allow smb_retry to be interrupted. Not sure of the benefit ... */
+/* #define SMB_RETRY_INTR */
+
 #define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
 #define SMB_CMD(packet) (*(packet+8))
 #define SMB_WCT(packet) (*(packet+SMB_HEADER_LEN - 1))
@@ -48,6 +53,20 @@
 smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,
                     struct smb_fattr *fattr);
 
+
+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));
+}
+
+
 static void
 str_upper(char *name, int len)
 {
@@ -83,6 +102,96 @@
         }
 }
 
+/* no conversion, just a wrapper for memcpy. */
+static int convert_memcpy(char *output, int olen,
+ const char *input, int ilen,
+ struct nls_table *nls_from,
+ struct nls_table *nls_to)
+{
+ memcpy(output, input, ilen);
+ return ilen;
+}
+
+/* convert from one "codepage" to another (possibly being utf8). */
+static int convert_cp(char *output, int olen,
+ const char *input, int ilen,
+ struct nls_table *nls_from,
+ struct nls_table *nls_to)
+{
+ int len = 0;
+ int n;
+ wchar_t ch;
+
+ if (!nls_from || !nls_to) {
+ PARANOIA("nls_from=%p, nls_to=%p\n", nls_from, nls_to);
+ return convert_memcpy(output, olen, input, ilen, NULL, NULL);
+ }
+
+ while (ilen > 0) {
+ /* convert by changing to unicode and back to the new cp */
+ n = nls_from->char2uni((unsigned char *)input, ilen, &ch);
+ if (n < 0)
+ goto out;
+ input += n;
+ ilen -= n;
+
+ n = nls_to->uni2char(ch, output, olen);
+ if (n < 0)
+ goto out;
+ output += n;
+ olen -= n;
+
+ len += n;
+ }
+out:
+ return len;
+}
+
+static int setcodepage(struct smb_sb_info *server,
+ struct nls_table **p, char *name)
+{
+ struct nls_table *nls;
+
+ if (!name || !*name) {
+ nls = NULL;
+ } else if ( (nls = load_nls(name)) == NULL) {
+ printk (KERN_ERR "smbfs: failed to load nls '%s'\n", name);
+ return -EINVAL;
+ }
+
+ /* if already set, unload the previous one. */
+ if (*p)
+ unload_nls(*p);
+ *p = nls;
+
+ return 0;
+}
+
+/* Handles all changes to codepage settings. */
+int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp)
+{
+ int n;
+
+ smb_lock_server(server);
+
+ n = setcodepage(server, &server->local_nls, cp->local_name);
+ if (n != 0)
+ goto out;
+ n = setcodepage(server, &server->remote_nls, cp->remote_name);
+ if (n != 0)
+ setcodepage(server, &server->local_nls, NULL);
+
+out:
+ if (server->local_nls != NULL && server->remote_nls != NULL)
+ server->convert = convert_cp;
+ else
+ server->convert = convert_memcpy;
+
+ smb_unlock_server(server);
+ return n;
+}
+
+
 /*****************************************************************************/
 /* */
 /* Encoding/Decoding section */
@@ -107,9 +216,11 @@
  * smb_build_path: build the path to entry and name storing it in buf.
  * The path returned will have the trailing '\0'.
  */
-static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf)
+static int smb_build_path(struct smb_sb_info *server, char * buf,
+ struct dentry * entry, struct qstr * name)
 {
         char *path = buf;
+ int len;
 
         if (entry == NULL)
                 goto test_name_and_out;
@@ -129,9 +240,16 @@
          * and store it in reversed order [see reverse_string()]
          */
         for (;;) {
- memcpy(path, entry->d_name.name, entry->d_name.len);
- reverse_string(path, entry->d_name.len);
- path += entry->d_name.len;
+ if (entry->d_name.len > SMB_MAXNAMELEN)
+ return -ENAMETOOLONG;
+ if (path - buf + entry->d_name.len > SMB_MAXPATHLEN)
+ return -ENAMETOOLONG;
+
+ len = server->convert(path, SMB_MAXNAMELEN,
+ entry->d_name.name, entry->d_name.len,
+ server->local_nls, server->remote_nls);
+ reverse_string(path, len);
+ path += len;
 
                 *(path++) = '\\';
 
@@ -147,25 +265,28 @@
         if (name != NULL) {
                 *(path++) = '\\';
 name_and_out:
- memcpy(path, name->name, name->len);
- path += name->len;
+ len = server->convert(path, SMB_MAXNAMELEN,
+ name->name, name->len,
+ server->local_nls, server->remote_nls);
+ path += len;
         }
 out:
         *(path++) = '\0';
         return (path-buf);
 }
 
-static char *smb_encode_path(struct smb_sb_info *server, char *buf,
- struct dentry *dir, struct qstr *name)
+static int smb_encode_path(struct smb_sb_info *server, char *buf,
+ struct dentry *dir, struct qstr *name)
 {
- char *start = buf;
-
- buf += smb_build_path(dir, name, buf);
+ int result;
 
+ result = smb_build_path(server, buf, dir, name);
+ if (result < 0)
+ goto out;
         if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
- str_upper(start, buf - start);
-
- return buf;
+ str_upper(buf, result);
+out:
+ return result;
 }
 
 /* The following are taken directly from msdos-fs */
@@ -464,18 +585,6 @@
         return EIO;
 }
 
-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));
-}
-
 /*
  * smb_retry: This function should be called when smb_request_ok has
  * indicated an error. If the error was indicated because the
@@ -495,8 +604,7 @@
 
         smb_close_socket(server);
 
- if (pid == 0)
- {
+ if (pid == 0) {
                 printk(KERN_ERR "smb_retry: no connection process\n");
                 server->state = CONN_RETRIED;
                 goto out;
@@ -511,26 +619,35 @@
          * Note: use the "priv" flag, as a user process may need to reconnect.
          */
         error = kill_proc(pid, SIGUSR1, 1);
- if (error)
- {
+ if (error) {
                 printk(KERN_ERR "smb_retry: signal failed, error=%d\n", error);
                 goto out_restore;
         }
- VERBOSE("signalled pid %d, waiting for new connection\n",
- server->conn_pid);
+ VERBOSE("signalled pid %d, waiting for new connection\n", pid);
 
         /*
          * Wait for the new connection.
          */
+#ifdef SMB_RETRY_INTR
         interruptible_sleep_on_timeout(&server->wait, 5*HZ);
         if (signal_pending(current))
                 printk(KERN_INFO "smb_retry: caught signal\n");
+#else
+ /*
+ * We don't want to be interrupted. For example, what if 'current'
+ * already has recieved a signal? sleep_on would terminate immediately
+ * and smbmount would not be able to re-establish connection.
+ *
+ * smbmount should be able to reconnect later, but it can't because
+ * it will get an -EIO on attempts to open the mountpoint!
+ */
+ sleep_on_timeout(&server->wait, 5*HZ);
+#endif
 
         /*
          * Check for a valid connection.
          */
- if (server->state == CONN_VALID)
- {
+ if (server->state == CONN_VALID) {
                 /* This should be changed to VERBOSE, except many smbfs
                    problems is with the userspace daemon not reconnecting. */
                 PARANOIA("sucessful, new pid=%d, generation=%d\n",
@@ -656,7 +773,7 @@
         if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
             (server->opt.max_xmit < 0x1000) &&
             !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
- server->mnt->version |= SMB_FIX_WIN95;
+ server->mnt->flags |= SMB_MOUNT_WIN95;
 #ifdef SMBFS_DEBUG_VERBOSE
                 printk(KERN_NOTICE "smb_newconn: detected WIN95 server\n");
 #endif
@@ -667,7 +784,11 @@
                 server->opt.capabilities);
 
 out:
+#ifdef SMB_RETRY_INTR
         wake_up_interruptible(&server->wait);
+#else
+ wake_up(&server->wait);
+#endif
         return error;
 
 out_putf:
@@ -738,7 +859,7 @@
 {
         struct inode *ino = dentry->d_inode;
         int mode, read_write = 0x42, read_only = 0x40;
- int error;
+ int res;
         char *p;
 
         /*
@@ -748,6 +869,9 @@
         if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
                 mode = read_only;
 #if 0
+ /* FIXME: why is this code not in? below we fix it so that a caller
+ wanting RO doesn't get RW. smb_revalidate_inode does some
+ optimization based on access mode. tail -f needs it to be correct. */
         if (!(wish & (O_WRONLY | O_RDWR)))
                 mode = read_only;
 #endif
@@ -757,20 +881,23 @@
         WSET(server->packet, smb_vwv0, mode);
         WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
         *p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ res = smb_encode_path(server, p, dentry, NULL);
+ if (res < 0)
+ goto out;
+ p += res;
+
         smb_setup_bcc(server, p);
 
- error = smb_request_ok(server, SMBopen, 7, 0);
- if (error != 0)
- {
+ res = smb_request_ok(server, SMBopen, 7, 0);
+ if (res != 0) {
                 if (smb_retry(server))
                         goto retry;
 
                 if (mode == read_write &&
- (error == -EACCES || error == -ETXTBSY || error == -EROFS))
+ (res == -EACCES || res == -ETXTBSY || res == -EROFS))
                 {
                         VERBOSE("%s/%s R/W failed, error=%d, retrying R/O\n",
- DENTRY_PATH(dentry), error);
+ DENTRY_PATH(dentry), res);
                         mode = read_only;
                         goto retry;
                 }
@@ -783,10 +910,12 @@
         /* smb_vwv2 has mtime */
         /* smb_vwv4 has size */
         ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
+ if (!(wish & (O_WRONLY | O_RDWR)))
+ ino->u.smbfs_i.access = SMB_O_RDONLY;
         ino->u.smbfs_i.open = server->generation;
 
 out:
- return error;
+ return res;
 }
 
 /*
@@ -1025,7 +1154,7 @@
 {
         struct smb_sb_info *server = server_from_dentry(dentry);
         char *p;
- int error;
+ int result;
 
         smb_lock_server(server);
 
@@ -1034,22 +1163,24 @@
         WSET(server->packet, smb_vwv0, attr);
         DSET(server->packet, smb_vwv1, utc2local(server, ctime));
         *p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ result = smb_encode_path(server, p, dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
         smb_setup_bcc(server, p);
 
- error = smb_request_ok(server, SMBcreate, 1, 0);
- if (error < 0)
- {
+ result = smb_request_ok(server, SMBcreate, 1, 0);
+ if (result < 0) {
                 if (smb_retry(server))
                         goto retry;
                 goto out;
         }
         *fileid = WVAL(server->packet, smb_vwv0);
- error = 0;
+ result = 0;
 
 out:
         smb_unlock_server(server);
- return error;
+ return result;
 }
 
 int
@@ -1064,14 +1195,22 @@
       retry:
         p = smb_setup_header(server, SMBmv, 1, 0);
         WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);
+
         *p++ = 4;
- p = smb_encode_path(server, p, old_dentry, NULL);
+ result = smb_encode_path(server, p, old_dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
+
         *p++ = 4;
- p = smb_encode_path(server, p, new_dentry, NULL);
+ result = smb_encode_path(server, p, new_dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
+
         smb_setup_bcc(server, p);
 
- if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
- {
+ if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
                 if (smb_retry(server))
                         goto retry;
                 goto out;
@@ -1097,12 +1236,14 @@
       retry:
         p = smb_setup_header(server, command, 0, 0);
         *p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ result = smb_encode_path(server, p, dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
         smb_setup_bcc(server, p);
 
         result = smb_request_ok(server, command, 0, 0);
- if (result < 0)
- {
+ if (result < 0) {
                 if (smb_retry(server))
                         goto retry;
                 goto out;
@@ -1165,11 +1306,13 @@
         p = smb_setup_header(server, SMBunlink, 1, 0);
         WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
         *p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ result = smb_encode_path(server, p, dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
         smb_setup_bcc(server, p);
 
- if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
- {
+ if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
 #if SMBFS_POSIX_UNLINK
                 if (result == -EACCES && !flag) {
                         /* Posix semantics is for the read-only state
@@ -1220,8 +1363,7 @@
         *p++ = 0;
         smb_setup_bcc(server, p);
 
- if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0)
- {
+ if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
                 if (smb_retry(server))
                         goto retry;
                 goto out;
@@ -1306,6 +1448,8 @@
                 len--;
         entry->len = len;
 
+ /* FIXME: These only work for ascii chars, and recent smbmount doesn't
+ allow the flag to be set anyway. Remove? */
         switch (server->opt.case_handling) {
         case SMB_CASE_UPPER:
                 str_upper(entry->name, len);
@@ -1316,7 +1460,13 @@
         default:
                 break;
         }
- DEBUG1("len=%d, name=%.*s\n", len, len, entry->name);
+
+ entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+ entry->name, len,
+ server->remote_nls, server->local_nls);
+ entry->name = server->name_buf;
+
+ DEBUG1("len=%d, name=%.*s\n", entry->len, entry->len, entry->name);
         return p + 22;
 }
 
@@ -1355,7 +1505,10 @@
                 WSET(server->packet, smb_vwv1, aDIR);
                 *p++ = 4;
                 if (first == 1) {
- p = smb_encode_path(server, p, dir, &mask);
+ result = smb_encode_path(server, p, dir, &mask);
+ if (result < 0)
+ goto unlock_return;
+ p += result;
                         *p++ = 5;
                         WSET(p, 0, 0);
                         p += 2;
@@ -1467,12 +1620,11 @@
         switch (level) {
         case 1:
                 len = *((unsigned char *) p + 22);
- entry->len = len;
                 entry->name = p + 23;
                 result = p + 24 + len;
 
                 VERBOSE("info 1 at %p, len=%d, name=%.*s\n",
- p, entry->len, entry->len, entry->name);
+ p, len, len, entry->name);
                 break;
         case 260:
                 result = p + WVAL(p, 0);
@@ -1482,14 +1634,14 @@
                 entry->name = p + 94;
                 if (len && entry->name[len-1] == '\0')
                         len--;
- entry->len = len;
 
                 VERBOSE("info 260 at %p, len=%d, name=%.*s\n",
- p, entry->len, entry->len, entry->name);
+ p, len, len, entry->name);
                 break;
         default:
                 PARANOIA("Unknown info level %d\n", level);
                 result = p + WVAL(p, 0);
+ goto out;
         }
 
         switch (server->opt.case_handling) {
@@ -1503,6 +1655,11 @@
                 break;
         }
 
+ entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+ entry->name, len,
+ server->remote_nls, server->local_nls);
+ entry->name = server->name_buf;
+out:
         return result;
 }
 
@@ -1561,7 +1718,12 @@
          * Encode the initial path
          */
         mask = param + 12;
- mask_len = smb_encode_path(server, mask, dir, &star) - mask;
+
+ mask_len = smb_encode_path(server, mask, dir, &star);
+ if (mask_len < 0) {
+ entries = mask_len;
+ goto unlock_return;
+ }
         first = 1;
         VERBOSE("starting fpos=%d, mask=%s\n", fpos, mask);
 
@@ -1753,7 +1915,11 @@
         int mask_len, result;
 
 retry:
- mask_len = smb_encode_path(server, mask, dentry, NULL) - mask;
+ mask_len = smb_encode_path(server, mask, dentry, NULL);
+ if (mask_len < 0) {
+ result = mask_len;
+ goto out;
+ }
         VERBOSE("name=%s, len=%d\n", mask, mask_len);
         WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
         WSET(param, 2, 1); /* max count */
@@ -1828,7 +1994,10 @@
       retry:
         p = smb_setup_header(server, SMBgetatr, 0, 0);
         *p++ = 4;
- p = smb_encode_path(server, p, dir, NULL);
+ result = smb_encode_path(server, p, dir, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
         smb_setup_bcc(server, p);
 
         if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
@@ -1874,7 +2043,10 @@
       retry:
         WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
         DSET(param, 2, 0);
- p = smb_encode_path(server, param + 6, dir, NULL);
+ result = smb_encode_path(server, param + 6, dir, NULL);
+ if (result < 0)
+ goto out;
+ p = param + 6 + result;
 
         result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
                                     0, NULL, p - param, param,
@@ -1905,7 +2077,7 @@
          * Kludge alert: Win 95 swaps the date and time field,
          * contrary to the CIFS docs and Win NT practice.
          */
- if (server->mnt->version & SMB_FIX_WIN95) {
+ if (server->mnt->flags & SMB_MOUNT_WIN95) {
                 off_date = 2;
                 off_time = 0;
         }
@@ -1945,21 +2117,16 @@
 
         /*
          * Select whether to use core or trans2 getattr.
+ * Win 95 appears to break with the trans2 getattr.
           */
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
- /*
- * Win 95 appears to break with the trans2 getattr.
- * Note: mnt->version options are set at mount time (inode.c)
- */
- if (server->mnt->version & (SMB_FIX_OLDATTR|SMB_FIX_WIN95))
- goto core_attr;
- if (server->mnt->version & SMB_FIX_DIRATTR)
+ if (server->opt.protocol < SMB_PROTOCOL_LANMAN2 ||
+ (server->mnt->flags & (SMB_MOUNT_OLDATTR|SMB_MOUNT_WIN95)) ) {
+ result = smb_proc_getattr_core(server, dir, fattr);
+ } else {
+ if (server->mnt->flags & SMB_MOUNT_DIRATTR)
                         result = smb_proc_getattr_ff(server, dir, fattr);
                 else
                         result = smb_proc_getattr_trans2(server, dir, fattr);
- } else {
- core_attr:
- result = smb_proc_getattr_core(server, dir, fattr);
         }
 
         smb_finish_dirent(server, fattr);
@@ -2008,14 +2175,16 @@
         WSET(server->packet, smb_vwv6, 0);
         WSET(server->packet, smb_vwv7, 0);
         *p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ result = smb_encode_path(server, p, dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
         *p++ = 4;
         *p++ = 0;
         smb_setup_bcc(server, p);
 
         result = smb_request_ok(server, SMBsetatr, 0, 0);
- if (result < 0)
- {
+ if (result < 0) {
                 if (smb_retry(server))
                         goto retry;
                 goto out;
@@ -2073,8 +2242,7 @@
 #endif
 
         result = smb_request_ok(server, SMBsetattrE, 0, 0);
- if (result < 0)
- {
+ if (result < 0) {
                 if (smb_retry(server))
                         goto retry;
                 goto out;
@@ -2107,7 +2275,10 @@
       retry:
         WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
         DSET(param, 2, 0);
- p = smb_encode_path(server, param + 6, dir, NULL);
+ result = smb_encode_path(server, param + 6, dir, NULL);
+ if (result < 0)
+ goto out;
+ p = param + 6 + result;
 
         WSET(data, 0, 0); /* creation time */
         WSET(data, 2, 0);
@@ -2170,8 +2341,7 @@
         smb_lock_server(server);
         /* setting the time on a Win95 server fails (tridge) */
         if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
- !(server->mnt->version & SMB_FIX_WIN95))
- {
+ !(server->mnt->flags & SMB_MOUNT_WIN95)) {
                 if (smb_is_open(inode) &&
                     inode->u.smbfs_i.access != SMB_O_RDONLY)
                         result = smb_proc_setattr_ext(server, inode, fattr);
@@ -2182,8 +2352,7 @@
                  * Fail silently on directories ... timestamp can't be set?
                  */
                 result = 0;
- if (S_ISREG(inode->i_mode))
- {
+ if (S_ISREG(inode->i_mode)) {
                         /*
                          * Set the mtime by opening and closing the file.
                          * Note that the file is opened read-only, but this
@@ -2192,8 +2361,7 @@
                         result = -EACCES;
                         if (!smb_is_open(inode))
                                 smb_proc_open(server, dentry, SMB_O_RDONLY);
- if (smb_is_open(inode))
- {
+ if (smb_is_open(inode)) {
                                 inode->i_mtime = fattr->f_mtime;
                                 result = smb_proc_close_inode(server, inode);
                         }
@@ -2208,7 +2376,7 @@
 smb_proc_dskattr(struct super_block *sb, struct statfs *attr)
 {
         struct smb_sb_info *server = &(sb->u.smbfs_sb);
- int error;
+ int result;
         char *p;
 
         smb_lock_server(server);
@@ -2216,8 +2384,7 @@
       retry:
         smb_setup_header(server, SMBdskattr, 0, 0);
 
- if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0)
- {
+ if ((result = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) {
                 if (smb_retry(server))
                         goto retry;
                 goto out;
@@ -2226,11 +2393,11 @@
         attr->f_blocks = WVAL(p, 0);
         attr->f_bsize = WVAL(p, 2) * WVAL(p, 4);
         attr->f_bavail = attr->f_bfree = WVAL(p, 6);
- error = 0;
+ result = 0;
 
 out:
         smb_unlock_server(server);
- return error;
+ return result;
 }
 
 int
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- linux-2.4.0-test7-pre4-orig/fs/smbfs/sock.c Sat Aug 12 21:04:17 2000
+++ linux/fs/smbfs/sock.c Mon Aug 14 21:27:16 2000
@@ -111,12 +111,16 @@
         unsigned char peek_buf[4];
         int result;
         mm_segment_t fs;
+ int count = 100; /* this is a lot, we should have some data waiting */
+ int found = 0;
 
         fs = get_fs();
         set_fs(get_ds());
 
         lock_kernel();
- while (1) {
+ while (count-- > 0) {
+ peek_buf[0] = 0;
+
                 result = -EIO;
                 if (job->sk->dead) {
                         PARANOIA("sock dead!\n");
@@ -125,7 +129,7 @@
 
                 result = _recvfrom(socket, (void *) peek_buf, 1,
                                    MSG_PEEK | MSG_DONTWAIT);
- if (result == -EAGAIN)
+ if (result < 0)
                         break;
                 if (peek_buf[0] != 0x85)
                         break;
@@ -136,13 +140,15 @@
 
                 DEBUG1("got SESSION KEEPALIVE\n");
 
- if (result == -EAGAIN)
+ if (result < 0)
                         break;
+ found = 1;
         }
         unlock_kernel();
         set_fs(fs);
 
- if (result != -EAGAIN)
+ DEBUG1("found=%d, count=%d, result=%d\n", found, count, result);
+ if (found)
                 found_data(job->sk);
         kfree(ptr);
 }
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/include/linux/smb.h linux/include/linux/smb.h
--- linux-2.4.0-test7-pre4-orig/include/linux/smb.h Fri Mar 24 00:36:06 2000
+++ linux/include/linux/smb.h Mon Aug 14 21:29:14 2000
@@ -62,6 +62,13 @@
 
 #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
 
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- linux-2.4.0-test7-pre4-orig/include/linux/smb_fs.h Sat Aug 12 21:04:18 2000
+++ linux/include/linux/smb_fs.h Mon Aug 14 21:35:28 2000
@@ -73,13 +73,6 @@
 #define SMB_F_CACHEVALID 0x01 /* directory cache valid */
 #define SMB_F_LOCALWRITE 0x02 /* file modified locally */
 
-/*
- * Bug fix flags
- */
-#define SMB_FIX_WIN95 0x0001 /* Win 95 server */
-#define SMB_FIX_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */
-#define SMB_FIX_DIRATTR 0x0004 /* Use find_first for getattr */
-
 
 /* NT1 protocol capability bits */
 #define SMB_CAP_RAW_MODE 0x0001
@@ -122,6 +115,7 @@
 struct inode *smb_iget(struct super_block *, struct smb_fattr *);
 
 /* linux/fs/smbfs/proc.c */
+int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp);
 __u32 smb_len(unsigned char *);
 __u8 *smb_encode_smb_length(__u8 *, __u32);
 __u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16);
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/include/linux/smb_fs_sb.h linux/include/linux/smb_fs_sb.h
--- linux-2.4.0-test7-pre4-orig/include/linux/smb_fs_sb.h Fri Mar 24 00:36:06 2000
+++ linux/include/linux/smb_fs_sb.h Mon Aug 14 21:29:14 2000
@@ -23,7 +23,7 @@
         enum smb_conn_state state;
         struct file * sock_file;
 
- struct smb_mount_data *mnt;
+ struct smb_mount_data_kernel *mnt;
         unsigned char *temp_buf;
 
         /* Connections are counted. Each time a new socket arrives,
@@ -41,8 +41,20 @@
         unsigned short rcls; /* The error codes we received */
         unsigned short err;
 
- /* We use our on data_ready callback, but need the original one */
+ /* 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;
+
+ /* utf8 can make strings longer so we can't do in-place conversion.
+ This is a buffer for temporary stuff. We only need one so no need
+ to put it on the stack. This points to temp_buf space. */
+ char *name_buf;
+
+ int (*convert)(char *, int, const char *, int,
+ struct nls_table *, struct nls_table *);
 };
 
 #endif /* __KERNEL__ */
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/include/linux/smb_mount.h linux/include/linux/smb_mount.h
--- linux-2.4.0-test7-pre4-orig/include/linux/smb_mount.h Thu Aug 27 19:58:23 1998
+++ linux/include/linux/smb_mount.h Mon Aug 14 21:35:28 2000
@@ -11,7 +11,7 @@
 
 #include <linux/types.h>
 
-#define SMB_MOUNT_VERSION 6
+#define SMB_MOUNT_VERSION 6
 
 struct smb_mount_data {
         int version;
@@ -21,5 +21,38 @@
         __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 */
+
+
+struct smb_mount_data_kernel {
+ 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;
+
+ u32 flags;
+
+ struct smb_nls_codepage codepage;
+};
+
+#endif
 
 #endif
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.0-test7-pre4-orig/Documentation/Configure.help Mon Aug 14 20:15:19 2000
+++ linux/Documentation/Configure.help Mon Aug 14 21:27:16 2000
@@ -11305,6 +11305,21 @@
   want), say M here and read Documentation/modules.txt. The module
   will be called smbfs.o. Most people say N, however.
 
+nls support setting
+CONFIG_SMB_NLS_REMOTE
+ 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.
+
+ Currently no smbmount distributed with samba supports this, it is
+ assumed future versions will. In the meantime you can get an
+ unofficial patch for samba 2.0.7 from:
+ http://www.hojdpunkten.ac.se/054/samba/index.html
+
 Coda file system support (advanced network fs)
 CONFIG_CODA_FS
   Coda is an advanced network file system, similar to NFS in that it
Binary files linux-2.4.0-test7-pre4-orig/drivers/net/hamradio/soundmodem/gentbl and linux/drivers/net/hamradio/soundmodem/gentbl differ
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/Config.in linux/fs/Config.in
--- linux-2.4.0-test7-pre4-orig/fs/Config.in Sat Aug 12 21:04:33 2000
+++ linux/fs/Config.in Mon Aug 14 21:27:16 2000
@@ -99,7 +99,9 @@
    fi
 
    dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
-
+ if [ "$CONFIG_SMB_FS" != "n" ]; then
+ string 'Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE ""
+ fi
    if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
       tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
       source fs/ncpfs/Config.in
diff -urN -X exclude linux-2.4.0-test7-pre4-orig/fs/nls/Config.in linux/fs/nls/Config.in
--- linux-2.4.0-test7-pre4-orig/fs/nls/Config.in Sat Aug 12 21:04:15 2000
+++ linux/fs/nls/Config.in Mon Aug 14 21:27:16 2000
@@ -4,7 +4,8 @@
 
 # msdos and Joliet want NLS
 if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
- -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" ]; then
+ -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
+ -o "$CONFIG_SMB_FS" ]; then
   define_bool CONFIG_NLS y
 else
   define_bool CONFIG_NLS n

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Aug 15 2000 - 21:00:34 EST