OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [smbfs/] [proc.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 *  proc.c
 *  proc.c
 *
 *
 *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
 *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
 *
 *
 *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
 *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
 */
 */
 
 
#include <linux/config.h>
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/smbno.h>
#include <linux/smbno.h>
#include <linux/smb_fs.h>
#include <linux/smb_fs.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
#include <asm/segment.h>
#include <asm/string.h>
#include <asm/string.h>
 
 
#define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
#define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
#define SMB_CMD(packet)  (BVAL(packet,8))
#define SMB_CMD(packet)  (BVAL(packet,8))
#define SMB_WCT(packet)  (BVAL(packet, SMB_HEADER_LEN - 1))
#define SMB_WCT(packet)  (BVAL(packet, SMB_HEADER_LEN - 1))
#define SMB_BCC(packet)  smb_bcc(packet)
#define SMB_BCC(packet)  smb_bcc(packet)
#define SMB_BUF(packet)  ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
#define SMB_BUF(packet)  ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
 
 
#define SMB_DIRINFO_SIZE 43
#define SMB_DIRINFO_SIZE 43
#define SMB_STATUS_SIZE  21
#define SMB_STATUS_SIZE  21
 
 
static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
 
 
static inline int
static inline int
min(int a, int b)
min(int a, int b)
{
{
        return a < b ? a : b;
        return a < b ? a : b;
}
}
 
 
static void
static void
str_upper(char *name)
str_upper(char *name)
{
{
        while (*name)
        while (*name)
        {
        {
                if (*name >= 'a' && *name <= 'z')
                if (*name >= 'a' && *name <= 'z')
                        *name -= ('a' - 'A');
                        *name -= ('a' - 'A');
                name++;
                name++;
        }
        }
}
}
 
 
static void
static void
str_lower(char *name)
str_lower(char *name)
{
{
        while (*name)
        while (*name)
        {
        {
                if (*name >= 'A' && *name <= 'Z')
                if (*name >= 'A' && *name <= 'Z')
                        *name += ('a' - 'A');
                        *name += ('a' - 'A');
                name++;
                name++;
        }
        }
}
}
 
 
/*****************************************************************************/
/*****************************************************************************/
/*                                                                           */
/*                                                                           */
/*  Encoding/Decoding section                                                */
/*  Encoding/Decoding section                                                */
/*                                                                           */
/*                                                                           */
/*****************************************************************************/
/*****************************************************************************/
 
 
static inline byte *
static inline byte *
smb_decode_word(byte * p, word * data)
smb_decode_word(byte * p, word * data)
{
{
        *data = WVAL(p, 0);
        *data = WVAL(p, 0);
        return p + 2;
        return p + 2;
}
}
 
 
byte *
byte *
smb_encode_smb_length(byte * p, dword len)
smb_encode_smb_length(byte * p, dword len)
{
{
        BSET(p, 0, 0);
        BSET(p, 0, 0);
        BSET(p, 1, 0);
        BSET(p, 1, 0);
        BSET(p, 2, (len & 0xFF00) >> 8);
        BSET(p, 2, (len & 0xFF00) >> 8);
        BSET(p, 3, (len & 0xFF));
        BSET(p, 3, (len & 0xFF));
        if (len > 0xFFFF)
        if (len > 0xFFFF)
        {
        {
                BSET(p, 1, 1);
                BSET(p, 1, 1);
        }
        }
        return p + 4;
        return p + 4;
}
}
 
 
static byte *
static byte *
smb_encode_ascii(byte * p, const byte * name, int len)
smb_encode_ascii(byte * p, const byte * name, int len)
{
{
        *p++ = 4;
        *p++ = 4;
        strcpy(p, name);
        strcpy(p, name);
        return p + len + 1;
        return p + len + 1;
}
}
 
 
static byte *
static byte *
smb_encode_this_name(byte * p, const char *name, const int len)
smb_encode_this_name(byte * p, const char *name, const int len)
{
{
        *p++ = '\\';
        *p++ = '\\';
        strncpy(p, name, len);
        strncpy(p, name, len);
        return p + len;
        return p + len;
}
}
 
 
/* I put smb_encode_parents into a separate function so that the
/* I put smb_encode_parents into a separate function so that the
   recursion only takes 16 bytes on the stack per path component on a
   recursion only takes 16 bytes on the stack per path component on a
   386. */
   386. */
 
 
static byte *
static byte *
smb_encode_parents(byte * p, struct smb_inode_info *ino)
smb_encode_parents(byte * p, struct smb_inode_info *ino)
{
{
        byte *q;
        byte *q;
 
 
        if (ino->dir == NULL)
        if (ino->dir == NULL)
        {
        {
                return p;
                return p;
        }
        }
        q = smb_encode_parents(p, ino->dir);
        q = smb_encode_parents(p, ino->dir);
        if (q - p + 1 + ino->finfo.len > SMB_MAXPATHLEN)
        if (q - p + 1 + ino->finfo.len > SMB_MAXPATHLEN)
        {
        {
                return p;
                return p;
        }
        }
        return smb_encode_this_name(q, ino->finfo.name, ino->finfo.len);
        return smb_encode_this_name(q, ino->finfo.name, ino->finfo.len);
}
}
 
 
static byte *
static byte *
smb_encode_path(struct smb_server *server,
smb_encode_path(struct smb_server *server,
                byte * p, struct smb_inode_info *dir,
                byte * p, struct smb_inode_info *dir,
                const char *name, const int len)
                const char *name, const int len)
{
{
        byte *start = p;
        byte *start = p;
        if (dir != NULL)
        if (dir != NULL)
        {
        {
                p = smb_encode_parents(p, dir);
                p = smb_encode_parents(p, dir);
        }
        }
        p = smb_encode_this_name(p, name, len);
        p = smb_encode_this_name(p, name, len);
        *p++ = 0;
        *p++ = 0;
        if (server->protocol <= PROTOCOL_COREPLUS)
        if (server->protocol <= PROTOCOL_COREPLUS)
        {
        {
                str_upper(start);
                str_upper(start);
        }
        }
        return p;
        return p;
}
}
 
 
static byte *
static byte *
smb_decode_data(byte * p, byte * data, word * data_len, int fs)
smb_decode_data(byte * p, byte * data, word * data_len, int fs)
{
{
        word len;
        word len;
 
 
        if (!(*p == 1 || *p == 5))
        if (!(*p == 1 || *p == 5))
        {
        {
                printk("smb_decode_data: Warning! Data block not starting "
                printk("smb_decode_data: Warning! Data block not starting "
                       "with 1 or 5\n");
                       "with 1 or 5\n");
        }
        }
        len = WVAL(p, 1);
        len = WVAL(p, 1);
        p += 3;
        p += 3;
 
 
        if (fs)
        if (fs)
                memcpy_tofs(data, p, len);
                memcpy_tofs(data, p, len);
        else
        else
                memcpy(data, p, len);
                memcpy(data, p, len);
 
 
        *data_len = len;
        *data_len = len;
 
 
        return p + len;
        return p + len;
}
}
 
 
static byte *
static byte *
smb_name_mangle(byte * p, const byte * name)
smb_name_mangle(byte * p, const byte * name)
{
{
        int len, pad = 0;
        int len, pad = 0;
 
 
        len = strlen(name);
        len = strlen(name);
 
 
        if (len < 16)
        if (len < 16)
                pad = 16 - len;
                pad = 16 - len;
 
 
        *p++ = 2 * (len + pad);
        *p++ = 2 * (len + pad);
 
 
        while (*name)
        while (*name)
        {
        {
                *p++ = (*name >> 4) + 'A';
                *p++ = (*name >> 4) + 'A';
                *p++ = (*name & 0x0F) + 'A';
                *p++ = (*name & 0x0F) + 'A';
                name++;
                name++;
        }
        }
        while (pad--)
        while (pad--)
        {
        {
                *p++ = 'C';
                *p++ = 'C';
                *p++ = 'A';
                *p++ = 'A';
        }
        }
        *p++ = '\0';
        *p++ = '\0';
 
 
        return p;
        return p;
}
}
 
 
/* The following are taken directly from msdos-fs */
/* The following are taken directly from msdos-fs */
 
 
/* Linear day numbers of the respective 1sts in non-leap years. */
/* Linear day numbers of the respective 1sts in non-leap years. */
 
 
static int day_n[] =
static int day_n[] =
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
                  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
                  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
 
 
 
 
extern struct timezone sys_tz;
extern struct timezone sys_tz;
 
 
static int
static int
utc2local(int time)
utc2local(int time)
{
{
        return time - sys_tz.tz_minuteswest * 60 + sys_tz.tz_dsttime * 3600;
        return time - sys_tz.tz_minuteswest * 60 + sys_tz.tz_dsttime * 3600;
}
}
 
 
static int
static int
local2utc(int time)
local2utc(int time)
{
{
        return time + sys_tz.tz_minuteswest * 60 - sys_tz.tz_dsttime * 3600;
        return time + sys_tz.tz_minuteswest * 60 - sys_tz.tz_dsttime * 3600;
}
}
 
 
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
 
 
static int
static int
date_dos2unix(unsigned short time, unsigned short date)
date_dos2unix(unsigned short time, unsigned short date)
{
{
        int month, year, secs;
        int month, year, secs;
 
 
        month = ((date >> 5) & 15) - 1;
        month = ((date >> 5) & 15) - 1;
        year = date >> 9;
        year = date >> 9;
        secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
        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 &&
            ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
                                                   month < 2 ? 1 : 0) + 3653);
                                                   month < 2 ? 1 : 0) + 3653);
        /* days since 1.1.70 plus 80's leap day */
        /* days since 1.1.70 plus 80's leap day */
        return local2utc(secs);
        return local2utc(secs);
}
}
 
 
/*****************************************************************************/
/*****************************************************************************/
/*                                                                           */
/*                                                                           */
/*  Support section.                                                         */
/*  Support section.                                                         */
/*                                                                           */
/*                                                                           */
/*****************************************************************************/
/*****************************************************************************/
 
 
dword
dword
smb_len(byte * p)
smb_len(byte * p)
{
{
        return ((BVAL(p, 1) & 0x1) << 16L) | (BVAL(p, 2) << 8L) | (BVAL(p, 3));
        return ((BVAL(p, 1) & 0x1) << 16L) | (BVAL(p, 2) << 8L) | (BVAL(p, 3));
}
}
 
 
static word
static word
smb_bcc(byte * packet)
smb_bcc(byte * packet)
{
{
        int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word);
        int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word);
        return WVAL(packet, pos);
        return WVAL(packet, pos);
}
}
 
 
/* smb_valid_packet: We check if packet fulfills the basic
/* smb_valid_packet: We check if packet fulfills the basic
   requirements of a smb packet */
   requirements of a smb packet */
 
 
static int
static int
smb_valid_packet(byte * packet)
smb_valid_packet(byte * packet)
{
{
        DDPRINTK("len: %d, wct: %d, bcc: %d\n",
        DDPRINTK("len: %d, wct: %d, bcc: %d\n",
                 smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
                 smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
        return (packet[4] == 0xff
        return (packet[4] == 0xff
                && packet[5] == 'S'
                && packet[5] == 'S'
                && packet[6] == 'M'
                && packet[6] == 'M'
                && packet[7] == 'B'
                && packet[7] == 'B'
                && (smb_len(packet) + 4 == SMB_HEADER_LEN
                && (smb_len(packet) + 4 == SMB_HEADER_LEN
                    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
                    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
}
}
 
 
/* smb_verify: We check if we got the answer we expected, and if we
/* smb_verify: We check if we got the answer we expected, and if we
   got enough data. If bcc == -1, we don't care. */
   got enough data. If bcc == -1, we don't care. */
 
 
static int
static int
smb_verify(byte * packet, int command, int wct, int bcc)
smb_verify(byte * packet, int command, int wct, int bcc)
{
{
        return (SMB_CMD(packet) == command &&
        return (SMB_CMD(packet) == command &&
                SMB_WCT(packet) >= wct &&
                SMB_WCT(packet) >= wct &&
                (bcc == -1 || SMB_BCC(packet) >= bcc)) ? 0 : -EIO;
                (bcc == -1 || SMB_BCC(packet) >= bcc)) ? 0 : -EIO;
}
}
 
 
static int
static int
smb_errno(int errcls, int error)
smb_errno(int errcls, int error)
{
{
        if (errcls == ERRDOS)
        if (errcls == ERRDOS)
                switch (error)
                switch (error)
                {
                {
                case ERRbadfunc:
                case ERRbadfunc:
                        return EINVAL;
                        return EINVAL;
                case ERRbadfile:
                case ERRbadfile:
                        return ENOENT;
                        return ENOENT;
                case ERRbadpath:
                case ERRbadpath:
                        return ENOENT;
                        return ENOENT;
                case ERRnofids:
                case ERRnofids:
                        return EMFILE;
                        return EMFILE;
                case ERRnoaccess:
                case ERRnoaccess:
                        return EACCES;
                        return EACCES;
                case ERRbadfid:
                case ERRbadfid:
                        return EBADF;
                        return EBADF;
                case ERRbadmcb:
                case ERRbadmcb:
                        return EREMOTEIO;
                        return EREMOTEIO;
                case ERRnomem:
                case ERRnomem:
                        return ENOMEM;
                        return ENOMEM;
                case ERRbadmem:
                case ERRbadmem:
                        return EFAULT;
                        return EFAULT;
                case ERRbadenv:
                case ERRbadenv:
                        return EREMOTEIO;
                        return EREMOTEIO;
                case ERRbadformat:
                case ERRbadformat:
                        return EREMOTEIO;
                        return EREMOTEIO;
                case ERRbadaccess:
                case ERRbadaccess:
                        return EACCES;
                        return EACCES;
                case ERRbaddata:
                case ERRbaddata:
                        return E2BIG;
                        return E2BIG;
                case ERRbaddrive:
                case ERRbaddrive:
                        return ENXIO;
                        return ENXIO;
                case ERRremcd:
                case ERRremcd:
                        return EREMOTEIO;
                        return EREMOTEIO;
                case ERRdiffdevice:
                case ERRdiffdevice:
                        return EXDEV;
                        return EXDEV;
                case ERRnofiles:
                case ERRnofiles:
                        return 0;
                        return 0;
                case ERRbadshare:
                case ERRbadshare:
                        return ETXTBSY;
                        return ETXTBSY;
                case ERRlock:
                case ERRlock:
                        return EDEADLK;
                        return EDEADLK;
                case ERRfilexists:
                case ERRfilexists:
                        return EEXIST;
                        return EEXIST;
                case 87:
                case 87:
                        return 0;        /* Unknown error!! */
                        return 0;        /* Unknown error!! */
                        /* This next error seems to occur on an mv when
                        /* This next error seems to occur on an mv when
                         * the destination exists */
                         * the destination exists */
                case 183:
                case 183:
                        return EEXIST;
                        return EEXIST;
                default:
                default:
                        return EIO;
                        return EIO;
        } else if (errcls == ERRSRV)
        } else if (errcls == ERRSRV)
                switch (error)
                switch (error)
                {
                {
                case ERRerror:
                case ERRerror:
                        return ENFILE;
                        return ENFILE;
                case ERRbadpw:
                case ERRbadpw:
                        return EINVAL;
                        return EINVAL;
                case ERRbadtype:
                case ERRbadtype:
                        return EIO;
                        return EIO;
                case ERRaccess:
                case ERRaccess:
                        return EACCES;
                        return EACCES;
                default:
                default:
                        return EIO;
                        return EIO;
        } else if (errcls == ERRHRD)
        } else if (errcls == ERRHRD)
                switch (error)
                switch (error)
                {
                {
                case ERRnowrite:
                case ERRnowrite:
                        return EROFS;
                        return EROFS;
                case ERRbadunit:
                case ERRbadunit:
                        return ENODEV;
                        return ENODEV;
                case ERRnotready:
                case ERRnotready:
                        return EUCLEAN;
                        return EUCLEAN;
                case ERRbadcmd:
                case ERRbadcmd:
                        return EIO;
                        return EIO;
                case ERRdata:
                case ERRdata:
                        return EIO;
                        return EIO;
                case ERRbadreq:
                case ERRbadreq:
                        return ERANGE;
                        return ERANGE;
                case ERRbadshare:
                case ERRbadshare:
                        return ETXTBSY;
                        return ETXTBSY;
                case ERRlock:
                case ERRlock:
                        return EDEADLK;
                        return EDEADLK;
                default:
                default:
                        return EIO;
                        return EIO;
        } else if (errcls == ERRCMD)
        } else if (errcls == ERRCMD)
                return EIO;
                return EIO;
        return 0;
        return 0;
}
}
 
 
static void
static void
smb_lock_server(struct smb_server *server)
smb_lock_server(struct smb_server *server)
{
{
        while (server->lock)
        while (server->lock)
                sleep_on(&server->wait);
                sleep_on(&server->wait);
        server->lock = 1;
        server->lock = 1;
}
}
 
 
static void
static void
smb_unlock_server(struct smb_server *server)
smb_unlock_server(struct smb_server *server)
{
{
        if (server->lock != 1)
        if (server->lock != 1)
        {
        {
                printk("smb_unlock_server: was not locked!\n");
                printk("smb_unlock_server: was not locked!\n");
        }
        }
        server->lock = 0;
        server->lock = 0;
        wake_up(&server->wait);
        wake_up(&server->wait);
}
}
 
 
/* smb_request_ok: We expect the server to be locked. Then we do the
/* smb_request_ok: We expect the server to be locked. Then we do the
   request and check the answer completely. When smb_request_ok
   request and check the answer completely. When smb_request_ok
   returns 0, you can be quite sure that everything went well. When
   returns 0, you can be quite sure that everything went well. When
   the answer is <=0, the returned number is a valid unix errno. */
   the answer is <=0, the returned number is a valid unix errno. */
 
 
static int
static int
smb_request_ok(struct smb_server *s, int command, int wct, int bcc)
smb_request_ok(struct smb_server *s, int command, int wct, int bcc)
{
{
        int result = 0;
        int result = 0;
        s->rcls = 0;
        s->rcls = 0;
        s->err = 0;
        s->err = 0;
 
 
        if (smb_request(s) < 0)
        if (smb_request(s) < 0)
        {
        {
                DPRINTK("smb_request failed\n");
                DPRINTK("smb_request failed\n");
                result = -EIO;
                result = -EIO;
        } else if (smb_valid_packet(s->packet) != 0)
        } else if (smb_valid_packet(s->packet) != 0)
        {
        {
                DPRINTK("not a valid packet!\n");
                DPRINTK("not a valid packet!\n");
                result = -EIO;
                result = -EIO;
        } else if (s->rcls != 0)
        } else if (s->rcls != 0)
        {
        {
                result = -smb_errno(s->rcls, s->err);
                result = -smb_errno(s->rcls, s->err);
        } else if (smb_verify(s->packet, command, wct, bcc) != 0)
        } else if (smb_verify(s->packet, command, wct, bcc) != 0)
        {
        {
                DPRINTK("smb_verify failed\n");
                DPRINTK("smb_verify failed\n");
                result = -EIO;
                result = -EIO;
        }
        }
        return result;
        return result;
}
}
 
 
/* smb_retry: This function should be called when smb_request_ok has
/* smb_retry: This function should be called when smb_request_ok has
   indicated an error. If the error was indicated because the
   indicated an error. If the error was indicated because the
   connection was killed, we try to reconnect. If smb_retry returns 0,
   connection was killed, we try to reconnect. If smb_retry returns 0,
   the error was indicated for another reason, so a retry would not be
   the error was indicated for another reason, so a retry would not be
   of any use. */
   of any use. */
 
 
static int
static int
smb_retry(struct smb_server *server)
smb_retry(struct smb_server *server)
{
{
        if (server->state != CONN_INVALID)
        if (server->state != CONN_INVALID)
        {
        {
                return 0;
                return 0;
        }
        }
        if (smb_release(server) < 0)
        if (smb_release(server) < 0)
        {
        {
                DPRINTK("smb_retry: smb_release failed\n");
                DPRINTK("smb_retry: smb_release failed\n");
                server->state = CONN_RETRIED;
                server->state = CONN_RETRIED;
                return 0;
                return 0;
        }
        }
        if (smb_proc_reconnect(server) < 0)
        if (smb_proc_reconnect(server) < 0)
        {
        {
                DPRINTK("smb_proc_reconnect failed\n");
                DPRINTK("smb_proc_reconnect failed\n");
                server->state = CONN_RETRIED;
                server->state = CONN_RETRIED;
                return 0;
                return 0;
        }
        }
        server->state = CONN_VALID;
        server->state = CONN_VALID;
        return 1;
        return 1;
}
}
 
 
static int
static int
smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc)
smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc)
{
{
        int result = smb_request_ok(s, command, wct, bcc);
        int result = smb_request_ok(s, command, wct, bcc);
 
 
        smb_unlock_server(s);
        smb_unlock_server(s);
 
 
        return result;
        return result;
}
}
 
 
/* smb_setup_header: We completely set up the packet. You only have to
/* smb_setup_header: We completely set up the packet. You only have to
   insert the command-specific fields */
   insert the command-specific fields */
 
 
__u8 *
__u8 *
smb_setup_header(struct smb_server * server, byte command, word wct, word bcc)
smb_setup_header(struct smb_server * server, byte command, word wct, word bcc)
{
{
        dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2;
        dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2;
        byte *p = server->packet;
        byte *p = server->packet;
        byte *buf = server->packet;
        byte *buf = server->packet;
 
 
        p = smb_encode_smb_length(p, xmit_len - 4);
        p = smb_encode_smb_length(p, xmit_len - 4);
 
 
        BSET(p, 0, 0xff);
        BSET(p, 0, 0xff);
        BSET(p, 1, 'S');
        BSET(p, 1, 'S');
        BSET(p, 2, 'M');
        BSET(p, 2, 'M');
        BSET(p, 3, 'B');
        BSET(p, 3, 'B');
        BSET(p, 4, command);
        BSET(p, 4, command);
 
 
        p += 5;
        p += 5;
        memset(p, '\0', 19);
        memset(p, '\0', 19);
        p += 19;
        p += 19;
        p += 8;
        p += 8;
 
 
        WSET(buf, smb_tid, server->tid);
        WSET(buf, smb_tid, server->tid);
        WSET(buf, smb_pid, server->pid);
        WSET(buf, smb_pid, server->pid);
        WSET(buf, smb_uid, server->server_uid);
        WSET(buf, smb_uid, server->server_uid);
        WSET(buf, smb_mid, server->mid);
        WSET(buf, smb_mid, server->mid);
 
 
        if (server->protocol > PROTOCOL_CORE)
        if (server->protocol > PROTOCOL_CORE)
        {
        {
                BSET(buf, smb_flg, 0x8);
                BSET(buf, smb_flg, 0x8);
                WSET(buf, smb_flg2, 0x3);
                WSET(buf, smb_flg2, 0x3);
        }
        }
        *p++ = wct;             /* wct */
        *p++ = wct;             /* wct */
        p += 2 * wct;
        p += 2 * wct;
        WSET(p, 0, bcc);
        WSET(p, 0, bcc);
        return p + 2;
        return p + 2;
}
}
 
 
/* smb_setup_header_exclusive waits on server->lock and locks the
/* smb_setup_header_exclusive waits on server->lock and locks the
   server, when it's free. You have to unlock it manually when you're
   server, when it's free. You have to unlock it manually when you're
   finished with server->packet! */
   finished with server->packet! */
 
 
static byte *
static byte *
smb_setup_header_exclusive(struct smb_server *server,
smb_setup_header_exclusive(struct smb_server *server,
                           byte command, word wct, word bcc)
                           byte command, word wct, word bcc)
{
{
        smb_lock_server(server);
        smb_lock_server(server);
        return smb_setup_header(server, command, wct, bcc);
        return smb_setup_header(server, command, wct, bcc);
}
}
 
 
static void
static void
smb_setup_bcc(struct smb_server *server, byte * p)
smb_setup_bcc(struct smb_server *server, byte * p)
{
{
        __u8 *packet = server->packet;
        __u8 *packet = server->packet;
        __u8 *pbcc = packet + SMB_HEADER_LEN + 2 * SMB_WCT(packet);
        __u8 *pbcc = packet + SMB_HEADER_LEN + 2 * SMB_WCT(packet);
        __u16 bcc = p - (pbcc + 2);
        __u16 bcc = p - (pbcc + 2);
 
 
        WSET(pbcc, 0, bcc);
        WSET(pbcc, 0, bcc);
        smb_encode_smb_length(packet,
        smb_encode_smb_length(packet,
                              SMB_HEADER_LEN + 2 * SMB_WCT(packet) - 2 + bcc);
                              SMB_HEADER_LEN + 2 * SMB_WCT(packet) - 2 + bcc);
}
}
 
 
 
 
/*****************************************************************************/
/*****************************************************************************/
/*                                                                           */
/*                                                                           */
/*  File operation section.                                                  */
/*  File operation section.                                                  */
/*                                                                           */
/*                                                                           */
/*****************************************************************************/
/*****************************************************************************/
 
 
int
int
smb_proc_open(struct smb_server *server,
smb_proc_open(struct smb_server *server,
              struct smb_inode_info *dir, const char *name, int len,
              struct smb_inode_info *dir, const char *name, int len,
              struct smb_dirent *entry)
              struct smb_dirent *entry)
{
{
        int error;
        int error;
        char *p;
        char *p;
        char *buf;
        char *buf;
        const word o_attr = aSYSTEM | aHIDDEN | aDIR;
        const word o_attr = aSYSTEM | aHIDDEN | aDIR;
 
 
        DPRINTK("smb_proc_open: name=%s\n", name);
        DPRINTK("smb_proc_open: name=%s\n", name);
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
        if (entry->opened != 0)
        if (entry->opened != 0)
        {
        {
                /* Somebody else opened the file while we slept */
                /* Somebody else opened the file while we slept */
                smb_unlock_server(server);
                smb_unlock_server(server);
                return 0;
                return 0;
        }
        }
      retry:
      retry:
        buf = server->packet;
        buf = server->packet;
        p = smb_setup_header(server, SMBopen, 2, 0);
        p = smb_setup_header(server, SMBopen, 2, 0);
        WSET(buf, smb_vwv0, 0x42);      /* read/write */
        WSET(buf, smb_vwv0, 0x42);      /* read/write */
        WSET(buf, smb_vwv1, o_attr);
        WSET(buf, smb_vwv1, o_attr);
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p, dir, name, len);
        p = smb_encode_path(server, p, dir, name, len);
        smb_setup_bcc(server, p);
        smb_setup_bcc(server, p);
 
 
        if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
        if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
        {
        {
 
 
                if (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
                if ((error != -EACCES) && (error != -ETXTBSY)
                if ((error != -EACCES) && (error != -ETXTBSY)
                    && (error != -EROFS))
                    && (error != -EROFS))
                {
                {
                        smb_unlock_server(server);
                        smb_unlock_server(server);
                        return error;
                        return error;
                }
                }
                /* N.B. Packet may change after request */
                /* N.B. Packet may change after request */
                buf = server->packet;
                buf = server->packet;
                p = smb_setup_header(server, SMBopen, 2, 0);
                p = smb_setup_header(server, SMBopen, 2, 0);
                WSET(buf, smb_vwv0, 0x40);      /* read only */
                WSET(buf, smb_vwv0, 0x40);      /* read only */
                WSET(buf, smb_vwv1, o_attr);
                WSET(buf, smb_vwv1, o_attr);
                *p++ = 4;
                *p++ = 4;
                p = smb_encode_path(server, p, dir, name, len);
                p = smb_encode_path(server, p, dir, name, len);
                smb_setup_bcc(server, p);
                smb_setup_bcc(server, p);
 
 
                if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
                if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
                {
                {
                        if (smb_retry(server))
                        if (smb_retry(server))
                        {
                        {
                                goto retry;
                                goto retry;
                        }
                        }
                        smb_unlock_server(server);
                        smb_unlock_server(server);
                        return error;
                        return error;
                }
                }
        }
        }
        /* We should now have data in vwv[0..6]. */
        /* We should now have data in vwv[0..6]. */
 
 
        /* N.B. Packet may change after request */
        /* N.B. Packet may change after request */
        buf = server->packet;
        buf = server->packet;
        entry->fileid = WVAL(buf, smb_vwv0);
        entry->fileid = WVAL(buf, smb_vwv0);
        entry->attr = WVAL(buf, smb_vwv1);
        entry->attr = WVAL(buf, smb_vwv1);
        entry->f_ctime = entry->f_atime =
        entry->f_ctime = entry->f_atime =
            entry->f_mtime = local2utc(DVAL(buf, smb_vwv2));
            entry->f_mtime = local2utc(DVAL(buf, smb_vwv2));
        entry->f_size = DVAL(buf, smb_vwv4);
        entry->f_size = DVAL(buf, smb_vwv4);
        entry->access = WVAL(buf, smb_vwv6);
        entry->access = WVAL(buf, smb_vwv6);
 
 
        entry->opened = 1;
        entry->opened = 1;
        entry->access &= 3;
        entry->access &= 3;
 
 
        smb_unlock_server(server);
        smb_unlock_server(server);
 
 
        DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
        DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
        return 0;
        return 0;
}
}
 
 
int
int
smb_proc_close(struct smb_server *server,
smb_proc_close(struct smb_server *server,
               __u16 fileid, __u32 mtime)
               __u16 fileid, __u32 mtime)
{
{
        char *buf;
        char *buf;
 
 
        smb_setup_header_exclusive(server, SMBclose, 3, 0);
        smb_setup_header_exclusive(server, SMBclose, 3, 0);
        buf = server->packet;
        buf = server->packet;
        WSET(buf, smb_vwv0, fileid);
        WSET(buf, smb_vwv0, fileid);
        DSET(buf, smb_vwv1, utc2local(mtime));
        DSET(buf, smb_vwv1, utc2local(mtime));
 
 
        return smb_request_ok_unlock(server, SMBclose, 0, 0);
        return smb_request_ok_unlock(server, SMBclose, 0, 0);
}
}
 
 
/* In smb_proc_read and smb_proc_write we do not retry, because the
/* In smb_proc_read and smb_proc_write we do not retry, because the
   file-id would not be valid after a reconnection. */
   file-id would not be valid after a reconnection. */
 
 
/* smb_proc_read: fs indicates if it should be copied with
/* smb_proc_read: fs indicates if it should be copied with
   memcpy_tofs. */
   memcpy_tofs. */
 
 
int
int
smb_proc_read(struct smb_server *server, struct smb_dirent *finfo,
smb_proc_read(struct smb_server *server, struct smb_dirent *finfo,
              off_t offset, long count, char *data, int fs)
              off_t offset, long count, char *data, int fs)
{
{
        word returned_count, data_len;
        word returned_count, data_len;
        char *buf;
        char *buf;
        int error;
        int error;
 
 
        smb_setup_header_exclusive(server, SMBread, 5, 0);
        smb_setup_header_exclusive(server, SMBread, 5, 0);
        buf = server->packet;
        buf = server->packet;
 
 
        WSET(buf, smb_vwv0, finfo->fileid);
        WSET(buf, smb_vwv0, finfo->fileid);
        WSET(buf, smb_vwv1, count);
        WSET(buf, smb_vwv1, count);
        DSET(buf, smb_vwv2, offset);
        DSET(buf, smb_vwv2, offset);
        WSET(buf, smb_vwv4, 0);
        WSET(buf, smb_vwv4, 0);
 
 
        if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0)
        if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0)
        {
        {
                smb_unlock_server(server);
                smb_unlock_server(server);
                return error;
                return error;
        }
        }
        returned_count = WVAL(server->packet, smb_vwv0);
        returned_count = WVAL(server->packet, smb_vwv0);
 
 
        smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs);
        smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs);
 
 
        smb_unlock_server(server);
        smb_unlock_server(server);
 
 
        if (returned_count != data_len)
        if (returned_count != data_len)
        {
        {
                printk("smb_proc_read: Warning, returned_count != data_len\n");
                printk("smb_proc_read: Warning, returned_count != data_len\n");
                printk("smb_proc_read: ret_c=%d, data_len=%d\n",
                printk("smb_proc_read: ret_c=%d, data_len=%d\n",
                       returned_count, data_len);
                       returned_count, data_len);
        }
        }
        return data_len;
        return data_len;
}
}
 
 
int
int
smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
               off_t offset, int count, const char *data)
               off_t offset, int count, const char *data)
{
{
        int res = 0;
        int res = 0;
        char *buf;
        char *buf;
        byte *p;
        byte *p;
 
 
        p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3);
        p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3);
        buf = server->packet;
        buf = server->packet;
        WSET(buf, smb_vwv0, finfo->fileid);
        WSET(buf, smb_vwv0, finfo->fileid);
        WSET(buf, smb_vwv1, count);
        WSET(buf, smb_vwv1, count);
        DSET(buf, smb_vwv2, offset);
        DSET(buf, smb_vwv2, offset);
        WSET(buf, smb_vwv4, 0);
        WSET(buf, smb_vwv4, 0);
 
 
        *p++ = 1;
        *p++ = 1;
        WSET(p, 0, count);
        WSET(p, 0, count);
        memcpy_fromfs(p + 2, data, count);
        memcpy_fromfs(p + 2, data, count);
 
 
        if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
        if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
        {
        {
                res = WVAL(server->packet, smb_vwv0);
                res = WVAL(server->packet, smb_vwv0);
        }
        }
        smb_unlock_server(server);
        smb_unlock_server(server);
 
 
        return res;
        return res;
}
}
 
 
int
int
smb_proc_create(struct inode *dir, const char *name, int len,
smb_proc_create(struct inode *dir, const char *name, int len,
                word attr, time_t ctime)
                word attr, time_t ctime)
{
{
        int error;
        int error;
        char *p;
        char *p;
        struct smb_server *server = SMB_SERVER(dir);
        struct smb_server *server = SMB_SERVER(dir);
        char *buf;
        char *buf;
        __u16 fileid;
        __u16 fileid;
 
 
        smb_lock_server(server);
        smb_lock_server(server);
      retry:
      retry:
        buf = server->packet;
        buf = server->packet;
        p = smb_setup_header(server, SMBcreate, 3, 0);
        p = smb_setup_header(server, SMBcreate, 3, 0);
        WSET(buf, smb_vwv0, attr);
        WSET(buf, smb_vwv0, attr);
        DSET(buf, smb_vwv1, utc2local(ctime));
        DSET(buf, smb_vwv1, utc2local(ctime));
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        smb_setup_bcc(server, p);
        smb_setup_bcc(server, p);
 
 
        if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
        if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
        {
        {
                if (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
                smb_unlock_server(server);
                smb_unlock_server(server);
                return error;
                return error;
        }
        }
        fileid = WVAL(server->packet, smb_vwv0);
        fileid = WVAL(server->packet, smb_vwv0);
        smb_unlock_server(server);
        smb_unlock_server(server);
 
 
        smb_proc_close(server, fileid, CURRENT_TIME);
        smb_proc_close(server, fileid, CURRENT_TIME);
 
 
        return 0;
        return 0;
}
}
 
 
int
int
smb_proc_mv(struct inode *odir, const char *oname, const int olen,
smb_proc_mv(struct inode *odir, const char *oname, const int olen,
            struct inode *ndir, const char *nname, const int nlen)
            struct inode *ndir, const char *nname, const int nlen)
{
{
        char *p;
        char *p;
        struct smb_server *server = SMB_SERVER(odir);
        struct smb_server *server = SMB_SERVER(odir);
        int result;
        int result;
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
        p = smb_setup_header(server, SMBmv, 1, 0);
        p = smb_setup_header(server, SMBmv, 1, 0);
        WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
        WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p, SMB_INOP(odir), oname, olen);
        p = smb_encode_path(server, p, SMB_INOP(odir), oname, olen);
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p, SMB_INOP(ndir), nname, nlen);
        p = smb_encode_path(server, p, SMB_INOP(ndir), nname, nlen);
        smb_setup_bcc(server, p);
        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))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
        }
        }
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
int
int
smb_proc_mkdir(struct inode *dir, const char *name, const int len)
smb_proc_mkdir(struct inode *dir, const char *name, const int len)
{
{
        char *p;
        char *p;
        int result;
        int result;
        struct smb_server *server = SMB_SERVER(dir);
        struct smb_server *server = SMB_SERVER(dir);
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
        p = smb_setup_header(server, SMBmkdir, 0, 0);
        p = smb_setup_header(server, SMBmkdir, 0, 0);
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        smb_setup_bcc(server, p);
        smb_setup_bcc(server, p);
 
 
        if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
        if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
        {
        {
                if (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
        }
        }
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
int
int
smb_proc_rmdir(struct inode *dir, const char *name, const int len)
smb_proc_rmdir(struct inode *dir, const char *name, const int len)
{
{
        char *p;
        char *p;
        int result;
        int result;
        struct smb_server *server = SMB_SERVER(dir);
        struct smb_server *server = SMB_SERVER(dir);
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
        p = smb_setup_header(server, SMBrmdir, 0, 0);
        p = smb_setup_header(server, SMBrmdir, 0, 0);
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        smb_setup_bcc(server, p);
        smb_setup_bcc(server, p);
 
 
        if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
        if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
        {
        {
                if (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
        }
        }
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
int
int
smb_proc_unlink(struct inode *dir, const char *name, const int len)
smb_proc_unlink(struct inode *dir, const char *name, const int len)
{
{
        char *p;
        char *p;
        struct smb_server *server = SMB_SERVER(dir);
        struct smb_server *server = SMB_SERVER(dir);
        int result;
        int result;
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
        p = smb_setup_header(server, SMBunlink, 1, 0);
        p = smb_setup_header(server, SMBunlink, 1, 0);
        WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
        WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        smb_setup_bcc(server, p);
        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 (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
        }
        }
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
int
int
smb_proc_trunc(struct smb_server *server, word fid, dword length)
smb_proc_trunc(struct smb_server *server, word fid, dword length)
{
{
        char *p;
        char *p;
        char *buf;
        char *buf;
        int result;
        int result;
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
        buf = server->packet;
        buf = server->packet;
        p = smb_setup_header(server, SMBwrite, 5, 0);
        p = smb_setup_header(server, SMBwrite, 5, 0);
        WSET(buf, smb_vwv0, fid);
        WSET(buf, smb_vwv0, fid);
        WSET(buf, smb_vwv1, 0);
        WSET(buf, smb_vwv1, 0);
        DSET(buf, smb_vwv2, length);
        DSET(buf, smb_vwv2, length);
        WSET(buf, smb_vwv4, 0);
        WSET(buf, smb_vwv4, 0);
        p = smb_encode_ascii(p, "", 0);
        p = smb_encode_ascii(p, "", 0);
        smb_setup_bcc(server, p);
        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))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
        }
        }
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
static void
static void
smb_init_dirent(struct smb_server *server, struct smb_dirent *entry)
smb_init_dirent(struct smb_server *server, struct smb_dirent *entry)
{
{
        memset(entry, 0, sizeof(struct smb_dirent));
        memset(entry, 0, sizeof(struct smb_dirent));
 
 
        entry->f_nlink = 1;
        entry->f_nlink = 1;
        entry->f_uid = server->m.uid;
        entry->f_uid = server->m.uid;
        entry->f_gid = server->m.gid;
        entry->f_gid = server->m.gid;
        entry->f_blksize = 512;
        entry->f_blksize = 512;
}
}
 
 
static void
static void
smb_finish_dirent(struct smb_server *server, struct smb_dirent *entry)
smb_finish_dirent(struct smb_server *server, struct smb_dirent *entry)
{
{
        if ((entry->attr & aDIR) != 0)
        if ((entry->attr & aDIR) != 0)
        {
        {
                entry->f_mode = server->m.dir_mode;
                entry->f_mode = server->m.dir_mode;
                entry->f_size = 512;
                entry->f_size = 512;
        } else
        } else
        {
        {
                entry->f_mode = server->m.file_mode;
                entry->f_mode = server->m.file_mode;
        }
        }
 
 
        if (entry->attr & aRONLY)
        if (entry->attr & aRONLY)
                entry->f_mode &= ~0222;
                entry->f_mode &= ~0222;
 
 
        if ((entry->f_blksize != 0) && (entry->f_size != 0))
        if ((entry->f_blksize != 0) && (entry->f_size != 0))
        {
        {
                entry->f_blocks =
                entry->f_blocks =
                    (entry->f_size - 1) / entry->f_blksize + 1;
                    (entry->f_size - 1) / entry->f_blksize + 1;
        } else
        } else
        {
        {
                entry->f_blocks = 0;
                entry->f_blocks = 0;
        }
        }
        return;
        return;
}
}
 
 
void
void
smb_init_root_dirent(struct smb_server *server, struct smb_dirent *entry)
smb_init_root_dirent(struct smb_server *server, struct smb_dirent *entry)
{
{
        smb_init_dirent(server, entry);
        smb_init_dirent(server, entry);
        entry->attr = aDIR;
        entry->attr = aDIR;
        entry->f_ino = 1;
        entry->f_ino = 1;
        smb_finish_dirent(server, entry);
        smb_finish_dirent(server, entry);
}
}
 
 
 
 
static char *
static char *
smb_decode_dirent(struct smb_server *server, char *p, struct smb_dirent *entry)
smb_decode_dirent(struct smb_server *server, char *p, struct smb_dirent *entry)
{
{
        smb_init_dirent(server, entry);
        smb_init_dirent(server, entry);
 
 
        p += SMB_STATUS_SIZE;   /* reserved (search_status) */
        p += SMB_STATUS_SIZE;   /* reserved (search_status) */
        entry->attr = BVAL(p, 0);
        entry->attr = BVAL(p, 0);
        entry->f_mtime = entry->f_atime = entry->f_ctime =
        entry->f_mtime = entry->f_atime = entry->f_ctime =
            date_dos2unix(WVAL(p, 1), WVAL(p, 3));
            date_dos2unix(WVAL(p, 1), WVAL(p, 3));
        entry->f_size = DVAL(p, 5);
        entry->f_size = DVAL(p, 5);
        entry->len = strlen(p + 9);
        entry->len = strlen(p + 9);
        if (entry->len > 12)
        if (entry->len > 12)
        {
        {
                entry->len = 12;
                entry->len = 12;
        }
        }
        memcpy(entry->name, p + 9, entry->len);
        memcpy(entry->name, p + 9, entry->len);
        entry->name[entry->len] = '\0';
        entry->name[entry->len] = '\0';
        while (entry->len > 2)
        while (entry->len > 2)
        {
        {
                /* Pathworks fills names with spaces */
                /* Pathworks fills names with spaces */
                entry->len -= 1;
                entry->len -= 1;
                if (entry->name[entry->len] == ' ')
                if (entry->name[entry->len] == ' ')
                {
                {
                        entry->name[entry->len] = '\0';
                        entry->name[entry->len] = '\0';
                }
                }
        }
        }
        switch (server->case_handling)
        switch (server->case_handling)
        {
        {
        case CASE_UPPER:
        case CASE_UPPER:
                str_upper(entry->name);
                str_upper(entry->name);
                break;
                break;
        case CASE_LOWER:
        case CASE_LOWER:
                str_lower(entry->name);
                str_lower(entry->name);
                break;
                break;
        default:
        default:
                break;
                break;
        }
        }
        DPRINTK("smb_decode_dirent: name = %s\n", entry->name);
        DPRINTK("smb_decode_dirent: name = %s\n", entry->name);
        smb_finish_dirent(server, entry);
        smb_finish_dirent(server, entry);
        return p + 22;
        return p + 22;
}
}
 
 
/* This routine is used to read in directory entries from the network.
/* This routine is used to read in directory entries from the network.
   Note that it is for short directory name seeks, i.e.: protocol <
   Note that it is for short directory name seeks, i.e.: protocol <
   PROTOCOL_LANMAN2 */
   PROTOCOL_LANMAN2 */
 
 
static int
static int
smb_proc_readdir_short(struct smb_server *server, struct inode *dir, int fpos,
smb_proc_readdir_short(struct smb_server *server, struct inode *dir, int fpos,
                       int cache_size, struct smb_dirent *entry)
                       int cache_size, struct smb_dirent *entry)
{
{
        char *p;
        char *p;
        char *buf;
        char *buf;
        int error;
        int error;
        int result;
        int result;
        int i;
        int i;
        int first, total_count;
        int first, total_count;
        struct smb_dirent *current_entry;
        struct smb_dirent *current_entry;
        word bcc;
        word bcc;
        word count;
        word count;
        char status[SMB_STATUS_SIZE];
        char status[SMB_STATUS_SIZE];
        int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE;
        int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE;
 
 
        DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);
        DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
        buf = server->packet;
        buf = server->packet;
        first = 1;
        first = 1;
        total_count = 0;
        total_count = 0;
        current_entry = entry;
        current_entry = entry;
 
 
        while (1)
        while (1)
        {
        {
                if (first == 1)
                if (first == 1)
                {
                {
                        p = smb_setup_header(server, SMBsearch, 2, 0);
                        p = smb_setup_header(server, SMBsearch, 2, 0);
                        WSET(buf, smb_vwv0, entries_asked);
                        WSET(buf, smb_vwv0, entries_asked);
                        WSET(buf, smb_vwv1, aDIR);
                        WSET(buf, smb_vwv1, aDIR);
                        *p++ = 4;
                        *p++ = 4;
                        p = smb_encode_path(server, p, SMB_INOP(dir), "*.*", 3);
                        p = smb_encode_path(server, p, SMB_INOP(dir), "*.*", 3);
                        *p++ = 5;
                        *p++ = 5;
                        WSET(p, 0, 0);
                        WSET(p, 0, 0);
                        p += 2;
                        p += 2;
                } else
                } else
                {
                {
                        p = smb_setup_header(server, SMBsearch, 2, 0);
                        p = smb_setup_header(server, SMBsearch, 2, 0);
                        WSET(buf, smb_vwv0, entries_asked);
                        WSET(buf, smb_vwv0, entries_asked);
                        WSET(buf, smb_vwv1, aDIR);
                        WSET(buf, smb_vwv1, aDIR);
                        p = smb_encode_ascii(p, "", 0);
                        p = smb_encode_ascii(p, "", 0);
                        *p++ = 5;
                        *p++ = 5;
                        WSET(p, 0, SMB_STATUS_SIZE);
                        WSET(p, 0, SMB_STATUS_SIZE);
                        p += 2;
                        p += 2;
                        memcpy(p, status, SMB_STATUS_SIZE);
                        memcpy(p, status, SMB_STATUS_SIZE);
                        p += SMB_STATUS_SIZE;
                        p += SMB_STATUS_SIZE;
                }
                }
 
 
                smb_setup_bcc(server, p);
                smb_setup_bcc(server, p);
 
 
                if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0)
                if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0)
                {
                {
                        if ((server->rcls == ERRDOS)
                        if ((server->rcls == ERRDOS)
                            && (server->err == ERRnofiles))
                            && (server->err == ERRnofiles))
                        {
                        {
                                result = total_count - fpos;
                                result = total_count - fpos;
                                goto unlock_return;
                                goto unlock_return;
                        } else
                        } else
                        {
                        {
                                if (smb_retry(server))
                                if (smb_retry(server))
                                {
                                {
                                        goto retry;
                                        goto retry;
                                }
                                }
                                result = error;
                                result = error;
                                goto unlock_return;
                                goto unlock_return;
                        }
                        }
                }
                }
                p = SMB_VWV(server->packet);
                p = SMB_VWV(server->packet);
                p = smb_decode_word(p, &count);
                p = smb_decode_word(p, &count);
                p = smb_decode_word(p, &bcc);
                p = smb_decode_word(p, &bcc);
 
 
                first = 0;
                first = 0;
 
 
                if (count <= 0)
                if (count <= 0)
                {
                {
                        result = total_count - fpos;
                        result = total_count - fpos;
                        goto unlock_return;
                        goto unlock_return;
                }
                }
                if (bcc != count * SMB_DIRINFO_SIZE + 3)
                if (bcc != count * SMB_DIRINFO_SIZE + 3)
                {
                {
                        result = -EIO;
                        result = -EIO;
                        goto unlock_return;
                        goto unlock_return;
                }
                }
                p += 3;         /* Skipping VBLOCK header
                p += 3;         /* Skipping VBLOCK header
                                   (5, length lo, length hi). */
                                   (5, length lo, length hi). */
 
 
                /* Read the last entry into the status field. */
                /* Read the last entry into the status field. */
                memcpy(status,
                memcpy(status,
                       SMB_BUF(server->packet) + 3 +
                       SMB_BUF(server->packet) + 3 +
                       (count - 1) * SMB_DIRINFO_SIZE,
                       (count - 1) * SMB_DIRINFO_SIZE,
                       SMB_STATUS_SIZE);
                       SMB_STATUS_SIZE);
 
 
                /* Now we are ready to parse smb directory entries. */
                /* Now we are ready to parse smb directory entries. */
 
 
                for (i = 0; i < count; i++)
                for (i = 0; i < count; i++)
                {
                {
                        if (total_count < fpos)
                        if (total_count < fpos)
                        {
                        {
                                p += SMB_DIRINFO_SIZE;
                                p += SMB_DIRINFO_SIZE;
                                DDPRINTK("smb_proc_readdir: skipped entry.\n");
                                DDPRINTK("smb_proc_readdir: skipped entry.\n");
                                DDPRINTK("                  total_count = %d\n"
                                DDPRINTK("                  total_count = %d\n"
                                         "                i = %d, fpos = %d\n",
                                         "                i = %d, fpos = %d\n",
                                         total_count, i, fpos);
                                         total_count, i, fpos);
                        } else if (total_count >= fpos + cache_size)
                        } else if (total_count >= fpos + cache_size)
                        {
                        {
                                result = total_count - fpos;
                                result = total_count - fpos;
                                goto unlock_return;
                                goto unlock_return;
                        } else
                        } else
                        {
                        {
                                p = smb_decode_dirent(server, p,
                                p = smb_decode_dirent(server, p,
                                                      current_entry);
                                                      current_entry);
                                current_entry->f_pos = total_count;
                                current_entry->f_pos = total_count;
                                DDPRINTK("smb_proc_readdir: entry->f_pos = "
                                DDPRINTK("smb_proc_readdir: entry->f_pos = "
                                         "%lu\n", entry->f_pos);
                                         "%lu\n", entry->f_pos);
                                current_entry += 1;
                                current_entry += 1;
                        }
                        }
                        total_count += 1;
                        total_count += 1;
                }
                }
        }
        }
      unlock_return:
      unlock_return:
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
/* interpret a long filename structure - this is mostly guesses at the
/* interpret a long filename structure - this is mostly guesses at the
   moment.  The length of the structure is returned.  The structure of
   moment.  The length of the structure is returned.  The structure of
   a long filename depends on the info level. 260 is used by NT and 2
   a long filename depends on the info level. 260 is used by NT and 2
   is used by OS/2. */
   is used by OS/2. */
 
 
static char *
static char *
smb_decode_long_dirent(struct smb_server *server, char *p,
smb_decode_long_dirent(struct smb_server *server, char *p,
                       struct smb_dirent *entry, int level)
                       struct smb_dirent *entry, int level)
{
{
        char *result;
        char *result;
 
 
        smb_init_dirent(server, entry);
        smb_init_dirent(server, entry);
 
 
        switch (level)
        switch (level)
        {
        {
                /* We might add more levels later... */
                /* We might add more levels later... */
        case 1:
        case 1:
                entry->len = BVAL(p, 26);
                entry->len = BVAL(p, 26);
                strncpy(entry->name, p + 27, entry->len);
                strncpy(entry->name, p + 27, entry->len);
                entry->name[entry->len] = '\0';
                entry->name[entry->len] = '\0';
                entry->f_size = DVAL(p, 16);
                entry->f_size = DVAL(p, 16);
                entry->attr = BVAL(p, 24);
                entry->attr = BVAL(p, 24);
 
 
                entry->f_ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
                entry->f_ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
                entry->f_atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
                entry->f_atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
                entry->f_mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
                entry->f_mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
                result = p + 28 + BVAL(p, 26);
                result = p + 28 + BVAL(p, 26);
                break;
                break;
 
 
        default:
        default:
                DPRINTK("Unknown long filename format %d\n", level);
                DPRINTK("Unknown long filename format %d\n", level);
                result = p + WVAL(p, 0);
                result = p + WVAL(p, 0);
        }
        }
 
 
        switch (server->case_handling)
        switch (server->case_handling)
        {
        {
        case CASE_UPPER:
        case CASE_UPPER:
                str_upper(entry->name);
                str_upper(entry->name);
                break;
                break;
        case CASE_LOWER:
        case CASE_LOWER:
                str_lower(entry->name);
                str_lower(entry->name);
                break;
                break;
        default:
        default:
                break;
                break;
        }
        }
 
 
        smb_finish_dirent(server, entry);
        smb_finish_dirent(server, entry);
        return result;
        return result;
}
}
 
 
int
int
smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos,
smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos,
                      int cache_size, struct smb_dirent *cache)
                      int cache_size, struct smb_dirent *cache)
{
{
        /* NT uses 260, OS/2 uses 2. Both accept 1. */
        /* NT uses 260, OS/2 uses 2. Both accept 1. */
        const int info_level = 1;
        const int info_level = 1;
        const int max_matches = 512;
        const int max_matches = 512;
 
 
        char *p;
        char *p;
        char *lastname;
        char *lastname;
        int lastname_len;
        int lastname_len;
        int i;
        int i;
        int first, entries, entries_seen;
        int first, entries, entries_seen;
 
 
        unsigned char *resp_data = NULL;
        unsigned char *resp_data = NULL;
        unsigned char *resp_param = NULL;
        unsigned char *resp_param = NULL;
        int resp_data_len = 0;
        int resp_data_len = 0;
        int resp_param_len = 0;
        int resp_param_len = 0;
 
 
        __u16 command;
        __u16 command;
 
 
        int result;
        int result;
 
 
        int ff_resume_key = 0;
        int ff_resume_key = 0;
        int ff_searchcount = 0;
        int ff_searchcount = 0;
        int ff_eos = 0;
        int ff_eos = 0;
        int ff_lastname = 0;
        int ff_lastname = 0;
        int ff_dir_handle = 0;
        int ff_dir_handle = 0;
        int loop_count = 0;
        int loop_count = 0;
 
 
        char param[SMB_MAXPATHLEN + 2 + 12];
        char param[SMB_MAXPATHLEN + 2 + 12];
        int mask_len;
        int mask_len;
        unsigned char *mask = &(param[12]);
        unsigned char *mask = &(param[12]);
 
 
        mask_len = smb_encode_path(server, mask,
        mask_len = smb_encode_path(server, mask,
                                   SMB_INOP(dir), "*", 1) - mask;
                                   SMB_INOP(dir), "*", 1) - mask;
 
 
        mask[mask_len] = 0;
        mask[mask_len] = 0;
        mask[mask_len + 1] = 0;
        mask[mask_len + 1] = 0;
 
 
        DPRINTK("smb_readdir_long cache=%d, fpos=%d, mask=%s\n",
        DPRINTK("smb_readdir_long cache=%d, fpos=%d, mask=%s\n",
                cache_size, fpos, mask);
                cache_size, fpos, mask);
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
 
 
        first = 1;
        first = 1;
        entries = 0;
        entries = 0;
        entries_seen = 2;
        entries_seen = 2;
 
 
        while (ff_eos == 0)
        while (ff_eos == 0)
        {
        {
                loop_count += 1;
                loop_count += 1;
                if (loop_count > 200)
                if (loop_count > 200)
                {
                {
                        printk("smb_proc_readdir_long: "
                        printk("smb_proc_readdir_long: "
                               "Looping in FIND_NEXT??\n");
                               "Looping in FIND_NEXT??\n");
                        break;
                        break;
                }
                }
                if (first != 0)
                if (first != 0)
                {
                {
                        command = TRANSACT2_FINDFIRST;
                        command = TRANSACT2_FINDFIRST;
                        WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
                        WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
                        WSET(param, 2, max_matches);    /* max count */
                        WSET(param, 2, max_matches);    /* max count */
                        WSET(param, 4, 8 + 4 + 2);      /* resume required +
                        WSET(param, 4, 8 + 4 + 2);      /* resume required +
                                                           close on end +
                                                           close on end +
                                                           continue */
                                                           continue */
                        WSET(param, 6, info_level);
                        WSET(param, 6, info_level);
                        DSET(param, 8, 0);
                        DSET(param, 8, 0);
                } else
                } else
                {
                {
                        command = TRANSACT2_FINDNEXT;
                        command = TRANSACT2_FINDNEXT;
                        DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
                        DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
                             ff_dir_handle, ff_resume_key, ff_lastname, mask);
                             ff_dir_handle, ff_resume_key, ff_lastname, mask);
                        WSET(param, 0, ff_dir_handle);
                        WSET(param, 0, ff_dir_handle);
                        WSET(param, 2, max_matches);    /* max count */
                        WSET(param, 2, max_matches);    /* max count */
                        WSET(param, 4, info_level);
                        WSET(param, 4, info_level);
                        DSET(param, 6, ff_resume_key);  /* ff_resume_key */
                        DSET(param, 6, ff_resume_key);  /* ff_resume_key */
                        WSET(param, 10, 8 + 4 + 2);     /* resume required +
                        WSET(param, 10, 8 + 4 + 2);     /* resume required +
                                                           close on end +
                                                           close on end +
                                                           continue */
                                                           continue */
                }
                }
#ifdef CONFIG_SMB_WIN95
#ifdef CONFIG_SMB_WIN95
                /* Windows 95 is not able to deliver answers
                /* Windows 95 is not able to deliver answers
                   to FIND_NEXT fast enough, so sleep 0.2 seconds */
                   to FIND_NEXT fast enough, so sleep 0.2 seconds */
                current->timeout = jiffies + HZ / 5;
                current->timeout = jiffies + HZ / 5;
                current->state = TASK_INTERRUPTIBLE;
                current->state = TASK_INTERRUPTIBLE;
                schedule();
                schedule();
                current->timeout = 0;
                current->timeout = 0;
#endif
#endif
 
 
                result = smb_trans2_request(server, command,
                result = smb_trans2_request(server, command,
                                            0, NULL, 12 + mask_len + 2, param,
                                            0, NULL, 12 + mask_len + 2, param,
                                            &resp_data_len, &resp_data,
                                            &resp_data_len, &resp_data,
                                            &resp_param_len, &resp_param);
                                            &resp_param_len, &resp_param);
 
 
                if (result < 0)
                if (result < 0)
                {
                {
                        if (smb_retry(server))
                        if (smb_retry(server))
                        {
                        {
                                goto retry;
                                goto retry;
                        }
                        }
                        DPRINTK("smb_proc_readdir_long: "
                        DPRINTK("smb_proc_readdir_long: "
                                "got error from trans2_request\n");
                                "got error from trans2_request\n");
                        break;
                        break;
                }
                }
                if (server->rcls != 0)
                if (server->rcls != 0)
                {
                {
                        result = -EIO;
                        result = -EIO;
                        break;
                        break;
                }
                }
                /* parse out some important return info */
                /* parse out some important return info */
                if (first != 0)
                if (first != 0)
                {
                {
                        ff_dir_handle = WVAL(resp_param, 0);
                        ff_dir_handle = WVAL(resp_param, 0);
                        ff_searchcount = WVAL(resp_param, 2);
                        ff_searchcount = WVAL(resp_param, 2);
                        ff_eos = WVAL(resp_param, 4);
                        ff_eos = WVAL(resp_param, 4);
                        ff_lastname = WVAL(resp_param, 8);
                        ff_lastname = WVAL(resp_param, 8);
                } else
                } else
                {
                {
                        ff_searchcount = WVAL(resp_param, 0);
                        ff_searchcount = WVAL(resp_param, 0);
                        ff_eos = WVAL(resp_param, 2);
                        ff_eos = WVAL(resp_param, 2);
                        ff_lastname = WVAL(resp_param, 6);
                        ff_lastname = WVAL(resp_param, 6);
                }
                }
 
 
                if (ff_searchcount == 0)
                if (ff_searchcount == 0)
                {
                {
                        break;
                        break;
                }
                }
                /* point to the data bytes */
                /* point to the data bytes */
                p = resp_data;
                p = resp_data;
 
 
                /* we might need the lastname for continuations */
                /* we might need the lastname for continuations */
                lastname = "";
                lastname = "";
                lastname_len = 0;
                lastname_len = 0;
                if (ff_lastname > 0)
                if (ff_lastname > 0)
                {
                {
                        switch (info_level)
                        switch (info_level)
                        {
                        {
                        case 260:
                        case 260:
                                lastname = p + ff_lastname;
                                lastname = p + ff_lastname;
                                lastname_len = resp_data_len - ff_lastname;
                                lastname_len = resp_data_len - ff_lastname;
                                ff_resume_key = 0;
                                ff_resume_key = 0;
                                break;
                                break;
                        case 1:
                        case 1:
                                lastname = p + ff_lastname + 1;
                                lastname = p + ff_lastname + 1;
                                lastname_len = BVAL(p, ff_lastname);
                                lastname_len = BVAL(p, ff_lastname);
                                ff_resume_key = 0;
                                ff_resume_key = 0;
                                break;
                                break;
                        }
                        }
                }
                }
                lastname_len = min(lastname_len, 256);
                lastname_len = min(lastname_len, 256);
                strncpy(mask, lastname, lastname_len);
                strncpy(mask, lastname, lastname_len);
                mask[lastname_len] = '\0';
                mask[lastname_len] = '\0';
 
 
                /* Now we are ready to parse smb directory entries. */
                /* Now we are ready to parse smb directory entries. */
 
 
                for (i = 0; i < ff_searchcount; i++)
                for (i = 0; i < ff_searchcount; i++)
                {
                {
                        struct smb_dirent *entry = &(cache[entries]);
                        struct smb_dirent *entry = &(cache[entries]);
 
 
                        p = smb_decode_long_dirent(server, p,
                        p = smb_decode_long_dirent(server, p,
                                                   entry, info_level);
                                                   entry, info_level);
 
 
                        DDPRINTK("smb_readdir_long: got %s\n", entry->name);
                        DDPRINTK("smb_readdir_long: got %s\n", entry->name);
 
 
                        if ((entry->name[0] == '.')
                        if ((entry->name[0] == '.')
                            && ((entry->name[1] == '\0')
                            && ((entry->name[1] == '\0')
                                || ((entry->name[1] == '.')
                                || ((entry->name[1] == '.')
                                    && (entry->name[2] == '\0'))))
                                    && (entry->name[2] == '\0'))))
                        {
                        {
                                /* ignore . and .. from the server */
                                /* ignore . and .. from the server */
                                continue;
                                continue;
                        }
                        }
                        if (entries_seen >= fpos)
                        if (entries_seen >= fpos)
                        {
                        {
                                entry->f_pos = entries_seen;
                                entry->f_pos = entries_seen;
                                entries += 1;
                                entries += 1;
                        }
                        }
                        if (entries >= cache_size)
                        if (entries >= cache_size)
                        {
                        {
                                goto finished;
                                goto finished;
                        }
                        }
                        entries_seen += 1;
                        entries_seen += 1;
                }
                }
 
 
                DPRINTK("received %d entries (eos=%d resume=%d)\n",
                DPRINTK("received %d entries (eos=%d resume=%d)\n",
                        ff_searchcount, ff_eos, ff_resume_key);
                        ff_searchcount, ff_eos, ff_resume_key);
 
 
                first = 0;
                first = 0;
        }
        }
 
 
      finished:
      finished:
        smb_unlock_server(server);
        smb_unlock_server(server);
        return entries;
        return entries;
}
}
 
 
int
int
smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos,
smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos,
                 int cache_size, struct smb_dirent *entry)
                 int cache_size, struct smb_dirent *entry)
{
{
        if (server->protocol >= PROTOCOL_LANMAN2)
        if (server->protocol >= PROTOCOL_LANMAN2)
                return smb_proc_readdir_long(server, dir, fpos, cache_size,
                return smb_proc_readdir_long(server, dir, fpos, cache_size,
                                             entry);
                                             entry);
        else
        else
                return smb_proc_readdir_short(server, dir, fpos, cache_size,
                return smb_proc_readdir_short(server, dir, fpos, cache_size,
                                              entry);
                                              entry);
}
}
 
 
/*
/*
 * This version uses the core protocol to get the attribute info.
 * This version uses the core protocol to get the attribute info.
 * It works OK with Win 3.11, 95 and NT 3.51, but NOT with NT 4 (bad mtime).
 * It works OK with Win 3.11, 95 and NT 3.51, but NOT with NT 4 (bad mtime).
 */
 */
static int
static int
smb_proc_getattr_core(struct inode *dir, const char *name, int len,
smb_proc_getattr_core(struct inode *dir, const char *name, int len,
                      struct smb_dirent *entry)
                      struct smb_dirent *entry)
{
{
        int result;
        int result;
        char *p;
        char *p;
        struct smb_server *server = SMB_SERVER(dir);
        struct smb_server *server = SMB_SERVER(dir);
        char *buf;
        char *buf;
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
        DDPRINTK("smb_proc_getattr_core: %s\n", name);
        DDPRINTK("smb_proc_getattr_core: %s\n", name);
 
 
      retry:
      retry:
        buf = server->packet;
        buf = server->packet;
        p = smb_setup_header(server, SMBgetatr, 0, 0);
        p = smb_setup_header(server, SMBgetatr, 0, 0);
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
        smb_setup_bcc(server, p);
        smb_setup_bcc(server, p);
 
 
        if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
        if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
        {
        {
                if (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
                smb_unlock_server(server);
                smb_unlock_server(server);
                return result;
                return result;
        }
        }
        /* N.B. Packet may change after request */
        /* N.B. Packet may change after request */
        buf = server->packet;
        buf = server->packet;
        entry->attr = WVAL(buf, smb_vwv0);
        entry->attr = WVAL(buf, smb_vwv0);
        entry->f_ctime = entry->f_atime =
        entry->f_ctime = entry->f_atime =
            entry->f_mtime = local2utc(DVAL(buf, smb_vwv1));
            entry->f_mtime = local2utc(DVAL(buf, smb_vwv1));
 
 
        DDPRINTK("smb_proc_getattr_core: mtime=%ld\n", entry->f_mtime);
        DDPRINTK("smb_proc_getattr_core: mtime=%ld\n", entry->f_mtime);
 
 
        entry->f_size = DVAL(buf, smb_vwv3);
        entry->f_size = DVAL(buf, smb_vwv3);
        smb_unlock_server(server);
        smb_unlock_server(server);
        return 0;
        return 0;
}
}
 
 
/*
/*
 * This version uses the trans2 findfirst to get the attribute info.
 * This version uses the trans2 findfirst to get the attribute info.
 * It works fine with NT 3.51 and NT 4 (any SP), but not with Win95 (ERRerror).
 * It works fine with NT 3.51 and NT 4 (any SP), but not with Win95 (ERRerror).
 */
 */
static int
static int
smb_proc_getattr_ff(struct inode *dir, const char *name, int len,
smb_proc_getattr_ff(struct inode *dir, const char *name, int len,
                    struct smb_dirent *entry)
                    struct smb_dirent *entry)
{
{
        unsigned char *resp_data = NULL;
        unsigned char *resp_data = NULL;
        unsigned char *resp_param = NULL;
        unsigned char *resp_param = NULL;
        int resp_data_len = 0;
        int resp_data_len = 0;
        int resp_param_len = 0;
        int resp_param_len = 0;
 
 
        char param[SMB_MAXPATHLEN + 1 + 12];
        char param[SMB_MAXPATHLEN + 1 + 12];
        int mask_len;
        int mask_len;
        unsigned char *mask = &(param[12]);
        unsigned char *mask = &(param[12]);
 
 
        int result;
        int result;
        char *p;
        char *p;
        struct smb_server *server = SMB_SERVER(dir);
        struct smb_server *server = SMB_SERVER(dir);
 
 
        mask_len = smb_encode_path(server, mask,
        mask_len = smb_encode_path(server, mask,
                                   SMB_INOP(dir), name, len) - mask;
                                   SMB_INOP(dir), name, len) - mask;
 
 
        mask[mask_len] = 0;
        mask[mask_len] = 0;
 
 
        DDPRINTK("smb_proc_getattr_ff: mask=%s\n", mask);
        DDPRINTK("smb_proc_getattr_ff: mask=%s\n", mask);
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
 
 
        WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
        WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
        WSET(param, 2, 1);      /* max count */
        WSET(param, 2, 1);      /* max count */
        WSET(param, 4, 2 + 1);  /* close on end + close after this call */
        WSET(param, 4, 2 + 1);  /* close on end + close after this call */
        WSET(param, 6, 1);      /* info level */
        WSET(param, 6, 1);      /* info level */
        DSET(param, 8, 0);
        DSET(param, 8, 0);
 
 
        result = smb_trans2_request(server, TRANSACT2_FINDFIRST,
        result = smb_trans2_request(server, TRANSACT2_FINDFIRST,
                                    0, NULL, 12 + mask_len + 1, param,
                                    0, NULL, 12 + mask_len + 1, param,
                                    &resp_data_len, &resp_data,
                                    &resp_data_len, &resp_data,
                                    &resp_param_len, &resp_param);
                                    &resp_param_len, &resp_param);
 
 
        if (result < 0)
        if (result < 0)
        {
        {
                if (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        DPRINTK("smb_proc_getattr_ff: error=%d, retrying\n",
                        DPRINTK("smb_proc_getattr_ff: error=%d, retrying\n",
                                 result);
                                 result);
                        goto retry;
                        goto retry;
                }
                }
                goto out;
                goto out;
        }
        }
        if (server->rcls != 0)
        if (server->rcls != 0)
        {
        {
                result = -smb_errno(server->rcls, server->err);
                result = -smb_errno(server->rcls, server->err);
                if (result != -ENOENT)
                if (result != -ENOENT)
                        DPRINTK("smb_proc_getattr_ff: rcls=%d, err=%d\n",
                        DPRINTK("smb_proc_getattr_ff: rcls=%d, err=%d\n",
                                 server->rcls, server->err);
                                 server->rcls, server->err);
                goto out;
                goto out;
        }
        }
        /* Make sure we got enough data ... */
        /* Make sure we got enough data ... */
        result = -EINVAL;      /* WVAL(resp_param, 2) is ff_searchcount */
        result = -EINVAL;      /* WVAL(resp_param, 2) is ff_searchcount */
        if (resp_data_len < 22 || WVAL(resp_param, 2) != 1)
        if (resp_data_len < 22 || WVAL(resp_param, 2) != 1)
        {
        {
                DPRINTK("smb_proc_getattr_ff: bad result, len=%d, count=%d\n",
                DPRINTK("smb_proc_getattr_ff: bad result, len=%d, count=%d\n",
                         resp_data_len, WVAL(resp_param, 2));
                         resp_data_len, WVAL(resp_param, 2));
                goto out;
                goto out;
        }
        }
        /* Decode the response (info level 1, as in smb_decode_long_dirent) */
        /* Decode the response (info level 1, as in smb_decode_long_dirent) */
        p = resp_data;
        p = resp_data;
        entry->f_ctime = date_dos2unix(WVAL(p, 2), WVAL(p, 0));
        entry->f_ctime = date_dos2unix(WVAL(p, 2), WVAL(p, 0));
        entry->f_atime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
        entry->f_atime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
        entry->f_mtime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
        entry->f_mtime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
        entry->f_size = DVAL(p, 12);
        entry->f_size = DVAL(p, 12);
        entry->attr = WVAL(p, 20);
        entry->attr = WVAL(p, 20);
 
 
        DDPRINTK("smb_proc_getattr_ff: attr=%x\n", entry->attr);
        DDPRINTK("smb_proc_getattr_ff: attr=%x\n", entry->attr);
 
 
        result = 0;
        result = 0;
 
 
out:
out:
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
int
int
smb_proc_getattr(struct inode *dir, const char *name, int len,
smb_proc_getattr(struct inode *dir, const char *name, int len,
                 struct smb_dirent *entry)
                 struct smb_dirent *entry)
{
{
        struct smb_server *server = SMB_SERVER(dir);
        struct smb_server *server = SMB_SERVER(dir);
        int result;
        int result;
 
 
        smb_init_dirent(server, entry);
        smb_init_dirent(server, entry);
 
 
        /* Use trans2 for NT, use core protocol for others (Win95/3.11/...).
        /* Use trans2 for NT, use core protocol for others (Win95/3.11/...).
         * We distinguish NT from Win95 by looking at the capabilities,
         * We distinguish NT from Win95 by looking at the capabilities,
         * in the same way as in Samba 1.9.18p2's reply.c.
         * in the same way as in Samba 1.9.18p2's reply.c.
         */
         */
        if ((server->protocol >= PROTOCOL_LANMAN2)
        if ((server->protocol >= PROTOCOL_LANMAN2)
            && (server->blkmode & (CAP_NT_SMBS | CAP_STATUS32)))
            && (server->blkmode & (CAP_NT_SMBS | CAP_STATUS32)))
                result = smb_proc_getattr_ff(dir, name, len, entry);
                result = smb_proc_getattr_ff(dir, name, len, entry);
        else
        else
                result = smb_proc_getattr_core(dir, name, len, entry);
                result = smb_proc_getattr_core(dir, name, len, entry);
 
 
        smb_finish_dirent(server, entry);
        smb_finish_dirent(server, entry);
 
 
        entry->len = len;
        entry->len = len;
        memcpy(entry->name, name, len);
        memcpy(entry->name, name, len);
        /* entry->name is null terminated from smb_init_dirent */
        /* entry->name is null terminated from smb_init_dirent */
 
 
        return result;
        return result;
}
}
 
 
int
int
smb_proc_setattr(struct smb_server *server,
smb_proc_setattr(struct smb_server *server,
                 struct inode *i, struct smb_dirent *new_finfo)
                 struct inode *i, struct smb_dirent *new_finfo)
{
{
        char *p;
        char *p;
        char *buf;
        char *buf;
        int result;
        int result;
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
        buf = server->packet;
        buf = server->packet;
        p = smb_setup_header(server, SMBsetatr, 8, 0);
        p = smb_setup_header(server, SMBsetatr, 8, 0);
        WSET(buf, smb_vwv0, new_finfo->attr);
        WSET(buf, smb_vwv0, new_finfo->attr);
        DSET(buf, smb_vwv1, 0);
        DSET(buf, smb_vwv1, 0);
        DSET(buf, smb_vwv3, 0);
        DSET(buf, smb_vwv3, 0);
        DSET(buf, smb_vwv5, 0);
        DSET(buf, smb_vwv5, 0);
        WSET(buf, smb_vwv7, 0);
        WSET(buf, smb_vwv7, 0);
        *p++ = 4;
        *p++ = 4;
        p = smb_encode_path(server, p,
        p = smb_encode_path(server, p,
                            SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
                            SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
                            SMB_INOP(i)->finfo.len);
                            SMB_INOP(i)->finfo.len);
 
 
        smb_setup_bcc(server, p);
        smb_setup_bcc(server, p);
        if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0)
        if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0)
        {
        {
                if (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
        }
        }
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
int
int
smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr)
smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr)
{
{
        int error;
        int error;
        char *p;
        char *p;
        struct smb_server *server = &(SMB_SBP(super)->s_server);
        struct smb_server *server = &(SMB_SBP(super)->s_server);
 
 
        smb_lock_server(server);
        smb_lock_server(server);
 
 
      retry:
      retry:
        smb_setup_header(server, SMBdskattr, 0, 0);
        smb_setup_header(server, SMBdskattr, 0, 0);
 
 
        if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0)
        if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0)
        {
        {
                if (smb_retry(server))
                if (smb_retry(server))
                {
                {
                        goto retry;
                        goto retry;
                }
                }
                smb_unlock_server(server);
                smb_unlock_server(server);
                return error;
                return error;
        }
        }
        p = SMB_VWV(server->packet);
        p = SMB_VWV(server->packet);
        p = smb_decode_word(p, &attr->total);
        p = smb_decode_word(p, &attr->total);
        p = smb_decode_word(p, &attr->allocblocks);
        p = smb_decode_word(p, &attr->allocblocks);
        p = smb_decode_word(p, &attr->blocksize);
        p = smb_decode_word(p, &attr->blocksize);
        p = smb_decode_word(p, &attr->free);
        p = smb_decode_word(p, &attr->free);
        smb_unlock_server(server);
        smb_unlock_server(server);
        return 0;
        return 0;
}
}
 
 
/*****************************************************************************/
/*****************************************************************************/
/*                                                                           */
/*                                                                           */
/*  Mount/umount operations.                                                 */
/*  Mount/umount operations.                                                 */
/*                                                                           */
/*                                                                           */
/*****************************************************************************/
/*****************************************************************************/
 
 
struct smb_prots
struct smb_prots
{
{
        enum smb_protocol prot;
        enum smb_protocol prot;
        const char *name;
        const char *name;
};
};
 
 
/* smb_proc_reconnect: We expect the server to be locked, so that you
/* smb_proc_reconnect: We expect the server to be locked, so that you
   can call the routine from within smb_retry. The socket must be
   can call the routine from within smb_retry. The socket must be
   created, like after a user-level socket()-call. It may not be
   created, like after a user-level socket()-call. It may not be
   connected. */
   connected. */
 
 
int
int
smb_proc_reconnect(struct smb_server *server)
smb_proc_reconnect(struct smb_server *server)
{
{
        struct smb_prots prots[] =
        struct smb_prots prots[] =
        {
        {
                {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
                {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
                {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
                {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
#ifdef LANMAN1
#ifdef LANMAN1
                {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
                {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
                {PROTOCOL_LANMAN1, "LANMAN1.0"},
                {PROTOCOL_LANMAN1, "LANMAN1.0"},
#endif
#endif
#ifdef LANMAN2
#ifdef LANMAN2
                {PROTOCOL_LANMAN2, "LM1.2X002"},
                {PROTOCOL_LANMAN2, "LM1.2X002"},
#endif
#endif
#ifdef NT1
#ifdef NT1
                {PROTOCOL_NT1, "NT LM 0.12"},
                {PROTOCOL_NT1, "NT LM 0.12"},
                {PROTOCOL_NT1, "NT LANMAN 1.0"},
                {PROTOCOL_NT1, "NT LANMAN 1.0"},
#endif
#endif
                {-1, NULL}};
                {-1, NULL}};
        char dev[] = "A:";
        char dev[] = "A:";
        int i, plength;
        int i, plength;
        int max_xmit = 1024;    /* Space needed for first request. */
        int max_xmit = 1024;    /* Space needed for first request. */
        int given_max_xmit = server->m.max_xmit;
        int given_max_xmit = server->m.max_xmit;
        int result;
        int result;
        byte *p;
        byte *p;
 
 
        if ((result = smb_connect(server)) < 0)
        if ((result = smb_connect(server)) < 0)
        {
        {
                DPRINTK("smb_proc_reconnect: could not smb_connect\n");
                DPRINTK("smb_proc_reconnect: could not smb_connect\n");
                goto fail;
                goto fail;
        }
        }
        /* Here we assume that the connection is valid */
        /* Here we assume that the connection is valid */
        server->state = CONN_VALID;
        server->state = CONN_VALID;
 
 
        if (server->packet != NULL)
        if (server->packet != NULL)
        {
        {
                smb_vfree(server->packet);
                smb_vfree(server->packet);
                server->packet = NULL;
                server->packet = NULL;
                server->packet_size = 0;
                server->packet_size = 0;
        }
        }
        server->packet = smb_vmalloc(max_xmit);
        server->packet = smb_vmalloc(max_xmit);
 
 
        if (server->packet == NULL)
        if (server->packet == NULL)
        {
        {
                printk("smb_proc_connect: No memory! Bailing out.\n");
                printk("smb_proc_connect: No memory! Bailing out.\n");
                result = -ENOMEM;
                result = -ENOMEM;
                goto fail;
                goto fail;
        }
        }
        server->packet_size = server->max_xmit = max_xmit;
        server->packet_size = server->max_xmit = max_xmit;
 
 
        /*
        /*
         * Start with an RFC1002 session request packet.
         * Start with an RFC1002 session request packet.
         */
         */
        p = server->packet + 4;
        p = server->packet + 4;
 
 
        p = smb_name_mangle(p, server->m.server_name);
        p = smb_name_mangle(p, server->m.server_name);
        p = smb_name_mangle(p, server->m.client_name);
        p = smb_name_mangle(p, server->m.client_name);
 
 
        smb_encode_smb_length(server->packet,
        smb_encode_smb_length(server->packet,
                              (void *) p - (void *) (server->packet));
                              (void *) p - (void *) (server->packet));
 
 
        server->packet[0] = 0x81;        /* SESSION REQUEST */
        server->packet[0] = 0x81;        /* SESSION REQUEST */
 
 
        if (smb_catch_keepalive(server) < 0)
        if (smb_catch_keepalive(server) < 0)
        {
        {
                printk("smb_proc_connect: could not catch_keepalives\n");
                printk("smb_proc_connect: could not catch_keepalives\n");
        }
        }
        if ((result = smb_request(server)) < 0)
        if ((result = smb_request(server)) < 0)
        {
        {
                DPRINTK("smb_proc_connect: Failed to send SESSION REQUEST.\n");
                DPRINTK("smb_proc_connect: Failed to send SESSION REQUEST.\n");
                smb_dont_catch_keepalive(server);
                smb_dont_catch_keepalive(server);
                goto fail;
                goto fail;
        }
        }
        if (server->packet[0] != 0x82)
        if (server->packet[0] != 0x82)
        {
        {
                printk("smb_proc_connect: Did not receive positive response "
                printk("smb_proc_connect: Did not receive positive response "
                       "(err = %x)\n",
                       "(err = %x)\n",
                       server->packet[0]);
                       server->packet[0]);
                smb_dont_catch_keepalive(server);
                smb_dont_catch_keepalive(server);
                result = -EIO;
                result = -EIO;
                goto fail;
                goto fail;
        }
        }
        DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n");
        DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n");
 
 
        /* Now we are ready to send a SMB Negotiate Protocol packet. */
        /* Now we are ready to send a SMB Negotiate Protocol packet. */
        memset(server->packet, 0, SMB_HEADER_LEN);
        memset(server->packet, 0, SMB_HEADER_LEN);
 
 
        plength = 0;
        plength = 0;
        for (i = 0; prots[i].name != NULL; i++)
        for (i = 0; prots[i].name != NULL; i++)
        {
        {
                plength += strlen(prots[i].name) + 2;
                plength += strlen(prots[i].name) + 2;
        }
        }
 
 
        smb_setup_header(server, SMBnegprot, 0, plength);
        smb_setup_header(server, SMBnegprot, 0, plength);
 
 
        p = SMB_BUF(server->packet);
        p = SMB_BUF(server->packet);
 
 
        for (i = 0; prots[i].name != NULL; i++)
        for (i = 0; prots[i].name != NULL; i++)
        {
        {
                *p++ = 2;
                *p++ = 2;
                strcpy(p, prots[i].name);
                strcpy(p, prots[i].name);
                p += strlen(prots[i].name) + 1;
                p += strlen(prots[i].name) + 1;
        }
        }
 
 
        if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0)
        if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0)
        {
        {
                DPRINTK("smb_proc_connect: Failure requesting SMBnegprot\n");
                DPRINTK("smb_proc_connect: Failure requesting SMBnegprot\n");
                smb_dont_catch_keepalive(server);
                smb_dont_catch_keepalive(server);
                goto fail;
                goto fail;
        } else
        } else
        {
        {
                DDPRINTK("smb_proc_connect: Request SMBnegprot..");
                DDPRINTK("smb_proc_connect: Request SMBnegprot..");
        }
        }
 
 
        DDPRINTK("Verified!\n");
        DDPRINTK("Verified!\n");
 
 
        p = SMB_VWV(server->packet);
        p = SMB_VWV(server->packet);
        p = smb_decode_word(p, (word *) & i);
        p = smb_decode_word(p, (word *) & i);
#ifdef CONFIG_COLDFIRE
#ifdef CONFIG_COLDFIRE
        /*
        /*
         *      Not quite sure why this is needed???
         *      Not quite sure why this is needed???
         *      Maybe the byte swapping code is broken, but the result
         *      Maybe the byte swapping code is broken, but the result
         *      byte is certainly in the wrong position within the word.
         *      byte is certainly in the wrong position within the word.
         */
         */
        i = i >> 16;
        i = i >> 16;
#endif
#endif
        server->protocol = prots[i].prot;
        server->protocol = prots[i].prot;
 
 
        DPRINTK("smb_proc_connect: Server wants %s protocol.\n",
        DPRINTK("smb_proc_connect: Server wants %s protocol.\n",
                prots[i].name);
                prots[i].name);
 
 
        if (server->protocol >= PROTOCOL_LANMAN1)
        if (server->protocol >= PROTOCOL_LANMAN1)
        {
        {
 
 
                word passlen = strlen(server->m.password);
                word passlen = strlen(server->m.password);
                word userlen = strlen(server->m.username);
                word userlen = strlen(server->m.username);
 
 
#ifdef DEBUG_SMB_PASSWORD
#ifdef DEBUG_SMB_PASSWORD
                DPRINTK("smb_proc_connect: password = %s\n",
                DPRINTK("smb_proc_connect: password = %s\n",
                        server->m.password);
                        server->m.password);
#endif                  
#endif                  
                DPRINTK("smb_proc_connect: usernam = %s\n",
                DPRINTK("smb_proc_connect: usernam = %s\n",
                        server->m.username);
                        server->m.username);
 
 
                if (server->protocol >= PROTOCOL_NT1)
                if (server->protocol >= PROTOCOL_NT1)
                {
                {
                        server->max_xmit = DVAL(server->packet, smb_vwv3 + 1);
                        server->max_xmit = DVAL(server->packet, smb_vwv3 + 1);
                        server->maxmux = WVAL(server->packet, smb_vwv1 + 1);
                        server->maxmux = WVAL(server->packet, smb_vwv1 + 1);
                        server->maxvcs = WVAL(server->packet, smb_vwv2 + 1);
                        server->maxvcs = WVAL(server->packet, smb_vwv2 + 1);
                        server->blkmode = DVAL(server->packet, smb_vwv9 + 1);
                        server->blkmode = DVAL(server->packet, smb_vwv9 + 1);
                        server->sesskey = DVAL(server->packet, smb_vwv7 + 1);
                        server->sesskey = DVAL(server->packet, smb_vwv7 + 1);
                } else
                } else
                {
                {
                        server->max_xmit = WVAL(server->packet, smb_vwv2);
                        server->max_xmit = WVAL(server->packet, smb_vwv2);
                        server->maxmux = WVAL(server->packet, smb_vwv3);
                        server->maxmux = WVAL(server->packet, smb_vwv3);
                        server->maxvcs = WVAL(server->packet, smb_vwv4);
                        server->maxvcs = WVAL(server->packet, smb_vwv4);
                        server->blkmode = WVAL(server->packet, smb_vwv5);
                        server->blkmode = WVAL(server->packet, smb_vwv5);
                        server->sesskey = DVAL(server->packet, smb_vwv6);
                        server->sesskey = DVAL(server->packet, smb_vwv6);
                }
                }
                DPRINTK("smb_proc_connect: blkmode (capabilities) = %x\n",
                DPRINTK("smb_proc_connect: blkmode (capabilities) = %x\n",
                        server->blkmode);
                        server->blkmode);
 
 
                if (server->max_xmit < given_max_xmit)
                if (server->max_xmit < given_max_xmit)
                {
                {
                        /* We do not distinguish between the client
                        /* We do not distinguish between the client
                           requests and the server response. */
                           requests and the server response. */
                        given_max_xmit = server->max_xmit;
                        given_max_xmit = server->max_xmit;
                }
                }
                if (server->protocol >= PROTOCOL_NT1)
                if (server->protocol >= PROTOCOL_NT1)
                {
                {
                        char *workgroup = server->m.domain;
                        char *workgroup = server->m.domain;
                        char *OS_id = "Unix";
                        char *OS_id = "Unix";
                        char *client_id = "ksmbfs";
                        char *client_id = "ksmbfs";
 
 
                        smb_setup_header(server, SMBsesssetupX, 13,
                        smb_setup_header(server, SMBsesssetupX, 13,
                                         5 + userlen + passlen +
                                         5 + userlen + passlen +
                                         strlen(workgroup) + strlen(OS_id) +
                                         strlen(workgroup) + strlen(OS_id) +
                                         strlen(client_id));
                                         strlen(client_id));
 
 
                        WSET(server->packet, smb_vwv0, 0x00ff);
                        WSET(server->packet, smb_vwv0, 0x00ff);
                        WSET(server->packet, smb_vwv1, 0);
                        WSET(server->packet, smb_vwv1, 0);
                        WSET(server->packet, smb_vwv2, given_max_xmit);
                        WSET(server->packet, smb_vwv2, given_max_xmit);
                        WSET(server->packet, smb_vwv3, 2);
                        WSET(server->packet, smb_vwv3, 2);
                        WSET(server->packet, smb_vwv4, server->pid);
                        WSET(server->packet, smb_vwv4, server->pid);
                        DSET(server->packet, smb_vwv5, server->sesskey);
                        DSET(server->packet, smb_vwv5, server->sesskey);
                        WSET(server->packet, smb_vwv7, passlen + 1);
                        WSET(server->packet, smb_vwv7, passlen + 1);
                        WSET(server->packet, smb_vwv8, 0);
                        WSET(server->packet, smb_vwv8, 0);
                        WSET(server->packet, smb_vwv9, 0);
                        WSET(server->packet, smb_vwv9, 0);
 
 
                        p = SMB_BUF(server->packet);
                        p = SMB_BUF(server->packet);
                        strcpy(p, server->m.password);
                        strcpy(p, server->m.password);
                        p += passlen + 1;
                        p += passlen + 1;
                        strcpy(p, server->m.username);
                        strcpy(p, server->m.username);
                        p += userlen + 1;
                        p += userlen + 1;
                        strcpy(p, workgroup);
                        strcpy(p, workgroup);
                        p += strlen(p) + 1;
                        p += strlen(p) + 1;
                        strcpy(p, OS_id);
                        strcpy(p, OS_id);
                        p += strlen(p) + 1;
                        p += strlen(p) + 1;
                        strcpy(p, client_id);
                        strcpy(p, client_id);
                } else
                } else
                {
                {
                        smb_setup_header(server, SMBsesssetupX, 10,
                        smb_setup_header(server, SMBsesssetupX, 10,
                                         2 + userlen + passlen);
                                         2 + userlen + passlen);
 
 
                        WSET(server->packet, smb_vwv0, 0x00ff);
                        WSET(server->packet, smb_vwv0, 0x00ff);
                        WSET(server->packet, smb_vwv1, 0);
                        WSET(server->packet, smb_vwv1, 0);
                        WSET(server->packet, smb_vwv2, given_max_xmit);
                        WSET(server->packet, smb_vwv2, given_max_xmit);
                        WSET(server->packet, smb_vwv3, 2);
                        WSET(server->packet, smb_vwv3, 2);
                        WSET(server->packet, smb_vwv4, server->pid);
                        WSET(server->packet, smb_vwv4, server->pid);
                        DSET(server->packet, smb_vwv5, server->sesskey);
                        DSET(server->packet, smb_vwv5, server->sesskey);
                        WSET(server->packet, smb_vwv7, passlen + 1);
                        WSET(server->packet, smb_vwv7, passlen + 1);
                        WSET(server->packet, smb_vwv8, 0);
                        WSET(server->packet, smb_vwv8, 0);
                        WSET(server->packet, smb_vwv9, 0);
                        WSET(server->packet, smb_vwv9, 0);
 
 
                        p = SMB_BUF(server->packet);
                        p = SMB_BUF(server->packet);
                        strcpy(p, server->m.password);
                        strcpy(p, server->m.password);
                        p += passlen + 1;
                        p += passlen + 1;
                        strcpy(p, server->m.username);
                        strcpy(p, server->m.username);
                }
                }
 
 
                if ((result = smb_request_ok(server, SMBsesssetupX, 3, 0)) < 0)
                if ((result = smb_request_ok(server, SMBsesssetupX, 3, 0)) < 0)
                {
                {
                        DPRINTK("smb_proc_connect: SMBsessetupX failed\n");
                        DPRINTK("smb_proc_connect: SMBsessetupX failed\n");
                        smb_dont_catch_keepalive(server);
                        smb_dont_catch_keepalive(server);
                        goto fail;
                        goto fail;
                }
                }
                smb_decode_word(server->packet + 32, &(server->server_uid));
                smb_decode_word(server->packet + 32, &(server->server_uid));
        } else
        } else
        {
        {
                server->max_xmit = 0;
                server->max_xmit = 0;
                server->maxmux = 0;
                server->maxmux = 0;
                server->maxvcs = 0;
                server->maxvcs = 0;
                server->blkmode = 0;
                server->blkmode = 0;
                server->sesskey = 0;
                server->sesskey = 0;
        }
        }
 
 
        /* Fine! We have a connection, send a tcon message. */
        /* Fine! We have a connection, send a tcon message. */
 
 
        smb_setup_header(server, SMBtcon, 0,
        smb_setup_header(server, SMBtcon, 0,
                         6 + strlen(server->m.service) +
                         6 + strlen(server->m.service) +
                         strlen(server->m.password) + strlen(dev));
                         strlen(server->m.password) + strlen(dev));
 
 
        p = SMB_BUF(server->packet);
        p = SMB_BUF(server->packet);
        p = smb_encode_ascii(p, server->m.service, strlen(server->m.service));
        p = smb_encode_ascii(p, server->m.service, strlen(server->m.service));
        p = smb_encode_ascii(p, server->m.password, strlen(server->m.password));
        p = smb_encode_ascii(p, server->m.password, strlen(server->m.password));
        p = smb_encode_ascii(p, dev, strlen(dev));
        p = smb_encode_ascii(p, dev, strlen(dev));
 
 
        if ((result = smb_request_ok(server, SMBtcon, 2, 0)) < 0)
        if ((result = smb_request_ok(server, SMBtcon, 2, 0)) < 0)
        {
        {
                DPRINTK("smb_proc_connect: SMBtcon not verified.\n");
                DPRINTK("smb_proc_connect: SMBtcon not verified.\n");
                smb_dont_catch_keepalive(server);
                smb_dont_catch_keepalive(server);
                goto fail;
                goto fail;
        }
        }
        DDPRINTK("OK! Managed to set up SMBtcon!\n");
        DDPRINTK("OK! Managed to set up SMBtcon!\n");
 
 
        p = SMB_VWV(server->packet);
        p = SMB_VWV(server->packet);
 
 
        if (server->protocol <= PROTOCOL_COREPLUS)
        if (server->protocol <= PROTOCOL_COREPLUS)
        {
        {
                word max_xmit;
                word max_xmit;
 
 
                p = smb_decode_word(p, &max_xmit);
                p = smb_decode_word(p, &max_xmit);
                server->max_xmit = max_xmit;
                server->max_xmit = max_xmit;
 
 
                if (server->max_xmit > given_max_xmit)
                if (server->max_xmit > given_max_xmit)
                {
                {
                        server->max_xmit = given_max_xmit;
                        server->max_xmit = given_max_xmit;
                }
                }
        } else
        } else
        {
        {
                p += 2;
                p += 2;
        }
        }
 
 
        p = smb_decode_word(p, &server->tid);
        p = smb_decode_word(p, &server->tid);
 
 
        /* Ok, everything is fine. max_xmit does not include */
        /* Ok, everything is fine. max_xmit does not include */
        /* the TCP-SMB header of 4 bytes. */
        /* the TCP-SMB header of 4 bytes. */
        server->max_xmit += 4;
        server->max_xmit += 4;
 
 
        DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid);
        DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid);
 
 
        /* Now make a new packet with the correct size. */
        /* Now make a new packet with the correct size. */
        smb_vfree(server->packet);
        smb_vfree(server->packet);
        server->packet = NULL;
        server->packet = NULL;
 
 
        server->packet = smb_vmalloc(server->max_xmit);
        server->packet = smb_vmalloc(server->max_xmit);
        if (server->packet == NULL)
        if (server->packet == NULL)
        {
        {
                printk("smb_proc_connect: No memory left in end of "
                printk("smb_proc_connect: No memory left in end of "
                       "connection phase :-(\n");
                       "connection phase :-(\n");
                smb_dont_catch_keepalive(server);
                smb_dont_catch_keepalive(server);
                goto fail;
                goto fail;
        }
        }
        server->packet_size = server->max_xmit;
        server->packet_size = server->max_xmit;
 
 
        DPRINTK("smb_proc_connect: Normal exit\n");
        DPRINTK("smb_proc_connect: Normal exit\n");
        return 0;
        return 0;
 
 
      fail:
      fail:
        server->state = CONN_INVALID;
        server->state = CONN_INVALID;
        return result;
        return result;
}
}
 
 
/* smb_proc_reconnect: server->packet is allocated with
/* smb_proc_reconnect: server->packet is allocated with
   server->max_xmit bytes if and only if we return >= 0 */
   server->max_xmit bytes if and only if we return >= 0 */
int
int
smb_proc_connect(struct smb_server *server)
smb_proc_connect(struct smb_server *server)
{
{
        int result;
        int result;
        smb_lock_server(server);
        smb_lock_server(server);
 
 
        result = smb_proc_reconnect(server);
        result = smb_proc_reconnect(server);
 
 
        if ((result < 0) && (server->packet != NULL))
        if ((result < 0) && (server->packet != NULL))
        {
        {
                smb_vfree(server->packet);
                smb_vfree(server->packet);
                server->packet = NULL;
                server->packet = NULL;
        }
        }
        smb_unlock_server(server);
        smb_unlock_server(server);
        return result;
        return result;
}
}
 
 
int
int
smb_proc_disconnect(struct smb_server *server)
smb_proc_disconnect(struct smb_server *server)
{
{
        smb_setup_header_exclusive(server, SMBtdis, 0, 0);
        smb_setup_header_exclusive(server, SMBtdis, 0, 0);
        return smb_request_ok_unlock(server, SMBtdis, 0, 0);
        return smb_request_ok_unlock(server, SMBtdis, 0, 0);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.