Commit 9ef6e588 authored by Urban Widmark's avatar Urban Widmark Committed by Linus Torvalds

[PATCH] smbfs nls oops fix

Fixes smbfs oopsing on failed nls translations and maps unknown chars to
:#### strings. Also PATHLEN vs NAMELEN mixups.
parent 8ca541f5
...@@ -84,7 +84,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) ...@@ -84,7 +84,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
struct list_head *next; struct list_head *next;
if (d_validate(dent, parent)) { 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) { (unsigned long)dent->d_fsdata == fpos) {
if (!dent->d_inode) { if (!dent->d_inode) {
dput(dent); dput(dent);
......
...@@ -109,6 +109,22 @@ static int convert_memcpy(char *output, int olen, ...@@ -109,6 +109,22 @@ static int convert_memcpy(char *output, int olen,
return ilen; 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). */ /* convert from one "codepage" to another (possibly being utf8). */
static int convert_cp(char *output, int olen, static int convert_cp(char *output, int olen,
const char *input, int ilen, const char *input, int ilen,
...@@ -119,20 +135,26 @@ static int convert_cp(char *output, int olen, ...@@ -119,20 +135,26 @@ static int convert_cp(char *output, int olen,
int n; int n;
wchar_t ch; 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) { while (ilen > 0) {
/* convert by changing to unicode and back to the new cp */ /* convert by changing to unicode and back to the new cp */
n = nls_from->char2uni((unsigned char *)input, ilen, &ch); n = nls_from->char2uni((unsigned char *)input, ilen, &ch);
if (n == -EINVAL) {
ilen--;
n = write_char(*input++, output, olen);
if (n < 0) if (n < 0)
goto fail; goto fail;
output += n;
olen -= n;
len += n;
continue;
} else if (n < 0)
goto fail;
input += n; input += n;
ilen -= n; ilen -= n;
n = nls_to->uni2char(ch, output, olen); n = nls_to->uni2char(ch, output, olen);
if (n == -EINVAL)
n = write_unichar(ch, output, olen);
if (n < 0) if (n < 0)
goto fail; goto fail;
output += n; output += n;
...@@ -226,8 +248,8 @@ static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen, ...@@ -226,8 +248,8 @@ static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,
if (maxlen < 2) if (maxlen < 2)
return -ENAMETOOLONG; return -ENAMETOOLONG;
if (maxlen > SMB_MAXNAMELEN + 1) if (maxlen > SMB_MAXPATHLEN + 1)
maxlen = SMB_MAXNAMELEN + 1; maxlen = SMB_MAXPATHLEN + 1;
if (entry == NULL) if (entry == NULL)
goto test_name_and_out; goto test_name_and_out;
...@@ -1567,7 +1589,6 @@ smb_decode_short_dirent(struct smb_sb_info *server, char *p, ...@@ -1567,7 +1589,6 @@ smb_decode_short_dirent(struct smb_sb_info *server, char *p,
*/ */
while (len > 2 && qname->name[len-1] == ' ') while (len > 2 && qname->name[len-1] == ' ')
len--; len--;
qname->len = len;
smb_finish_dirent(server, fattr); smb_finish_dirent(server, fattr);
...@@ -1586,12 +1607,16 @@ smb_decode_short_dirent(struct smb_sb_info *server, char *p, ...@@ -1586,12 +1607,16 @@ smb_decode_short_dirent(struct smb_sb_info *server, char *p,
} }
#endif #endif
qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN, qname->len = 0;
len = server->convert(server->name_buf, SMB_MAXNAMELEN,
qname->name, len, qname->name, len,
server->remote_nls, server->local_nls); server->remote_nls, server->local_nls);
if (len > 0) {
qname->len = len;
qname->name = server->name_buf; 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; return p + 22;
} }
...@@ -1707,6 +1732,8 @@ smb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir, ...@@ -1707,6 +1732,8 @@ smb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir,
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
p = smb_decode_short_dirent(server, p, p = smb_decode_short_dirent(server, p,
&qname, &fattr); &qname, &fattr);
if (qname.len == 0)
continue;
if (entries_seen == 2 && qname.name[0] == '.') { if (entries_seen == 2 && qname.name[0] == '.') {
if (qname.len == 1) if (qname.len == 1)
...@@ -1744,6 +1771,7 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level, ...@@ -1744,6 +1771,7 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
{ {
char *result; char *result;
unsigned int len = 0; unsigned int len = 0;
int n;
__u16 date, time; __u16 date, time;
/* /*
...@@ -1819,10 +1847,14 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level, ...@@ -1819,10 +1847,14 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
} }
#endif #endif
qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN, qname->len = 0;
n = server->convert(server->name_buf, SMB_MAXNAMELEN,
qname->name, len, qname->name, len,
server->remote_nls, server->local_nls); server->remote_nls, server->local_nls);
if (n > 0) {
qname->len = n;
qname->name = server->name_buf; qname->name = server->name_buf;
}
out: out:
return result; return result;
...@@ -1888,7 +1920,7 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir, ...@@ -1888,7 +1920,7 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir,
*/ */
mask = param + 12; 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) { if (mask_len < 0) {
result = mask_len; result = mask_len;
goto unlock_return; goto unlock_return;
...@@ -2095,7 +2127,7 @@ smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry, ...@@ -2095,7 +2127,7 @@ smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
int mask_len, result; int mask_len, result;
retry: 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) { if (mask_len < 0) {
result = mask_len; result = mask_len;
goto out; goto out;
...@@ -2221,7 +2253,7 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir, ...@@ -2221,7 +2253,7 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
retry: retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0); 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) if (result < 0)
goto out; goto out;
p = param + 6 + result; p = param + 6 + result;
...@@ -2471,7 +2503,7 @@ smb_proc_setattr_trans2(struct smb_sb_info *server, ...@@ -2471,7 +2503,7 @@ smb_proc_setattr_trans2(struct smb_sb_info *server,
retry: retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0); 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) if (result < 0)
goto out; goto out;
p = param + 6 + result; p = param + 6 + result;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment