patch-2.4.11-dontuse linux/fs/smbfs/proc.c
Next file: linux/fs/smbfs/proto.h
Previous file: linux/fs/smbfs/ioctl.c
Back to the patch index
Back to the overall index
- Lines: 512
- Date:
Sun Oct 7 16:47:43 2001
- Orig file:
v2.4.10/linux/fs/smbfs/proc.c
- Orig date:
Tue Jul 3 17:08:21 2001
diff -u --recursive --new-file v2.4.10/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
@@ -23,16 +23,18 @@
#include <linux/smb_mount.h>
#include <asm/string.h>
+#include <asm/div64.h>
#include "smb_debug.h"
+#include "proto.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 */
+/* Allow smb_retry to be interrupted. */
+#define SMB_RETRY_INTR
#define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
#define SMB_CMD(packet) (*(packet+8))
@@ -43,6 +45,9 @@
#define SMB_DIRINFO_SIZE 43
#define SMB_STATUS_SIZE 21
+#define SMB_ST_BLKSIZE (PAGE_SIZE)
+#define SMB_ST_BLKSHIFT (PAGE_SHIFT)
+
static int
smb_proc_setattr_ext(struct smb_sb_info *, struct inode *,
struct smb_fattr *);
@@ -137,8 +142,7 @@
return len;
}
-static int setcodepage(struct smb_sb_info *server,
- struct nls_table **p, char *name)
+static int setcodepage(struct nls_table **p, char *name)
{
struct nls_table *nls;
@@ -160,16 +164,20 @@
/* Handles all changes to codepage settings. */
int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp)
{
- int n;
+ int n = 0;
smb_lock_server(server);
- n = setcodepage(server, &server->local_nls, cp->local_name);
+ /* Don't load any nls_* at all, if no remote is requested */
+ if (!*cp->remote_name)
+ goto out;
+
+ n = setcodepage(&server->local_nls, cp->local_name);
if (n != 0)
goto out;
- n = setcodepage(server, &server->remote_nls, cp->remote_name);
+ n = setcodepage(&server->remote_nls, cp->remote_name);
if (n != 0)
- setcodepage(server, &server->local_nls, NULL);
+ setcodepage(&server->local_nls, NULL);
out:
if (server->local_nls != NULL && server->remote_nls != NULL)
@@ -188,7 +196,7 @@
/* */
/*****************************************************************************/
-__u8 *
+static __u8 *
smb_encode_smb_length(__u8 * p, __u32 len)
{
*p = 0;
@@ -308,7 +316,9 @@
int month, year;
time_t secs;
- month = ((date >> 5) & 15) - 1;
+ /* first subtract and mask after that... Otherwise, if
+ date == 0, bad things happen */
+ month = ((date >> 5) - 1) & 15;
year = date >> 9;
secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
@@ -327,6 +337,9 @@
int day, year, nl_day, month;
unix_date = utc2local(server, unix_date);
+ if (unix_date < 315532800)
+ unix_date = 315532800;
+
*time = (unix_date % 60) / 2 +
(((unix_date / 60) % 60) << 5) +
(((unix_date / 3600) % 24) << 11);
@@ -350,57 +363,20 @@
/* The following are taken from fs/ntfs/util.c */
+#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
+
/*
* Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
* into Unix UTC (based 1970-01-01, in seconds).
- *
- * This is very gross because
- * 1: We must do 64-bit division on a 32-bit machine
- * 2: We can't use libgcc for long long operations in the kernel
- * 3: Floating point math in the kernel would corrupt user data
*/
static time_t
-smb_ntutc2unixutc(struct smb_sb_info *server, u64 ntutc)
+smb_ntutc2unixutc(u64 ntutc)
{
- const unsigned int D = 10000000;
- unsigned int H = (unsigned int)(ntutc >> 32);
- unsigned int L = (unsigned int)ntutc;
- unsigned int numerator2;
- unsigned int lowseconds;
- unsigned int result;
-
- /*
- * It is best to subtract 0x019db1ded53e8000 first.
- * Then the 1601-based date becomes a 1970-based date.
- */
- if (L < (unsigned)0xd53e8000) H--;
- L -= (unsigned)0xd53e8000;
- H -= (unsigned)0x019db1de;
-
- /*
- * Now divide 64-bit numbers on a 32-bit machine :-)
- * With the subtraction already done, the result fits in 32 bits.
- * The numerator fits in 56 bits and the denominator fits
- * in 24 bits, so we can shift by 8 bits to make this work.
- */
-
- numerator2 = (H<<8) | (L>>24);
- result = (numerator2 / D); /* shifted 24 right!! */
- lowseconds = result << 24;
-
- numerator2 = ((numerator2-result*D)<<8) | ((L>>16)&0xff);
- result = (numerator2 / D); /* shifted 16 right!! */
- lowseconds |= result << 16;
-
- numerator2 = ((numerator2-result*D)<<8) | ((L>>8)&0xff);
- result = (numerator2 / D); /* shifted 8 right!! */
- lowseconds |= result << 8;
-
- numerator2 = ((numerator2-result*D)<<8) | (L&0xff);
- result = (numerator2 / D); /* not shifted */
- lowseconds |= result;
-
- return lowseconds;
+ /* FIXME: what about the timezone difference? */
+ /* Subtract the NTFS time offset, then convert to 1s intervals. */
+ u64 t = ntutc - NTFS_TIME_OFFSET;
+ do_div(t, 10000000);
+ return (time_t)t;
}
#if 0
@@ -409,7 +385,7 @@
smb_unixutc2ntutc(struct smb_sb_info *server, time_t t)
{
/* Note: timezone conversion is probably wrong. */
- return ((utc2local(server, t) + (u64)(369*365+89)*24*3600) * 10000000);
+ return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET;
}
#endif
@@ -519,6 +495,9 @@
return size;
}
+/*
+ * Convert SMB error codes to -E... errno values.
+ */
int
smb_errno(struct smb_sb_info *server)
{
@@ -529,110 +508,117 @@
VERBOSE("errcls %d code %d from command 0x%x\n",
errcls, error, SMB_CMD(server->packet));
- if (errcls == ERRDOS)
- switch (error)
- {
+ if (errcls == ERRDOS) {
+ switch (error) {
case ERRbadfunc:
- return EINVAL;
+ return -EINVAL;
case ERRbadfile:
case ERRbadpath:
- return ENOENT;
+ return -ENOENT;
case ERRnofids:
- return EMFILE;
+ return -EMFILE;
case ERRnoaccess:
- return EACCES;
+ return -EACCES;
case ERRbadfid:
- return EBADF;
+ return -EBADF;
case ERRbadmcb:
- return EREMOTEIO;
+ return -EREMOTEIO;
case ERRnomem:
- return ENOMEM;
+ return -ENOMEM;
case ERRbadmem:
- return EFAULT;
+ return -EFAULT;
case ERRbadenv:
case ERRbadformat:
- return EREMOTEIO;
+ return -EREMOTEIO;
case ERRbadaccess:
- return EACCES;
+ return -EACCES;
case ERRbaddata:
- return E2BIG;
+ return -E2BIG;
case ERRbaddrive:
- return ENXIO;
+ return -ENXIO;
case ERRremcd:
- return EREMOTEIO;
+ return -EREMOTEIO;
case ERRdiffdevice:
- return EXDEV;
- case ERRnofiles: /* Why is this mapped to 0?? */
- return 0;
+ return -EXDEV;
+ case ERRnofiles:
+ return -ENOENT;
case ERRbadshare:
- return ETXTBSY;
+ return -ETXTBSY;
case ERRlock:
- return EDEADLK;
+ return -EDEADLK;
case ERRfilexists:
- return EEXIST;
- case 87: /* should this map to 0?? */
- return 0; /* Unknown error!! */
- case 123: /* Invalid name?? e.g. .tmp* */
- return ENOENT;
- case 145: /* Win NT 4.0: non-empty directory? */
- return ENOTEMPTY;
- /* This next error seems to occur on an mv when
- * the destination exists */
- case 183:
- return EEXIST;
+ return -EEXIST;
+ case ERROR_INVALID_PARAMETER:
+ return -EINVAL;
+ case ERROR_DISK_FULL:
+ return -ENOSPC;
+ case ERROR_INVALID_NAME:
+ return -ENOENT;
+ case ERROR_DIR_NOT_EMPTY:
+ return -ENOTEMPTY;
+ case ERROR_NOT_LOCKED:
+ return -ENOLCK;
+ case ERROR_ALREADY_EXISTS:
+ return -EEXIST;
default:
class = "ERRDOS";
goto err_unknown;
- } else if (errcls == ERRSRV)
- switch (error)
- {
+ }
+ } else if (errcls == ERRSRV) {
+ switch (error) {
/* N.B. This is wrong ... EIO ? */
case ERRerror:
- return ENFILE;
+ return -ENFILE;
case ERRbadpw:
- return EINVAL;
+ return -EINVAL;
case ERRbadtype:
- return EIO;
+ return -EIO;
case ERRaccess:
- return EACCES;
+ return -EACCES;
/*
* This is a fatal error, as it means the "tree ID"
* for this connection is no longer valid. We map
* to a special error code and get a new connection.
*/
case ERRinvnid:
- return EBADSLT;
+ return -EBADSLT;
default:
class = "ERRSRV";
goto err_unknown;
- } else if (errcls == ERRHRD)
- switch (error)
- {
+ }
+ } else if (errcls == ERRHRD) {
+ switch (error) {
case ERRnowrite:
- return EROFS;
+ return -EROFS;
case ERRbadunit:
- return ENODEV;
+ return -ENODEV;
case ERRnotready:
- return EUCLEAN;
+ return -EUCLEAN;
case ERRbadcmd:
case ERRdata:
- return EIO;
+ return -EIO;
case ERRbadreq:
- return ERANGE;
+ return -ERANGE;
case ERRbadshare:
- return ETXTBSY;
+ return -ETXTBSY;
case ERRlock:
- return EDEADLK;
+ return -EDEADLK;
+ case ERRdiskfull:
+ return -ENOSPC;
default:
class = "ERRHRD";
goto err_unknown;
- } else if (errcls == ERRCMD)
+ }
+ } else if (errcls == ERRCMD) {
class = "ERRCMD";
+ } else if (errcls == SUCCESS) {
+ return 0; /* This is the only valid 0 return */
+ }
err_unknown:
printk(KERN_ERR "smb_errno: class %s, code %d from command 0x%x\n",
class, error, SMB_CMD(server->packet));
- return EIO;
+ return -EIO;
}
/*
@@ -749,12 +735,10 @@
}
/*
- * Check for server errors. The current smb_errno() routine
- * is squashing some error codes, but I don't think this is
- * correct: after a server error the packet won't be valid.
+ * Check for server errors.
*/
if (s->rcls != 0) {
- result = -smb_errno(s);
+ result = smb_errno(s);
if (!result)
printk(KERN_DEBUG "smb_request_ok: rcls=%d, err=%d mapped to 0\n",
s->rcls, s->err);
@@ -850,17 +834,23 @@
out:
smb_unlock_server(server);
+ smb_wakeup(server);
+ return error;
+
+out_putf:
+ fput(filp);
+ goto out;
+}
+int
+smb_wakeup(struct smb_sb_info *server)
+{
#ifdef SMB_RETRY_INTR
wake_up_interruptible(&server->wait);
#else
wake_up(&server->wait);
#endif
- return error;
-
-out_putf:
- fput(filp);
- goto out;
+ return 0;
}
/* smb_setup_header: We completely set up the packet. You only have to
@@ -1490,7 +1480,7 @@
fattr->f_nlink = 1;
fattr->f_uid = server->mnt->uid;
fattr->f_gid = server->mnt->gid;
- fattr->f_blksize = 512;
+ fattr->f_blksize = SMB_ST_BLKSIZE;
}
static void
@@ -1500,18 +1490,16 @@
if (fattr->attr & aDIR)
{
fattr->f_mode = server->mnt->dir_mode;
- fattr->f_size = 512;
+ fattr->f_size = SMB_ST_BLKSIZE;
}
/* Check the read-only flag */
if (fattr->attr & aRONLY)
fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ /* How many 512 byte blocks do we need for this file? */
fattr->f_blocks = 0;
- if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
- {
- fattr->f_blocks =
- (fattr->f_size - 1) / fattr->f_blksize + 1;
- }
+ if (fattr->f_size != 0)
+ fattr->f_blocks = 1 + ((fattr->f_size-1) >> 9);
return;
}
@@ -1770,9 +1758,9 @@
if (len && qname->name[len-1] == '\0')
len--;
- fattr->f_ctime = smb_ntutc2unixutc(server, LVAL(p, 8));
- fattr->f_atime = smb_ntutc2unixutc(server, LVAL(p, 16));
- fattr->f_mtime = smb_ntutc2unixutc(server, LVAL(p, 24));
+ fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 8));
+ fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 16));
+ fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 24));
/* change time (32) */
fattr->f_size = DVAL(p, 40);
/* alloc size (48) */
@@ -1940,7 +1928,7 @@
}
if (server->rcls != 0) {
- result = -smb_errno(server);
+ result = smb_errno(server);
PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n",
mask, result, server->rcls, server->err);
break;
@@ -2104,7 +2092,7 @@
}
if (server->rcls != 0)
{
- result = -smb_errno(server);
+ result = smb_errno(server);
#ifdef SMBFS_PARANOIA
if (result != -ENOENT)
PARANOIA("error for %s, rcls=%d, err=%d\n",
@@ -2227,7 +2215,7 @@
{
VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
¶m[6], result, server->rcls, server->err);
- result = -smb_errno(server);
+ result = smb_errno(server);
goto out;
}
result = -ENOENT;
@@ -2490,7 +2478,7 @@
}
result = 0;
if (server->rcls != 0)
- result = -smb_errno(server);
+ result = smb_errno(server);
out:
return result;
@@ -2559,6 +2547,7 @@
struct smb_sb_info *server = &(sb->u.smbfs_sb);
int result;
char *p;
+ long unit;
smb_lock_server(server);
@@ -2571,23 +2560,13 @@
goto out;
}
p = SMB_VWV(server->packet);
- attr->f_blocks = WVAL(p, 0);
- attr->f_bsize = WVAL(p, 2) * WVAL(p, 4);
- attr->f_bavail = attr->f_bfree = WVAL(p, 6);
+ unit = (WVAL(p, 2) * WVAL(p, 4)) >> SMB_ST_BLKSHIFT;
+ attr->f_blocks = WVAL(p, 0) * unit;
+ attr->f_bsize = SMB_ST_BLKSIZE;
+ attr->f_bavail = attr->f_bfree = WVAL(p, 6) * unit;
result = 0;
out:
- smb_unlock_server(server);
- return result;
-}
-
-int
-smb_proc_disconnect(struct smb_sb_info *server)
-{
- int result;
- smb_lock_server(server);
- smb_setup_header(server, SMBtdis, 0, 0);
- result = smb_request_ok(server, SMBtdis, 0, 0);
smb_unlock_server(server);
return result;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)