patch-2.1.61 linux/fs/smbfs/proc.c
Next file: linux/fs/smbfs/sock.c
Previous file: linux/fs/smbfs/ioctl.c
Back to the patch index
Back to the overall index
- Lines: 609
- Date:
Thu Oct 30 11:12:51 1997
- Orig file:
v2.1.60/linux/fs/smbfs/proc.c
- Orig date:
Wed Oct 15 16:04:23 1997
diff -u --recursive --new-file v2.1.60/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
@@ -9,10 +9,7 @@
* by Riccardo Facchetti
*/
-#include <linux/config.h>
#include <linux/fs.h>
-#include <linux/smbno.h>
-#include <linux/smb_fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/malloc.h>
@@ -20,10 +17,16 @@
#include <linux/fcntl.h>
#include <linux/dcache.h>
#include <linux/dirent.h>
+#include <linux/smb_fs.h>
+#include <linux/smbno.h>
+#include <linux/smb_mount.h>
-#include <asm/uaccess.h>
#include <asm/string.h>
+#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_VERBOSE 1 */
+/* #define pr_debug printk */
+
#define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
#define SMB_CMD(packet) (*(packet+8))
#define SMB_WCT(packet) (*(packet+SMB_HEADER_LEN - 1))
@@ -33,12 +36,6 @@
#define SMB_DIRINFO_SIZE 43
#define SMB_STATUS_SIZE 21
-#define SMBFS_PARANOIA 1
-/* #define SMBFS_DEBUG_VERBOSE 1 */
-/* #define pr_debug printk */
-
-extern void smb_renew_times(struct dentry *);
-
static inline int
min(int a, int b)
{
@@ -46,9 +43,9 @@
}
static void
-str_upper(char *name)
+str_upper(char *name, int len)
{
- while (*name)
+ while (len--)
{
if (*name >= 'a' && *name <= 'z')
*name -= ('a' - 'A');
@@ -57,9 +54,9 @@
}
static void
-str_lower(char *name)
+str_lower(char *name, int len)
{
- while (*name)
+ while (len--)
{
if (*name >= 'A' && *name <= 'Z')
*name += ('a' - 'A');
@@ -158,7 +155,7 @@
buf += smb_build_path(dir, name, buf);
if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
- str_upper(start);
+ str_upper(start, buf - start);
return buf;
}
@@ -569,7 +566,7 @@
int error;
error = -EACCES;
- if (!suser() && (current->uid != server->m.mounted_uid))
+ if ((current->uid != server->mnt->mounted_uid) && !suser())
goto out;
if (atomic_read(&server->sem.count) == 1)
{
@@ -609,7 +606,7 @@
goto out;
error = -EACCES;
- if (!suser() && (current->uid != server->m.mounted_uid))
+ if ((current->uid != server->mnt->mounted_uid) && !suser())
goto out;
if (atomic_read(&server->sem.count) == 1)
{
@@ -888,12 +885,11 @@
}
smb_unlock_server(server);
}
- }
- /* Consider dropping negative dentries? */
-#if 0
- else
- d_drop(dentry);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_close_dentry: closed %s/%s, count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
#endif
+ }
}
/* In smb_proc_read and smb_proc_write we do not retry, because the
@@ -951,11 +947,10 @@
smb_lock_server(server);
#if SMBFS_DEBUG_VERBOSE
-{struct dentry * dentry = ino->u.smbfs_i.dentry;
printk("smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
+((struct dentry *)ino->u.smbfs_i.dentry)->d_parent->d_name.name,
+((struct dentry *)ino->u.smbfs_i.dentry)->d_name.name,
count, offset, server->packet_size);
-}
#endif
p = smb_setup_header(server, SMBwrite, 5, count + 3);
WSET(server->packet, smb_vwv0, ino->u.smbfs_i.fileid);
@@ -967,11 +962,11 @@
WSET(p, 0, count);
memcpy(p+2, data, count);
- if ((result = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
+ result = smb_request_ok(server, SMBwrite, 1, 0);
+ if (result >= 0)
result = WVAL(server->packet, smb_vwv0);
smb_unlock_server(server);
-
return result;
}
@@ -997,9 +992,7 @@
if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
goto out;
}
smb_proc_close(server, WVAL(server->packet, smb_vwv0), CURRENT_TIME);
@@ -1033,10 +1026,11 @@
if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -1060,10 +1054,11 @@
if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -1087,10 +1082,11 @@
if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -1115,10 +1111,11 @@
if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -1127,18 +1124,16 @@
smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length)
{
char *p;
- char *buf;
int result;
smb_lock_server(server);
retry:
- buf = server->packet;
p = smb_setup_header(server, SMBwrite, 5, 0);
- WSET(buf, smb_vwv0, fid);
- WSET(buf, smb_vwv1, 0);
- DSET(buf, smb_vwv2, length);
- WSET(buf, smb_vwv4, 0);
+ WSET(server->packet, smb_vwv0, fid);
+ WSET(server->packet, smb_vwv1, 0);
+ DSET(server->packet, smb_vwv2, length);
+ WSET(server->packet, smb_vwv4, 0);
*p++ = 4;
*p++ = 0;
smb_setup_bcc(server, p);
@@ -1146,10 +1141,11 @@
if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -1160,18 +1156,18 @@
memset(fattr, 0, sizeof(*fattr));
fattr->f_nlink = 1;
- fattr->f_uid = server->m.uid;
- fattr->f_gid = server->m.gid;
+ fattr->f_uid = server->mnt->uid;
+ fattr->f_gid = server->mnt->gid;
fattr->f_blksize = 512;
}
static void
smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
{
- fattr->f_mode = server->m.file_mode;
+ fattr->f_mode = server->mnt->file_mode;
if (fattr->attr & aDIR)
{
- fattr->f_mode = server->m.dir_mode;
+ fattr->f_mode = server->mnt->dir_mode;
fattr->f_size = 512;
}
@@ -1194,42 +1190,47 @@
smb_finish_dirent(server, fattr);
}
-
+/*
+ * Note that we are now returning the name as a reference to avoid
+ * an extra copy, and that the upper/lower casing is done in place.
+ */
static __u8 *
-smb_decode_dirent(struct smb_sb_info *server, __u8 *p, struct dirent *entry)
+smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
+ struct cache_dirent *entry)
{
int len;
+ /*
+ * SMB doesn't have a concept of inode numbers ...
+ */
+ entry->ino = 0;
+
p += SMB_STATUS_SIZE; /* reserved (search_status) */
- len = strlen(p + 9);
+ entry->name = p + 9;
+ len = strlen(entry->name);
if (len > 12)
{
len = 12;
}
- memcpy(entry->d_name, p + 9, len);
-#ifdef SMBFS_TRIM_BLANKS
/*
* Trim trailing blanks for Pathworks servers
*/
- while (len > 2 && entry->d_name[len-1] == ' ')
+ while (len > 2 && entry->name[len-1] == ' ')
len--;
-#endif
- entry->d_name[len] = '\0';
- entry->d_reclen = len;
- entry->d_ino = 0; /* no inode number available */
+ entry->len = len;
switch (server->opt.case_handling)
{
case SMB_CASE_UPPER:
- str_upper(entry->d_name);
+ str_upper(entry->name, len);
break;
case SMB_CASE_LOWER:
- str_lower(entry->d_name);
+ str_lower(entry->name, len);
break;
default:
break;
}
- pr_debug("smb_decode_dirent: name = %s\n", entry->name);
+ pr_debug("smb_decode_dirent: len=%d, name=%s\n", len, entry->name);
return p + 22;
}
@@ -1250,7 +1251,10 @@
char status[SMB_STATUS_SIZE];
static struct qstr mask = { "*.*", 3, 0 };
- pr_debug("smb_proc_readdir_short: %d @ %d\n", cache_size, fpos);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir_short: %s/%s, pos=%d\n",
+dir->d_parent->d_name.name, dir->d_name.name, fpos);
+#endif
smb_lock_server(server);
@@ -1317,15 +1321,14 @@
for (i = 0; i < count; i++)
{
- struct dirent this_ent, *entry = &this_ent;
+ struct cache_dirent this_ent, *entry = &this_ent;
p = smb_decode_dirent(server, p, entry);
- if (entries_seen == 2 && entry->d_name[0] == '.')
+ if (entries_seen == 2 && entry->name[0] == '.')
{
- if (entry->d_reclen == 1)
+ if (entry->len == 1)
continue;
- if (entry->d_name[1] == '.' &&
- entry->d_reclen == 2)
+ if (entry->name[1] == '.' && entry->len == 2)
continue;
}
if (entries_seen >= fpos)
@@ -1334,12 +1337,13 @@
entries_seen);
smb_add_to_cache(cachep, entry, entries_seen);
entries++;
- }
+ } else
+ {
#ifdef SMBFS_DEBUG_VERBOSE
-else
printk("smb_proc_readdir: skipped, seen=%d, i=%d, fpos=%d\n",
entries_seen, i, fpos);
#endif
+ }
entries_seen++;
}
}
@@ -1352,58 +1356,53 @@
/*
* Interpret a long filename structure using the specified info level:
- * level 1 -- Win NT, Win 95, OS/2
- * level 2 -- OS/2
+ * level 1 -- Win NT, Win 95, OS/2
* level 259 -- File name and length only, Win NT, Win 95
- * level 260 -- Win NT, Win 95
* There seem to be numerous inconsistencies and bugs in implementation.
+ *
+ * We return a reference to the name string to avoid copying, and perform
+ * any needed upper/lower casing in place. Note!! Level 259 entries may
+ * not have any space beyond the name, so don't try to write a null byte!
*/
static char *
smb_decode_long_dirent(struct smb_sb_info *server, char *p,
- struct dirent *entry, int level)
+ struct cache_dirent *entry, int level)
{
char *result;
- unsigned int len;
+ unsigned int len = 0;
/*
* SMB doesn't have a concept of inode numbers ...
*/
- entry->d_ino = 0;
+ entry->ino = 0;
switch (level)
{
case 1:
len = *((unsigned char *) p + 26);
- entry->d_reclen = len;
- strncpy(entry->d_name, p + 27, len);
- entry->d_name[len] = '\0';
-
+ entry->len = len;
+ entry->name = p + 27;
result = p + 28 + len;
break;
case 259: /* SMB_FIND_FILE_NAMES_INFO = 0x103 */
- /*
- * This info level returns just the file name and length,
- * which is all we need right now.
- */
result = p + DVAL(p, 0);
/* DVAL(p, 4) should be resume key? Seems to be 0 .. */
len = DVAL(p, 8);
if (len > 255)
len = 255;
- strncpy(entry->d_name, p + 12, len);
+ entry->name = p + 12;
/*
* Kludge alert: Win NT 4.0 adds a trailing null byte and
* counts it in the name length, but Win 95 doesn't. Hence
* we test for a trailing null and decrement the length ...
*/
- if (len && entry->d_name[len-1] == '\0')
+ if (len && entry->name[len-1] == '\0')
len--;
- entry->d_name[len] = '\0';
- entry->d_reclen = len;
+ entry->len = len;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_decode_long_dirent: info 259, len=%d, name=%s\n",
-len, entry->d_name);
+printk("smb_decode_long_dirent: info 259 at %p, len=%d, name=%s\n",
+p, len, entry->name);
#endif
break;
@@ -1415,10 +1414,10 @@
switch (server->opt.case_handling)
{
case SMB_CASE_UPPER:
- str_upper(entry->d_name);
+ str_upper(entry->name, len);
break;
case SMB_CASE_LOWER:
- str_lower(entry->d_name);
+ str_lower(entry->name, len);
break;
default:
break;
@@ -1460,7 +1459,7 @@
* Check whether to change the info level. There appears to be
* a bug in Win NT 4.0's handling of info level 1, whereby it
* truncates the directory scan for certain patterns of files.
- * Hence we use level 259 for NT. (Win 95 uses this too?)
+ * Hence we use level 259 for NT. (And Win 95 as well ...)
*/
if (server->opt.protocol >= SMB_PROTOCOL_NT1)
info_level = 259;
@@ -1520,14 +1519,16 @@
WSET(param, 10, 8 + 4 + 2); /* resume required +
close on end +
continue */
-#ifdef CONFIG_SMB_WIN95
- /* Windows 95 is not able to deliver answers
- to FIND_NEXT fast enough, so sleep 0.2 seconds */
- current->timeout = jiffies + HZ / 5;
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- current->timeout = 0;
-#endif
+ if (server->mnt->version & 1)
+ {
+ /* Windows 95 is not able to deliver answers
+ * to FIND_NEXT fast enough, so sleep 0.2 sec
+ */
+ current->timeout = jiffies + HZ / 5;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ current->timeout = 0;
+ }
}
result = smb_trans2_request(server, command,
@@ -1591,7 +1592,7 @@
lastname = resp_data + ff_lastname;
switch (info_level)
{
- case 260:
+ case 259:
if (ff_lastname < resp_data_len)
mask_len = resp_data_len - ff_lastname;
break;
@@ -1622,7 +1623,7 @@
p = resp_data;
for (i = 0; i < ff_searchcount; i++)
{
- struct dirent this_ent, *entry = &this_ent;
+ struct cache_dirent this_ent, *entry = &this_ent;
p = smb_decode_long_dirent(server, p, entry,
info_level);
@@ -1630,12 +1631,11 @@
pr_debug("smb_readdir_long: got %s\n", entry->name);
/* ignore . and .. from the server */
- if (entries_seen == 2 && entry->d_name[0] == '.')
+ if (entries_seen == 2 && entry->name[0] == '.')
{
- if (entry->d_reclen == 1)
+ if (entry->len == 1)
continue;
- if (entry->d_name[1] == '.' &&
- entry->d_reclen == 2)
+ if (entry->name[1] == '.' && entry->len == 2)
continue;
}
if (entries_seen >= fpos)
@@ -1742,7 +1742,13 @@
}
result = -ENOENT;
if (resp_data_len < 22)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_getattr_trans2: not enough data for %s, len=%d\n",
+¶m[6], resp_data_len);
+#endif
goto out;
+ }
attr->f_ctime = date_dos2unix(WVAL(resp_data, 2),
WVAL(resp_data, 0));
@@ -1770,11 +1776,10 @@
smb_init_dirent(server, fattr);
/*
- * N.B. Why would we want to fall back to xxx_core on error?
- * If the file doesn't exist (a very common case), the core
- * protocol won't find it either.
- */
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+ * Win 95 is painfully slow at returning trans2 getattr info ...
+ */
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
+ !(server->mnt->version & 1))
result = smb_proc_getattr_trans2(server, dir, name, fattr);
else
result = smb_proc_getattr_core(server, dir, name, fattr);
@@ -1784,7 +1789,6 @@
return result;
}
-
/* In core protocol, there is only 1 time to be set, we use
entry->f_mtime, to make touch work. */
static int
@@ -1808,10 +1812,15 @@
*p++ = 0;
smb_setup_bcc(server, p);
- if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0)
+ result = smb_request_ok(server, SMBsetatr, 0, 0);
+ if (result < 0)
+ {
if (smb_retry(server))
goto retry;
-
+ goto out;
+ }
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -1855,12 +1864,13 @@
goto retry;
goto out;
}
+ result = 0;
if (server->rcls != 0)
result = -smb_errno(server->rcls, server->err);
out:
smb_unlock_server(server);
- return 0;
+ return result;
}
int
@@ -1869,9 +1879,6 @@
{
int result;
- /*
- * N.B. Why would we want to fall back to xxx_core on error?
- */
if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
result = smb_proc_setattr_trans2(server, dir, fattr);
else
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov