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

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