root/fs/smbfs/proc.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smb_encode_word
  2. smb_decode_word
  3. smb_decode_dword
  4. smb_encode_smb_length
  5. smb_encode_dialect
  6. smb_encode_ascii
  7. smb_encode_vblock
  8. smb_decode_data
  9. smb_name_mangle
  10. utc2local
  11. local2utc
  12. date_dos2unix
  13. date_unix2dos
  14. smb_len
  15. smb_bcc
  16. smb_valid_packet
  17. smb_verify
  18. smb_errno
  19. print_char
  20. smb_dump_packet
  21. smb_lock_server
  22. smb_unlock_server
  23. smb_request_ok
  24. smb_retry
  25. smb_request_ok_unlock
  26. smb_setup_header
  27. smb_setup_header_exclusive
  28. smb_proc_open
  29. smb_proc_close
  30. smb_proc_read
  31. smb_proc_write
  32. smb_proc_do_create
  33. smb_proc_create
  34. smb_proc_mknew
  35. smb_proc_mv
  36. smb_proc_mkdir
  37. smb_proc_rmdir
  38. smb_proc_unlink
  39. smb_proc_trunc
  40. smb_decode_dirent
  41. smb_proc_readdir_short
  42. smb_decode_long_dirent
  43. smb_proc_readdir_long
  44. smb_proc_readdir
  45. smb_proc_getattr_core
  46. smb_proc_getattrE
  47. smb_proc_getattr
  48. smb_proc_setattr_core
  49. smb_proc_setattrE
  50. smb_proc_setattr
  51. smb_proc_dskattr
  52. smb_proc_reconnect
  53. smb_proc_connect
  54. smb_proc_disconnect
  55. smb_printerr

   1 /*
   2  *  proc.c
   3  *
   4  *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
   5  *
   6  */
   7 
   8 #include <linux/config.h>
   9 #ifdef MODULE
  10 #include <linux/module.h>
  11 #include <linux/version.h>
  12 #endif
  13 
  14 
  15 #include <linux/fs.h>
  16 #include <linux/smbno.h>
  17 #include <linux/smb_fs.h>
  18 #include <linux/types.h>
  19 #include <linux/errno.h>
  20 #include <linux/malloc.h>
  21 #include <linux/stat.h>
  22 #include <linux/fcntl.h>
  23 #include <asm/segment.h>
  24 #include <asm/string.h>
  25 
  26 #define ARCH i386
  27 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
  28 #define SMB_CMD(packet)  ((packet)[8])
  29 #define SMB_WCT(packet)  ((packet)[SMB_HEADER_LEN - 1])
  30 #define SMB_BCC(packet)  smb_bcc(packet)
  31 #define SMB_BUF(packet)  ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
  32 
  33 #define SMB_DIRINFO_SIZE 43
  34 #define SMB_STATUS_SIZE  21
  35 
  36 #define HI_WORD(l) ((word)(l >> 16))
  37 #define LO_WORD(l) ((word)(l % 0xFFFF))
  38 
  39 void smb_printerr(int class, int num);
  40 static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
  41 
  42 /*****************************************************************************/
  43 /*                                                                           */
  44 /*  Encoding/Decoding section                                                */
  45 /*                                                                           */
  46 /*****************************************************************************/
  47 
  48 static byte *
  49 smb_encode_word(byte *p, word data)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51 #if (ARCH == i386)
  52         *((word *)p) = data;
  53 #else
  54         p[0] = data & 0x00ffU;
  55         p[1] = (data & 0xff00U) >> 8;
  56 #error "Non-Intel"
  57 #endif
  58         return &p[2];
  59 }
  60 
  61 static byte *
  62 smb_decode_word(byte *p, word *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64 #if (ARCH == i386)
  65         *data = *(word *)p;
  66 #else
  67         *data = (word) p[0] | p[1] << 8;
  68 #endif 
  69         return &p[2];
  70 }
  71 
  72 static byte *
  73 smb_decode_dword(byte *p, dword *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75 #if (ARCH == i386)
  76         *data = *((dword *)p);
  77 #else
  78         *data = (dword)p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
  79 #endif
  80         return &p[4];
  81 }
  82 
  83 static byte *
  84 smb_encode_smb_length(byte *p, dword len)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86         p[0] = p[1] = 0;
  87         p[2] = (len & 0xFF00) >> 8;
  88         p[3] = (len & 0xFF);
  89         if (len > 0xFFFF)
  90                 p[1] |= 0x01;
  91         return &p[4];
  92 }
  93 
  94 static byte *
  95 smb_encode_dialect(byte *p, const byte *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         *p ++ = 2;
  98         strcpy(p, name);
  99         return p + len + 1;
 100 }
 101 
 102 static byte *
 103 smb_encode_ascii(byte *p, const byte *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105         *p ++ = 4;
 106         strcpy(p, name);
 107         return p + len + 1;
 108 }
 109 
 110 static byte *
 111 smb_encode_vblock(byte *p, const byte *data, word len, int fs)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113         *p ++ = 5;
 114         p = smb_encode_word(p, len);
 115         if (fs)
 116                 memcpy_fromfs(p, data, len);
 117         else
 118                 memcpy(p, data, len);
 119         return p + len;
 120 }
 121 
 122 static byte *
 123 smb_decode_data(byte *p, byte *data, word *data_len, int fs)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125         word len;
 126 
 127         if (!(*p == 1 || *p == 5)) {
 128                 printk("smb_decode_data: Warning! Data block not starting "
 129                        "with 1 or 5\n");
 130         }
 131 
 132         len = WVAL(p, 1);
 133         p += 3;
 134 
 135         if (fs)
 136                 memcpy_tofs(data, p, len);
 137         else
 138                 memcpy(data, p, len);
 139 
 140         *data_len = len;
 141 
 142         return p + len;
 143 }
 144 
 145 static byte *
 146 smb_name_mangle(byte *p, const byte *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148         int len, pad = 0;
 149 
 150         len = strlen(name);
 151 
 152         if (len < 16)
 153                 pad = 16 - len;
 154 
 155         *p ++ = 2 * (len + pad);
 156 
 157         while (*name) {
 158                 *p ++ = (*name >> 4) + 'A';
 159                 *p ++ = (*name & 0x0F) + 'A';
 160                 name ++;
 161         }
 162         while (pad --) {
 163                 *p ++ = 'C';
 164                 *p ++ = 'A';
 165         }
 166         *p++ = '\0';
 167         
 168         return p;
 169 }
 170 
 171 /* The following are taken directly from msdos-fs */
 172 
 173 /* Linear day numbers of the respective 1sts in non-leap years. */
 174 
 175 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
 176                   /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
 177 
 178 
 179 extern struct timezone sys_tz;
 180 
 181 static int
 182 utc2local(int time)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184         return time - sys_tz.tz_minuteswest*60;
 185 }
 186 
 187 static int
 188 local2utc(int time)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190         return time + sys_tz.tz_minuteswest*60;
 191 }
 192 
 193 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
 194 
 195 static int
 196 date_dos2unix(unsigned short time,unsigned short date)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198         int month,year,secs;
 199 
 200         month = ((date >> 5) & 15)-1;
 201         year = date >> 9;
 202         secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
 203             ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
 204             month < 2 ? 1 : 0)+3653);
 205                         /* days since 1.1.70 plus 80's leap day */
 206         return local2utc(secs);
 207 }
 208 
 209 
 210 /* Convert linear UNIX date to a MS-DOS time/date pair. */
 211 
 212 static void
 213 date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215         int day,year,nl_day,month;
 216 
 217         unix_date = utc2local(unix_date);
 218         *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
 219             (((unix_date/3600) % 24) << 11);
 220         day = unix_date/86400-3652;
 221         year = day/365;
 222         if ((year+3)/4+365*year > day) year--;
 223         day -= (year+3)/4+365*year;
 224         if (day == 59 && !(year & 3)) {
 225                 nl_day = day;
 226                 month = 2;
 227         }
 228         else {
 229                 nl_day = (year & 3) || day <= 59 ? day : day-1;
 230                 for (month = 0; month < 12; month++)
 231                         if (day_n[month] > nl_day) break;
 232         }
 233         *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
 234 }
 235 
 236 
 237 
 238 /*****************************************************************************/
 239 /*                                                                           */
 240 /*  Support section.                                                         */
 241 /*                                                                           */
 242 /*****************************************************************************/
 243 
 244 dword
 245 smb_len(byte *packet) 
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247         return ((packet[1] & 0x1) << 16L) | (packet[2] << 8L) | (packet[3]);
 248 }
 249 
 250 static word
 251 smb_bcc(byte *packet)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253         int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word);
 254 #if (ARCH == i386)
 255         return *((word *)((byte *)packet + pos));
 256 #else
 257         return packet[pos] | packet[pos+1] << 8;
 258 #endif
 259 }
 260 
 261 /* smb_valid_packet: We check if packet fulfills the basic
 262    requirements of a smb packet */
 263 
 264 static int
 265 smb_valid_packet(byte *packet)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267         DDPRINTK("len: %ld, wct: %d, bcc: %d\n",
 268                  smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
 269         return (   packet[4] == 0xff
 270                 && packet[5] == 'S'
 271                 && packet[6] == 'M'
 272                 && packet[7] == 'B'
 273                 && (smb_len(packet) + 4 == SMB_HEADER_LEN
 274                     + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
 275 }
 276 
 277 /* smb_verify: We check if we got the answer we expected, and if we
 278    got enough data. If bcc == -1, we don't care. */
 279 
 280 static int
 281 smb_verify(byte *packet, int command, int wct, int bcc)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283         return (SMB_CMD(packet) == command &&
 284                 SMB_WCT(packet) >= wct &&
 285                 (bcc == -1 || SMB_BCC(packet) == bcc)) ? 0 : -EIO;
 286 }
 287 
 288 static int
 289 smb_errno(int errcls, int error)
     /* [previous][next][first][last][top][bottom][index][help] */
 290 {
 291 
 292 #if DEBUG_SMB > 1
 293         if (errcls) {
 294                 printk("smb_errno: ");
 295                 smb_printerr(errcls, error);
 296                 printk("\n");
 297         }
 298 #endif
 299 
 300         if (errcls == ERRDOS) 
 301                 switch (error) {
 302                         case ERRbadfunc:    return EINVAL;
 303                         case ERRbadfile:    return ENOENT;
 304                         case ERRbadpath:    return ENOENT;
 305                         case ERRnofids:     return EMFILE;
 306                         case ERRnoaccess:   return EACCES;
 307                         case ERRbadfid:     return EBADF;
 308                         case ERRbadmcb:     return EREMOTEIO;
 309                         case ERRnomem:      return ENOMEM;
 310                         case ERRbadmem:     return EFAULT;
 311                         case ERRbadenv:     return EREMOTEIO;
 312                         case ERRbadformat:  return EREMOTEIO;
 313                         case ERRbadaccess:  return EACCES;
 314                         case ERRbaddata:    return E2BIG;
 315                         case ERRbaddrive:   return ENXIO;
 316                         case ERRremcd:      return EREMOTEIO;
 317                         case ERRdiffdevice: return EXDEV;
 318                         case ERRnofiles:    return 0;
 319                         case ERRbadshare:   return ETXTBSY;
 320                         case ERRlock:       return EDEADLOCK;
 321                         case ERRfilexists:  return EEXIST;
 322                         case 87:            return 0; /* Unknown error!! */
 323                         default:            return EIO;
 324                 }
 325         else if (errcls == ERRSRV) 
 326                 switch (error) {
 327                         case ERRerror: return ENFILE;
 328                         case ERRbadpw: return EINVAL;
 329                         case ERRbadtype: return EIO;
 330                         case ERRaccess: return EACCES;
 331                         default: return EIO;
 332                 }
 333         else if (errcls == ERRHRD) 
 334                 switch (error) {
 335                         case ERRnowrite: return EROFS; 
 336                         case ERRbadunit: return ENODEV;
 337                         case ERRnotready: return EUCLEAN;
 338                         case ERRbadcmd: return EIO;
 339                         case ERRdata: return EIO;
 340                         case ERRbadreq: return ERANGE;
 341                         case ERRbadshare: return ETXTBSY;
 342                         case ERRlock: return EDEADLOCK;
 343                         default: return EIO;
 344                 }
 345         else if (errcls == ERRCMD) 
 346                 return EIO;
 347         return 0;
 348 }
 349 
 350 #if DEBUG_SMB > 0
 351 static char
 352 print_char(char c)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354         if ((c < ' ') || (c > '~'))
 355                 return '.';
 356         return c;
 357 }
 358 
 359 static void
 360 smb_dump_packet(byte *packet) {
     /* [previous][next][first][last][top][bottom][index][help] */
 361         int i, j, len;
 362         int errcls, error;
 363 
 364         errcls = (int)packet[9];
 365         error  = (int)(int)(packet[11]|packet[12]<<8);
 366 
 367         printk("smb_len = %d  valid = %d    \n", 
 368                len = smb_len(packet), smb_valid_packet(packet));
 369         printk("smb_cmd = %d  smb_wct = %d  smb_bcc = %d\n", 
 370                packet[8], SMB_WCT(packet), SMB_BCC(packet)); 
 371         printk("smb_rcls = %d smb_err = %d\n", errcls, error);
 372 
 373         if (errcls) {
 374                 smb_printerr(errcls, error);
 375                 printk("\n");
 376         }
 377 
 378         if (len > 100)
 379                 len = 100;
 380         
 381         for (i = 0; i < len; i += 10) {
 382                 printk("%03d:", i);
 383                 for (j = i; j < i+10; j++)
 384                         if (j < len)
 385                                 printk("%02x ", packet[j]);
 386                         else
 387                                 printk("   ");
 388                 printk(": ");
 389                 for (j = i; j < i+10; j++)
 390                         if (j < len)
 391                                 printk("%c", print_char(packet[j]));
 392                 printk("\n");
 393         }
 394 }
 395 #endif
 396 
 397 static void
 398 smb_lock_server(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 399 {
 400         while (server->lock)
 401                 sleep_on(&server->wait);
 402         server->lock = 1;
 403 }
 404 
 405 static void
 406 smb_unlock_server(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 407 {
 408         if (server->lock != 1) {
 409                 printk("smb_unlock_server: was not locked!\n");
 410         }
 411 
 412         server->lock = 0;
 413         wake_up(&server->wait);
 414 }
 415         
 416 /* smb_request_ok: We expect the server to be locked. Then we do the
 417    request and check the answer completely. When smb_request_ok
 418    returns 0, you can be quite sure that everything went well. When
 419    the answer is <=0, the returned number is a valid unix errno. */
 420 
 421 static int
 422 smb_request_ok(struct smb_server *s, int command, int wct, int bcc)
     /* [previous][next][first][last][top][bottom][index][help] */
 423 {
 424         int result = 0;
 425         s->rcls = 0;
 426         s->err  = 0;
 427 
 428         if (smb_request(s) < 0) {
 429                 DPRINTK("smb_request failed\n");
 430                 result = -EIO;
 431         }
 432         else if (smb_valid_packet(s->packet) != 0) {
 433                 DPRINTK("not a valid packet!\n");
 434                 result = -EIO;
 435         }
 436         else if (s->rcls != 0) {
 437                 result =  -smb_errno(s->rcls, s->err);
 438         }
 439         else if (smb_verify(s->packet, command, wct, bcc) != 0) {
 440                 DPRINTK("smb_verify failed\n");
 441                 result = -EIO;
 442         }
 443 
 444         return result;
 445 }
 446 
 447 /* smb_retry: This function should be called when smb_request_ok has
 448    indicated an error. If the error was indicated because the
 449    connection was killed, we try to reconnect. If smb_retry returns 0,
 450    the error was indicated for another reason, so a retry would not be
 451    of any use. */
 452 
 453 static int
 454 smb_retry(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 455 {
 456         if (server->state != CONN_INVALID) {
 457                 return 0;
 458         }
 459         
 460         if (smb_release(server) < 0) {
 461                 DPRINTK("smb_retry: smb_release failed\n");
 462                 server->state = CONN_RETRIED;
 463                 return 0;
 464         }
 465         if(smb_proc_reconnect(server) < 0) {
 466                 DPRINTK("smb_proc_reconnect failed\n");
 467                 server->state = CONN_RETRIED;
 468                 return 0;
 469         }
 470 
 471         server->state = CONN_VALID;
 472         return 1;
 473 }
 474 
 475 static int
 476 smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc)
     /* [previous][next][first][last][top][bottom][index][help] */
 477 {
 478         int result = smb_request_ok(s, command, wct, bcc);
 479 
 480         smb_unlock_server(s);
 481 
 482         return result;
 483 }
 484         
 485 /* smb_setup_header: We completely set up the packet. You only have to
 486    insert the command-specific fields */
 487 
 488 static byte *
 489 smb_setup_header(struct smb_server *server, byte command, word wct, word bcc)
     /* [previous][next][first][last][top][bottom][index][help] */
 490 {
 491         dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2;
 492         byte *p = server->packet;
 493         byte *buf = server->packet;
 494 
 495         p = smb_encode_smb_length(p, xmit_len);
 496 
 497         BSET(p,0,0xff);
 498         BSET(p,1,'S');
 499         BSET(p,2,'M');
 500         BSET(p,3,'B');
 501         BSET(p,4,command);
 502 
 503         p += 5;
 504         memset(p, '\0', 19);
 505         p += 19;
 506         p += 8;
 507 
 508         WSET(buf, smb_tid, server->tid);
 509         WSET(buf, smb_pid, server->pid);
 510         WSET(buf, smb_uid, server->server_uid);
 511         WSET(buf, smb_mid, server->mid);
 512 
 513         if (server->protocol > PROTOCOL_CORE) {
 514                 BSET(buf, smb_flg, 0x8);
 515                 WSET(buf, smb_flg2, 0x3);
 516         }
 517         
 518         *p++ = wct;             /* wct */
 519         p += 2*wct;
 520         WSET(p, 0, bcc);
 521         return p+2;
 522 }
 523 
 524 /* smb_setup_header_exclusive waits on server->lock and locks the
 525    server, when it's free. You have to unlock it manually when you're
 526    finished with server->packet! */
 527 
 528 static byte *
 529 smb_setup_header_exclusive(struct smb_server *server,
     /* [previous][next][first][last][top][bottom][index][help] */
 530                            byte command, word wct, word bcc)
 531 {
 532         smb_lock_server(server);
 533         return smb_setup_header(server, command, wct, bcc);
 534 }
 535 
 536 
 537 /*****************************************************************************/
 538 /*                                                                           */
 539 /*  File operation section.                                                  */
 540 /*                                                                           */
 541 /*****************************************************************************/
 542 
 543 int
 544 smb_proc_open(struct smb_server *server, const char *pathname, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 545               struct smb_dirent *entry)
 546 {
 547         int error;
 548         char* p;
 549         char* buf = server->packet;
 550         const word o_attr = aSYSTEM | aHIDDEN | aDIR;
 551 
 552         DPRINTK("smb_proc_open: path=%s\n", pathname);
 553 
 554         smb_lock_server(server);
 555 
 556  retry:
 557         p = smb_setup_header(server, SMBopen, 2, 2 + len);
 558         WSET(buf, smb_vwv0, 0x42); /* read/write */
 559         WSET(buf, smb_vwv1, o_attr);
 560         smb_encode_ascii(p, pathname, len);
 561 
 562         if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) {
 563 
 564                 if (smb_retry(server)) {
 565                         goto retry;
 566                 }
 567                 
 568                 if (error != -EACCES) {
 569                         smb_unlock_server(server);
 570                         return error;
 571                 }
 572 
 573                 p = smb_setup_header(server, SMBopen, 2, 2 + len);
 574                 WSET(buf, smb_vwv0, 0x40); /* read only */
 575                 WSET(buf, smb_vwv1, o_attr);
 576                 smb_encode_ascii(p, pathname, len);
 577 
 578                 if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) {
 579                         if (smb_retry(server)) {
 580                                 goto retry;
 581                         }
 582                         smb_unlock_server(server);
 583                         return error;
 584                 }
 585         }
 586 
 587         /* We should now have data in vwv[0..6]. */
 588 
 589         entry->fileid = WVAL(buf, smb_vwv0);
 590         entry->attr   = WVAL(buf, smb_vwv1);
 591         entry->ctime = entry->atime =
 592                 entry->mtime = local2utc(DVAL(buf, smb_vwv2));
 593         entry->size   = DVAL(buf, smb_vwv4);
 594         entry->access = WVAL(buf, smb_vwv6);
 595 
 596         smb_unlock_server(server);
 597 
 598         entry->access &= 3;
 599         DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
 600         return 0;
 601 }
 602 
 603 /* smb_proc_close: in finfo->mtime we can send a modification time to
 604    the server */
 605 int
 606 smb_proc_close(struct smb_server *server, struct smb_dirent *finfo)
     /* [previous][next][first][last][top][bottom][index][help] */
 607 {
 608         char *buf = server->packet;
 609 
 610         smb_setup_header_exclusive(server, SMBclose, 3, 0);
 611         WSET(buf, smb_vwv0, finfo->fileid);
 612         DSET(buf, smb_vwv1, utc2local(finfo->mtime));
 613 
 614         return smb_request_ok_unlock(server, SMBclose, 0, 0);
 615 }
 616 
 617 /* In smb_proc_read and smb_proc_write we do not retry, because the
 618    file-id would not be valid after a reconnection. */
 619 
 620 /* smb_proc_read: fs indicates if it should be copied with
 621    memcpy_tofs. */
 622 
 623 int
 624 smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, 
     /* [previous][next][first][last][top][bottom][index][help] */
 625               off_t offset, long count, char *data, int fs)
 626 {
 627         word returned_count, data_len;
 628         char *buf = server->packet;
 629         int error;
 630 
 631         smb_setup_header_exclusive(server, SMBread, 5, 0);
 632 
 633         WSET(buf, smb_vwv0, finfo->fileid);
 634         WSET(buf, smb_vwv1, count);
 635         DSET(buf, smb_vwv2, offset);
 636         WSET(buf, smb_vwv4, 0);
 637         
 638         if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0) {
 639                 smb_unlock_server(server);
 640                 return error;
 641         }
 642 
 643         returned_count = WVAL(buf, smb_vwv0);
 644         
 645         smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs);
 646 
 647         smb_unlock_server(server);
 648 
 649         if (returned_count != data_len) {
 650                 printk("smb_proc_read: Warning, returned_count != data_len\n");
 651                 printk("smb_proc_read: ret_c=%d, data_len=%d\n",
 652                        returned_count, data_len);
 653         }
 654 
 655         return data_len;
 656 }
 657 
 658 int
 659 smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
     /* [previous][next][first][last][top][bottom][index][help] */
 660                off_t offset, int count, const char *data)
 661 {
 662         int res = 0;
 663         char *buf = server->packet;
 664         byte *p;
 665 
 666         p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3);
 667         WSET(buf, smb_vwv0, finfo->fileid);
 668         WSET(buf, smb_vwv1, count);
 669         DSET(buf, smb_vwv2, offset);
 670         WSET(buf, smb_vwv4, 0);
 671 
 672         *p++ = 1;
 673         WSET(p, 0, count);
 674         memcpy_fromfs(p+2, data, count);
 675 
 676         if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0) {
 677                 res = WVAL(buf, smb_vwv0);
 678         }
 679 
 680         smb_unlock_server(server);
 681 
 682         return res;
 683 }
 684 
 685 /* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */
 686 
 687 static int
 688 smb_proc_do_create(struct smb_server *server, const char *path, int len, 
     /* [previous][next][first][last][top][bottom][index][help] */
 689                    struct smb_dirent *entry, word command)
 690 {
 691         int error;
 692         char *p;
 693         char *buf = server->packet;
 694 
 695         smb_lock_server(server);
 696  retry:
 697         p = smb_setup_header(server, command, 3, len + 2);
 698         WSET(buf, smb_vwv0, entry->attr);
 699         DSET(buf, smb_vwv1, utc2local(entry->ctime));
 700         smb_encode_ascii(p, path, len);
 701 
 702         if ((error = smb_request_ok(server, command, 1, 0)) < 0) {
 703                 if (smb_retry(server)) {
 704                         goto retry;
 705                 }
 706                 smb_unlock_server(server);
 707                 return error;
 708         }
 709 
 710         entry->opened = 1;
 711         entry->fileid = WVAL(buf, smb_vwv0);
 712         smb_unlock_server(server);
 713 
 714         smb_proc_close(server, entry);
 715 
 716         return 0;
 717 }
 718         
 719 int
 720 smb_proc_create(struct smb_server *server, const char *path, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 721                 struct smb_dirent *entry)
 722 {
 723         return smb_proc_do_create(server, path, len, entry, SMBcreate);
 724 }
 725 
 726 int
 727 smb_proc_mknew(struct smb_server *server, const char *path, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 728                struct smb_dirent *entry)
 729 {
 730         return smb_proc_do_create(server, path, len, entry, SMBmknew);
 731 }
 732 
 733 int
 734 smb_proc_mv(struct smb_server *server, 
     /* [previous][next][first][last][top][bottom][index][help] */
 735             const char *opath, const int olen,
 736             const char *npath, const int nlen)
 737 {
 738         char *p;
 739         char *buf = server->packet;
 740         int result;
 741 
 742         smb_lock_server(server);
 743 
 744  retry:
 745         p = smb_setup_header(server, SMBmv, 1, olen + nlen + 4);
 746         WSET(buf, smb_vwv0, 0);
 747         p = smb_encode_ascii(p, opath, olen);
 748         smb_encode_ascii(p, npath, olen);
 749 
 750         if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
 751                 if (smb_retry(server)) {
 752                         goto retry;
 753                 }
 754         }
 755         smb_unlock_server(server);
 756         return result;
 757 }
 758 
 759 int
 760 smb_proc_mkdir(struct smb_server *server, const char *path, const int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 761 {
 762         char *p;
 763         int result;
 764 
 765         smb_lock_server(server);
 766 
 767  retry:
 768         p = smb_setup_header(server, SMBmkdir, 0, 2 + len);
 769         smb_encode_ascii(p, path, len);
 770 
 771         if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0) {
 772                 if (smb_retry(server)) {
 773                         goto retry;
 774                 }
 775         }
 776         smb_unlock_server(server);
 777         return result;
 778 }
 779 
 780 int
 781 smb_proc_rmdir(struct smb_server *server, const char *path, const int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 782 {
 783         char *p;
 784         int result;
 785 
 786         smb_lock_server(server);
 787 
 788  retry:
 789         p = smb_setup_header(server, SMBrmdir, 0, 2 + len);
 790         smb_encode_ascii(p, path, len);
 791 
 792         if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0) {
 793                 if (smb_retry(server)) {
 794                         goto retry;
 795                 }
 796         }
 797         smb_unlock_server(server);
 798         return result;
 799 }
 800 
 801 int
 802 smb_proc_unlink(struct smb_server *server, const char *path, const int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 803 {
 804         char *p;
 805         char *buf = server->packet;
 806         int result;
 807 
 808         smb_lock_server(server);
 809 
 810  retry:
 811         p = smb_setup_header(server, SMBunlink, 1, 2 + len);
 812         WSET(buf, smb_vwv0, 0);
 813         smb_encode_ascii(p, path, len);
 814 
 815         if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
 816                 if (smb_retry(server)) {
 817                         goto retry;
 818                 }
 819         }
 820         smb_unlock_server(server);
 821         return result;
 822 }
 823 
 824 int
 825 smb_proc_trunc(struct smb_server *server, word fid, dword length)
     /* [previous][next][first][last][top][bottom][index][help] */
 826 {
 827         char *p;
 828         char *buf = server->packet;
 829         int result;
 830 
 831         smb_lock_server(server);
 832 
 833  retry:
 834         p = smb_setup_header(server, SMBwrite, 5, 3);
 835         WSET(buf, smb_vwv0, fid);
 836         WSET(buf, smb_vwv1, 0);
 837         DSET(buf, smb_vwv2, length);
 838         WSET(buf, smb_vwv4, 0);
 839         smb_encode_ascii(p, "", 0);
 840         
 841         if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
 842                 if (smb_retry(server)) {
 843                         goto retry;
 844                 }
 845         }
 846         smb_unlock_server(server);
 847         return result;
 848 }
 849 
 850 static char *
 851 smb_decode_dirent(char *p, struct smb_dirent *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 852 {
 853         p += SMB_STATUS_SIZE;                  /* reserved (search_status) */
 854         entry->attr = BVAL(p, 0);
 855         entry->mtime = entry->atime = entry->ctime =
 856                 date_dos2unix(WVAL(p, 1), WVAL(p, 3));
 857         entry->size = DVAL(p, 5);
 858         memcpy(entry->path, p+9, 13);
 859         DDPRINTK("smb_decode_dirent: path = %s\n", entry->path);
 860         return p + 22;
 861 }
 862 
 863 /* This routine is used to read in directory entries from the network.
 864    Note that it is for short directory name seeks, i.e.: protocol <
 865    PROTOCOL_LANMAN2 */
 866 
 867 static int
 868 smb_proc_readdir_short(struct smb_server *server, struct inode *dir, int fpos,
     /* [previous][next][first][last][top][bottom][index][help] */
 869                        int cache_size, struct smb_dirent *entry)
 870 {
 871         char *p;
 872         char *buf;
 873         int error;
 874         int result;
 875         int i;
 876         int first, total_count;
 877         struct smb_dirent *current_entry;
 878         word bcc;
 879         word count;
 880         char status[SMB_STATUS_SIZE];
 881         int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE;
 882         int dirlen = strlen(SMB_FINFO(dir)->path);
 883         char mask[dirlen + 5];
 884 
 885         strcpy(mask, SMB_FINFO(dir)->path);
 886         strcat(mask, "\\*.*");
 887 
 888         DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);        
 889         DPRINTK("          mask = %s\n", mask);
 890 
 891         buf = server->packet;
 892 
 893         smb_lock_server(server);
 894 
 895  retry:
 896         first = 1;
 897         total_count = 0;
 898         current_entry = entry;
 899         
 900         while (1) {
 901                 if (first == 1) {
 902                         p = smb_setup_header(server, SMBsearch, 2,
 903                                              5 + strlen(mask));
 904                         WSET(buf, smb_vwv0, entries_asked);
 905                         WSET(buf, smb_vwv1, aDIR);
 906                         p = smb_encode_ascii(p, mask, strlen(mask));
 907                         *p ++ = 5;
 908                         p = smb_encode_word(p, 0);
 909                 } else {
 910                         p = smb_setup_header(server, SMBsearch, 2,
 911                                              5 + SMB_STATUS_SIZE);
 912                         WSET(buf, smb_vwv0, entries_asked);
 913                         WSET(buf, smb_vwv1, aDIR);
 914                         p = smb_encode_ascii(p, "", 0);
 915                         p = smb_encode_vblock(p, status, SMB_STATUS_SIZE, 0);
 916                 }
 917                 
 918                 if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0) {
 919                         if (   (server->rcls == ERRDOS)
 920                             && (server->err  == ERRnofiles)) {
 921                                 result = total_count - fpos;
 922                                 goto unlock_return;
 923                         }
 924                         else
 925                         {
 926                                 if (smb_retry(server)) {
 927                                         goto retry;
 928                                 }
 929                                 result = error;
 930                                 goto unlock_return;
 931                         }
 932                 }
 933 
 934                 p = SMB_VWV(server->packet);
 935                 p = smb_decode_word(p, &count); /* vwv[0] = count-returned */
 936                 p = smb_decode_word(p, &bcc);           
 937                 
 938                 first = 0;
 939                 
 940                 if (count <= 0) {
 941                         result = total_count - fpos;
 942                         goto unlock_return;
 943                 }
 944                 if (bcc != count * SMB_DIRINFO_SIZE + 3) {
 945                         result = -EIO;
 946                         goto unlock_return;
 947                 }
 948 
 949                 p += 3; /* Skipping VBLOCK header (5, length lo, length hi). */
 950 
 951                 /* Read the last entry into the status field. */
 952                 memcpy(status,
 953                        SMB_BUF(server->packet) + 3 +
 954                        (count - 1) * SMB_DIRINFO_SIZE, 
 955                        SMB_STATUS_SIZE);
 956 
 957                 /* Now we are ready to parse smb directory entries. */
 958                 
 959                 for (i = 0; i < count; i ++) {
 960                         if (total_count < fpos) {
 961                                 p += SMB_DIRINFO_SIZE;
 962                                 DDPRINTK("smb_proc_readdir: skipped entry.\n");
 963                                 DDPRINTK("                  total_count = %d\n"
 964                                          "                i = %d, fpos = %d\n",
 965                                          total_count, i, fpos);
 966                         }
 967                         else if (total_count >= fpos + cache_size) {
 968                                 result = total_count - fpos;
 969                                 goto unlock_return;
 970                         }
 971                         else {
 972                                 p = smb_decode_dirent(p, current_entry);
 973                                 current_entry->f_pos = total_count;
 974                                 DDPRINTK("smb_proc_readdir: entry->f_pos = "
 975                                          "%lu\n", entry->f_pos);        
 976                                 current_entry += 1;
 977                         }
 978                         total_count += 1;
 979                 }
 980         }
 981  unlock_return:
 982         smb_unlock_server(server);
 983         return result;
 984 }
 985 
 986 /* interpret a long filename structure - this is mostly guesses at the
 987    moment.  The length of the structure is returned.  The structure of
 988    a long filename depends on the info level. 260 is used by NT and 2
 989    is used by OS/2. */
 990 
 991 static char *
 992 smb_decode_long_dirent(char *p, struct smb_dirent *finfo, int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 993 {
 994         char *result;
 995 
 996         if (finfo) {
 997                 /* I have to set times to 0 here, because I do not
 998                    have specs about this for all info levels. */
 999                 finfo->ctime = finfo->mtime = finfo->atime = 0;
1000         }
1001 
1002         switch (level)
1003         {
1004         case 1:                 /* OS/2 understands this */
1005                 if (finfo)
1006                 {
1007                         DPRINTK("received entry\n");
1008                         strcpy(finfo->path,p+27);
1009                         finfo->len  = strlen(finfo->path);
1010                         finfo->size = DVAL(p,16);
1011                         finfo->attr = BVAL(p,24);
1012 
1013                         finfo->ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
1014                         finfo->atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
1015                         finfo->mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
1016                 }
1017                 result = p + 28 + BVAL(p,26);
1018                 break;
1019 
1020         case 2:                 /* this is what OS/2 uses */
1021                 if (finfo)
1022                 {
1023                         strcpy(finfo->path,p+31);
1024                         finfo->len  = strlen(finfo->path);
1025                         finfo->size = DVAL(p,16);
1026                         finfo->attr = BVAL(p,24);
1027 #if 0
1028                         finfo->atime = make_unix_date2(p+8);
1029                         finfo->mtime = make_unix_date2(p+12);
1030 #endif
1031                 }
1032                 result = p + 32 + BVAL(p,30);
1033                 break;
1034 
1035         case 260:               /* NT uses this, but also accepts 2 */
1036                 result = p + WVAL(p,0);
1037                 if (finfo)
1038                 {
1039                         int namelen;
1040                         p += 4; /* next entry offset */
1041                         p += 4; /* fileindex */
1042                         /* finfo->ctime = interpret_filetime(p);*/
1043                         p += 8;
1044                         /* finfo->atime = interpret_filetime(p);*/
1045                         p += 8;
1046                         p += 8; /* write time */
1047                         /* finfo->mtime = interpret_filetime(p);*/
1048                         p += 8;
1049                         finfo->size = DVAL(p,0);
1050                         p += 8;
1051                         p += 8; /* alloc size */
1052                         finfo->attr = BVAL(p,0);
1053                         p += 4;
1054                         namelen = min(DVAL(p,0), SMB_MAXNAMELEN);
1055                         p += 4;
1056                         p += 4; /* EA size */
1057                         p += 2; /* short name len? */
1058                         p += 24; /* short name? */        
1059                         strncpy(finfo->path,p,namelen);
1060                         finfo->len = namelen;
1061                 }
1062                 break;
1063 
1064         default:
1065                 DPRINTK("Unknown long filename format %d\n",level);
1066                 result = p + WVAL(p,0);
1067         }
1068         return result;
1069 }
1070 
1071 int
1072 smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos,
     /* [previous][next][first][last][top][bottom][index][help] */
1073                       int cache_size, struct smb_dirent *entry)
1074 {
1075         int max_matches = 512;
1076   
1077         /* NT uses 260, OS/2 uses 2. Both accept 1. */
1078         int info_level = 1;
1079 
1080         char *p;
1081         int i;
1082         int first, total_count;
1083         struct smb_dirent *current_entry;
1084 
1085         char *resp_data;
1086         char *resp_param;
1087         int resp_data_len = 0;
1088         int resp_param_len=0;
1089 
1090         int attribute = aSYSTEM | aHIDDEN | aDIR;
1091         int result;
1092 
1093         int ff_resume_key = 0;
1094         int ff_searchcount=0;
1095         int ff_eos=0;
1096         int ff_lastname=0;
1097         int ff_dir_handle=0;
1098         int loop_count = 0;
1099 
1100         int dirlen = strlen(SMB_FINFO(dir)->path);
1101         char mask[dirlen + 5];
1102 
1103         strcpy(mask, SMB_FINFO(dir)->path);
1104         strcat(mask, "\\*");
1105 
1106         DPRINTK("SMB call lreaddir %d @ %d\n", cache_size, fpos);        
1107         DPRINTK("          mask = %s\n", mask);
1108 
1109         resp_param = NULL;
1110         resp_data  = NULL;
1111 
1112         smb_lock_server(server);
1113 
1114  retry:
1115 
1116         first = 1;
1117         total_count = 0;
1118         current_entry = entry;
1119         
1120         while (ff_eos == 0)
1121         {
1122                 int masklen = strlen(mask);
1123                 unsigned char *outbuf = server->packet;
1124                 
1125                 loop_count += 1;
1126                 if (loop_count > 200)
1127                 {
1128                         printk("smb_proc_readdir_long: "
1129                                "Looping in FIND_NEXT??\n");
1130                         break;
1131                 }
1132 
1133                 smb_setup_header(server, SMBtrans2, 15,
1134                                  5 + 12 + masklen + 1);
1135 
1136                 WSET(outbuf,smb_tpscnt,12 + masklen +1);
1137                 WSET(outbuf,smb_tdscnt,0);
1138                 WSET(outbuf,smb_mprcnt,10); 
1139                 WSET(outbuf,smb_mdrcnt,TRANS2_MAX_TRANSFER);
1140                 WSET(outbuf,smb_msrcnt,0);
1141                 WSET(outbuf,smb_flags,0); 
1142                 DSET(outbuf,smb_timeout,0);
1143                 WSET(outbuf,smb_pscnt,WVAL(outbuf,smb_tpscnt));
1144                 WSET(outbuf,smb_psoff,((SMB_BUF(outbuf)+3) - outbuf)-4);
1145                 WSET(outbuf,smb_dscnt,0);
1146                 WSET(outbuf,smb_dsoff,0);
1147                 WSET(outbuf,smb_suwcnt,1);
1148                 WSET(outbuf,smb_setup0,
1149                      first == 1 ? TRANSACT2_FINDFIRST : TRANSACT2_FINDNEXT);
1150 
1151                 p = SMB_BUF(outbuf);
1152                 *p++=0;         /* put in a null smb_name */
1153                 *p++='D'; *p++ = ' '; /* this was added because OS/2 does it */
1154 
1155                 if (first != 0)
1156                 {
1157                         WSET(p,0,attribute); /* attribute */
1158                         WSET(p,2,max_matches); /* max count */
1159                         WSET(p,4,8+4+2); /* resume required + close on end +
1160                                             continue */
1161                         WSET(p,6,info_level); 
1162                         DSET(p,8,0);
1163                         p += 12;
1164                         strncpy(p, mask, masklen);
1165                         p += masklen;
1166                         *p++ = 0; *p++ = 0;
1167                 }
1168                 else
1169                 {
1170                         DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
1171                                 ff_dir_handle,ff_resume_key,ff_lastname,mask);
1172                         WSET(p,0,ff_dir_handle);
1173                         WSET(p,2,max_matches); /* max count */
1174                         WSET(p,4,info_level); 
1175                         DSET(p,6,ff_resume_key); /* ff_resume_key */
1176                         WSET(p,10,8+4+2); /* resume required + close on end +
1177                                              continue */
1178                         p += 12;
1179                         strncpy(p, mask, masklen);
1180                         p += masklen;
1181                         *p++ = 0; *p++ = 0;
1182                 }
1183 
1184                 result = smb_trans2_request(server,
1185                                             &resp_data_len,&resp_param_len,
1186                                             &resp_data,&resp_param);
1187 
1188                 if (result < 0) {
1189                         if (smb_retry(server)) {
1190                                 goto retry;
1191                         }
1192                         DPRINTK("smb_proc_readdir_long: "
1193                                 "got error from trans2_request\n");
1194                         break;
1195                 }
1196 
1197                 if (server->rcls != 0)
1198                 {
1199                         result = -EIO;
1200                         break;
1201                 }
1202 
1203                 /* parse out some important return info */
1204                 p = resp_param;
1205                 if (first != 0)
1206                 {
1207                         ff_dir_handle = WVAL(p,0);
1208                         ff_searchcount = WVAL(p,2);
1209                         ff_eos = WVAL(p,4);
1210                         ff_lastname = WVAL(p,8);
1211                 }
1212                 else
1213                 {
1214                         ff_searchcount = WVAL(p,0);
1215                         ff_eos = WVAL(p,2);
1216                         ff_lastname = WVAL(p,6);
1217                 }
1218 
1219                 if (ff_searchcount == 0) 
1220                         break;
1221 
1222                 /* point to the data bytes */
1223                 p = resp_data;
1224 
1225                 /* we might need the lastname for continuations */
1226                 if (ff_lastname > 0)
1227                 {
1228                         switch(info_level)
1229                         {
1230                         case 260:
1231                                 ff_resume_key =0;
1232                                 strcpy(mask,p+ff_lastname+94);
1233                                 break;
1234                         case 1:
1235                                 strcpy(mask,p + ff_lastname + 1);
1236                                 ff_resume_key = 0;
1237                                 break;
1238                         }
1239                 }
1240                 else
1241                         strcpy(mask,"");
1242   
1243                 /* Now we are ready to parse smb directory entries. */
1244                 
1245                 for (i = 0; i < ff_searchcount; i ++) {
1246                         if (total_count < fpos) {
1247                                 p = smb_decode_long_dirent(p, NULL,
1248                                                            info_level);
1249                                 DPRINTK("smb_proc_readdir: skipped entry.\n");
1250                                 DDPRINTK("                  total_count = %d\n"
1251                                          "                i = %d, fpos = %d\n",
1252                                          total_count, i, fpos);
1253                         }
1254                         else if (total_count >= fpos + cache_size) {
1255                                 goto finished;
1256                         }
1257                         else {
1258                                 p = smb_decode_long_dirent(p, current_entry,
1259                                                            info_level);
1260                                 current_entry->f_pos = total_count;
1261                                 DDPRINTK("smb_proc_readdir: entry->f_pos = "
1262                                          "%lu\n", entry->f_pos);        
1263                                 current_entry += 1;
1264                         }
1265                         total_count += 1;
1266                 }
1267 
1268                 if (resp_data != NULL) {
1269                         smb_kfree_s(resp_data,  0);
1270                         resp_data = NULL;
1271                 }
1272                 if (resp_param != NULL) {
1273                         smb_kfree_s(resp_param, 0);
1274                         resp_param = NULL;
1275                 }
1276 
1277                 DPRINTK("received %d entries (eos=%d resume=%d)\n",
1278                         ff_searchcount,ff_eos,ff_resume_key);
1279 
1280                 first = 0;
1281         }
1282 
1283  finished:
1284         if (resp_data != NULL) {
1285                 smb_kfree_s(resp_data,  0);
1286                 resp_data = NULL;
1287         }
1288         if (resp_param != NULL) {
1289                 smb_kfree_s(resp_param, 0);
1290                 resp_param = NULL;
1291         }
1292 
1293         smb_unlock_server(server);
1294 
1295         return total_count - fpos;
1296 }
1297 
1298 int
1299 smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos,
     /* [previous][next][first][last][top][bottom][index][help] */
1300                  int cache_size, struct smb_dirent *entry)
1301 {
1302         if (server->protocol >= PROTOCOL_LANMAN2)
1303                 return smb_proc_readdir_long(server, dir, fpos, cache_size,
1304                                              entry);
1305         else
1306                 return smb_proc_readdir_short(server, dir, fpos, cache_size,
1307                                               entry);
1308 }
1309                 
1310 static int
1311 smb_proc_getattr_core(struct smb_server *server, const char *path, int len, 
     /* [previous][next][first][last][top][bottom][index][help] */
1312                       struct smb_dirent *entry)
1313 {
1314         int result;
1315         char *p;
1316         char *buf = server->packet;
1317 
1318         smb_lock_server(server);
1319 
1320         DDPRINTK("smb_proc_getattr: %s\n", path);
1321 
1322  retry:
1323         p = smb_setup_header(server, SMBgetatr, 0, 2 + len);
1324         smb_encode_ascii(p, path, len);
1325         
1326         if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) {
1327                 if (smb_retry(server)) {
1328                         goto retry;
1329                 }
1330                 smb_unlock_server(server);
1331                 return result;
1332         }
1333 
1334         entry->attr         = WVAL(buf, smb_vwv0);
1335         entry->ctime = entry->atime = /* The server only tells us 1 time */
1336                 entry->mtime = local2utc(DVAL(buf, smb_vwv1));
1337 
1338         entry->size         = DVAL(buf, smb_vwv3);
1339         smb_unlock_server(server);
1340         return 0;
1341 }
1342 
1343 /* smb_proc_getattrE: entry->fid must be valid */
1344 
1345 static int
1346 smb_proc_getattrE(struct smb_server *server, struct smb_dirent *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
1347 {
1348         char* buf = server->packet;
1349         int result;
1350 
1351         smb_setup_header_exclusive(server, SMBgetattrE, 1, 0);
1352         WSET(buf, smb_vwv0, entry->fileid);
1353 
1354         if ((result = smb_request_ok(server, SMBgetattrE, 11, 0)) != 0) {
1355                 smb_unlock_server(server);
1356                 return result;
1357         }
1358 
1359         entry->ctime = date_dos2unix(WVAL(buf, smb_vwv1), WVAL(buf, smb_vwv0));
1360         entry->atime = date_dos2unix(WVAL(buf, smb_vwv3), WVAL(buf, smb_vwv2));
1361         entry->mtime = date_dos2unix(WVAL(buf, smb_vwv5), WVAL(buf, smb_vwv4));
1362         entry->size  = DVAL(buf, smb_vwv6);
1363         entry->attr  = WVAL(buf, smb_vwv10);
1364 
1365         smb_unlock_server(server);
1366         return 0;
1367 }
1368 
1369 int
1370 smb_proc_getattr(struct smb_server *server, const char *path, int len, 
     /* [previous][next][first][last][top][bottom][index][help] */
1371                  struct smb_dirent *entry)
1372 {
1373         if (server->protocol >= PROTOCOL_LANMAN1) {
1374 
1375                 int result = 0;
1376                 struct smb_dirent temp_entry;
1377 
1378                 if ((result=smb_proc_open(server,path,len,
1379                                           &temp_entry)) < 0) {
1380                         /* We cannot open directories, so we try to use the
1381                            core variant */
1382                         return smb_proc_getattr_core(server,path,len,entry);
1383                 }
1384 
1385                 if ((result=smb_proc_getattrE(server, &temp_entry)) >= 0) {
1386                         entry->attr  = temp_entry.attr;
1387                         entry->atime = temp_entry.atime;
1388                         entry->mtime = temp_entry.mtime;
1389                         entry->ctime = temp_entry.ctime;
1390                         entry->size  = temp_entry.size;
1391                 }
1392                 
1393                 smb_proc_close(server, &temp_entry);
1394                 return result;
1395 
1396         } else {
1397                 return smb_proc_getattr_core(server, path, len, entry);
1398         }
1399 }
1400 
1401 
1402 /* In core protocol, there is only 1 time to be set, we use
1403    entry->mtime, to make touch work. */
1404 static int
1405 smb_proc_setattr_core(struct smb_server *server,
     /* [previous][next][first][last][top][bottom][index][help] */
1406                       const char *path, int len,
1407                       struct smb_dirent *new_finfo)
1408 {
1409         char *p;
1410         char *buf = server->packet;
1411         int result;
1412 
1413         smb_lock_server(server);
1414 
1415  retry:
1416         p = smb_setup_header(server, SMBsetatr, 8, 4 + len);
1417         WSET(buf, smb_vwv0, new_finfo->attr);
1418         DSET(buf, smb_vwv1, utc2local(new_finfo->mtime));
1419         p = smb_encode_ascii(p, path, len);
1420         p = smb_encode_ascii(p, "", 0);
1421 
1422         if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0) {
1423                 if (smb_retry(server)) {
1424                         goto retry;
1425                 }
1426         }
1427         smb_unlock_server(server);
1428         return result;
1429 }
1430 
1431 /* smb_proc_setattrE: we do not retry here, because we rely on fid,
1432    which would not be valid after a retry. */
1433 static int
1434 smb_proc_setattrE(struct smb_server *server, word fid,
     /* [previous][next][first][last][top][bottom][index][help] */
1435                   struct smb_dirent *new_entry)
1436 {
1437         char *buf = server->packet;
1438         word date, time;
1439 
1440         smb_setup_header_exclusive(server, SMBsetattrE, 7, 0);
1441 
1442         WSET(buf, smb_vwv0, fid);
1443 
1444         date_unix2dos(new_entry->ctime, &time, &date);
1445         WSET(buf, smb_vwv1, date);
1446         WSET(buf, smb_vwv2, time);
1447         
1448         date_unix2dos(new_entry->atime, &time, &date);
1449         WSET(buf, smb_vwv3, date);
1450         WSET(buf, smb_vwv4, time);
1451         
1452         date_unix2dos(new_entry->mtime, &time, &date);
1453         WSET(buf, smb_vwv5, date);
1454         WSET(buf, smb_vwv6, time);
1455 
1456         return smb_request_ok_unlock(server, SMBsetattrE, 0, 0);
1457 }
1458 
1459 /* smb_proc_setattr: for protocol >= LANMAN1 we expect the file to be
1460    opened for writing. */
1461 int
1462 smb_proc_setattr(struct smb_server *server, struct inode *inode,
     /* [previous][next][first][last][top][bottom][index][help] */
1463                  struct smb_dirent *new_finfo)
1464 {
1465         struct smb_dirent *finfo = SMB_FINFO(inode);
1466         int result;
1467 
1468         if (server->protocol >= PROTOCOL_LANMAN1) {
1469                 if ((result = smb_make_open(inode, O_RDWR)) < 0)
1470                         return result;
1471                 return smb_proc_setattrE(server, finfo->fileid, new_finfo);
1472         } else {
1473                 return smb_proc_setattr_core(server, finfo->path, finfo->len,
1474                                              new_finfo);
1475         }
1476 }
1477 
1478 int
1479 smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr)
     /* [previous][next][first][last][top][bottom][index][help] */
1480 {
1481         int error;
1482         char *p;
1483         struct smb_server *server = &(SMB_SBP(super)->s_server);
1484 
1485         smb_lock_server(server);
1486 
1487  retry:
1488         smb_setup_header(server, SMBdskattr, 0, 0);
1489         
1490         if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) {
1491                 if (smb_retry(server)) {
1492                         goto retry;
1493                 }
1494                 smb_unlock_server(server);
1495                 return error;
1496         }
1497         
1498         p = SMB_VWV(server->packet);
1499         p = smb_decode_word(p, &attr->total);
1500         p = smb_decode_word(p, &attr->allocblocks);
1501         p = smb_decode_word(p, &attr->blocksize);
1502         p = smb_decode_word(p, &attr->free);
1503         smb_unlock_server(server);
1504         return 0;
1505 }
1506 
1507 /*****************************************************************************/
1508 /*                                                                           */
1509 /*  Mount/umount operations.                                                 */
1510 /*                                                                           */
1511 /*****************************************************************************/
1512 
1513 struct smb_prots {
1514         enum smb_protocol prot;
1515         const char *name;
1516 };
1517 
1518 /* smb_proc_reconnect: We expect the server to be locked, so that you
1519    can call the routine from within smb_retry. The socket must be
1520    created, like after a user-level socket()-call. It may not be
1521    connected. */
1522 
1523 int
1524 smb_proc_reconnect(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
1525 {
1526         struct smb_prots prots[] =
1527         { { PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
1528           { PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
1529 #ifdef LANMAN1
1530           { PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
1531           { PROTOCOL_LANMAN1,"LANMAN1.0"},
1532 #endif
1533 #ifdef LANMAN2
1534           { PROTOCOL_LANMAN2,"LM1.2X002"},
1535 #endif
1536           {-1, NULL} };
1537         char dev[] = "A:";
1538         int i, plength;
1539         int max_xmit = 1024;    /* Space needed for first request. */
1540         int given_max_xmit = server->m.max_xmit;
1541         int result;
1542         byte *p;
1543 
1544         if ((result = smb_connect(server)) < 0) {
1545                 DPRINTK("smb_proc_reconnect: could not smb_connect\n");
1546                 goto fail;
1547         }
1548 
1549         /* Here we assume that the connection is valid */
1550         server->state = CONN_VALID;
1551 
1552         if (server->packet != NULL) {
1553                 smb_kfree_s(server->packet, server->max_xmit);
1554         }
1555         
1556         server->packet = smb_kmalloc(max_xmit, GFP_KERNEL);
1557 
1558         if (server->packet == NULL) {
1559                 printk("smb_proc_connect: No memory! Bailing out.\n");
1560                 result = -ENOMEM;
1561                 goto fail;
1562         }
1563 
1564         server->max_xmit = max_xmit;
1565 
1566         /*
1567          * Start with an RFC1002 session request packet.
1568          */
1569         p = server->packet + 4;
1570 
1571         p = smb_name_mangle(p, server->m.server_name);
1572         p = smb_name_mangle(p, server->m.client_name);
1573         
1574         smb_encode_smb_length(server->packet,
1575                               (void *)p - (void *)(server->packet));
1576         
1577         server->packet[0] = 0x81; /* SESSION REQUEST */
1578 
1579         if (smb_catch_keepalive(server) < 0) {
1580                 printk("smb_proc_connect: could not catch_keepalives\n");
1581         }
1582         
1583         if ((result = smb_request(server)) < 0) {
1584                 printk("smb_proc_connect: Failed to send SESSION REQUEST.\n");
1585                 smb_dont_catch_keepalive(server);
1586                 goto fail;
1587         }
1588         
1589         if (server->packet[0] != 0x82) {
1590                 printk("smb_proc_connect: Did not recieve positive response "
1591                        "(err = %x)\n", 
1592                        server->packet[0]);
1593                 smb_dont_catch_keepalive(server);
1594 #if DEBUG_SMB > 0
1595                 smb_dump_packet(server->packet);
1596 #endif
1597                 result = -EIO;
1598                 goto fail;
1599         }
1600 
1601         DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n");
1602         
1603         /* Now we are ready to send a SMB Negotiate Protocol packet. */
1604         memset(server->packet, 0, SMB_HEADER_LEN);
1605 
1606         plength = 0;
1607         for (i = 0; prots[i].name != NULL; i++) {
1608                 plength += strlen(prots[i].name) + 2;
1609         }
1610 
1611         smb_setup_header(server, SMBnegprot, 0, plength);
1612 
1613         p = SMB_BUF(server->packet);
1614         
1615         for (i = 0; prots[i].name != NULL; i++) {
1616                 p = smb_encode_dialect(p,prots[i].name, strlen(prots[i].name));
1617         }
1618         
1619         if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0) {
1620                 printk("smb_proc_connect: Failure requesting SMBnegprot\n");
1621                 smb_dont_catch_keepalive(server);
1622                 goto fail;
1623         } else {
1624                 DDPRINTK("smb_proc_connect: Request SMBnegprot..");
1625         }
1626 
1627         DDPRINTK("Verified!\n");
1628 
1629         p = SMB_VWV(server->packet);
1630         p = smb_decode_word(p, (word *)&i);
1631         server->protocol = prots[i].prot;
1632 
1633         DPRINTK("smb_proc_connect: Server wants %s protocol.\n",
1634                 prots[i].name);
1635 
1636         if (server->protocol > PROTOCOL_LANMAN1) {
1637 
1638                 word passlen = strlen(server->m.password);
1639                 word userlen = strlen(server->m.username);
1640                 
1641                 DPRINTK("smb_proc_connect: password = %s\n",
1642                         server->m.password);
1643                 DPRINTK("smb_proc_connect: usernam = %s\n",
1644                         server->m.username);
1645 
1646                 p = smb_decode_word(p, &(server->maxxmt));
1647                 p = smb_decode_word(p, &(server->maxmux));
1648                 p = smb_decode_word(p, &(server->maxvcs));
1649                 p = smb_decode_word(p, &(server->blkmode));
1650                 p = smb_decode_dword(p, &(server->sesskey));
1651 
1652                 smb_setup_header(server, SMBsesssetupX, 10,
1653                                  2 + userlen + passlen);
1654 
1655                 WSET(server->packet, smb_vwv0, 0x00ff);
1656                 WSET(server->packet, smb_vwv1, 0);
1657                 WSET(server->packet, smb_vwv2, given_max_xmit);
1658                 WSET(server->packet, smb_vwv3, 2);
1659                 WSET(server->packet, smb_vwv4, server->pid);
1660                 DSET(server->packet, smb_vwv5, server->sesskey);
1661                 WSET(server->packet, smb_vwv7, passlen + 1);
1662                 WSET(server->packet, smb_vwv8, 0);
1663                 WSET(server->packet, smb_vwv9, 0);
1664 
1665                 p = SMB_BUF(server->packet);
1666                 strcpy(p, server->m.password);
1667                 p += passlen + 1;
1668                 strcpy(p, server->m.username);
1669 
1670                 if ((result = smb_request_ok(server,SMBsesssetupX,3,0)) < 0) {
1671                         DPRINTK("smb_proc_connect: SMBsessetupX failed\n");
1672                         smb_dont_catch_keepalive(server);
1673                         goto fail;
1674                 }
1675                 smb_decode_word(server->packet+32, &(server->server_uid));
1676         }
1677 
1678         /* Fine! We have a connection, send a tcon message. */
1679 
1680         smb_setup_header(server, SMBtcon, 0,
1681                          6 + strlen(server->m.service) +
1682                          strlen(server->m.password) + strlen(dev));
1683         p = SMB_BUF(server->packet);
1684         p = smb_encode_ascii(p, server->m.service, strlen(server->m.service));
1685         p = smb_encode_ascii(p,server->m.password, strlen(server->m.password));
1686         p = smb_encode_ascii(p, dev, strlen(dev));
1687 
1688         if ((result = smb_request_ok(server, SMBtcon, 2, 0)) < 0) {
1689                 DPRINTK("smb_proc_connect: SMBtcon not verified.\n");
1690                 smb_dont_catch_keepalive(server);
1691                 goto fail;
1692         }
1693 
1694         DDPRINTK("OK! Managed to set up SMBtcon!\n");
1695    
1696         p = SMB_VWV(server->packet);
1697         p = smb_decode_word(p, &server->max_xmit);
1698 
1699         if (server->max_xmit > given_max_xmit)
1700                 server->max_xmit = given_max_xmit;
1701         
1702         p = smb_decode_word(p, &server->tid);
1703 
1704         /* Ok, everything is fine. max_xmit does not include */
1705         /* the TCP-SMB header of 4 bytes. */
1706         server->max_xmit += 4;
1707 
1708         DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid);
1709 
1710         /* Now make a new packet with the correct size. */
1711         smb_kfree_s(server->packet, max_xmit); 
1712 
1713         server->packet = smb_kmalloc(server->max_xmit, GFP_KERNEL);
1714         if (server->packet == NULL) {
1715                 printk("smb_proc_connect: No memory left in end of "
1716                        "connection phase :-(\n");
1717                 smb_dont_catch_keepalive(server);
1718                 goto fail;
1719         }
1720 
1721         DPRINTK("smb_proc_connect: Normal exit\n");
1722         return 0;
1723 
1724  fail:
1725         server->state = CONN_INVALID;
1726         return result;
1727 }
1728 
1729 /* smb_proc_reconnect: server->packet is allocated with
1730    server->max_xmit bytes if and only if we return >= 0 */
1731 int
1732 smb_proc_connect(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
1733 {
1734         int result;
1735         smb_lock_server(server);
1736         result = smb_proc_reconnect(server);
1737         if ((result < 0) && (server->packet != NULL)) {
1738                 smb_kfree_s(server->packet, server->max_xmit);
1739                 server->packet = NULL;
1740         }
1741         smb_unlock_server(server);
1742         return result;
1743 }
1744         
1745 int
1746 smb_proc_disconnect(struct smb_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
1747 {
1748         smb_setup_header_exclusive(server, SMBtdis, 0, 0);
1749         return smb_request_ok_unlock(server, SMBtdis, 0, 0);
1750 }
1751 
1752 /* error code stuff - put together by Merik Karman
1753    merik@blackadder.dsh.oz.au */
1754 
1755 #if DEBUG_SMB > 0
1756 
1757 typedef struct {
1758         char *name;
1759         int code;
1760         char *message;
1761 } err_code_struct;
1762 
1763 /* Dos Error Messages */
1764 err_code_struct dos_msgs[] = {
1765   { "ERRbadfunc",1,"Invalid function."},
1766   { "ERRbadfile",2,"File not found."},
1767   { "ERRbadpath",3,"Directory invalid."},
1768   { "ERRnofids",4,"No file descriptors available"},
1769   { "ERRnoaccess",5,"Access denied."},
1770   { "ERRbadfid",6,"Invalid file handle."},
1771   { "ERRbadmcb",7,"Memory control blocks destroyed."},
1772   { "ERRnomem",8,"Insufficient server memory to perform the requested function."},
1773   { "ERRbadmem",9,"Invalid memory block address."},
1774   { "ERRbadenv",10,"Invalid environment."},
1775   { "ERRbadformat",11,"Invalid format."},
1776   { "ERRbadaccess",12,"Invalid open mode."},
1777   { "ERRbaddata",13,"Invalid data."},
1778   { "ERR",14,"reserved."},
1779   { "ERRbaddrive",15,"Invalid drive specified."},
1780   { "ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
1781   { "ERRdiffdevice",17,"Not same device."},
1782   { "ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
1783   { "ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
1784   { "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."},
1785   { "ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
1786   { "ERRbadpipe",230,"Pipe invalid."},
1787   { "ERRpipebusy",231,"All instances of the requested pipe are busy."},
1788   { "ERRpipeclosing",232,"Pipe close in progress."},
1789   { "ERRnotconnected",233,"No process on other end of pipe."},
1790   { "ERRmoredata",234,"There is more data to be returned."},
1791   { NULL,-1,NULL}};
1792 
1793 /* Server Error Messages */
1794 err_code_struct server_msgs[] = { 
1795   { "ERRerror",1,"Non-specific error code."},
1796   { "ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
1797   { "ERRbadtype",3,"reserved."},
1798   { "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."},
1799   { "ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
1800   { "ERRinvnetname",6,"Invalid network name in tree connect."},
1801   { "ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
1802   { "ERRqfull",49,"Print queue full (files) -- returned by open print file."},
1803   { "ERRqtoobig",50,"Print queue full -- no space."},
1804   { "ERRqeof",51,"EOF on print queue dump."},
1805   { "ERRinvpfid",52,"Invalid print file FID."},
1806   { "ERRsmbcmd",64,"The server did not recognize the command received."},
1807   { "ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
1808   { "ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
1809   { "ERRreserved",68,"reserved."},
1810   { "ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
1811   { "ERRreserved",70,"reserved."},
1812   { "ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
1813   { "ERRpaused",81,"Server is paused."},
1814   { "ERRmsgoff",82,"Not receiving messages."},
1815   { "ERRnoroom",83,"No room to buffer message."},
1816   { "ERRrmuns",87,"Too many remote user names."},
1817   { "ERRtimeout",88,"Operation timed out."},
1818   { "ERRnoresource",89,"No resources currently available for request."},
1819   { "ERRtoomanyuids",90,"Too many UIDs active on this session."},
1820   { "ERRbaduid",91,"The UID is not known as a valid ID on this session."},
1821   { "ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
1822   { "ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
1823   { "ERRcontmpx",252,"Continue in MPX mode."},
1824   { "ERRreserved",253,"reserved."},
1825   { "ERRreserved",254,"reserved."},
1826   { "ERRnosupport",0xFFFF,"Function not supported."},
1827   { NULL,-1,NULL}};
1828 
1829 /* Hard Error Messages */
1830 err_code_struct hard_msgs[] = { 
1831   { "ERRnowrite",19,"Attempt to write on write-protected diskette."},
1832   { "ERRbadunit",20,"Unknown unit."},
1833   { "ERRnotready",21,"Drive not ready."},
1834   { "ERRbadcmd",22,"Unknown command."},
1835   { "ERRdata",23,"Data error (CRC)."},
1836   { "ERRbadreq",24,"Bad request structure length."},
1837   { "ERRseek",25 ,"Seek error."},
1838   { "ERRbadmedia",26,"Unknown media type."},
1839   { "ERRbadsector",27,"Sector not found."},
1840   { "ERRnopaper",28,"Printer out of paper."},
1841   { "ERRwrite",29,"Write fault."},
1842   { "ERRread",30,"Read fault."},
1843   { "ERRgeneral",31,"General failure."},
1844   { "ERRbadshare",32,"A open conflicts with an existing open."},
1845   { "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."},
1846   { "ERRwrongdisk",34,"The wrong disk was found in a drive."},
1847   { "ERRFCBUnavail",35,"No FCBs are available to process request."},
1848   { "ERRsharebufexc",36,"A sharing buffer has been exceeded."},
1849   { NULL,-1,NULL}
1850 };
1851 
1852 
1853 struct { 
1854         int code;
1855         char *class;
1856         err_code_struct *err_msgs;
1857 } err_classes[] = {  
1858   { 0,"SUCCESS",NULL},
1859   { 0x01,"ERRDOS",dos_msgs},
1860   { 0x02,"ERRSRV",server_msgs},
1861   { 0x03,"ERRHRD",hard_msgs},
1862   { 0x04,"ERRXOS",NULL},
1863   { 0xE1,"ERRRMX1",NULL},
1864   { 0xE2,"ERRRMX2",NULL},
1865   { 0xE3,"ERRRMX3",NULL},
1866   { 0xFF,"ERRCMD",NULL},
1867   { -1,NULL,NULL}
1868 };
1869 
1870 void
1871 smb_printerr(int class, int num)
     /* [previous][next][first][last][top][bottom][index][help] */
1872 {
1873         int i,j;
1874         err_code_struct *err;
1875 
1876         for (i=0; err_classes[i].class; i++) {
1877                 if (err_classes[i].code != class)
1878                         continue;
1879                 if (!err_classes[i].err_msgs) {
1880                         printk("%s - %d", err_classes[i].class, num);
1881                         return;
1882                 }
1883 
1884                 err = err_classes[i].err_msgs;
1885                 for (j=0; err[j].name; j++) {
1886                         if (num != err[j].code)
1887                                 continue;
1888                         printk("%s - %s (%s)",
1889                                err_classes[i].class, err[j].name,
1890                                err[j].message);
1891                         return;
1892                 }
1893         }
1894         
1895         printk("Unknown error - (%d,%d)", class, num);
1896         return;
1897 }
1898 
1899 #endif /* DEBUG_SMB > 0 */
1900 
1901 /*
1902  * Overrides for Emacs so that we follow Linus's tabbing style.
1903  * Emacs will notice this stuff at the end of the file and automatically
1904  * adjust the settings for this buffer only.  This must remain at the end
1905  * of the file.
1906  * ---------------------------------------------------------------------------
1907  * Local variables:
1908  * c-indent-level: 8
1909  * c-brace-imaginary-offset: 0
1910  * c-brace-offset: -8
1911  * c-argdecl-indent: 8
1912  * c-label-offset: -8
1913  * c-continued-statement-offset: 8
1914  * c-continued-brace-offset: 0
1915  * End:
1916  */

/* [previous][next][first][last][top][bottom][index][help] */