]> git.hungrycats.org Git - linux/commitdiff
[PATCH] smbfs nls oops fix
authorUrban Widmark <urban@teststation.com>
Thu, 7 Mar 2002 08:55:46 +0000 (00:55 -0800)
committerLinus Torvalds <torvalds@penguin.transmeta.com>
Thu, 7 Mar 2002 08:55:46 +0000 (00:55 -0800)
Fixes smbfs oopsing on failed nls translations and maps unknown chars to
:#### strings. Also PATHLEN vs NAMELEN mixups.

fs/smbfs/cache.c
fs/smbfs/proc.c

index 369c13927b74e13777ea8b45eead67352eaebd1d..20ba2c24aef6e3c24cbca22fbe796e815f516a1b 100644 (file)
@@ -84,7 +84,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
        struct list_head *next;
 
        if (d_validate(dent, parent)) {
-               if (dent->d_name.len <= SMB_MAXPATHLEN &&
+               if (dent->d_name.len <= SMB_MAXNAMELEN &&
                    (unsigned long)dent->d_fsdata == fpos) {
                        if (!dent->d_inode) {
                                dput(dent);
index e2df6e23d73ab7e9f0473cb6772d80fb25169acc..25e223a279607312fa1829d9d0df180476d3f120 100644 (file)
@@ -109,6 +109,22 @@ static int convert_memcpy(char *output, int olen,
        return ilen;
 }
 
+static inline int write_char(unsigned char ch, char *output, int olen)
+{
+       if (olen < 4)
+               return -ENAMETOOLONG;
+       sprintf(output, ":x%02x", ch);
+       return 4;
+}
+
+static inline int write_unichar(wchar_t ch, char *output, int olen)
+{
+       if (olen < 5)
+               return -ENAMETOOLONG;
+       sprintf(output, ":%04x", ch);
+       return 5;
+}
+
 /* convert from one "codepage" to another (possibly being utf8). */
 static int convert_cp(char *output, int olen,
                      const char *input, int ilen,
@@ -119,20 +135,26 @@ static int convert_cp(char *output, int olen,
        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)
+               if (n == -EINVAL) {
+                       ilen--;
+                       n = write_char(*input++, output, olen);
+                       if (n < 0)
+                               goto fail;
+                       output += n;
+                       olen -= n;
+                       len += n;
+                       continue;
+               } else if (n < 0)
                        goto fail;
                input += n;
                ilen -= n;
 
                n = nls_to->uni2char(ch, output, olen);
+               if (n == -EINVAL)
+                       n = write_unichar(ch, output, olen);
                if (n < 0)
                        goto fail;
                output += n;
@@ -226,8 +248,8 @@ static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,
        if (maxlen < 2)
                return -ENAMETOOLONG;
 
-       if (maxlen > SMB_MAXNAMELEN + 1)
-               maxlen = SMB_MAXNAMELEN + 1;
+       if (maxlen > SMB_MAXPATHLEN + 1)
+               maxlen = SMB_MAXPATHLEN + 1;
 
        if (entry == NULL)
                goto test_name_and_out;
@@ -1567,7 +1589,6 @@ smb_decode_short_dirent(struct smb_sb_info *server, char *p,
         */
        while (len > 2 && qname->name[len-1] == ' ')
                len--;
-       qname->len = len;
 
        smb_finish_dirent(server, fattr);
 
@@ -1586,12 +1607,16 @@ smb_decode_short_dirent(struct smb_sb_info *server, char *p,
        }
 #endif
 
-       qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
-                                    qname->name, len,
-                                    server->remote_nls, server->local_nls);
-       qname->name = server->name_buf;
+       qname->len = 0;
+       len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+                             qname->name, len,
+                             server->remote_nls, server->local_nls);
+       if (len > 0) {
+               qname->len = len;
+               qname->name = server->name_buf;
+               DEBUG1("len=%d, name=%.*s\n",qname->len,qname->len,qname->name);
+       }
 
-       DEBUG1("len=%d, name=%.*s\n", qname->len, qname->len, qname->name);
        return p + 22;
 }
 
@@ -1707,6 +1732,8 @@ smb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir,
                for (i = 0; i < count; i++) {
                        p = smb_decode_short_dirent(server, p, 
                                                    &qname, &fattr);
+                       if (qname.len == 0)
+                               continue;
 
                        if (entries_seen == 2 && qname.name[0] == '.') {
                                if (qname.len == 1)
@@ -1744,6 +1771,7 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
 {
        char *result;
        unsigned int len = 0;
+       int n;
        __u16 date, time;
 
        /*
@@ -1819,10 +1847,14 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
        }
 #endif
 
-       qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
-                                    qname->name, len,
-                                    server->remote_nls, server->local_nls);
-       qname->name = server->name_buf;
+       qname->len = 0;
+       n = server->convert(server->name_buf, SMB_MAXNAMELEN,
+                           qname->name, len,
+                           server->remote_nls, server->local_nls);
+       if (n > 0) {
+               qname->len = n;
+               qname->name = server->name_buf;
+       }
 
 out:
        return result;
@@ -1888,7 +1920,7 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir,
         */
        mask = param + 12;
 
-       mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dir, &star);
+       mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dir, &star);
        if (mask_len < 0) {
                result = mask_len;
                goto unlock_return;
@@ -2095,7 +2127,7 @@ smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
        int mask_len, result;
 
 retry:
-       mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dentry, NULL);
+       mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dentry,NULL);
        if (mask_len < 0) {
                result = mask_len;
                goto out;
@@ -2221,7 +2253,7 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
       retry:
        WSET(param, 0, 1);      /* Info level SMB_INFO_STANDARD */
        DSET(param, 2, 0);
-       result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL);
+       result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
        if (result < 0)
                goto out;
        p = param + 6 + result;
@@ -2471,7 +2503,7 @@ smb_proc_setattr_trans2(struct smb_sb_info *server,
       retry:
        WSET(param, 0, 1);      /* Info level SMB_INFO_STANDARD */
        DSET(param, 2, 0);
-       result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL);
+       result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
        if (result < 0)
                goto out;
        p = param + 6 + result;