patch-2.0.27 linux/fs/smbfs/proc.c

Next file: linux/fs/smbfs/sock.c
Previous file: linux/fs/smbfs/mmap.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.26/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
@@ -1,7 +1,7 @@
 /*
  *  proc.c
  *
- *  Copyright (C) 1995 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
  */
@@ -18,25 +18,43 @@
 #include <asm/segment.h>
 #include <asm/string.h>
 
-#define ARCH i386
 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
-#define SMB_CMD(packet)  ((packet)[8])
-#define SMB_WCT(packet)  ((packet)[SMB_HEADER_LEN - 1])
+#define SMB_CMD(packet)  (BVAL(packet,8))
+#define SMB_WCT(packet)  (BVAL(packet, SMB_HEADER_LEN - 1))
 #define SMB_BCC(packet)  smb_bcc(packet)
 #define SMB_BUF(packet)  ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
 
 #define SMB_DIRINFO_SIZE 43
 #define SMB_STATUS_SIZE  21
 
-#define HI_WORD(l) ((word)(l >> 16))
-#define LO_WORD(l) ((word)(l % 0xFFFF))
-
-void smb_printerr(int class, int num);
 static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
 
-static inline int min(int a, int b)
+static inline int
+min(int a, int b)
+{
+	return a < b ? a : b;
+}
+
+static void
+str_upper(char *name)
+{
+	while (*name)
+	{
+		if (*name >= 'a' && *name <= 'z')
+			*name -= ('a' - 'A');
+		name++;
+	}
+}
+
+static void
+str_lower(char *name)
 {
-	return a<b ? a : b;
+	while (*name)
+	{
+		if (*name >= 'A' && *name <= 'Z')
+			*name += ('a' - 'A');
+		name++;
+	}
 }
 
 /*****************************************************************************/
@@ -45,94 +63,105 @@
 /*                                                                           */
 /*****************************************************************************/
 
-static byte *
-smb_encode_word(byte *p, word data)
-{
-#if (ARCH == i386)
-        *((word *)p) = data;
-#else
-	p[0] = data & 0x00ffU;
-	p[1] = (data & 0xff00U) >> 8;
-#error "Non-Intel"
-#endif
-	return &p[2];
-}
-
-static byte *
-smb_decode_word(byte *p, word *data)
+static inline byte *
+smb_decode_word(byte * p, word * data)
 {
-#if (ARCH == i386)
-	*data = *(word *)p;
-#else
-	*data = (word) p[0] | p[1] << 8;
-#endif 
-	return &p[2];
+	*data = WVAL(p, 0);
+	return p + 2;
 }
 
 byte *
-smb_encode_smb_length(byte *p, dword len)
+smb_encode_smb_length(byte * p, dword len)
 {
-	p[0] = p[1] = 0;
-	p[2] = (len & 0xFF00) >> 8;
-	p[3] = (len & 0xFF);
+	BSET(p, 0, 0);
+	BSET(p, 1, 0);
+	BSET(p, 2, (len & 0xFF00) >> 8);
+	BSET(p, 3, (len & 0xFF));
 	if (len > 0xFFFF)
-		p[1] |= 0x01;
-	return &p[4];
+	{
+		BSET(p, 1, 1);
+	}
+	return p + 4;
 }
 
 static byte *
-smb_encode_dialect(byte *p, const byte *name, int len)
+smb_encode_ascii(byte * p, const byte * name, int len)
 {
-	*p ++ = 2;
+	*p++ = 4;
 	strcpy(p, name);
 	return p + len + 1;
 }
 
 static byte *
-smb_encode_ascii(byte *p, const byte *name, int len)
+smb_encode_this_name(byte * p, const char *name, const int len)
 {
-	*p ++ = 4;
-	strcpy(p, name);
-	return p + len + 1;
+	*p++ = '\\';
+	strncpy(p, name, len);
+	return p + len;
 }
 
+/* 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
+   386. */
+
 static byte *
-smb_encode_vblock(byte *p, const byte *data, word len, int fs)
+smb_encode_parents(byte * p, struct smb_inode_info *ino)
 {
-	*p ++ = 5;
-	p = smb_encode_word(p, len);
-	if (fs)
-		memcpy_fromfs(p, data, len);
-	else
-		memcpy(p, data, len);
-	return p + len;
+	byte *q;
+
+	if (ino->dir == NULL)
+	{
+		return p;
+	}
+	q = smb_encode_parents(p, ino->dir);
+	if (q - p + 1 + ino->finfo.len > SMB_MAXPATHLEN)
+	{
+		return p;
+	}
+	return smb_encode_this_name(q, ino->finfo.name, ino->finfo.len);
 }
 
 static byte *
-smb_decode_data(byte *p, byte *data, word *data_len, int fs)
-{
-        word len;
+smb_encode_path(struct smb_server *server,
+		byte * p, struct smb_inode_info *dir,
+		const char *name, const int len)
+{
+	byte *start = p;
+	p = smb_encode_parents(p, dir);
+	p = smb_encode_this_name(p, name, len);
+	*p++ = 0;
+	if (server->protocol <= PROTOCOL_COREPLUS)
+	{
+		str_upper(start);
+	}
+	return p;
+}
 
-	if (!(*p == 1 || *p == 5)) {
-                printk("smb_decode_data: Warning! Data block not starting "
-                       "with 1 or 5\n");
-        }
+static byte *
+smb_decode_data(byte * p, byte * data, word * data_len, int fs)
+{
+	word len;
 
-        len = WVAL(p, 1);
-        p += 3;
+	if (!(*p == 1 || *p == 5))
+	{
+		printk("smb_decode_data: Warning! Data block not starting "
+		       "with 1 or 5\n");
+	}
+	len = WVAL(p, 1);
+	p += 3;
 
-        if (fs)
-                memcpy_tofs(data, p, len);
-        else
-                memcpy(data, p, len);
+	if (fs)
+		memcpy_tofs(data, p, len);
+	else
+		memcpy(data, p, len);
 
-        *data_len = len;
+	*data_len = len;
 
-        return p + len;
+	return p + len;
 }
 
 static byte *
-smb_name_mangle(byte *p, const byte *name)
+smb_name_mangle(byte * p, const byte * name)
 {
 	int len, pad = 0;
 
@@ -141,19 +170,21 @@
 	if (len < 16)
 		pad = 16 - len;
 
-	*p ++ = 2 * (len + pad);
+	*p++ = 2 * (len + pad);
 
-	while (*name) {
-		*p ++ = (*name >> 4) + 'A';
-		*p ++ = (*name & 0x0F) + 'A';
-		name ++;
-	}
-	while (pad --) {
-		*p ++ = 'C';
-		*p ++ = 'A';
+	while (*name)
+	{
+		*p++ = (*name >> 4) + 'A';
+		*p++ = (*name & 0x0F) + 'A';
+		name++;
+	}
+	while (pad--)
+	{
+		*p++ = 'C';
+		*p++ = 'A';
 	}
 	*p++ = '\0';
-	
+
 	return p;
 }
 
@@ -161,7 +192,8 @@
 
 /* Linear day numbers of the respective 1sts in non-leap years. */
 
-static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+static int day_n[] =
+{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 */
 
 
@@ -170,28 +202,28 @@
 static int
 utc2local(int time)
 {
-        return time - sys_tz.tz_minuteswest*60;
+	return time - sys_tz.tz_minuteswest * 60;
 }
 
 static int
 local2utc(int time)
 {
-        return time + sys_tz.tz_minuteswest*60;
+	return time + sys_tz.tz_minuteswest * 60;
 }
 
 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
 
 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;
-	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 &&
-	    month < 2 ? 1 : 0)+3653);
-			/* days since 1.1.70 plus 80's leap day */
+	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 &&
+						   month < 2 ? 1 : 0) + 3653);
+	/* days since 1.1.70 plus 80's leap day */
 	return local2utc(secs);
 }
 
@@ -199,27 +231,32 @@
 /* Convert linear UNIX date to a MS-DOS time/date pair. */
 
 static void
-date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
+date_unix2dos(int unix_date, byte * date, byte * time)
 {
-	int day,year,nl_day,month;
+	int day, year, nl_day, month;
 
 	unix_date = utc2local(unix_date);
-	*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
-	    (((unix_date/3600) % 24) << 11);
-	day = unix_date/86400-3652;
-	year = day/365;
-	if ((year+3)/4+365*year > day) year--;
-	day -= (year+3)/4+365*year;
-	if (day == 59 && !(year & 3)) {
+	WSET(time, 0,
+	     (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
+	     (((unix_date / 3600) % 24) << 11));
+	day = unix_date / 86400 - 3652;
+	year = day / 365;
+	if ((year + 3) / 4 + 365 * year > day)
+		year--;
+	day -= (year + 3) / 4 + 365 * year;
+	if (day == 59 && !(year & 3))
+	{
 		nl_day = day;
 		month = 2;
-	}
-	else {
-		nl_day = (year & 3) || day <= 59 ? day : day-1;
+	} else
+	{
+		nl_day = (year & 3) || day <= 59 ? day : day - 1;
 		for (month = 0; month < 12; month++)
-			if (day_n[month] > nl_day) break;
+			if (day_n[month] > nl_day)
+				break;
 	}
-	*date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
+	WSET(date, 0,
+	     nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
 }
 
 
@@ -231,43 +268,39 @@
 /*****************************************************************************/
 
 dword
-smb_len(byte *packet) 
+smb_len(byte * p)
 {
-	return ((packet[1] & 0x1) << 16L) | (packet[2] << 8L) | (packet[3]);
+	return ((BVAL(p, 1) & 0x1) << 16L) | (BVAL(p, 2) << 8L) | (BVAL(p, 3));
 }
 
 static word
-smb_bcc(byte *packet)
+smb_bcc(byte * packet)
 {
 	int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word);
-#if (ARCH == i386)
-	return *((word *)((byte *)packet + pos));
-#else
-	return packet[pos] | packet[pos+1] << 8;
-#endif
+	return WVAL(packet, pos);
 }
 
 /* smb_valid_packet: We check if packet fulfills the basic
    requirements of a smb packet */
 
 static int
-smb_valid_packet(byte *packet)
+smb_valid_packet(byte * packet)
 {
-        DDPRINTK("len: %ld, wct: %d, bcc: %d\n",
-                 smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
-	return (   packet[4] == 0xff
-                && packet[5] == 'S'
-                && packet[6] == 'M'
-                && packet[7] == 'B'
-                && (smb_len(packet) + 4 == SMB_HEADER_LEN
-                    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
+	DDPRINTK("len: %d, wct: %d, bcc: %d\n",
+		 smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
+	return (packet[4] == 0xff
+		&& packet[5] == 'S'
+		&& packet[6] == 'M'
+		&& packet[7] == 'B'
+		&& (smb_len(packet) + 4 == SMB_HEADER_LEN
+		    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
 }
 
 /* smb_verify: We check if we got the answer we expected, and if we
    got enough data. If bcc == -1, we don't care. */
 
 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 &&
 		SMB_WCT(packet) >= wct &&
@@ -277,119 +310,100 @@
 static int
 smb_errno(int errcls, int error)
 {
-
-#if DEBUG_SMB > 1
-	if (errcls) {
-		printk("smb_errno: ");
-		smb_printerr(errcls, error);
-		printk("\n");
-	}
-#endif
-
-	if (errcls == ERRDOS) 
-		switch (error) {
-			case ERRbadfunc:    return EINVAL;
-			case ERRbadfile:    return ENOENT;
-			case ERRbadpath:    return ENOENT;
-			case ERRnofids:     return EMFILE;
-			case ERRnoaccess:   return EACCES;
-			case ERRbadfid:     return EBADF;
-			case ERRbadmcb:     return EREMOTEIO;
-			case ERRnomem:      return ENOMEM;
-			case ERRbadmem:     return EFAULT;
-			case ERRbadenv:     return EREMOTEIO;
-			case ERRbadformat:  return EREMOTEIO;
-			case ERRbadaccess:  return EACCES;
-			case ERRbaddata:    return E2BIG;
-			case ERRbaddrive:   return ENXIO;
-			case ERRremcd:      return EREMOTEIO;
-			case ERRdiffdevice: return EXDEV;
-			case ERRnofiles:    return 0;
-			case ERRbadshare:   return ETXTBSY;
-			case ERRlock:       return EDEADLK;
-			case ERRfilexists:  return EEXIST;
-			case 87:            return 0; /* Unknown error!! */
+	if (errcls == ERRDOS)
+		switch (error)
+		{
+		case ERRbadfunc:
+			return EINVAL;
+		case ERRbadfile:
+			return ENOENT;
+		case ERRbadpath:
+			return ENOENT;
+		case ERRnofids:
+			return EMFILE;
+		case ERRnoaccess:
+			return EACCES;
+		case ERRbadfid:
+			return EBADF;
+		case ERRbadmcb:
+			return EREMOTEIO;
+		case ERRnomem:
+			return ENOMEM;
+		case ERRbadmem:
+			return EFAULT;
+		case ERRbadenv:
+			return EREMOTEIO;
+		case ERRbadformat:
+			return EREMOTEIO;
+		case ERRbadaccess:
+			return EACCES;
+		case ERRbaddata:
+			return E2BIG;
+		case ERRbaddrive:
+			return ENXIO;
+		case ERRremcd:
+			return EREMOTEIO;
+		case ERRdiffdevice:
+			return EXDEV;
+		case ERRnofiles:
+			return 0;
+		case ERRbadshare:
+			return ETXTBSY;
+		case ERRlock:
+			return EDEADLK;
+		case ERRfilexists:
+			return EEXIST;
+		case 87:
+			return 0;	/* Unknown error!! */
 			/* This next error seems to occur on an mv when
 			 * the destination exists */
-			case 183:	    return EEXIST;
-			default:            return EIO;
-		}
-	else if (errcls == ERRSRV) 
-		switch (error) {
-			case ERRerror: return ENFILE;
-			case ERRbadpw: return EINVAL;
-			case ERRbadtype: return EIO;
-			case ERRaccess: return EACCES;
-			default: return EIO;
-		}
-	else if (errcls == ERRHRD) 
-		switch (error) {
-			case ERRnowrite: return EROFS; 
-			case ERRbadunit: return ENODEV;
-			case ERRnotready: return EUCLEAN;
-			case ERRbadcmd: return EIO;
-			case ERRdata: return EIO;
-			case ERRbadreq: return ERANGE;
-			case ERRbadshare: return ETXTBSY;
-			case ERRlock: return EDEADLK;
-			default: return EIO;
-		}
-	else if (errcls == ERRCMD) 
-	        return EIO;
+		case 183:
+			return EEXIST;
+		default:
+			return EIO;
+	} else if (errcls == ERRSRV)
+		switch (error)
+		{
+		case ERRerror:
+			return ENFILE;
+		case ERRbadpw:
+			return EINVAL;
+		case ERRbadtype:
+			return EIO;
+		case ERRaccess:
+			return EACCES;
+		default:
+			return EIO;
+	} else if (errcls == ERRHRD)
+		switch (error)
+		{
+		case ERRnowrite:
+			return EROFS;
+		case ERRbadunit:
+			return ENODEV;
+		case ERRnotready:
+			return EUCLEAN;
+		case ERRbadcmd:
+			return EIO;
+		case ERRdata:
+			return EIO;
+		case ERRbadreq:
+			return ERANGE;
+		case ERRbadshare:
+			return ETXTBSY;
+		case ERRlock:
+			return EDEADLK;
+		default:
+			return EIO;
+	} else if (errcls == ERRCMD)
+		return EIO;
 	return 0;
 }
 
-#if DEBUG_SMB > 0
-static char
-print_char(char c)
-{
-	if ((c < ' ') || (c > '~'))
-		return '.';
-	return c;
-}
-
-static void
-smb_dump_packet(byte *packet) {
-	int i, j, len;
-        int errcls, error;
-
-        errcls = (int)packet[9];
-        error  = (int)(int)(packet[11]|packet[12]<<8);
-
-	printk("smb_len = %d  valid = %d    \n", 
-	       len = smb_len(packet), smb_valid_packet(packet));
-	printk("smb_cmd = %d  smb_wct = %d  smb_bcc = %d\n", 
-	       packet[8], SMB_WCT(packet), SMB_BCC(packet)); 
-	printk("smb_rcls = %d smb_err = %d\n", errcls, error);
-
-	if (errcls) {
-		smb_printerr(errcls, error);
-		printk("\n");
-	}
-
-        if (len > 100)
-                len = 100;
-	
-	for (i = 0; i < len; i += 10) {
-		printk("%03d:", i);
-		for (j = i; j < i+10; j++)
-			if (j < len)
-				printk("%02x ", packet[j]);
-			else
-				printk("   ");
-		printk(": ");
-	        for (j = i; j < i+10; j++)
-			if (j < len)
-				printk("%c", print_char(packet[j]));
-		printk("\n");
-	}
-}
-#endif
-
 static void
 smb_lock_server(struct smb_server *server)
 {
-        while (server->lock)
+	while (server->lock)
 		sleep_on(&server->wait);
 	server->lock = 1;
 }
@@ -397,14 +411,14 @@
 static void
 smb_unlock_server(struct smb_server *server)
 {
-        if (server->lock != 1) {
-                printk("smb_unlock_server: was not locked!\n");
-        }
-
-        server->lock = 0;
-        wake_up(&server->wait);
+	if (server->lock != 1)
+	{
+		printk("smb_unlock_server: was not locked!\n");
+	}
+	server->lock = 0;
+	wake_up(&server->wait);
 }
-        
+
 /* smb_request_ok: We expect the server to be locked. Then we do the
    request and check the answer completely. When smb_request_ok
    returns 0, you can be quite sure that everything went well. When
@@ -413,27 +427,27 @@
 static int
 smb_request_ok(struct smb_server *s, int command, int wct, int bcc)
 {
-        int result = 0;
-        s->rcls = 0;
-        s->err  = 0;
-
-        if (smb_request(s) < 0) {
-                DPRINTK("smb_request failed\n");
-                result = -EIO;
-        }
-        else if (smb_valid_packet(s->packet) != 0) {
-                DPRINTK("not a valid packet!\n");
-                result = -EIO;
-        }
-        else if (s->rcls != 0) {
-                result =  -smb_errno(s->rcls, s->err);
-        }
-        else if (smb_verify(s->packet, command, wct, bcc) != 0) {
-                DPRINTK("smb_verify failed\n");
-                result = -EIO;
-        }
+	int result = 0;
+	s->rcls = 0;
+	s->err = 0;
 
-        return result;
+	if (smb_request(s) < 0)
+	{
+		DPRINTK("smb_request failed\n");
+		result = -EIO;
+	} else if (smb_valid_packet(s->packet) != 0)
+	{
+		DPRINTK("not a valid packet!\n");
+		result = -EIO;
+	} else if (s->rcls != 0)
+	{
+		result = -smb_errno(s->rcls, s->err);
+	} else if (smb_verify(s->packet, command, wct, bcc) != 0)
+	{
+		DPRINTK("smb_verify failed\n");
+		result = -EIO;
+	}
+	return result;
 }
 
 /* smb_retry: This function should be called when smb_request_ok has
@@ -445,72 +459,73 @@
 static int
 smb_retry(struct smb_server *server)
 {
-        if (server->state != CONN_INVALID) {
-                return 0;
-        }
-        
-        if (smb_release(server) < 0) {
-                DPRINTK("smb_retry: smb_release failed\n");
-                server->state = CONN_RETRIED;
-                return 0;
-        }
-        if(smb_proc_reconnect(server) < 0) {
-                DPRINTK("smb_proc_reconnect failed\n");
-                server->state = CONN_RETRIED;
-                return 0;
-        }
-
-        server->state = CONN_VALID;
-        return 1;
+	if (server->state != CONN_INVALID)
+	{
+		return 0;
+	}
+	if (smb_release(server) < 0)
+	{
+		DPRINTK("smb_retry: smb_release failed\n");
+		server->state = CONN_RETRIED;
+		return 0;
+	}
+	if (smb_proc_reconnect(server) < 0)
+	{
+		DPRINTK("smb_proc_reconnect failed\n");
+		server->state = CONN_RETRIED;
+		return 0;
+	}
+	server->state = CONN_VALID;
+	return 1;
 }
 
 static int
 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
    insert the command-specific fields */
 
-static byte *
-smb_setup_header(struct smb_server *server, byte command, word wct, word bcc)
+__u8 *
+smb_setup_header(struct smb_server * server, byte command, word wct, word bcc)
 {
 	dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2;
 	byte *p = server->packet;
-        byte *buf = server->packet;
+	byte *buf = server->packet;
 
-	p = smb_encode_smb_length(p, xmit_len);
+	p = smb_encode_smb_length(p, xmit_len - 4);
 
-        BSET(p,0,0xff);
-        BSET(p,1,'S');
-        BSET(p,2,'M');
-        BSET(p,3,'B');
-        BSET(p,4,command);
+	BSET(p, 0, 0xff);
+	BSET(p, 1, 'S');
+	BSET(p, 2, 'M');
+	BSET(p, 3, 'B');
+	BSET(p, 4, command);
 
-        p += 5;
+	p += 5;
 	memset(p, '\0', 19);
 	p += 19;
-        p += 8;
+	p += 8;
 
-        WSET(buf, smb_tid, server->tid);
-        WSET(buf, smb_pid, server->pid);
-        WSET(buf, smb_uid, server->server_uid);
-        WSET(buf, smb_mid, server->mid);
-
-        if (server->protocol > PROTOCOL_CORE) {
-                BSET(buf, smb_flg, 0x8);
-                WSET(buf, smb_flg2, 0x3);
-        }
-        
+	WSET(buf, smb_tid, server->tid);
+	WSET(buf, smb_pid, server->pid);
+	WSET(buf, smb_uid, server->server_uid);
+	WSET(buf, smb_mid, server->mid);
+
+	if (server->protocol > PROTOCOL_CORE)
+	{
+		BSET(buf, smb_flg, 0x8);
+		WSET(buf, smb_flg2, 0x3);
+	}
 	*p++ = wct;		/* wct */
-        p += 2*wct;
-        WSET(p, 0, bcc);
-        return p+2;
+	p += 2 * wct;
+	WSET(p, 0, bcc);
+	return p + 2;
 }
 
 /* smb_setup_header_exclusive waits on server->lock and locks the
@@ -519,10 +534,22 @@
 
 static byte *
 smb_setup_header_exclusive(struct smb_server *server,
-                           byte command, word wct, word bcc)
+			   byte command, word wct, word bcc)
 {
-        smb_lock_server(server);
-        return smb_setup_header(server, command, wct, bcc);
+	smb_lock_server(server);
+	return smb_setup_header(server, command, wct, bcc);
+}
+
+static void
+smb_setup_bcc(struct smb_server *server, byte * p)
+{
+	__u8 *packet = server->packet;
+	__u8 *pbcc = packet + SMB_HEADER_LEN + 2 * SMB_WCT(packet);
+	__u16 bcc = p - (pbcc + 2);
+
+	WSET(pbcc, 0, bcc);
+	smb_encode_smb_length(packet,
+			      SMB_HEADER_LEN + 2 * SMB_WCT(packet) - 2 + bcc);
 }
 
 
@@ -533,17 +560,19 @@
 /*****************************************************************************/
 
 int
-smb_proc_open(struct smb_server *server, const char *pathname, int len,
-              struct smb_dirent *entry)
+smb_proc_open(struct smb_server *server,
+	      struct smb_inode_info *dir, const char *name, int len,
+	      struct smb_dirent *entry)
 {
 	int error;
-	char* p;
-        char* buf = server->packet;
+	char *p;
+	char *buf;
 	const word o_attr = aSYSTEM | aHIDDEN | aDIR;
 
-        DPRINTK("smb_proc_open: path=%s\n", pathname);
+	DPRINTK("smb_proc_open: name=%s\n", name);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
 	if (entry->opened != 0)
 	{
@@ -551,69 +580,74 @@
 		smb_unlock_server(server);
 		return 0;
 	}
+      retry:
+	p = smb_setup_header(server, SMBopen, 2, 0);
+	WSET(buf, smb_vwv0, 0x42);	/* read/write */
+	WSET(buf, smb_vwv1, o_attr);
+	*p++ = 4;
+	p = smb_encode_path(server, p, dir, name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-        p = smb_setup_header(server, SMBopen, 2, 2 + len);
-        WSET(buf, smb_vwv0, 0x42); /* read/write */
-        WSET(buf, smb_vwv1, o_attr);
-        smb_encode_ascii(p, pathname, len);
-
-        if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) {
-
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                
-                if (error != -EACCES) {
-                        smb_unlock_server(server);
-                        return error;
-                }
-
-                p = smb_setup_header(server, SMBopen, 2, 2 + len);
-                WSET(buf, smb_vwv0, 0x40); /* read only */
-                WSET(buf, smb_vwv1, o_attr);
-                smb_encode_ascii(p, pathname, len);
-
-                if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) {
-                        if (smb_retry(server)) {
-                                goto retry;
-                        }
-                        smb_unlock_server(server);
-                        return error;
-                }
-        }
+	if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
+	{
 
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		if ((error != -EACCES) && (error != -ETXTBSY)
+		    && (error != -EROFS))
+		{
+			smb_unlock_server(server);
+			return error;
+		}
+		p = smb_setup_header(server, SMBopen, 2, 0);
+		WSET(buf, smb_vwv0, 0x40);	/* read only */
+		WSET(buf, smb_vwv1, o_attr);
+		*p++ = 4;
+		p = smb_encode_path(server, p, dir, name, len);
+		smb_setup_bcc(server, p);
+
+		if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
+		{
+			if (smb_retry(server))
+			{
+				goto retry;
+			}
+			smb_unlock_server(server);
+			return error;
+		}
+	}
 	/* We should now have data in vwv[0..6]. */
 
-        entry->fileid = WVAL(buf, smb_vwv0);
-        entry->attr   = WVAL(buf, smb_vwv1);
-        entry->ctime = entry->atime =
-                entry->mtime = local2utc(DVAL(buf, smb_vwv2));
-        entry->size   = DVAL(buf, smb_vwv4);
-        entry->access = WVAL(buf, smb_vwv6);
+	entry->fileid = WVAL(buf, smb_vwv0);
+	entry->attr = WVAL(buf, smb_vwv1);
+	entry->f_ctime = entry->f_atime =
+	    entry->f_mtime = local2utc(DVAL(buf, smb_vwv2));
+	entry->f_size = DVAL(buf, smb_vwv4);
+	entry->access = WVAL(buf, smb_vwv6);
 
 	entry->opened = 1;
 	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;
 }
 
-/* smb_proc_close: in finfo->mtime we can send a modification time to
-   the server */
 int
 smb_proc_close(struct smb_server *server,
 	       __u16 fileid, __u32 mtime)
 {
-        char *buf = server->packet;
+	char *buf;
 
 	smb_setup_header_exclusive(server, SMBclose, 3, 0);
-        WSET(buf, smb_vwv0, fileid);
-        DSET(buf, smb_vwv1, utc2local(mtime));
+	buf = server->packet;
+	WSET(buf, smb_vwv0, fileid);
+	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
@@ -623,311 +657,333 @@
    memcpy_tofs. */
 
 int
-smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, 
-              off_t offset, long count, char *data, int fs)
+smb_proc_read(struct smb_server *server, struct smb_dirent *finfo,
+	      off_t offset, long count, char *data, int fs)
 {
 	word returned_count, data_len;
-        char *buf = server->packet;
-        int error;
+	char *buf;
+	int error;
 
 	smb_setup_header_exclusive(server, SMBread, 5, 0);
+	buf = server->packet;
 
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        DSET(buf, smb_vwv2, offset);
-        WSET(buf, smb_vwv4, 0);
-	
-	if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0) {
-                smb_unlock_server(server);
-		return error;
-        }
+	WSET(buf, smb_vwv0, finfo->fileid);
+	WSET(buf, smb_vwv1, count);
+	DSET(buf, smb_vwv2, offset);
+	WSET(buf, smb_vwv4, 0);
 
+	if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0)
+	{
+		smb_unlock_server(server);
+		return error;
+	}
 	returned_count = WVAL(buf, smb_vwv0);
-	
+
 	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: ret_c=%d, data_len=%d\n",
-                       returned_count, data_len);
-        }
-
-        return data_len;
-}
-
-/* count must be <= 65535. No error number is returned.  A result of 0
-   indicates an error, which has to be investigated by a normal read
-   call. */
-int
-smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, 
-                  off_t offset, long count, char *data)
-{
-        char *buf = server->packet;
-        int result;
-
-        if ((count <= 0) || (count > 65535)) {
-                return -EINVAL;
-        }
-
-	smb_setup_header_exclusive(server, SMBreadbraw, 8, 0);
-
-        WSET(buf, smb_vwv0, finfo->fileid);
-        DSET(buf, smb_vwv1, offset);
-        WSET(buf, smb_vwv3, count);
-        WSET(buf, smb_vwv4, 0);
-        DSET(buf, smb_vwv5, 0);
-
-        result = smb_request_read_raw(server, data, count);
-        smb_unlock_server(server);
-        return result;
+		printk("smb_proc_read: ret_c=%d, data_len=%d\n",
+		       returned_count, data_len);
+	}
+	return data_len;
 }
 
 int
 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;
-        char *buf = server->packet;
-        byte *p;
+	int res = 0;
+	char *buf;
+	byte *p;
 
 	p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3);
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        DSET(buf, smb_vwv2, offset);
-        WSET(buf, smb_vwv4, 0);
-
-        *p++ = 1;
-        WSET(p, 0, count);
-        memcpy_fromfs(p+2, data, count);
-
-	if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0) {
-                res = WVAL(buf, smb_vwv0);
-        }
+	buf = server->packet;
+	WSET(buf, smb_vwv0, finfo->fileid);
+	WSET(buf, smb_vwv1, count);
+	DSET(buf, smb_vwv2, offset);
+	WSET(buf, smb_vwv4, 0);
+
+	*p++ = 1;
+	WSET(p, 0, count);
+	memcpy_fromfs(p + 2, data, count);
 
-        smb_unlock_server(server);
+	if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
+	{
+		res = WVAL(buf, smb_vwv0);
+	}
+	smb_unlock_server(server);
 
 	return res;
 }
 
-/* count must be <= 65535 */
 int
-smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, 
-                   off_t offset, long count, const char *data)
+smb_proc_create(struct inode *dir, const char *name, int len,
+		word attr, time_t ctime)
 {
-        char *buf = server->packet;
-        int result;
+	int error;
+	char *p;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
+	__u16 fileid;
 
-        if ((count <= 0) || (count > 65535)) {
-                return -EINVAL;
-        }
-
-	smb_setup_header_exclusive(server, SMBwritebraw, 11, 0);
-
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        WSET(buf, smb_vwv2, 0); /* reserved */
-        DSET(buf, smb_vwv3, offset);
-        DSET(buf, smb_vwv5, 0); /* timeout */
-        WSET(buf, smb_vwv7, 1); /* send final result response */
-        DSET(buf, smb_vwv8, 0); /* reserved */
-        WSET(buf, smb_vwv10, 0); /* no data in this buf */
-        WSET(buf, smb_vwv11, 0); /* no data in this buf */
-
-        result = smb_request_ok(server, SMBwritebraw, 1, 0);
-
-        DPRINTK("smb_proc_write_raw: first request returned %d\n", result);
-        
-        if (result < 0) {
-                smb_unlock_server(server);
-                return result;
-        }
-        
-        result = smb_request_write_raw(server, data, count);
-
-        DPRINTK("smb_proc_write_raw: raw request returned %d\n", result);
-        
-        if (result > 0) {
-                /* We have to do the checks of smb_request_ok here as well */
-                if (smb_valid_packet(server->packet) != 0) {
-                        DPRINTK("not a valid packet!\n");
-                        result = -EIO;
-                } else if (server->rcls != 0) {
-                        result = -smb_errno(server->rcls, server->err);
-                } else if (smb_verify(server->packet, SMBwritec,1,0) != 0) {
-                        DPRINTK("smb_verify failed\n");
-                        result = -EIO;
-                }
-        }
+	smb_lock_server(server);
+	buf = server->packet;
+      retry:
+	p = smb_setup_header(server, SMBcreate, 3, 0);
+	WSET(buf, smb_vwv0, attr);
+	DSET(buf, smb_vwv1, utc2local(ctime));
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
-        smb_unlock_server(server);
-        return result;
-}
+	if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
+		return error;
+	}
+	fileid = WVAL(buf, smb_vwv0);
+	smb_unlock_server(server);
 
+	smb_proc_close(server, fileid, CURRENT_TIME);
 
-/* smb_proc_create: We expect entry->attr & entry->ctime to be set. */
+	return 0;
+}
 
 int
-smb_proc_create(struct smb_server *server, const char *path, int len, 
-		struct smb_dirent *entry)
+smb_proc_mv(struct inode *odir, const char *oname, const int olen,
+	    struct inode *ndir, const char *nname, const int nlen)
 {
-	int error;
 	char *p;
-        char *buf = server->packet;
-	__u16 fileid;
+	struct smb_server *server = SMB_SERVER(odir);
+	char *buf;
+	int result;
 
 	smb_lock_server(server);
- retry:
-	p = smb_setup_header(server, SMBcreate, 3, len + 2);
-        WSET(buf, smb_vwv0, entry->attr);
-        DSET(buf, smb_vwv1, utc2local(entry->ctime));
-	smb_encode_ascii(p, path, len);
-
-	if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
-		return error;
-        }
-
-        entry->opened = 0;
-        fileid = WVAL(buf, smb_vwv0);
-        smb_unlock_server(server);
+	buf = server->packet;
 
-        smb_proc_close(server, fileid, 0);
+      retry:
+	p = smb_setup_header(server, SMBmv, 1, 0);
+	WSET(buf, smb_vwv0, aSYSTEM | aHIDDEN);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(odir), oname, olen);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(ndir), nname, nlen);
+	smb_setup_bcc(server, p);
 
-	return 0;
+	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_mv(struct smb_server *server, 
-            const char *opath, const int olen,
-            const char *npath, const int nlen)
+smb_proc_mkdir(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        char *buf = server->packet;
-        int result;
+	int result;
+	struct smb_server *server = SMB_SERVER(dir);
+
+	smb_lock_server(server);
 
-        smb_lock_server(server);
+      retry:
+	p = smb_setup_header(server, SMBmkdir, 0, 0);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBmv, 1, olen + nlen + 4);
-        WSET(buf, smb_vwv0, 0);
-	p = smb_encode_ascii(p, opath, olen);
-	smb_encode_ascii(p, npath, olen);
-
-        if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_mkdir(struct smb_server *server, const char *path, const int len)
+smb_proc_rmdir(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        int result;
+	int result;
+	struct smb_server *server = SMB_SERVER(dir);
+
+	smb_lock_server(server);
+
 
-        smb_lock_server(server);
+      retry:
+	p = smb_setup_header(server, SMBrmdir, 0, 0);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBmkdir, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_rmdir(struct smb_server *server, const char *path, const int len)
+smb_proc_unlink(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        int result;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
+	int result;
+
+	smb_lock_server(server);
+	buf = server->packet;
 
-        smb_lock_server(server);
+      retry:
+	p = smb_setup_header(server, SMBunlink, 1, 0);
+	WSET(buf, smb_vwv0, aSYSTEM | aHIDDEN);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBrmdir, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_unlink(struct smb_server *server, const char *path, const int len)
+smb_proc_trunc(struct smb_server *server, word fid, dword length)
 {
 	char *p;
-        char *buf = server->packet;
-        int result;
+	char *buf;
+	int result;
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
- retry:
-	p = smb_setup_header(server, SMBunlink, 1, 2 + len);
-        WSET(buf, smb_vwv0, 0);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+      retry:
+	p = smb_setup_header(server, SMBwrite, 5, 0);
+	WSET(buf, smb_vwv0, fid);
+	WSET(buf, smb_vwv1, 0);
+	DSET(buf, smb_vwv2, length);
+	WSET(buf, smb_vwv4, 0);
+	p = smb_encode_ascii(p, "", 0);
+	smb_setup_bcc(server, p);
+
+	if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
-int
-smb_proc_trunc(struct smb_server *server, word fid, dword length)
+static void
+smb_init_dirent(struct smb_server *server, struct smb_dirent *entry)
 {
-        char *p;
-        char *buf = server->packet;
-        int result;
-
-        smb_lock_server(server);
-
- retry:
-        p = smb_setup_header(server, SMBwrite, 5, 3);
-        WSET(buf, smb_vwv0, fid);
-        WSET(buf, smb_vwv1, 0);
-        DSET(buf, smb_vwv2, length);
-        WSET(buf, smb_vwv4, 0);
-	smb_encode_ascii(p, "", 0);
-	
-        if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	memset(entry, 0, sizeof(struct smb_dirent));
+
+	entry->f_nlink = 1;
+	entry->f_uid = server->m.uid;
+	entry->f_gid = server->m.gid;
+	entry->f_blksize = 512;
 }
 
+static void
+smb_finish_dirent(struct smb_server *server, struct smb_dirent *entry)
+{
+	if ((entry->attr & aDIR) != 0)
+	{
+		entry->f_mode = server->m.dir_mode;
+		entry->f_size = 512;
+	} else
+	{
+		entry->f_mode = server->m.file_mode;
+	}
+
+	if ((entry->f_blksize != 0) && (entry->f_size != 0))
+	{
+		entry->f_blocks =
+		    (entry->f_size - 1) / entry->f_blksize + 1;
+	} else
+	{
+		entry->f_blocks = 0;
+	}
+	return;
+}
+
+void
+smb_init_root_dirent(struct smb_server *server, struct smb_dirent *entry)
+{
+	smb_init_dirent(server, entry);
+	entry->attr = aDIR;
+	entry->f_ino = 1;
+	smb_finish_dirent(server, entry);
+}
+
+
 static char *
-smb_decode_dirent(char *p, struct smb_dirent *entry)
+smb_decode_dirent(struct smb_server *server, char *p, struct smb_dirent *entry)
 {
-	p += SMB_STATUS_SIZE;                  /* reserved (search_status) */
-        entry->attr = BVAL(p, 0);
-        entry->mtime = entry->atime = entry->ctime =
-                date_dos2unix(WVAL(p, 1), WVAL(p, 3));
-        entry->size = DVAL(p, 5);
-        memcpy(entry->path, p+9, 13);
-	DDPRINTK("smb_decode_dirent: path = %s\n", entry->path);
+	smb_init_dirent(server, entry);
+
+	p += SMB_STATUS_SIZE;	/* reserved (search_status) */
+	entry->attr = BVAL(p, 0);
+	entry->f_mtime = entry->f_atime = entry->f_ctime =
+	    date_dos2unix(WVAL(p, 1), WVAL(p, 3));
+	entry->f_size = DVAL(p, 5);
+	entry->len = strlen(p + 9);
+	if (entry->len > 12)
+	{
+		entry->len = 12;
+	}
+	memcpy(entry->name, p + 9, entry->len);
+	entry->name[entry->len] = '\0';
+	while (entry->len > 2)
+	{
+		/* Pathworks fills names with spaces */
+		entry->len -= 1;
+		if (entry->name[entry->len] == ' ')
+		{
+			entry->name[entry->len] = '\0';
+		}
+	}
+	switch (server->case_handling)
+	{
+	case CASE_UPPER:
+		str_upper(entry->name);
+		break;
+	case CASE_LOWER:
+		str_lower(entry->name);
+		break;
+	default:
+		break;
+	}
+	DPRINTK("smb_decode_dirent: name = %s\n", entry->name);
+	smb_finish_dirent(server, entry);
 	return p + 22;
 }
 
@@ -940,118 +996,126 @@
 		       int cache_size, struct smb_dirent *entry)
 {
 	char *p;
-        char *buf;
+	char *buf;
 	int error;
-        int result;
+	int result;
 	int i;
 	int first, total_count;
-        struct smb_dirent *current_entry;
+	struct smb_dirent *current_entry;
 	word bcc;
 	word count;
 	char status[SMB_STATUS_SIZE];
 	int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE;
-	int dirlen = strlen(SMB_FINFO(dir)->path);
-	char mask[dirlen + 5];
-
-	strcpy(mask, SMB_FINFO(dir)->path);
-	strcat(mask, "\\*.*");
-
- 	DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);        
-	DPRINTK("          mask = %s\n", mask);
 
-        buf = server->packet;
+	DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
- retry:
+      retry:
 	first = 1;
-        total_count = 0;
-        current_entry = entry;
-	
-	while (1) {
-		if (first == 1) {
-			p = smb_setup_header(server, SMBsearch, 2,
-                                             5 + strlen(mask));
-                        WSET(buf, smb_vwv0, entries_asked);
-                        WSET(buf, smb_vwv1, aDIR);
-			p = smb_encode_ascii(p, mask, strlen(mask));
-			*p ++ = 5;
-		        p = smb_encode_word(p, 0);
-		} else {
-			p = smb_setup_header(server, SMBsearch, 2,
-                                             5 + SMB_STATUS_SIZE);
-                        WSET(buf, smb_vwv0, entries_asked);
-                        WSET(buf, smb_vwv1, aDIR);
+	total_count = 0;
+	current_entry = entry;
+
+	while (1)
+	{
+		if (first == 1)
+		{
+			p = smb_setup_header(server, SMBsearch, 2, 0);
+			WSET(buf, smb_vwv0, entries_asked);
+			WSET(buf, smb_vwv1, aDIR);
+			*p++ = 4;
+			p = smb_encode_path(server, p, SMB_INOP(dir), "*.*", 3);
+			*p++ = 5;
+			WSET(p, 0, 0);
+			p += 2;
+		} else
+		{
+			p = smb_setup_header(server, SMBsearch, 2, 0);
+			WSET(buf, smb_vwv0, entries_asked);
+			WSET(buf, smb_vwv1, aDIR);
 			p = smb_encode_ascii(p, "", 0);
-			p = smb_encode_vblock(p, status, SMB_STATUS_SIZE, 0);
+			*p++ = 5;
+			WSET(p, 0, SMB_STATUS_SIZE);
+			p += 2;
+			memcpy(p, status, SMB_STATUS_SIZE);
+			p += SMB_STATUS_SIZE;
 		}
-		
-		if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0) {
-                        if (   (server->rcls == ERRDOS)
-                            && (server->err  == ERRnofiles)) {
-                                result = total_count - fpos;
-                                goto unlock_return;
-                        }
-                        else
-                        {
-                                if (smb_retry(server)) {
-                                        goto retry;
-                                }
-                                result = error;
-                                goto unlock_return;
-                        }
-                }
 
+		smb_setup_bcc(server, p);
+
+		if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0)
+		{
+			if ((server->rcls == ERRDOS)
+			    && (server->err == ERRnofiles))
+			{
+				result = total_count - fpos;
+				goto unlock_return;
+			} else
+			{
+				if (smb_retry(server))
+				{
+					goto retry;
+				}
+				result = error;
+				goto unlock_return;
+			}
+		}
 		p = SMB_VWV(server->packet);
-		p = smb_decode_word(p, &count); /* vwv[0] = count-returned */
-		p = smb_decode_word(p, &bcc);           
-		
+		p = smb_decode_word(p, &count);
+		p = smb_decode_word(p, &bcc);
+
 		first = 0;
-		
-		if (count <= 0) {
+
+		if (count <= 0)
+		{
 			result = total_count - fpos;
-                        goto unlock_return;
-                }
-		if (bcc != count * SMB_DIRINFO_SIZE + 3) {
+			goto unlock_return;
+		}
+		if (bcc != count * SMB_DIRINFO_SIZE + 3)
+		{
 			result = -EIO;
-                        goto unlock_return;
-                }
-
-		p += 3; /* Skipping VBLOCK header (5, length lo, length hi). */
+			goto unlock_return;
+		}
+		p += 3;		/* Skipping VBLOCK header
+				   (5, length lo, length hi). */
 
 		/* Read the last entry into the status field. */
 		memcpy(status,
-                       SMB_BUF(server->packet) + 3 +
-                       (count - 1) * SMB_DIRINFO_SIZE, 
-                       SMB_STATUS_SIZE);
+		       SMB_BUF(server->packet) + 3 +
+		       (count - 1) * SMB_DIRINFO_SIZE,
+		       SMB_STATUS_SIZE);
 
 		/* Now we are ready to parse smb directory entries. */
-		
-		for (i = 0; i < count; i ++) {
-			if (total_count < fpos) {
+
+		for (i = 0; i < count; i++)
+		{
+			if (total_count < fpos)
+			{
 				p += SMB_DIRINFO_SIZE;
 				DDPRINTK("smb_proc_readdir: skipped entry.\n");
 				DDPRINTK("                  total_count = %d\n"
-                                         "                i = %d, fpos = %d\n",
-                                         total_count, i, fpos);
-                        }
-                        else if (total_count >= fpos + cache_size) {
-                                result = total_count - fpos;
-                                goto unlock_return;
-			}
-			else {
-				p = smb_decode_dirent(p, current_entry);
+					 "                i = %d, fpos = %d\n",
+					 total_count, i, fpos);
+			} else if (total_count >= fpos + cache_size)
+			{
+				result = total_count - fpos;
+				goto unlock_return;
+			} else
+			{
+				p = smb_decode_dirent(server, p,
+						      current_entry);
 				current_entry->f_pos = total_count;
 				DDPRINTK("smb_proc_readdir: entry->f_pos = "
-                                         "%lu\n", entry->f_pos);	
+					 "%lu\n", entry->f_pos);
 				current_entry += 1;
 			}
 			total_count += 1;
 		}
 	}
- unlock_return:
-        smb_unlock_server(server);
-        return result;
+      unlock_return:
+	smb_unlock_server(server);
+	return result;
 }
 
 /* interpret a long filename structure - this is mostly guesses at the
@@ -1060,524 +1124,483 @@
    is used by OS/2. */
 
 static char *
-smb_decode_long_dirent(char *p, struct smb_dirent *finfo, int level)
+smb_decode_long_dirent(struct smb_server *server, char *p,
+		       struct smb_dirent *entry, int level)
 {
-        char *result;
+	char *result;
 
-        if (finfo) {
-                /* I have to set times to 0 here, because I do not
-                   have specs about this for all info levels. */
-                finfo->ctime = finfo->mtime = finfo->atime = 0;
-        }
-
-        switch (level)
-        {
-        case 1:                 /* OS/2 understands this */
-                if (finfo)
-                {
-                        DPRINTK("received entry\n");
-                        strcpy(finfo->path,p+27);
-                        finfo->len  = strlen(finfo->path);
-                        finfo->size = DVAL(p,16);
-                        finfo->attr = BVAL(p,24);
-
-                        finfo->ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
-                        finfo->atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
-                        finfo->mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
-                }
-                result = p + 28 + BVAL(p,26);
-                break;
-
-        case 2:                 /* this is what OS/2 uses */
-                if (finfo)
-                {
-                        strcpy(finfo->path,p+31);
-                        finfo->len  = strlen(finfo->path);
-                        finfo->size = DVAL(p,16);
-                        finfo->attr = BVAL(p,24);
-#if 0
-                        finfo->atime = make_unix_date2(p+8);
-                        finfo->mtime = make_unix_date2(p+12);
-#endif
-                }
-                result = p + 32 + BVAL(p,30);
-                break;
-
-        case 260:               /* NT uses this, but also accepts 2 */
-                result = p + WVAL(p,0);
-                if (finfo)
-                {
-                        int namelen;
-                        p += 4; /* next entry offset */
-                        p += 4; /* fileindex */
-                        /* finfo->ctime = interpret_filetime(p);*/
-                        p += 8;
-                        /* finfo->atime = interpret_filetime(p);*/
-                        p += 8;
-                        p += 8; /* write time */
-                        /* finfo->mtime = interpret_filetime(p);*/
-                        p += 8;
-                        finfo->size = DVAL(p,0);
-                        p += 8;
-                        p += 8; /* alloc size */
-                        finfo->attr = BVAL(p,0);
-                        p += 4;
-                        namelen = min(DVAL(p,0), SMB_MAXNAMELEN);
-                        p += 4;
-                        p += 4; /* EA size */
-                        p += 2; /* short name len? */
-                        p += 24; /* short name? */	  
-                        strncpy(finfo->path,p,namelen);
-                        finfo->len = namelen;
-                }
-                break;
-
-        default:
-                DPRINTK("Unknown long filename format %d\n",level);
-                result = p + WVAL(p,0);
-        }
-        return result;
+	smb_init_dirent(server, entry);
+
+	switch (level)
+	{
+		/* We might add more levels later... */
+	case 1:
+		entry->len = BVAL(p, 26);
+		strncpy(entry->name, p + 27, entry->len);
+		entry->name[entry->len] = '\0';
+		entry->f_size = DVAL(p, 16);
+		entry->attr = BVAL(p, 24);
+
+		entry->f_ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
+		entry->f_atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
+		entry->f_mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
+		result = p + 28 + BVAL(p, 26);
+		break;
+
+	default:
+		DPRINTK("Unknown long filename format %d\n", level);
+		result = p + WVAL(p, 0);
+	}
+
+	switch (server->case_handling)
+	{
+	case CASE_UPPER:
+		str_upper(entry->name);
+		break;
+	case CASE_LOWER:
+		str_lower(entry->name);
+		break;
+	default:
+		break;
+	}
+
+	smb_finish_dirent(server, entry);
+	return result;
 }
 
 int
 smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos,
-                      int cache_size, struct smb_dirent *entry)
+		      int cache_size, struct smb_dirent *cache)
 {
-        int max_matches = 64; /* this should actually be based on the 
-				 maxxmit */
-  
-        /* NT uses 260, OS/2 uses 2. Both accept 1. */
-        int info_level = 1;
+	/* NT uses 260, OS/2 uses 2. Both accept 1. */
+	const int info_level = 1;
+	const int max_matches = 512;
 
 	char *p;
 	char *lastname;
-	int   lastname_len;
+	int lastname_len;
 	int i;
-	int first, total_count;
-        struct smb_dirent *current_entry;
+	int first, entries, entries_seen;
 
-        char *resp_data;
-        char *resp_param;
-        int resp_data_len = 0;
-        int resp_param_len=0;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
 
-        int attribute = aSYSTEM | aHIDDEN | aDIR;
-        int result;
+	__u16 command;
 
-        int ff_resume_key = 0;
-        int ff_searchcount=0;
-        int ff_eos=0;
-        int ff_lastname=0;
-        int ff_dir_handle=0;
-        int loop_count = 0;
+	int result;
 
-	int dirlen = strlen(SMB_FINFO(dir)->path) + 3;
-	char *mask;
+	int ff_resume_key = 0;
+	int ff_searchcount = 0;
+	int ff_eos = 0;
+	int ff_lastname = 0;
+	int ff_dir_handle = 0;
+	int loop_count = 0;
+
+	char param[SMB_MAXPATHLEN + 2 + 12];
+	int mask_len;
+	unsigned char *mask = &(param[12]);
 
-	mask = smb_kmalloc(dirlen, GFP_KERNEL);
-	if (mask == NULL)
-	{
-		printk("smb_proc_readdir_long: Memory allocation failed\n");
-		return -ENOMEM;
-	}
-	strcpy(mask, SMB_FINFO(dir)->path);
-	strcat(mask, "\\*");
+	mask_len = smb_encode_path(server, mask,
+				   SMB_INOP(dir), "*", 1) - mask;
 
- 	DPRINTK("SMB call lreaddir %d @ %d\n", cache_size, fpos);        
-	DPRINTK("          mask = %s\n", mask);
+	mask[mask_len] = 0;
+	mask[mask_len + 1] = 0;
 
-        resp_param = NULL;
-        resp_data  = NULL;
+	DPRINTK("smb_readdir_long cache=%d, fpos=%d, mask=%s\n",
+		cache_size, fpos, mask);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
 
- retry:
+      retry:
 
 	first = 1;
-        total_count = 0;
-        current_entry = entry;
-	
-        while (ff_eos == 0)
-        {
-                int masklen = strlen(mask);
-                unsigned char *outbuf = server->packet;
-                
-                loop_count += 1;
-                if (loop_count > 200)
-                {
-                        printk("smb_proc_readdir_long: "
-                               "Looping in FIND_NEXT??\n");
-                        break;
-                }
-
-                smb_setup_header(server, SMBtrans2, 15,
-                                 5 + 12 + masklen + 1);
-
-                WSET(outbuf,smb_tpscnt,12 + masklen +1);
-                WSET(outbuf,smb_tdscnt,0);
-                WSET(outbuf,smb_mprcnt,10); 
-                WSET(outbuf,smb_mdrcnt,TRANS2_MAX_TRANSFER);
-                WSET(outbuf,smb_msrcnt,0);
-                WSET(outbuf,smb_flags,0); 
-                DSET(outbuf,smb_timeout,0);
-                WSET(outbuf,smb_pscnt,WVAL(outbuf,smb_tpscnt));
-                WSET(outbuf,smb_psoff,((SMB_BUF(outbuf)+3) - outbuf)-4);
-                WSET(outbuf,smb_dscnt,0);
-                WSET(outbuf,smb_dsoff,0);
-                WSET(outbuf,smb_suwcnt,1);
-                WSET(outbuf,smb_setup0,
-                     first == 1 ? TRANSACT2_FINDFIRST : TRANSACT2_FINDNEXT);
-
-                p = SMB_BUF(outbuf);
-                *p++=0;         /* put in a null smb_name */
-                *p++='D'; *p++ = ' '; /* this was added because OS/2 does it */
-
-                if (first != 0)
-                {
-                        WSET(p,0,attribute); /* attribute */
-                        WSET(p,2,max_matches); /* max count */
-                        WSET(p,4,8+4+2); /* resume required + close on end +
-                                            continue */
-                        WSET(p,6,info_level); 
-                        DSET(p,8,0);
-                        p += 12;
-                        strncpy(p, mask, masklen);
-                        p += masklen;
-                        *p++ = 0; *p++ = 0;
-                }
-                else
-                {
-                        DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
-                                ff_dir_handle,ff_resume_key,ff_lastname,mask);
-                        WSET(p,0,ff_dir_handle);
-                        WSET(p,2,max_matches); /* max count */
-                        WSET(p,4,info_level); 
-                        DSET(p,6,ff_resume_key); /* ff_resume_key */
-                        WSET(p,10,8+4+2); /* resume required + close on end +
-                                             continue */
-                        p += 12;
-                        strncpy(p, mask, masklen);
-                        p += masklen;
-                        *p++ = 0; *p++ = 0;
-                }
-
-                result = smb_trans2_request(server,
-                                            &resp_data_len,&resp_param_len,
-                                            &resp_data,&resp_param);
-
-                if (result < 0) {
-                        if (smb_retry(server)) {
-                                goto retry;
-                        }
-                        DPRINTK("smb_proc_readdir_long: "
-                                "got error from trans2_request\n");
-                        break;
-                }
-
-                if (server->rcls != 0)
-                {
-                        result = -EIO;
-                        break;
-                }
-
-                /* parse out some important return info */
-                p = resp_param;
-                if (first != 0)
-                {
-                        ff_dir_handle  = WVAL(p,0);
-                        ff_searchcount = WVAL(p,2);
-                        ff_eos         = WVAL(p,4);
-                        ff_lastname    = WVAL(p,8);
-                }
-                else
-                {
-                        ff_searchcount = WVAL(p,0);
-                        ff_eos         = WVAL(p,2);
-                        ff_lastname    = WVAL(p,6);
-                }
+	entries = 0;
+	entries_seen = 2;
+
+	while (ff_eos == 0)
+	{
+		loop_count += 1;
+		if (loop_count > 200)
+		{
+			printk("smb_proc_readdir_long: "
+			       "Looping in FIND_NEXT??\n");
+			break;
+		}
+		if (first != 0)
+		{
+			command = TRANSACT2_FINDFIRST;
+			WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
+			WSET(param, 2, max_matches);	/* max count */
+			WSET(param, 4, 8 + 4 + 2);	/* resume required +
+							   close on end +
+							   continue */
+			WSET(param, 6, info_level);
+			DSET(param, 8, 0);
+		} else
+		{
+			command = TRANSACT2_FINDNEXT;
+			DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
+			     ff_dir_handle, ff_resume_key, ff_lastname, mask);
+			WSET(param, 0, ff_dir_handle);
+			WSET(param, 2, max_matches);	/* max count */
+			WSET(param, 4, info_level);
+			DSET(param, 6, ff_resume_key);	/* ff_resume_key */
+			WSET(param, 10, 8 + 4 + 2);	/* resume required +
+							   close on end +
+							   continue */
+#ifdef CONFIG_SMB_WIN95
+			/* Windows 95 is not able to deliver answers
+			   to FIND_NEXT fast enough, so sleep 0.2 seconds */
+			current->timeout = jiffies + HZ / 5;
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			current->timeout = 0;
+#endif
+		}
 
-                if (ff_searchcount == 0) 
-                        break;
+		result = smb_trans2_request(server, command,
+					    0, NULL, 12 + mask_len + 2, param,
+					    &resp_data_len, &resp_data,
+					    &resp_param_len, &resp_param);
+
+		if (result < 0)
+		{
+			if (smb_retry(server))
+			{
+				goto retry;
+			}
+			DPRINTK("smb_proc_readdir_long: "
+				"got error from trans2_request\n");
+			break;
+		}
+		if (server->rcls != 0)
+		{
+			result = -EIO;
+			break;
+		}
+		/* parse out some important return info */
+		if (first != 0)
+		{
+			ff_dir_handle = WVAL(resp_param, 0);
+			ff_searchcount = WVAL(resp_param, 2);
+			ff_eos = WVAL(resp_param, 4);
+			ff_lastname = WVAL(resp_param, 8);
+		} else
+		{
+			ff_searchcount = WVAL(resp_param, 0);
+			ff_eos = WVAL(resp_param, 2);
+			ff_lastname = WVAL(resp_param, 6);
+		}
 
-                /* point to the data bytes */
-                p = resp_data;
+		if (ff_searchcount == 0)
+		{
+			break;
+		}
+		/* point to the data bytes */
+		p = resp_data;
 
-                /* we might need the lastname for continuations */
+		/* we might need the lastname for continuations */
 		lastname = "";
 		lastname_len = 0;
-                if (ff_lastname > 0)
-                {
-                        switch(info_level)
-                        {
-                        case 260:
+		if (ff_lastname > 0)
+		{
+			switch (info_level)
+			{
+			case 260:
 				lastname = p + ff_lastname;
 				lastname_len = resp_data_len - ff_lastname;
 				ff_resume_key = 0;
-                                break;
-                        case 1:
+				break;
+			case 1:
 				lastname = p + ff_lastname + 1;
-				lastname_len = strlen(lastname);
-                                ff_resume_key = 0;
-                                break;
-                        }
-                }
-  
-		/* Increase size of mask, if it is too small */
-		i = strlen(lastname) + 1;
-		if (i > dirlen)
-		{
-			smb_kfree_s(mask,  0);
-			dirlen = i;
-			mask = smb_kmalloc(dirlen, GFP_KERNEL);
-			if (mask == NULL)
-			{
-				printk("smb_proc_readdir_long: "
-				       "Memory allocation failed\n");
-				result = -ENOMEM;
+				lastname_len = BVAL(p, ff_lastname);
+				ff_resume_key = 0;
 				break;
 			}
 		}
+		lastname_len = min(lastname_len, 256);
 		strncpy(mask, lastname, lastname_len);
 		mask[lastname_len] = '\0';
-  
+
 		/* Now we are ready to parse smb directory entries. */
-		
-		for (i = 0; i < ff_searchcount; i ++) {
-			if (total_count < fpos) {
-				p = smb_decode_long_dirent(p, NULL,
-                                                           info_level);
-				DPRINTK("smb_proc_readdir: skipped entry.\n");
-				DDPRINTK("                  total_count = %d\n"
-                                         "                i = %d, fpos = %d\n",
-                                         total_count, i, fpos);
-                        }
-                        else if (total_count >= fpos + cache_size) {
-                                goto finished;
+
+		for (i = 0; i < ff_searchcount; i++)
+		{
+			struct smb_dirent *entry = &(cache[entries]);
+
+			p = smb_decode_long_dirent(server, p,
+						   entry, info_level);
+
+			DDPRINTK("smb_readdir_long: got %s\n", entry->name);
+
+			if ((entry->name[0] == '.')
+			    && ((entry->name[1] == '\0')
+				|| ((entry->name[1] == '.')
+				    && (entry->name[2] == '\0'))))
+			{
+				/* ignore . and .. from the server */
+				continue;
 			}
-			else {
-				p = smb_decode_long_dirent(p, current_entry,
-                                                           info_level);
-				current_entry->f_pos = total_count;
-				DDPRINTK("smb_proc_readdir: entry->f_pos = "
-                                         "%lu\n", entry->f_pos);	
-				current_entry += 1;
+			if (entries_seen >= fpos)
+			{
+				entry->f_pos = entries_seen;
+				entries += 1;
 			}
-			total_count += 1;
+			if (entries >= cache_size)
+			{
+				goto finished;
+			}
+			entries_seen += 1;
 		}
 
-                if (resp_data != NULL) {
-                        smb_kfree_s(resp_data,  0);
-                        resp_data = NULL;
-                }
-                if (resp_param != NULL) {
-                        smb_kfree_s(resp_param, 0);
-                        resp_param = NULL;
-                }
-
-                DPRINTK("received %d entries (eos=%d resume=%d)\n",
-                        ff_searchcount,ff_eos,ff_resume_key);
-
-                first = 0;
-        }
-
- finished:
- 	if (mask != NULL)
-		smb_kfree_s(mask,  0);
-
-        if (resp_data != NULL) {
-                smb_kfree_s(resp_data,  0);
-                resp_data = NULL;
-        }
-        if (resp_param != NULL) {
-                smb_kfree_s(resp_param, 0);
-                resp_param = NULL;
-        }
+		DPRINTK("received %d entries (eos=%d resume=%d)\n",
+			ff_searchcount, ff_eos, ff_resume_key);
 
-        smb_unlock_server(server);
+		first = 0;
+	}
 
-        return total_count - fpos;
+      finished:
+	smb_unlock_server(server);
+	return entries;
 }
 
 int
 smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos,
 		 int cache_size, struct smb_dirent *entry)
 {
-        if (server->protocol >= PROTOCOL_LANMAN2)
-                return smb_proc_readdir_long(server, dir, fpos, cache_size,
-                                             entry);
-        else
-                return smb_proc_readdir_short(server, dir, fpos, cache_size,
-                                              entry);
+	if (server->protocol >= PROTOCOL_LANMAN2)
+		return smb_proc_readdir_long(server, dir, fpos, cache_size,
+					     entry);
+	else
+		return smb_proc_readdir_short(server, dir, fpos, cache_size,
+					      entry);
 }
-		
+
 static int
-smb_proc_getattr_core(struct smb_server *server, const char *path, int len, 
-                      struct smb_dirent *entry)
+smb_proc_getattr_core(struct inode *dir, const char *name, int len,
+		      struct smb_dirent *entry)
 {
 	int result;
 	char *p;
-        char *buf = server->packet;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
-        DDPRINTK("smb_proc_getattr: %s\n", path);
+	DDPRINTK("smb_proc_getattr: %s\n", name);
 
- retry:
-	p = smb_setup_header(server, SMBgetatr, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-	
-	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
-		return result;
-        }
+      retry:
+	p = smb_setup_header(server, SMBgetatr, 0, 0);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
-        entry->attr         = WVAL(buf, smb_vwv0);
-        entry->ctime = entry->atime = /* The server only tells us 1 time */
-                entry->mtime = local2utc(DVAL(buf, smb_vwv1));
+	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
+		return result;
+	}
+	entry->attr = WVAL(buf, smb_vwv0);
+	entry->f_ctime = entry->f_atime =
+	    entry->f_mtime = local2utc(DVAL(buf, smb_vwv1));
 
-        entry->size         = DVAL(buf, smb_vwv3);
-        smb_unlock_server(server);
+	entry->f_size = DVAL(buf, smb_vwv3);
+	smb_unlock_server(server);
 	return 0;
 }
 
-/* smb_proc_getattrE: entry->fid must be valid */
-
 static int
-smb_proc_getattrE(struct smb_server *server, struct smb_dirent *entry)
+smb_proc_getattr_trans2(struct inode *dir, const char *name, int len,
+			struct smb_dirent *entry)
 {
-        char* buf = server->packet;
-        int result;
+	struct smb_server *server = SMB_SERVER(dir);
+	char param[SMB_MAXPATHLEN + 20];
+	char *p;
+	int result;
 
-        smb_setup_header_exclusive(server, SMBgetattrE, 1, 0);
-        WSET(buf, smb_vwv0, entry->fileid);
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+
+	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
+	DSET(param, 2, 0);
+	p = smb_encode_path(server, param + 6, SMB_INOP(dir), name, len);
 
-        if ((result = smb_request_ok(server, SMBgetattrE, 11, 0)) != 0) {
-                smb_unlock_server(server);
-                return result;
-        }
-
-        entry->ctime = date_dos2unix(WVAL(buf, smb_vwv1), WVAL(buf, smb_vwv0));
-        entry->atime = date_dos2unix(WVAL(buf, smb_vwv3), WVAL(buf, smb_vwv2));
-        entry->mtime = date_dos2unix(WVAL(buf, smb_vwv5), WVAL(buf, smb_vwv4));
-        entry->size  = DVAL(buf, smb_vwv6);
-        entry->attr  = WVAL(buf, smb_vwv10);
+	smb_lock_server(server);
+      retry:
+	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
+				    0, NULL, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
 
-        smb_unlock_server(server);
-        return 0;
+	if (server->rcls != 0)
+	{
+		smb_unlock_server(server);
+		return -smb_errno(server->rcls, server->err);
+	}
+	if (result < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
+		return result;
+	}
+	if (resp_data_len < 22)
+	{
+		smb_unlock_server(server);
+		return -ENOENT;
+	}
+	entry->f_ctime = date_dos2unix(WVAL(resp_data, 2),
+				       WVAL(resp_data, 0));
+	entry->f_atime = date_dos2unix(WVAL(resp_data, 6),
+				       WVAL(resp_data, 4));
+	entry->f_mtime = date_dos2unix(WVAL(resp_data, 10),
+				       WVAL(resp_data, 8));
+	entry->f_size = DVAL(resp_data, 12);
+	entry->attr = WVAL(resp_data, 20);
+	smb_unlock_server(server);
+
+	return 0;
 }
 
 int
-smb_proc_getattr(struct smb_server *server, const char *path, int len, 
-                 struct smb_dirent *entry)
+smb_proc_getattr(struct inode *dir, const char *name, int len,
+		 struct smb_dirent *entry)
 {
-        if (server->protocol >= PROTOCOL_LANMAN1) {
+	struct smb_server *server = SMB_SERVER(dir);
+	int result = 0;
 
-                int result = 0;
-                struct smb_dirent temp_entry;
+	smb_init_dirent(server, entry);
 
-		memset(&temp_entry, 0, sizeof(temp_entry));
-
-                if ((result=smb_proc_open(server,path,len,
-                                          &temp_entry)) < 0) {
-                        /* We cannot open directories, so we try to use the
-                           core variant */
-                        return smb_proc_getattr_core(server,path,len,entry);
-                }
-
-                if ((result=smb_proc_getattrE(server, &temp_entry)) >= 0) {
-                        entry->attr  = temp_entry.attr;
-                        entry->atime = temp_entry.atime;
-                        entry->mtime = temp_entry.mtime;
-                        entry->ctime = temp_entry.ctime;
-                        entry->size  = temp_entry.size;
-                }
-
-                smb_proc_close(server, temp_entry.fileid, temp_entry.mtime);
-                return result;
-
-        } else {
-                return smb_proc_getattr_core(server, path, len, entry);
-        }
+	if (server->protocol >= PROTOCOL_LANMAN2)
+	{
+		result = smb_proc_getattr_trans2(dir, name, len, entry);
+	}
+	if ((server->protocol < PROTOCOL_LANMAN2) || (result < 0))
+	{
+		result = smb_proc_getattr_core(dir, name, len, entry);
+	}
+	smb_finish_dirent(server, entry);
+
+	entry->len = len;
+	memcpy(entry->name, name, len);
+	/* entry->name is null terminated from smb_init_dirent */
+
+	return result;
 }
 
 
 /* In core protocol, there is only 1 time to be set, we use
-   entry->mtime, to make touch work. */
+   entry->f_mtime, to make touch work. */
 static int
 smb_proc_setattr_core(struct smb_server *server,
-                      const char *path, int len,
-                      struct smb_dirent *new_finfo)
+		      struct inode *i, struct smb_dirent *new_finfo)
 {
-        char *p;
-        char *buf = server->packet;
-        int result;
-
-        smb_lock_server(server);
-
- retry:
-        p = smb_setup_header(server, SMBsetatr, 8, 4 + len);
-        WSET(buf, smb_vwv0, new_finfo->attr);
-        DSET(buf, smb_vwv1, utc2local(new_finfo->mtime));
-        p = smb_encode_ascii(p, path, len);
-        p = smb_encode_ascii(p, "", 0);
-
-        if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	char *p;
+	char *buf;
+	int result;
+
+	smb_lock_server(server);
+	buf = server->packet;
+
+      retry:
+	p = smb_setup_header(server, SMBsetatr, 8, 0);
+	WSET(buf, smb_vwv0, new_finfo->attr);
+	DSET(buf, smb_vwv1, utc2local(new_finfo->f_mtime));
+	*p++ = 4;
+	p = smb_encode_path(server, p,
+			    SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
+			    SMB_INOP(i)->finfo.len);
+	p = smb_encode_ascii(p, "", 0);
+
+	smb_setup_bcc(server, p);
+	if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
-/* smb_proc_setattrE: we do not retry here, because we rely on fid,
-   which would not be valid after a retry. */
 static int
-smb_proc_setattrE(struct smb_server *server, word fid,
-                  struct smb_dirent *new_entry)
+smb_proc_setattr_trans2(struct smb_server *server,
+			struct inode *i, struct smb_dirent *new_finfo)
 {
-        char *buf = server->packet;
-        word date, time;
-
-        smb_setup_header_exclusive(server, SMBsetattrE, 7, 0);
+	char param[SMB_MAXPATHLEN + 20];
+	char data[26];
+	char *p;
+	int result;
 
-        WSET(buf, smb_vwv0, fid);
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+
+	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
+	DSET(param, 2, 0);
+	p = smb_encode_path(server, param + 6,
+			    SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
+			    SMB_INOP(i)->finfo.len);
+
+	date_unix2dos(new_finfo->f_ctime, &(data[0]), &(data[2]));
+	date_unix2dos(new_finfo->f_atime, &(data[4]), &(data[6]));
+	date_unix2dos(new_finfo->f_mtime, &(data[8]), &(data[10]));
+	DSET(data, 12, new_finfo->f_size);
+	DSET(data, 16, new_finfo->f_blksize);
+	WSET(data, 20, new_finfo->attr);
+	WSET(data, 22, 0);
 
-        date_unix2dos(new_entry->ctime, &time, &date);
-        WSET(buf, smb_vwv1, date);
-        WSET(buf, smb_vwv2, time);
-        
-        date_unix2dos(new_entry->atime, &time, &date);
-        WSET(buf, smb_vwv3, date);
-        WSET(buf, smb_vwv4, time);
-        
-        date_unix2dos(new_entry->mtime, &time, &date);
-        WSET(buf, smb_vwv5, date);
-        WSET(buf, smb_vwv6, time);
+	smb_lock_server(server);
+      retry:
+	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
+				    26, data, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
 
-        return smb_request_ok_unlock(server, SMBsetattrE, 0, 0);
+	if (server->rcls != 0)
+	{
+		smb_unlock_server(server);
+		return -smb_errno(server->rcls, server->err);
+	}
+	if (result < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return 0;
 }
 
-/* smb_proc_setattr: for protocol >= LANMAN1 we expect the file to be
-   opened for writing. */
 int
 smb_proc_setattr(struct smb_server *server, struct inode *inode,
-                 struct smb_dirent *new_finfo)
+		 struct smb_dirent *new_finfo)
 {
-        struct smb_dirent *finfo = SMB_FINFO(inode);
-        int result;
+	int result;
 
-        if (server->protocol >= PROTOCOL_LANMAN1) {
-                if ((result = smb_make_open(inode, O_RDWR)) < 0)
-                        return result;
-                return smb_proc_setattrE(server, finfo->fileid, new_finfo);
-        } else {
-                return smb_proc_setattr_core(server, finfo->path, finfo->len,
-                                             new_finfo);
-        }
+	if (server->protocol >= PROTOCOL_LANMAN2)
+	{
+		result = smb_proc_setattr_trans2(server, inode, new_finfo);
+	}
+	if ((server->protocol < PROTOCOL_LANMAN2) || (result < 0))
+	{
+		result = smb_proc_setattr_core(server, inode, new_finfo);
+	}
+	return result;
 }
 
 int
@@ -1587,25 +1610,26 @@
 	char *p;
 	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);
-	
-	if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
+
+	if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
 		return error;
-        }
-	
+	}
 	p = SMB_VWV(server->packet);
 	p = smb_decode_word(p, &attr->total);
 	p = smb_decode_word(p, &attr->allocblocks);
 	p = smb_decode_word(p, &attr->blocksize);
 	p = smb_decode_word(p, &attr->free);
-        smb_unlock_server(server);
+	smb_unlock_server(server);
 	return 0;
 }
 
@@ -1615,7 +1639,8 @@
 /*                                                                           */
 /*****************************************************************************/
 
-struct smb_prots {
+struct smb_prots
+{
 	enum smb_protocol prot;
 	const char *name;
 };
@@ -1629,50 +1654,50 @@
 smb_proc_reconnect(struct smb_server *server)
 {
 	struct smb_prots prots[] =
-        { { PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
-          { PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
+	{
+		{PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
+		{PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
 #ifdef LANMAN1
-          { PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
-          { PROTOCOL_LANMAN1,"LANMAN1.0"},
+		{PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
+		{PROTOCOL_LANMAN1, "LANMAN1.0"},
 #endif
-#ifdef CONFIG_SMB_LONG
 #ifdef LANMAN2
-          { PROTOCOL_LANMAN2,"LM1.2X002"},
+		{PROTOCOL_LANMAN2, "LM1.2X002"},
 #endif
 #ifdef NT1
-	  { PROTOCOL_NT1,"NT LM 0.12"},
-	  { PROTOCOL_NT1,"NT LANMAN 1.0"},
-#endif
+		{PROTOCOL_NT1, "NT LM 0.12"},
+		{PROTOCOL_NT1, "NT LANMAN 1.0"},
 #endif
-          {-1, NULL} };
+		{-1, NULL}};
 	char dev[] = "A:";
 	int i, plength;
 	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;
 	byte *p;
 
-        if ((result = smb_connect(server)) < 0) {
-                DPRINTK("smb_proc_reconnect: could not smb_connect\n");
-                goto fail;
-        }
-
-        /* Here we assume that the connection is valid */
-        server->state = CONN_VALID;
-
-        if (server->packet != NULL) {
-                smb_kfree_s(server->packet, server->max_xmit);
-        }
-        
-	server->packet = smb_kmalloc(max_xmit, GFP_KERNEL);
+	if ((result = smb_connect(server)) < 0)
+	{
+		DPRINTK("smb_proc_reconnect: could not smb_connect\n");
+		goto fail;
+	}
+	/* Here we assume that the connection is valid */
+	server->state = CONN_VALID;
 
-	if (server->packet == NULL) {
-		printk("smb_proc_connect: No memory! Bailing out.\n");
-                result = -ENOMEM;
-                goto fail;
+	if (server->packet != NULL)
+	{
+		smb_vfree(server->packet);
+		server->packet_size = 0;
 	}
+	server->packet = smb_vmalloc(max_xmit);
 
-        server->max_xmit = max_xmit;
+	if (server->packet == NULL)
+	{
+		printk("smb_proc_connect: No memory! Bailing out.\n");
+		result = -ENOMEM;
+		goto fail;
+	}
+	server->packet_size = server->max_xmit = max_xmit;
 
 	/*
 	 * Start with an RFC1002 session request packet.
@@ -1681,98 +1706,110 @@
 
 	p = smb_name_mangle(p, server->m.server_name);
 	p = smb_name_mangle(p, server->m.client_name);
-	
+
 	smb_encode_smb_length(server->packet,
-                              (void *)p - (void *)(server->packet));
-	
-	server->packet[0] = 0x81; /* SESSION REQUEST */
-
-        if (smb_catch_keepalive(server) < 0) {
-                printk("smb_proc_connect: could not catch_keepalives\n");
-        }
-        
-	if ((result = smb_request(server)) < 0) {
-		printk("smb_proc_connect: Failed to send SESSION REQUEST.\n");
-                smb_dont_catch_keepalive(server);
-                goto fail;
+			      (void *) p - (void *) (server->packet));
+
+	server->packet[0] = 0x81;	/* SESSION REQUEST */
+
+	if (smb_catch_keepalive(server) < 0)
+	{
+		printk("smb_proc_connect: could not catch_keepalives\n");
 	}
-	
-	if (server->packet[0] != 0x82) {
+	if ((result = smb_request(server)) < 0)
+	{
+		DPRINTK("smb_proc_connect: Failed to send SESSION REQUEST.\n");
+		smb_dont_catch_keepalive(server);
+		goto fail;
+	}
+	if (server->packet[0] != 0x82)
+	{
 		printk("smb_proc_connect: Did not receive positive response "
-                       "(err = %x)\n", 
+		       "(err = %x)\n",
 		       server->packet[0]);
-                smb_dont_catch_keepalive(server);
-#if DEBUG_SMB > 0
-                smb_dump_packet(server->packet);
-#endif
-                result = -EIO;
-                goto fail;
+		smb_dont_catch_keepalive(server);
+		result = -EIO;
+		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. */
 	memset(server->packet, 0, SMB_HEADER_LEN);
 
 	plength = 0;
-	for (i = 0; prots[i].name != NULL; i++) {
+	for (i = 0; prots[i].name != NULL; i++)
+	{
 		plength += strlen(prots[i].name) + 2;
-        }
+	}
 
 	smb_setup_header(server, SMBnegprot, 0, plength);
 
 	p = SMB_BUF(server->packet);
-	
-	for (i = 0; prots[i].name != NULL; i++) {
-		p = smb_encode_dialect(p,prots[i].name, strlen(prots[i].name));
-        }
-	
-	if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0) {
-         	printk("smb_proc_connect: Failure requesting SMBnegprot\n");
-                smb_dont_catch_keepalive(server);
-                goto fail;
-	} else {
-                DDPRINTK("smb_proc_connect: Request SMBnegprot..");
-        }
-
-        DDPRINTK("Verified!\n");
-
-        p = SMB_VWV(server->packet);
-	p = smb_decode_word(p, (word *)&i);
-        server->protocol = prots[i].prot;
+
+	for (i = 0; prots[i].name != NULL; i++)
+	{
+		*p++ = 2;
+		strcpy(p, prots[i].name);
+		p += strlen(prots[i].name) + 1;
+	}
+
+	if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0)
+	{
+		DPRINTK("smb_proc_connect: Failure requesting SMBnegprot\n");
+		smb_dont_catch_keepalive(server);
+		goto fail;
+	} else
+	{
+		DDPRINTK("smb_proc_connect: Request SMBnegprot..");
+	}
+
+	DDPRINTK("Verified!\n");
+
+	p = SMB_VWV(server->packet);
+	p = smb_decode_word(p, (word *) & i);
+	server->protocol = prots[i].prot;
 
 	DPRINTK("smb_proc_connect: Server wants %s protocol.\n",
-                prots[i].name);
+		prots[i].name);
+
+	if (server->protocol >= PROTOCOL_LANMAN1)
+	{
+
+		word passlen = strlen(server->m.password);
+		word userlen = strlen(server->m.username);
 
-        if (server->protocol >= PROTOCOL_LANMAN1) {
+		DPRINTK("smb_proc_connect: password = %s\n",
+			server->m.password);
+		DPRINTK("smb_proc_connect: usernam = %s\n",
+			server->m.username);
+		DPRINTK("smb_proc_connect: blkmode = %d\n",
+			WVAL(server->packet, smb_vwv5));
 
-                word passlen = strlen(server->m.password);
-                word userlen = strlen(server->m.username);
-                
-                DPRINTK("smb_proc_connect: password = %s\n",
-                        server->m.password);
-                DPRINTK("smb_proc_connect: usernam = %s\n",
-                        server->m.username);
-                DPRINTK("smb_proc_connect: blkmode = %d\n",
-                        WVAL(server->packet, smb_vwv5));
-
-		if (server->protocol >= PROTOCOL_NT1) {
-			server->maxxmt = DVAL(server->packet,smb_vwv3+1);
-			server->maxmux = WVAL(server->packet, smb_vwv1+1);
-			server->maxvcs = WVAL(server->packet, smb_vwv2+1);
-			server->blkmode= DVAL(server->packet, smb_vwv9+1);
-			server->sesskey= DVAL(server->packet, smb_vwv7+1);
-		} else {
-			server->maxxmt = WVAL(server->packet, smb_vwv2);
+		if (server->protocol >= PROTOCOL_NT1)
+		{
+			server->max_xmit = DVAL(server->packet, smb_vwv3 + 1);
+			server->maxmux = WVAL(server->packet, smb_vwv1 + 1);
+			server->maxvcs = WVAL(server->packet, smb_vwv2 + 1);
+			server->blkmode = DVAL(server->packet, smb_vwv9 + 1);
+			server->sesskey = DVAL(server->packet, smb_vwv7 + 1);
+		} else
+		{
+			server->max_xmit = WVAL(server->packet, smb_vwv2);
 			server->maxmux = WVAL(server->packet, smb_vwv3);
 			server->maxvcs = WVAL(server->packet, smb_vwv4);
-			server->blkmode= WVAL(server->packet, smb_vwv5);
-			server->sesskey= DVAL(server->packet, smb_vwv6);
+			server->blkmode = WVAL(server->packet, smb_vwv5);
+			server->sesskey = DVAL(server->packet, smb_vwv6);
 		}
 
-
-		if (server->protocol >= PROTOCOL_NT1) {
-			char *workgroup = "WORKGROUP";
+		if (server->max_xmit < given_max_xmit)
+		{
+			/* We do not distinguish between the client
+			   requests and the server response. */
+			given_max_xmit = server->max_xmit;
+		}
+		if (server->protocol >= PROTOCOL_NT1)
+		{
+			char *workgroup = server->m.domain;
 			char *OS_id = "Unix";
 			char *client_id = "ksmbfs";
 
@@ -1780,7 +1817,7 @@
 					 5 + userlen + passlen +
 					 strlen(workgroup) + strlen(OS_id) +
 					 strlen(client_id));
-			
+
 			WSET(server->packet, smb_vwv0, 0x00ff);
 			WSET(server->packet, smb_vwv1, 0);
 			WSET(server->packet, smb_vwv2, given_max_xmit);
@@ -1801,7 +1838,8 @@
 			strcpy(p, OS_id);
 			p += strlen(p) + 1;
 			strcpy(p, client_id);
-		} else {
+		} else
+		{
 			smb_setup_header(server, SMBsesssetupX, 10,
 					 2 + userlen + passlen);
 
@@ -1821,47 +1859,59 @@
 			strcpy(p, server->m.username);
 		}
 
-                if ((result = smb_request_ok(server,SMBsesssetupX,3,0)) < 0) {
-                        DPRINTK("smb_proc_connect: SMBsessetupX failed\n");
-                        smb_dont_catch_keepalive(server);
-                        goto fail;
-                }
-                smb_decode_word(server->packet+32, &(server->server_uid));
-        }
-        else
-        {
-                server->maxxmt = 0;
-                server->maxmux = 0;
-                server->maxvcs = 0;
-                server->blkmode = 0;
-                server->sesskey = 0;
-        }
+		if ((result = smb_request_ok(server, SMBsesssetupX, 3, 0)) < 0)
+		{
+			DPRINTK("smb_proc_connect: SMBsessetupX failed\n");
+			smb_dont_catch_keepalive(server);
+			goto fail;
+		}
+		smb_decode_word(server->packet + 32, &(server->server_uid));
+	} else
+	{
+		server->max_xmit = 0;
+		server->maxmux = 0;
+		server->maxvcs = 0;
+		server->blkmode = 0;
+		server->sesskey = 0;
+	}
 
 	/* Fine! We have a connection, send a tcon message. */
 
 	smb_setup_header(server, SMBtcon, 0,
-                         6 + strlen(server->m.service) +
-                         strlen(server->m.password) + strlen(dev));
+			 6 + strlen(server->m.service) +
+			 strlen(server->m.password) + strlen(dev));
 
 	p = SMB_BUF(server->packet);
 	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));
 
-	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");
-                smb_dont_catch_keepalive(server);
-                goto fail;
+		smb_dont_catch_keepalive(server);
+		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_decode_word(p, &server->max_xmit);
 
-        if (server->max_xmit > given_max_xmit)
-                server->max_xmit = given_max_xmit;
-        
+	if (server->protocol <= PROTOCOL_COREPLUS)
+	{
+		word max_xmit;
+
+		p = smb_decode_word(p, &max_xmit);
+		server->max_xmit = max_xmit;
+
+		if (server->max_xmit > given_max_xmit)
+		{
+			server->max_xmit = given_max_xmit;
+		}
+	} else
+	{
+		p += 2;
+	}
+
 	p = smb_decode_word(p, &server->tid);
 
 	/* Ok, everything is fine. max_xmit does not include */
@@ -1871,22 +1921,24 @@
 	DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid);
 
 	/* Now make a new packet with the correct size. */
-	smb_kfree_s(server->packet, max_xmit); 
+	smb_vfree(server->packet);
 
-	server->packet = smb_kmalloc(server->max_xmit, GFP_KERNEL);
-	if (server->packet == NULL) {
+	server->packet = smb_vmalloc(server->max_xmit);
+	if (server->packet == NULL)
+	{
 		printk("smb_proc_connect: No memory left in end of "
-                       "connection phase :-(\n");
-                smb_dont_catch_keepalive(server);
-                goto fail;
+		       "connection phase :-(\n");
+		smb_dont_catch_keepalive(server);
+		goto fail;
 	}
+	server->packet_size = server->max_xmit;
 
-        DPRINTK("smb_proc_connect: Normal exit\n");
-        return 0;
+	DPRINTK("smb_proc_connect: Normal exit\n");
+	return 0;
 
- fail:
-        server->state = CONN_INVALID;
-        return result;
+      fail:
+	server->state = CONN_INVALID;
+	return result;
 }
 
 /* smb_proc_reconnect: server->packet is allocated with
@@ -1894,172 +1946,23 @@
 int
 smb_proc_connect(struct smb_server *server)
 {
-        int result;
-        smb_lock_server(server);
-
-        result = smb_proc_reconnect(server);
+	int result;
+	smb_lock_server(server);
 
-        if ((result < 0) && (server->packet != NULL)) {
-                smb_kfree_s(server->packet, server->max_xmit);
-                server->packet = NULL;
-        }
+	result = smb_proc_reconnect(server);
 
-        smb_unlock_server(server);
-        return result;
+	if ((result < 0) && (server->packet != NULL))
+	{
+		smb_vfree(server->packet);
+		server->packet = NULL;
+	}
+	smb_unlock_server(server);
+	return result;
 }
-	
+
 int
 smb_proc_disconnect(struct smb_server *server)
 {
 	smb_setup_header_exclusive(server, SMBtdis, 0, 0);
 	return smb_request_ok_unlock(server, SMBtdis, 0, 0);
 }
-
-/* error code stuff - put together by Merik Karman
-   merik@blackadder.dsh.oz.au */
-
-#if DEBUG_SMB > 0
-
-typedef struct {
-	char *name;
-	int code;
-	char *message;
-} err_code_struct;
-
-/* Dos Error Messages */
-err_code_struct dos_msgs[] = {
-  { "ERRbadfunc",1,"Invalid function."},
-  { "ERRbadfile",2,"File not found."},
-  { "ERRbadpath",3,"Directory invalid."},
-  { "ERRnofids",4,"No file descriptors available"},
-  { "ERRnoaccess",5,"Access denied."},
-  { "ERRbadfid",6,"Invalid file handle."},
-  { "ERRbadmcb",7,"Memory control blocks destroyed."},
-  { "ERRnomem",8,"Insufficient server memory to perform the requested function."},
-  { "ERRbadmem",9,"Invalid memory block address."},
-  { "ERRbadenv",10,"Invalid environment."},
-  { "ERRbadformat",11,"Invalid format."},
-  { "ERRbadaccess",12,"Invalid open mode."},
-  { "ERRbaddata",13,"Invalid data."},
-  { "ERR",14,"reserved."},
-  { "ERRbaddrive",15,"Invalid drive specified."},
-  { "ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
-  { "ERRdiffdevice",17,"Not same device."},
-  { "ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
-  { "ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
-  { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an  invalid mode,  or an Unlock requested attempted to remove a lock held by another process."},
-  { "ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
-  { "ERRbadpipe",230,"Pipe invalid."},
-  { "ERRpipebusy",231,"All instances of the requested pipe are busy."},
-  { "ERRpipeclosing",232,"Pipe close in progress."},
-  { "ERRnotconnected",233,"No process on other end of pipe."},
-  { "ERRmoredata",234,"There is more data to be returned."},
-  { NULL,-1,NULL}};
-
-/* Server Error Messages */
-err_code_struct server_msgs[] = { 
-  { "ERRerror",1,"Non-specific error code."},
-  { "ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
-  { "ERRbadtype",3,"reserved."},
-  { "ERRaccess",4,"The requester does not have  the  necessary  access  rights  within  the specified  context for the requested function. The context is defined by the TID or the UID."},
-  { "ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
-  { "ERRinvnetname",6,"Invalid network name in tree connect."},
-  { "ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
-  { "ERRqfull",49,"Print queue full (files) -- returned by open print file."},
-  { "ERRqtoobig",50,"Print queue full -- no space."},
-  { "ERRqeof",51,"EOF on print queue dump."},
-  { "ERRinvpfid",52,"Invalid print file FID."},
-  { "ERRsmbcmd",64,"The server did not recognize the command received."},
-  { "ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
-  { "ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
-  { "ERRreserved",68,"reserved."},
-  { "ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
-  { "ERRreserved",70,"reserved."},
-  { "ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
-  { "ERRpaused",81,"Server is paused."},
-  { "ERRmsgoff",82,"Not receiving messages."},
-  { "ERRnoroom",83,"No room to buffer message."},
-  { "ERRrmuns",87,"Too many remote user names."},
-  { "ERRtimeout",88,"Operation timed out."},
-  { "ERRnoresource",89,"No resources currently available for request."},
-  { "ERRtoomanyuids",90,"Too many UIDs active on this session."},
-  { "ERRbaduid",91,"The UID is not known as a valid ID on this session."},
-  { "ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
-  { "ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
-  { "ERRcontmpx",252,"Continue in MPX mode."},
-  { "ERRreserved",253,"reserved."},
-  { "ERRreserved",254,"reserved."},
-  { "ERRnosupport",0xFFFF,"Function not supported."},
-  { NULL,-1,NULL}};
-
-/* Hard Error Messages */
-err_code_struct hard_msgs[] = { 
-  { "ERRnowrite",19,"Attempt to write on write-protected diskette."},
-  { "ERRbadunit",20,"Unknown unit."},
-  { "ERRnotready",21,"Drive not ready."},
-  { "ERRbadcmd",22,"Unknown command."},
-  { "ERRdata",23,"Data error (CRC)."},
-  { "ERRbadreq",24,"Bad request structure length."},
-  { "ERRseek",25 ,"Seek error."},
-  { "ERRbadmedia",26,"Unknown media type."},
-  { "ERRbadsector",27,"Sector not found."},
-  { "ERRnopaper",28,"Printer out of paper."},
-  { "ERRwrite",29,"Write fault."},
-  { "ERRread",30,"Read fault."},
-  { "ERRgeneral",31,"General failure."},
-  { "ERRbadshare",32,"A open conflicts with an existing open."},
-  { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
-  { "ERRwrongdisk",34,"The wrong disk was found in a drive."},
-  { "ERRFCBUnavail",35,"No FCBs are available to process request."},
-  { "ERRsharebufexc",36,"A sharing buffer has been exceeded."},
-  { NULL,-1,NULL}
-};
-
-
-struct { 
-	int code;
-	char *class;
-	err_code_struct *err_msgs;
-} err_classes[] = {  
-  { 0,"SUCCESS",NULL},
-  { 0x01,"ERRDOS",dos_msgs},
-  { 0x02,"ERRSRV",server_msgs},
-  { 0x03,"ERRHRD",hard_msgs},
-  { 0x04,"ERRXOS",NULL},
-  { 0xE1,"ERRRMX1",NULL},
-  { 0xE2,"ERRRMX2",NULL},
-  { 0xE3,"ERRRMX3",NULL},
-  { 0xFF,"ERRCMD",NULL},
-  { -1,NULL,NULL}
-};
-
-void
-smb_printerr(int class, int num)
-{
-	int i,j;
-	err_code_struct *err;
-
-	for (i=0; err_classes[i].class; i++) {
-		if (err_classes[i].code != class)
-			continue;
-		if (!err_classes[i].err_msgs) {
-			printk("%s - %d", err_classes[i].class, num);
-			return;
-		}
-
-		err = err_classes[i].err_msgs;
-		for (j=0; err[j].name; j++) {
-			if (num != err[j].code)
-				continue;
-			printk("%s - %s (%s)",
-			       err_classes[i].class, err[j].name,
-                               err[j].message);
-			return;
-		}
-	}
-	
-	printk("Unknown error - (%d,%d)", class, num);
-	return;
-}
-
-#endif /* DEBUG_SMB > 0 */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov