home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #9 / Amiga Plus CD - 2004 - No. 09.iso / amigaplus / tools / amigaos4_only / smbfs / source / proc.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-08-03  |  63.5 KB  |  2,617 lines

  1. /*
  2.  * $Id: proc.c,v 1.55 2004/05/18 08:39:13 obarthel Exp $
  3.  *
  4.  * :ts=8
  5.  *
  6.  * proc.c
  7.  *
  8.  * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
  9.  *
  10.  * 28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
  11.  *
  12.  * Modified for big endian support by Christian Starkjohann.
  13.  * Modified for use with AmigaOS by Olaf Barthel <olsen@sourcery.han.de>
  14.  */
  15.  
  16. #include "smbfs.h"
  17.  
  18. /*****************************************************************************/
  19.  
  20. #include <smb/smb.h>
  21. #include <smb/smbno.h>
  22. #include <smb/smb_fs.h>
  23.  
  24. /*****************************************************************************/
  25.  
  26. #define SMB_VWV(packet)    ((packet) + SMB_HEADER_LEN)
  27. #define SMB_CMD(packet)    ((packet)[8])
  28. #define SMB_WCT(packet)    ((packet)[SMB_HEADER_LEN - 1])
  29. #define SMB_BCC(packet)    smb_bcc(packet)
  30. #define SMB_BUF(packet)    ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
  31.  
  32. #define SMB_DIRINFO_SIZE 43
  33. #define SMB_STATUS_SIZE  21
  34.  
  35. /*****************************************************************************/
  36.  
  37. static INLINE byte * smb_encode_word(byte *p, word data);
  38. static INLINE byte * smb_decode_word(byte *p, word *data);
  39. static INLINE int utc2local(int time_value);
  40. static INLINE int local2utc(int time_value);
  41. static INLINE word smb_bcc(byte *packet);
  42. static INLINE int smb_verify(byte *packet, int command, int wct, int bcc);
  43. static byte *smb_encode_dialect(byte *p, const byte *name, int len);
  44. static byte *smb_encode_ascii(byte *p, const byte *name, int len);
  45. static void smb_encode_vblock(byte *p, const byte *data, word len, int unused_fs);
  46. static byte *smb_decode_data(byte *p, byte *data, word *data_len, int fs);
  47. static byte *smb_name_mangle(byte *p, const byte *name);
  48. static int date_dos2unix(unsigned short time_value, unsigned short date);
  49. static void date_unix2dos(int unix_date, unsigned short *time_value, unsigned short *date);
  50. static INLINE int smb_valid_packet(byte *packet);
  51. static int smb_errno(int errcls, int error);
  52. static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
  53. static int smb_retry(struct smb_server *server);
  54. static int smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc);
  55. static byte *smb_setup_header(struct smb_server *server, byte command, word wct, word bcc);
  56. static byte *smb_setup_header_exclusive(struct smb_server *server, byte command, word wct, word bcc);
  57. static int smb_proc_do_create(struct smb_server *server, const char *path, int len, struct smb_dirent *entry, word command);
  58. static char *smb_decode_dirent(char *p, struct smb_dirent *entry);
  59. static int smb_proc_readdir_short(struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry);
  60. static char *smb_decode_long_dirent(char *p, struct smb_dirent *finfo, int level);
  61. static int smb_proc_readdir_long(struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry);
  62. static int smb_proc_reconnect(struct smb_server *server);
  63. static void smb_printerr(int class, int num);
  64.  
  65. /*****************************************************************************/
  66.  
  67. /*****************************************************************************
  68.  *
  69.  *  Encoding/Decoding section
  70.  *
  71.  *****************************************************************************/
  72. static INLINE byte *
  73. smb_encode_word (byte * p, word data)
  74. {
  75.   p[0] = data & 0x00ffU;
  76.   p[1] = (data & 0xff00U) >> 8;
  77.   return &p[2];
  78. }
  79.  
  80. static INLINE byte *
  81. smb_decode_word (byte * p, word * data)
  82. {
  83.   (*data) = (word) p[0] | p[1] << 8;
  84.   return &(p[2]);
  85. }
  86.  
  87. byte *
  88. smb_encode_smb_length (byte * p, dword len)
  89. {
  90.   p[0] = p[1] = 0;
  91.   p[2] = (len & 0xFF00) >> 8;
  92.   p[3] = (len & 0xFF);
  93.  
  94.   if (len > 0xFFFF)
  95.     p[1] |= 0x01;
  96.  
  97.   return &p[4];
  98. }
  99.  
  100. static byte *
  101. smb_encode_dialect (byte * p, const byte * name, int len)
  102. {
  103.   (*p++) = 2;
  104.   strcpy (p, name);
  105.  
  106.   return p + len + 1;
  107. }
  108.  
  109. static byte *
  110. smb_encode_ascii (byte * p, const byte * name, int len)
  111. {
  112.   (*p++) = 4;
  113.   strcpy (p, name);
  114.  
  115.   return p + len + 1;
  116. }
  117.  
  118. static void
  119. smb_encode_vblock (byte * p, const byte * data, word len, int unused_fs)
  120. {
  121.   (*p++) = 5;
  122.   p = smb_encode_word (p, len);
  123.   memcpy (p, data, len);
  124. }
  125.  
  126. static byte *
  127. smb_decode_data (byte * p, byte * data, word * data_len, int unused_fs)
  128. {
  129.   word len;
  130.  
  131.   if (!((*p) == 1 || (*p) == 5))
  132.     LOG (("Warning! Data block not starting with 1 or 5\n"));
  133.  
  134.   len = WVAL (p, 1);
  135.   p += 3;
  136.  
  137.   memcpy (data, p, len);
  138.  
  139.   (*data_len) = len;
  140.  
  141.   return p + len;
  142. }
  143.  
  144. static byte *
  145. smb_name_mangle (byte * p, const byte * name)
  146. {
  147.   int len, pad = 0;
  148.  
  149.   len = strlen (name);
  150.  
  151.   if (len < 16)
  152.     pad = 16 - len;
  153.  
  154.   (*p++) = 2 * (len + pad);
  155.  
  156.   while ((*name) != '\0')
  157.   {
  158.     (*p++) = ((*name) >> 4) + 'A';
  159.     (*p++) = ((*name) & 0x0F) + 'A';
  160.  
  161.     name++;
  162.   }
  163.  
  164.   while (pad-- > 0)
  165.   {
  166.     (*p++) = 'C';
  167.     (*p++) = 'A';
  168.   }
  169.  
  170.   (*p++) = '\0';
  171.  
  172.   return p;
  173. }
  174.  
  175. static INLINE int
  176. utc2local (int time_value)
  177. {
  178.   int result;
  179.  
  180.   result = time_value - GetTimeZoneDelta();
  181.  
  182.   return result;
  183. }
  184.  
  185. static INLINE int
  186. local2utc (int time_value)
  187. {
  188.   int result;
  189.  
  190.   result = time_value + GetTimeZoneDelta();
  191.  
  192.   return result;
  193. }
  194.  
  195. /* Convert a MS-DOS time/date pair to a UNIX date (seconds since January 1st 1970). */
  196. static int
  197. date_dos2unix (unsigned short time_value, unsigned short date)
  198. {
  199.   time_t seconds;
  200.   struct tm tm;
  201.  
  202.   memset(&tm,0,sizeof(tm));
  203.  
  204.   tm.tm_sec  = 2 * (time_value & 0x1F);
  205.   tm.tm_min  = (time_value >> 5) & 0x3F;
  206.   tm.tm_hour = (time_value >> 11) & 0x1F;
  207.   tm.tm_mday = date & 0x1F;
  208.   tm.tm_mon  = ((date >> 5) & 0xF) - 1;
  209.   tm.tm_year = ((date >> 9) & 0x7F) + 80;
  210.  
  211.   seconds = MakeTime(&tm);
  212.  
  213.   return(seconds);
  214. }
  215.  
  216. /* Convert linear UNIX date to a MS-DOS time/date pair. */
  217. static void
  218. date_unix2dos (int unix_date, unsigned short *time_value, unsigned short *date)
  219. {
  220.   struct tm tm;
  221.  
  222.   LocalTime(unix_date,&tm);
  223.  
  224.   (*time_value) = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec / 2);
  225.   (*date) = ((tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday;
  226. }
  227.  
  228. /****************************************************************************
  229.  *
  230.  *  Support section.
  231.  *
  232.  ****************************************************************************/
  233. dword
  234. smb_len (byte * packet)
  235. {
  236.   return (dword)( ((packet[1] & 0x1) << 16L) | (packet[2] << 8L) | (packet[3]) );
  237. }
  238.  
  239. static INLINE word
  240. smb_bcc (byte * packet)
  241. {
  242.   int pos = SMB_HEADER_LEN + SMB_WCT (packet) * sizeof (word);
  243.  
  244.   return (word)(packet[pos] | packet[pos + 1] << 8);
  245. }
  246.  
  247. /* smb_valid_packet: We check if packet fulfills the basic
  248.    requirements of a smb packet */
  249. static INLINE int
  250. smb_valid_packet (byte * packet)
  251. {
  252.   int result;
  253.  
  254.   LOG (("len: %ld, wct: %ld, bcc: %ld\n", smb_len (packet), SMB_WCT (packet), SMB_BCC (packet)));
  255.  
  256.   result = (packet[4] == 0xff
  257.          && packet[5] == 'S'
  258.          && packet[6] == 'M'
  259.          && packet[7] == 'B'
  260.          && (smb_len (packet) + 4 == (dword)(
  261.              SMB_HEADER_LEN + SMB_WCT (packet) * 2 + SMB_BCC (packet) + 2))) ? 0 : (-EIO);
  262.  
  263.   return result;
  264. }
  265.  
  266. /* smb_verify: We check if we got the answer we expected, and if we
  267.    got enough data. If bcc == -1, we don't care. */
  268. static INLINE int
  269. smb_verify (byte * packet, int command, int wct, int bcc)
  270. {
  271.   return (SMB_CMD (packet) == command &&
  272.           SMB_WCT (packet) >= wct &&
  273.           (bcc == -1 || SMB_BCC (packet) >= bcc)) ? 0 : -EIO;
  274. }
  275.  
  276. static int
  277. smb_errno (int errcls, int error)
  278. {
  279.   int result,i;
  280.  
  281.   if (errcls)
  282.     smb_printerr (errcls, error);
  283.  
  284.   if (errcls == ERRDOS)
  285.   {
  286.     static const int map[][2] =
  287.     {
  288.       { ERRbadfunc,EINVAL },
  289.       { ERRbadfile,ENOENT },
  290.       { ERRbadpath,ENOENT },
  291.       { ERRnofids,EMFILE },
  292.       { ERRnoaccess,EACCES },
  293.       { ERRbadfid,EBADF },
  294.       { ERRbadmcb,EIO },
  295.       { ERRnomem,ENOMEM },
  296.       { ERRbadmem,EFAULT },
  297.       { ERRbadenv,EIO },
  298.       { ERRbadformat,EIO },
  299.       { ERRbadaccess,EACCES },
  300.       { ERRbaddata,E2BIG },
  301.       { ERRbaddrive,ENXIO },
  302.       { ERRremcd,EIO },
  303.       { ERRdiffdevice,EXDEV },
  304.       { ERRnofiles,0 },
  305.       { ERRbadshare,ETXTBSY },
  306.       { ERRlock,EDEADLK },
  307.       { ERRfilexists,EEXIST },
  308.       { 87,0 },/* Unknown error! */
  309.       { 183,EEXIST },/* This next error seems to occur on an mv when
  310.                         the destination exists */
  311.       { -1,-1 }
  312.     };
  313.  
  314.     result = EIO;
  315.  
  316.     for(i = 0 ; map[i][0] != -1 ; i++)
  317.     {
  318.       if(map[i][0] == error)
  319.       {
  320.         result = map[i][1];
  321.         break;
  322.       }
  323.     }
  324.   }
  325.   else if (errcls == ERRSRV)
  326.   {
  327.     static const int map[][2] =
  328.     {
  329.       { ERRerror,ENFILE },
  330.       { ERRbadpw,EINVAL },
  331.       { ERRbadtype,EIO },
  332.       { ERRaccess,EACCES },
  333.       { -1, -1 }
  334.     };
  335.  
  336.     result = EIO;
  337.  
  338.     for(i = 0 ; map[i][0] != -1 ; i++)
  339.     {
  340.       if(map[i][0] == error)
  341.       {
  342.         result = map[i][1];
  343.         break;
  344.       }
  345.     }
  346.   }
  347.   else if (errcls == ERRHRD)
  348.   {
  349.     static const int map[][2] =
  350.     {
  351.       { ERRnowrite,EROFS },
  352.       { ERRbadunit,ENODEV },
  353.       { ERRnotready,EBUSY },
  354.       { ERRbadcmd,EIO },
  355.       { ERRdata,EIO },
  356.       { ERRbadreq,ERANGE },
  357.       { ERRbadshare,ETXTBSY },
  358.       { ERRlock,EDEADLK },
  359.       { -1, -1 }
  360.     };
  361.  
  362.     result = EIO;
  363.  
  364.     for(i = 0 ; map[i][0] != -1 ; i++)
  365.     {
  366.       if(map[i][0] == error)
  367.       {
  368.         result = map[i][1];
  369.         break;
  370.       }
  371.     }
  372.   }
  373.   else if (errcls == ERRCMD)
  374.   {
  375.     result = EIO;
  376.   }
  377.   else
  378.   {
  379.     result = 0;
  380.   }
  381.  
  382.   return(result);
  383. }
  384.  
  385. #if DEBUG
  386.  
  387. static char
  388. print_char (char c)
  389. {
  390.   if ((c < ' ') || (c > '~'))
  391.     return '.';
  392.  
  393.   return c;
  394. }
  395.  
  396. static void
  397. smb_dump_packet (byte * packet)
  398. {
  399.   int i, j, len;
  400.   int errcls, error;
  401.  
  402.   errcls = (int) packet[9];
  403.   error = (int) (int) (packet[11] | packet[12] << 8);
  404.  
  405.   LOG (("smb_len = %ld  valid = %ld    \n", len = smb_len (packet), smb_valid_packet (packet)));
  406.   LOG (("smb_cmd = %ld  smb_wct = %ld  smb_bcc = %ld\n", packet[8], SMB_WCT (packet), SMB_BCC (packet)));
  407.   LOG (("smb_rcls = %ld smb_err = %ld\n", errcls, error));
  408.  
  409.   if (errcls)
  410.     smb_printerr (errcls, error);
  411.  
  412.   if (len > 100)
  413.     len = 100;
  414.  
  415.   PRINTHEADER();
  416.  
  417.   for (i = 0; i < len; i += 10)
  418.   {
  419.     PRINTF (("%03ld:", i));
  420.  
  421.     for (j = i; j < i + 10; j++)
  422.     {
  423.       if (j < len)
  424.         PRINTF (("%02lx ", packet[j]));
  425.       else
  426.         PRINTF (("   "));
  427.     }
  428.  
  429.     PRINTF ((": "));
  430.  
  431.     for (j = i; j < i + 10; j++)
  432.     {
  433.       if (j < len)
  434.         PRINTF (("%lc", print_char (packet[j])));
  435.     }
  436.  
  437.     PRINTF (("\n"));
  438.   }
  439. }
  440.  
  441. #endif /* DEBUG */
  442.  
  443. /* smb_request_ok: We expect the server to be locked. Then we do the
  444.    request and check the answer completely. When smb_request_ok
  445.    returns 0, you can be quite sure that everything went well. When
  446.    the answer is <=0, the returned number is a valid unix errno. */
  447. static int
  448. smb_request_ok (struct smb_server *s, int command, int wct, int bcc)
  449. {
  450.   int result;
  451.   int error;
  452.  
  453.   s->rcls = 0;
  454.   s->err = 0;
  455.  
  456.   result = smb_request (s);
  457.   if (result < 0)
  458.   {
  459.     LOG (("smb_request failed\n"));
  460.   }
  461.   else if ((error = smb_valid_packet (s->packet)) != 0)
  462.   {
  463.     LOG (("not a valid packet!\n"));
  464.     result = error;
  465.   }
  466.   else if (s->rcls != 0)
  467.   {
  468.     result = -smb_errno (s->rcls, s->err);
  469.   }
  470.   else if ((error = smb_verify (s->packet, command, wct, bcc)) != 0)
  471.   {
  472.     LOG (("smb_verify failed\n"));
  473.     result = error;
  474.   }
  475.  
  476.   return(result);
  477. }
  478.  
  479. /* smb_retry: This function should be called when smb_request_ok has
  480.    indicated an error. If the error was indicated because the
  481.    connection was killed, we try to reconnect. If smb_retry returns 0,
  482.    the error was indicated for another reason, so a retry would not be
  483.    of any use. */
  484. static int
  485. smb_retry (struct smb_server *server)
  486. {
  487.   int result = 0;
  488.  
  489.   if (server->state == CONN_VALID)
  490.     goto out;
  491.  
  492.   if (smb_release (server) < 0)
  493.   {
  494.     LOG (("smb_retry: smb_release failed\n"));
  495.     server->state = CONN_RETRIED;
  496.     goto out;
  497.   }
  498.  
  499.   if (smb_proc_reconnect (server) < 0)
  500.   {
  501.     LOG (("smb_proc_reconnect failed\n"));
  502.     server->state = CONN_RETRIED;
  503.     goto out;
  504.   }
  505.  
  506.   server->state = CONN_VALID;
  507.   result = 1;
  508.  
  509.  out:
  510.  
  511.   return result;
  512. }
  513.  
  514. static int
  515. smb_request_ok_unlock (struct smb_server *s, int command, int wct, int bcc)
  516. {
  517.   int result;
  518.  
  519.   result = smb_request_ok (s, command, wct, bcc);
  520.  
  521.   return result;
  522. }
  523.  
  524. /* smb_setup_header: We completely set up the packet. You only have to
  525.    insert the command-specific fields */
  526. static byte *
  527. smb_setup_header (struct smb_server *server, byte command, word wct, word bcc)
  528. {
  529.   dword xmit_len = SMB_HEADER_LEN + wct * sizeof (word) + bcc + 2;
  530.   byte *p = server->packet;
  531.   byte *buf = server->packet;
  532.  
  533.   p = smb_encode_smb_length (p, xmit_len);
  534.  
  535.   BSET (p, 0, 0xff);
  536.   BSET (p, 1, 'S');
  537.   BSET (p, 2, 'M');
  538.   BSET (p, 3, 'B');
  539.   BSET (p, 4, command);
  540.  
  541.   p += 5;
  542.   memset (p, '\0', 19);
  543.   p += 19;
  544.   p += 8;
  545.  
  546.   WSET (buf, smb_tid, server->tid);
  547.   WSET (buf, smb_pid, 0); /* server->pid */
  548.   WSET (buf, smb_uid, server->server_uid);
  549.   WSET (buf, smb_mid, 0); /* server->mid */
  550.  
  551.   if (server->protocol > PROTOCOL_CORE)
  552.   {
  553.     BSET (buf, smb_flg, 0x8);
  554.     WSET (buf, smb_flg2, 0x3);
  555.   }
  556.  
  557.   (*p++) = wct; /* wct */
  558.   p += 2 * wct;
  559.   WSET (p, 0, bcc);
  560.  
  561.   return p + 2;
  562. }
  563.  
  564. /* smb_setup_header_exclusive waits on server->lock and locks the
  565.    server, when it's free. You have to unlock it manually when you're
  566.    finished with server->packet! */
  567. static byte *
  568. smb_setup_header_exclusive (struct smb_server *server, byte command, word wct, word bcc)
  569. {
  570.   byte * result;
  571.  
  572.   result = smb_setup_header (server, command, wct, bcc);
  573.  
  574.   return result;
  575. }
  576.  
  577. /*****************************************************************************
  578.  *
  579.  *  File operation section.
  580.  *
  581.  ****************************************************************************/
  582.  
  583. int
  584. smb_proc_open (struct smb_server *server, const char *pathname, int len, struct smb_dirent *entry)
  585. {
  586.   int error;
  587.   char *p;
  588.   char *buf = server->packet;
  589.   const word o_attr = aSYSTEM | aHIDDEN | aDIR;
  590.  
  591.   LOG (("path=%s\n", pathname));
  592.  
  593.  retry:
  594.  
  595.   p = smb_setup_header (server, SMBopen, 2, 2 + len);
  596.   WSET (buf, smb_vwv0, 0x42); /* read/write */
  597.   WSET (buf, smb_vwv1, o_attr);
  598.   smb_encode_ascii (p, pathname, len);
  599.  
  600.   if ((error = smb_request_ok (server, SMBopen, 7, 0)) < 0)
  601.   {
  602.     if (smb_retry (server))
  603.       goto retry;
  604.  
  605.     if (error != -EACCES)
  606.       goto out;
  607.  
  608.     p = smb_setup_header (server, SMBopen, 2, 2 + len);
  609.     WSET (buf, smb_vwv0, 0x40); /* read only */
  610.     WSET (buf, smb_vwv1, o_attr);
  611.     smb_encode_ascii (p, pathname, len);
  612.  
  613.     if ((error = smb_request_ok (server, SMBopen, 7, 0)) < 0)
  614.     {
  615.       if (smb_retry (server))
  616.         goto retry;
  617.  
  618.       goto out;
  619.     }
  620.   }
  621.  
  622.   /* We should now have data in vwv[0..6]. */
  623.   entry->fileid = WVAL (buf, smb_vwv0);
  624.   entry->attr = WVAL (buf, smb_vwv1);
  625.   entry->ctime = entry->atime = entry->mtime = local2utc (DVAL (buf, smb_vwv2));
  626.   entry->size = DVAL (buf, smb_vwv4);
  627.   entry->opened = 1;
  628.  
  629.  out:
  630.  
  631.   return error;
  632. }
  633.  
  634. /* smb_proc_close: in finfo->mtime we can send a modification time to
  635.    the server */
  636. int
  637. smb_proc_close (struct smb_server *server, word fileid, dword mtime)
  638. {
  639.   char *buf = server->packet;
  640.   int local_time;
  641.   int result;
  642.  
  643.   if(mtime != 0 && mtime != 0xffffffff)
  644.   {
  645.     /* 0 and 0xffffffff mean: do not set mtime */
  646.     local_time = utc2local (mtime);
  647.   }
  648.   else
  649.   {
  650.     local_time = mtime;
  651.   }
  652.  
  653.   smb_setup_header_exclusive (server, SMBclose, 3, 0);
  654.   WSET (buf, smb_vwv0, fileid);
  655.   DSET (buf, smb_vwv1, local_time);
  656.  
  657.   result = smb_request_ok_unlock (server, SMBclose, 0, 0);
  658.  
  659.   return result;
  660. }
  661.  
  662. /* In smb_proc_read and smb_proc_write we do not retry, because the
  663.    file-id would not be valid after a reconnection. */
  664.  
  665. /* smb_proc_read: fs indicates if it should be copied with
  666.    memcpy_tofs. */
  667. int
  668. smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data, int fs)
  669. {
  670.   word returned_count, data_len;
  671.   char *buf = server->packet;
  672.   int result;
  673.   int error;
  674.  
  675.   smb_setup_header_exclusive (server, SMBread, 5, 0);
  676.  
  677.   WSET (buf, smb_vwv0, finfo->fileid);
  678.   WSET (buf, smb_vwv1, count);
  679.   DSET (buf, smb_vwv2, offset);
  680.   WSET (buf, smb_vwv4, 0);
  681.  
  682.   if ((error = smb_request_ok (server, SMBread, 5, -1)) < 0)
  683.   {
  684.     result = error;
  685.     goto out;
  686.   }
  687.  
  688.   returned_count = WVAL (buf, smb_vwv0);
  689.  
  690.   smb_decode_data (SMB_BUF (server->packet), data, &data_len, fs);
  691.  
  692.   if (returned_count != data_len)
  693.   {
  694.     LOG (("Warning, returned_count != data_len\n"));
  695.     LOG (("ret_c=%ld, data_len=%ld\n", returned_count, data_len));
  696.   }
  697.   else
  698.   {
  699.     LOG (("ret_c=%ld, data_len=%ld\n", returned_count, data_len));
  700.   }
  701.  
  702.   result = data_len;
  703.  
  704.  out:
  705.  
  706.   return result;
  707. }
  708.  
  709. /* count must be <= 65535. No error number is returned.  A result of 0
  710.    indicates an error, which has to be investigated by a normal read
  711.    call. */
  712. int
  713. smb_proc_read_raw (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data)
  714. {
  715.   char *buf = server->packet;
  716.   int result;
  717.  
  718.   smb_setup_header_exclusive (server, SMBreadbraw, 8, 0);
  719.  
  720.   WSET (buf, smb_vwv0, finfo->fileid);
  721.   DSET (buf, smb_vwv1, offset);
  722.   WSET (buf, smb_vwv3, count);
  723.   WSET (buf, smb_vwv4, 0);
  724.   DSET (buf, smb_vwv5, 0);
  725.  
  726.   result = smb_request_read_raw (server, data, count);
  727.  
  728.   return result;
  729. }
  730.  
  731. int
  732. smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, const char *data)
  733. {
  734.   int res;
  735.   char *buf = server->packet;
  736.   byte *p;
  737.  
  738.   p = smb_setup_header_exclusive (server, SMBwrite, 5, count + 3);
  739.   WSET (buf, smb_vwv0, finfo->fileid);
  740.   WSET (buf, smb_vwv1, count);
  741.   DSET (buf, smb_vwv2, offset);
  742.   WSET (buf, smb_vwv4, 0);
  743.  
  744.   (*p++) = 1;
  745.   WSET (p, 0, count);
  746.   memcpy (p + 2, data, count);
  747.  
  748.   if ((res = smb_request_ok (server, SMBwrite, 1, 0)) >= 0)
  749.     res = WVAL (buf, smb_vwv0);
  750.  
  751.   return res;
  752. }
  753.  
  754. /* count must be <= 65535 */
  755. int
  756. smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, const char *data)
  757. {
  758.   char *buf = server->packet;
  759.   int result;
  760.   long len = server->max_xmit - 4;
  761.   byte *p;
  762.  
  763.   if (len >= count)
  764.     len = 0;
  765.   else
  766.     len = count - len;  /* transfer the larger part using the second packet */
  767.  
  768.   p = smb_setup_header_exclusive (server, SMBwritebraw, 11, len);
  769.  
  770.   WSET (buf, smb_vwv0, finfo->fileid);
  771.   DSET (buf, smb_vwv1, count);
  772.   DSET (buf, smb_vwv3, offset);
  773.   DSET (buf, smb_vwv5, 0);      /* timeout */
  774.   WSET (buf, smb_vwv7, 1);      /* send final result response */
  775.   DSET (buf, smb_vwv8, 0);      /* reserved */
  776.  
  777.   if (server->protocol > PROTOCOL_COREPLUS)
  778.   {
  779.     WSET (buf, smb_vwv10, len);
  780.     WSET (buf, smb_vwv11, p - smb_base(buf));
  781.   }
  782.  
  783.   if (len > 0)
  784.     memcpy (p, data, len);
  785.  
  786.   result = smb_request_ok (server, SMBwritebraw, 1, 0);
  787.  
  788.   LOG (("first request returned %ld\n", result));
  789.  
  790.   if (result < 0)
  791.     goto out;
  792.  
  793.   result = smb_request_write_raw (server, data + len, count - len);
  794.  
  795.   LOG(("raw request returned %ld\n", result));
  796.  
  797.   if (result > 0)
  798.   {
  799.     int error;
  800.  
  801.     /* We have to do the checks of smb_request_ok here as well */
  802.     if ((error = smb_valid_packet (server->packet)) != 0)
  803.     {
  804.       LOG (("not a valid packet!\n"));
  805.       result = error;
  806.     }
  807.     else if (server->rcls != 0)
  808.     {
  809.       result = -smb_errno (server->rcls, server->err);
  810.     }
  811.     else if ((error = smb_verify (server->packet, SMBwritec, 1, 0)) != 0)
  812.     {
  813.       LOG (("smb_verify failed\n"));
  814.       result = error;
  815.     }
  816.  
  817.     /* If everything went fine, the whole block has been transfered. */
  818.     if (result == (count - len))
  819.       result = count;
  820.   }
  821.  
  822.  out:
  823.  
  824.   return result;
  825. }
  826.  
  827. int
  828. smb_proc_lseek (struct smb_server *server, struct smb_dirent *finfo, off_t offset, int mode, off_t * new_position_ptr)
  829. {
  830.   char *buf = server->packet;
  831.   int error;
  832.  
  833.  retry:
  834.  
  835.   smb_setup_header (server, SMBlseek, 4,0);
  836.  
  837.   WSET (buf, smb_vwv0, finfo->fileid);
  838.   WSET (buf, smb_vwv1, mode);
  839.   DSET (buf, smb_vwv2, offset);
  840.  
  841.   if ((error = smb_request_ok (server, SMBlseek, 1, 0)) < 0)
  842.   {
  843.     if (smb_retry (server))
  844.       goto retry;
  845.   }
  846.   else
  847.   {
  848.     (*new_position_ptr) = DVAL(buf, smb_vwv0);
  849.   }
  850.  
  851.   return error;
  852. }
  853.  
  854. /* smb_proc_lockingX: We don't chain any further packets to the initial one  */
  855. int
  856. smb_proc_lockingX (struct smb_server *server, struct smb_dirent *finfo, struct smb_lkrng *locks, int num_entries, int mode, long timeout)
  857. {
  858.   int result;
  859.   int num_locks, num_unlocks;
  860.   char *buf = server->packet;
  861.   char *data;
  862.   struct smb_lkrng *p;
  863.   int i;
  864.  
  865.   num_locks = num_unlocks = 0;
  866.  
  867.   if (mode & 2)
  868.     num_unlocks = num_entries;
  869.   else
  870.     num_locks = num_entries;
  871.  
  872.  retry:
  873.  
  874.   data = smb_setup_header(server, SMBlockingX, 8, num_entries * 10);
  875.  
  876.   BSET (buf, smb_vwv0, 0xFF);
  877.   WSET (buf, smb_vwv1, 0);
  878.   WSET (buf, smb_vwv2, finfo->fileid);
  879.   BSET (buf, smb_vwv3, mode & 1);
  880.   DSET (buf, smb_vwv4, timeout);
  881.   WSET (buf, smb_vwv6, num_unlocks);
  882.   WSET (buf, smb_vwv7, num_locks);
  883.  
  884.   for (i = 0, p = locks; i < num_entries; i++, p++)
  885.   {
  886.     WSET (data, SMB_LPID_OFFSET(i), 0);  /* server->pid */
  887.     DSET (data, SMB_LKOFF_OFFSET(i), p->offset);
  888.     DSET (data, SMB_LKLEN_OFFSET(i), p->len);
  889.   }
  890.  
  891.   if ((result = smb_request_ok (server, SMBlockingX, 0, 0)) < 0)
  892.   {
  893.     if (smb_retry (server))
  894.       goto retry;
  895.   }
  896.   
  897.   return result;
  898. }
  899.  
  900. /* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */
  901. static int
  902. smb_proc_do_create (struct smb_server *server, const char *path, int len, struct smb_dirent *entry, word command)
  903. {
  904.   int error;
  905.   char *p;
  906.   char *buf = server->packet;
  907.   int local_time;
  908.  
  909.  retry:
  910.  
  911.   p = smb_setup_header (server, command, 3, len + 2);
  912.   WSET (buf, smb_vwv0, entry->attr);
  913.   local_time = utc2local (entry->ctime);
  914.   DSET (buf, smb_vwv1, local_time);
  915.   smb_encode_ascii (p, path, len);
  916.  
  917.   if ((error = smb_request_ok (server, command, 1, 0)) < 0)
  918.   {
  919.     if (smb_retry (server))
  920.       goto retry;
  921.  
  922.     goto out;
  923.   }
  924.  
  925.   entry->opened = 1;
  926.   entry->fileid = WVAL (buf, smb_vwv0);
  927.  
  928.   smb_proc_close (server, entry->fileid, entry->mtime);
  929.  
  930.  out:
  931.  
  932.   return error;
  933. }
  934.  
  935. int
  936. smb_proc_create (struct smb_server *server, const char *path, int len, struct smb_dirent *entry)
  937. {
  938.   return smb_proc_do_create (server, path, len, entry, SMBcreate);
  939. }
  940.  
  941. int
  942. smb_proc_mv (struct smb_server *server, const char *opath, const int olen, const char *npath, const int nlen)
  943. {
  944.   char *p;
  945.   char *buf = server->packet;
  946.   int result;
  947.  
  948.  retry:
  949.  
  950.   p = smb_setup_header (server, SMBmv, 1, olen + nlen + 4);
  951.  
  952.   WSET (buf, smb_vwv0, 0);
  953.  
  954.   p = smb_encode_ascii (p, opath, olen);
  955.   smb_encode_ascii (p, npath, olen);
  956.  
  957.   if ((result = smb_request_ok (server, SMBmv, 0, 0)) < 0)
  958.   {
  959.     if (smb_retry (server))
  960.       goto retry;
  961.   }
  962.  
  963.   return result;
  964. }
  965.  
  966. int
  967. smb_proc_mkdir (struct smb_server *server, const char *path, const int len)
  968. {
  969.   char *p;
  970.   int result;
  971.  
  972.  retry:
  973.  
  974.   p = smb_setup_header (server, SMBmkdir, 0, 2 + len);
  975.  
  976.   smb_encode_ascii (p, path, len);
  977.  
  978.   if ((result = smb_request_ok (server, SMBmkdir, 0, 0)) < 0)
  979.   {
  980.     if (smb_retry (server))
  981.       goto retry;
  982.   }
  983.  
  984.   return result;
  985. }
  986.  
  987. int
  988. smb_proc_rmdir (struct smb_server *server, const char *path, const int len)
  989. {
  990.   char *p;
  991.   int result;
  992.  
  993.  retry:
  994.  
  995.   p = smb_setup_header (server, SMBrmdir, 0, 2 + len);
  996.  
  997.   smb_encode_ascii (p, path, len);
  998.  
  999.   if ((result = smb_request_ok (server, SMBrmdir, 0, 0)) < 0)
  1000.   {
  1001.     if (smb_retry (server))
  1002.       goto retry;
  1003.   }
  1004.  
  1005.   return result;
  1006. }
  1007.  
  1008. int
  1009. smb_proc_unlink (struct smb_server *server, const char *path, const int len)
  1010. {
  1011.   char *p;
  1012.   char *buf = server->packet;
  1013.   int result;
  1014.  
  1015.  retry:
  1016.  
  1017.   p = smb_setup_header (server, SMBunlink, 1, 2 + len);
  1018.  
  1019.   WSET (buf, smb_vwv0, 0);
  1020.  
  1021.   smb_encode_ascii (p, path, len);
  1022.  
  1023.   if ((result = smb_request_ok (server, SMBunlink, 0, 0)) < 0)
  1024.   {
  1025.     if (smb_retry (server))
  1026.       goto retry;
  1027.   }
  1028.  
  1029.   return result;
  1030. }
  1031.  
  1032. int
  1033. smb_proc_trunc (struct smb_server *server, word fid, dword length)
  1034. {
  1035.   char *p;
  1036.   char *buf = server->packet;
  1037.   int result;
  1038.  
  1039.   p = smb_setup_header (server, SMBwrite, 5, 3);
  1040.   WSET (buf, smb_vwv0, fid);
  1041.   WSET (buf, smb_vwv1, 0);
  1042.   DSET (buf, smb_vwv2, length);
  1043.   WSET (buf, smb_vwv4, 0);
  1044.   smb_encode_ascii (p, "", 0);
  1045.  
  1046.   result = smb_request_ok (server, SMBwrite, 1, 0);
  1047.   if (result >= 0)
  1048.     result = DVAL(buf, smb_vwv0);
  1049.  
  1050.   return result;
  1051. }
  1052.  
  1053. static char *
  1054. smb_decode_dirent (char *p, struct smb_dirent *entry)
  1055. {
  1056.   size_t name_size;
  1057.  
  1058.   p += SMB_STATUS_SIZE; /* reserved (search_status) */
  1059.  
  1060.   entry->attr = BVAL (p, 0);
  1061.   entry->mtime = entry->atime = entry->ctime = date_dos2unix (WVAL (p, 1), WVAL (p, 3));
  1062.   entry->size = DVAL (p, 5);
  1063.  
  1064.   name_size = 13;
  1065.  
  1066.   if(name_size > entry->complete_path_size-1)
  1067.     name_size = entry->complete_path_size-1;
  1068.  
  1069.   memcpy (entry->complete_path, p + 9, name_size);
  1070.  
  1071.   entry->complete_path[name_size] = '\0';
  1072.  
  1073.   LOG (("smb_decode_dirent: path = %s\n", entry->complete_path));
  1074.  
  1075.   return p + 22;
  1076. }
  1077.  
  1078. /* This routine is used to read in directory entries from the network.
  1079.    Note that it is for short directory name seeks, i.e.: protocol < PROTOCOL_LANMAN2 */
  1080. static int
  1081. smb_proc_readdir_short (struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry)
  1082. {
  1083.   char *p;
  1084.   char *buf;
  1085.   int error;
  1086.   int result = 0;
  1087.   int i;
  1088.   int first, total_count;
  1089.   struct smb_dirent *current_entry;
  1090.   word bcc;
  1091.   word count;
  1092.   char status[SMB_STATUS_SIZE];
  1093.   int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE;
  1094.   int dirlen = strlen (path);
  1095.   char * mask;
  1096.  
  1097.   mask = malloc(dirlen + 4 + 1);
  1098.   if (mask == NULL)
  1099.   {
  1100.      result = (-ENOMEM);
  1101.      goto out;
  1102.   }
  1103.  
  1104.   strcpy (mask, path);
  1105.   strcat (mask, "\\*.*");
  1106.  
  1107.   LOG (("SMB call  readdir %ld @ %ld\n", cache_size, fpos));
  1108.   LOG (("          mask = %s\n", mask));
  1109.  
  1110.   buf = server->packet;
  1111.  
  1112.  retry:
  1113.  
  1114.   first = 1;
  1115.   total_count = 0;
  1116.   current_entry = entry;
  1117.  
  1118.   while (1)
  1119.   {
  1120.     if (first == 1)
  1121.     {
  1122.       p = smb_setup_header (server, SMBsearch, 2, 5 + strlen (mask));
  1123.       WSET (buf, smb_vwv0, entries_asked);
  1124.       WSET (buf, smb_vwv1, aDIR);
  1125.       p = smb_encode_ascii (p, mask, strlen (mask));
  1126.       (*p++) = 5;
  1127.       (void) smb_encode_word (p, 0);
  1128.     }
  1129.     else
  1130.     {
  1131.       p = smb_setup_header (server, SMBsearch, 2, 5 + SMB_STATUS_SIZE);
  1132.       WSET (buf, smb_vwv0, entries_asked);
  1133.       WSET (buf, smb_vwv1, aDIR);
  1134.       p = smb_encode_ascii (p, "", 0);
  1135.       (void) smb_encode_vblock (p, status, SMB_STATUS_SIZE, 0);
  1136.     }
  1137.  
  1138.     if ((error = smb_request_ok (server, SMBsearch, 1, -1)) < 0)
  1139.     {
  1140.       if ((server->rcls == ERRDOS) && (server->err == ERRnofiles))
  1141.       {
  1142.         result = total_count - fpos;
  1143.         goto unlock_return;
  1144.       }
  1145.       else
  1146.       {
  1147.         if (smb_retry (server))
  1148.           goto retry;
  1149.  
  1150.         result = error;
  1151.  
  1152.         goto unlock_return;
  1153.       }
  1154.     }
  1155.  
  1156.     p = SMB_VWV (server->packet);
  1157.     p = smb_decode_word (p, &count); /* vwv[0] = count-returned */
  1158.     p = smb_decode_word (p, &bcc);
  1159.  
  1160.     first = 0;
  1161.  
  1162.     if (count <= 0)
  1163.     {
  1164.       result = total_count - fpos;
  1165.  
  1166.       goto unlock_return;
  1167.     }
  1168.  
  1169.     if (bcc != count * SMB_DIRINFO_SIZE + 3)
  1170.     {
  1171.       result = -EIO;
  1172.  
  1173.       goto unlock_return;
  1174.     }
  1175.  
  1176.     p += 3; /* Skipping VBLOCK header (5, length lo, length hi). */
  1177.  
  1178.     /* Read the last entry into the status field. */
  1179.     memcpy (status, SMB_BUF (server->packet) + 3 + (count - 1) * SMB_DIRINFO_SIZE, SMB_STATUS_SIZE);
  1180.  
  1181.     /* Now we are ready to parse smb directory entries. */
  1182.  
  1183.     for (i = 0; i < count; i++)
  1184.     {
  1185.       if (total_count < fpos)
  1186.       {
  1187.         p += SMB_DIRINFO_SIZE;
  1188.  
  1189.         LOG (("smb_proc_readdir: skipped entry; total_count = %ld, i = %ld, fpos = %ld\n", total_count, i, fpos));
  1190.       }
  1191.       else if (total_count >= fpos + cache_size)
  1192.       {
  1193.         result = total_count - fpos;
  1194.  
  1195.         goto unlock_return;
  1196.       }
  1197.       else
  1198.       {
  1199.         p = smb_decode_dirent (p, current_entry);
  1200.  
  1201.         current_entry += 1;
  1202.       }
  1203.  
  1204.       total_count += 1;
  1205.     }
  1206.   }
  1207.  
  1208.  unlock_return:
  1209.  
  1210.   if(mask != NULL)
  1211.     free(mask);
  1212.  
  1213.  out:
  1214.  
  1215.   return result;
  1216. }
  1217.  
  1218. /*****************************************************************************/
  1219.  
  1220. #define MAX_DIGITS 4 /* NOTE: this is actually a hard-coded value (see below) */
  1221.  
  1222. /* Multiprecision arithmetics for beginners; we use 64 bits, chopped
  1223.  * into 16 bit pieces each. That allows us to comfortably execute all
  1224.  * calculations with 'long' arguments and not get into trouble because
  1225.  * of overflows and carry bits that don't exist. The assumption is that
  1226.  * the size of a 'long' is twice as large as that of a 'short'.
  1227.  */
  1228. struct digits
  1229. {
  1230.   unsigned short d[MAX_DIGITS];
  1231. };
  1232.  
  1233. /* Divide a multiprecision number by a positive integer. This is
  1234.  * essentially the division by a single "digit", as described in
  1235.  * Donald E. Knuth's "The Art of Computer Programming, Volume 2
  1236.  * Seminumerical Algorithms", 3rd edition, page 625 as the answer
  1237.  * to exercise 16 on page 282 in section 4.3.1. We don't really
  1238.  * need the more complex version since we just need to divide by
  1239.  * 10,000 and then by 1,000. The complex version is much more
  1240.  * complex than calling this division routine twice.
  1241.  */
  1242. static void
  1243. divide_by(struct digits * q,unsigned long d)
  1244. {
  1245.   int m;
  1246.  
  1247.   m = MAX_DIGITS;
  1248.   while(m > 0 && q->d[m-1] == 0)
  1249.     m--;
  1250.  
  1251.   if(m > 0)
  1252.   {
  1253.     unsigned long r,s;
  1254.     int j;
  1255.  
  1256.     r = 0;
  1257.     j = m - 1;
  1258.  
  1259.     do
  1260.     {
  1261.       r <<= 16;
  1262.  
  1263.       s = (r + q->d[j]);
  1264.  
  1265.       q->d[j] = s / d;
  1266.       r = s % d;
  1267.     }
  1268.     while(--j >= 0);
  1269.   }
  1270. }
  1271.  
  1272. /* This is an application of algorithm S ('Subtraction of
  1273.  * non-negative integers') described in Donald E. Knuth's
  1274.  * "The Art of Computer Programming, Volume 2 / Seminumerical
  1275.  * Algorithms", 3rd edition, page 267.
  1276.  */
  1277. static long
  1278. subtract_number(struct digits * u,unsigned long v)
  1279. {
  1280.   long d;
  1281.  
  1282.   /* This implementation takes advantage of the fact that
  1283.    * the 'width' of 'v' (64 bits) is just half the size of
  1284.    * 'u' (32 bits), which allows us to unroll the loop and
  1285.    * leave out some of the arguments which would not
  1286.    * contribute to the result anyway.
  1287.    */
  1288.  
  1289.   /* First round */
  1290.   d = ((long)u->d[0]) - (long)(v & 0xFFFF);
  1291.   u->d[0] = d;
  1292.  
  1293.   /* Second round */
  1294.   d = ((long)u->d[1]) - ((long)((v >> 16) & 0xFFFF)) - (d < 0);
  1295.   u->d[1] = d;
  1296.  
  1297.   /* Third round */
  1298.   d = ((long)u->d[2]) - (d < 0);
  1299.   u->d[2] = d;
  1300.  
  1301.   /* Fourth round */
  1302.   d = ((long)u->d[3]) - (d < 0);
  1303.   u->d[3] = d;
  1304.  
  1305.   return(d < 0);
  1306. }
  1307.  
  1308. /* Interpret an 8 byte "filetime" structure to a 'time_t'.
  1309.  * It's originally in "100ns units since jan 1st 1601".
  1310.  *
  1311.  * Unlike the Samba implementation of that date conversion
  1312.  * algorithm this one tries to perform the entire
  1313.  * calculation using integer operations only.
  1314.  */
  1315. static time_t
  1316. interpret_long_date(char * p)
  1317. {
  1318.   unsigned long hi,lo;
  1319.   struct digits d;
  1320.   time_t result;
  1321.   int i,k;
  1322.  
  1323.   /* Extract the 64 bit time value. */
  1324.   lo = DVAL(p,0);
  1325.   hi = DVAL(p,4);
  1326.  
  1327.   /* Chop the time into handy 16 bit chunks. */
  1328.   d.d[3] = hi >> 16;
  1329.   d.d[2] = hi & 0xFFFF;
  1330.   d.d[1] = lo >> 16;
  1331.   d.d[0] = lo & 0xFFFF;
  1332.  
  1333.   /* Divide by 10,000,000 in two easy pieces. */
  1334.   divide_by(&d,10000);
  1335.   divide_by(&d,1000);
  1336.  
  1337.   /* Adjust by 369 years (11,644,473,600 seconds). */
  1338.   k = 0;
  1339.   for(i = 0 ; k == 0 && i < 4 ; i++)
  1340.     k += subtract_number(&d,2911118400UL);
  1341.  
  1342.   /* If the result did not produce an underflow or overflow,
  1343.    * return the number of seconds encoded in the two least
  1344.    * significant 'digits'.
  1345.    */
  1346.   if(k == 0 && d.d[3] == 0 && d.d[2] == 0)
  1347.     result = (time_t)((((unsigned long)d.d[1]) << 16) + d.d[0]);
  1348.   else
  1349.     result = 0;
  1350.  
  1351.   return(result);
  1352. }
  1353.  
  1354. /*****************************************************************************/
  1355.  
  1356. static void
  1357. smb_get_dirent_name(char *p,int level,char ** name_ptr,int * len_ptr)
  1358. {
  1359.   switch (level)
  1360.   {
  1361.     case 1: /* OS/2 understands this */
  1362.       (*name_ptr) = p + 27;
  1363.       (*len_ptr) = strlen(p + 27);
  1364.       break;
  1365.  
  1366.     case 2: /* this is what OS/2 uses */
  1367.       (*name_ptr) = p + 31;
  1368.       (*len_ptr) = strlen(p + 31);
  1369.       break;
  1370.  
  1371.     case 260: /* NT uses this, but also accepts 2 */
  1372.       (*name_ptr) = p + 94;
  1373.       (*len_ptr) = min (DVAL (p+60, 0), SMB_MAXNAMELEN);
  1374.       break;
  1375.  
  1376.     default:
  1377.       (*name_ptr) = NULL;
  1378.       (*len_ptr) = 0;
  1379.       break;
  1380.   }
  1381. }
  1382.  
  1383. /* interpret a long filename structure - this is mostly guesses at the
  1384.    moment.  The length of the structure is returned.  The structure of
  1385.    a long filename depends on the info level. 260 is used by NT and 2
  1386.    is used by OS/2. */
  1387. static char *
  1388. smb_decode_long_dirent (char *p, struct smb_dirent *finfo, int level)
  1389. {
  1390.   char *result;
  1391.  
  1392.   switch (level)
  1393.   {
  1394.     case 1: /* OS/2 understands this */
  1395.  
  1396.       #if DEBUG
  1397.       {
  1398.         char buffer[255];
  1399.  
  1400.         memcpy(buffer,p + 27,sizeof(buffer)-1);
  1401.         buffer[sizeof(buffer)-1] = '\0';
  1402.  
  1403.         LOG(("type=%ld, name='%s'\n",level,buffer));
  1404.       }
  1405.       #endif /* DEBUG */
  1406.  
  1407.       if (finfo != NULL)
  1408.       {
  1409.         strlcpy (finfo->complete_path, p + 27, finfo->complete_path_size);
  1410.         finfo->len = strlen (finfo->complete_path);
  1411.         finfo->size = DVAL (p, 16);
  1412.         finfo->attr = BVAL (p, 24);
  1413.         finfo->ctime = date_dos2unix (WVAL (p, 6), WVAL (p, 4));
  1414.         finfo->atime = date_dos2unix (WVAL (p, 10), WVAL (p, 8));
  1415.         finfo->mtime = date_dos2unix (WVAL (p, 14), WVAL (p, 12));
  1416.       }
  1417.  
  1418.       result = p + 28 + BVAL (p, 26);
  1419.  
  1420.       break;
  1421.  
  1422.     case 2: /* this is what OS/2 uses */
  1423.  
  1424.       #if DEBUG
  1425.       {
  1426.         char buffer[255];
  1427.  
  1428.         memcpy(buffer,p + 31,sizeof(buffer)-1);
  1429.         buffer[sizeof(buffer)-1] = '\0';
  1430.  
  1431.         LOG(("type=%ld, name='%s'\n",level,buffer));
  1432.       }
  1433.       #endif /* DEBUG */
  1434.  
  1435.       if (finfo != NULL)
  1436.       {
  1437.         strlcpy (finfo->complete_path, p + 31, finfo->complete_path_size);
  1438.         finfo->len = strlen (finfo->complete_path);
  1439.         finfo->size = DVAL (p, 16);
  1440.         finfo->attr = BVAL (p, 24);
  1441.         finfo->ctime = date_dos2unix (WVAL (p, 6), WVAL (p, 4));
  1442.         finfo->atime = date_dos2unix (WVAL (p, 10), WVAL (p, 8));
  1443.         finfo->mtime = date_dos2unix (WVAL (p, 14), WVAL (p, 12));
  1444.       }
  1445.  
  1446.       result = p + 32 + BVAL (p, 30);
  1447.  
  1448.       break;
  1449.  
  1450.     case 260: /* NT uses this, but also accepts 2 */
  1451.  
  1452.       #if DEBUG
  1453.       {
  1454.         char buffer[255];
  1455.         int len;
  1456.  
  1457.         len = min (DVAL (p+60, 0), sizeof(buffer)-1);
  1458.  
  1459.         memcpy(buffer,p+94,len);
  1460.         buffer[len] = '\0';
  1461.  
  1462.         LOG(("type=%ld, name='%s'\n",level,buffer));
  1463.       }
  1464.       #endif /* DEBUG */
  1465.  
  1466.       result = p + WVAL (p, 0);
  1467.  
  1468.       if (finfo != NULL)
  1469.       {
  1470.         int namelen;
  1471.  
  1472.         p += 4;                   /* next entry offset */
  1473.         p += 4;                   /* fileindex */
  1474.         finfo->ctime = interpret_long_date(p);
  1475.         p += 8;
  1476.         finfo->atime = interpret_long_date(p);
  1477.         p += 8;
  1478.         p += 8;                   /* write time */
  1479.         finfo->mtime = interpret_long_date(p);
  1480.         p += 8;
  1481.         finfo->size = DVAL (p, 0);
  1482.         p += 8;
  1483.         p += 8;                   /* alloc size */
  1484.         finfo->attr = BVAL (p, 0);
  1485.         p += 4;
  1486.         namelen = min (DVAL (p, 0), SMB_MAXNAMELEN);
  1487.         p += 4;
  1488.         p += 4;                   /* EA size */
  1489.         p += 2;                   /* short name len? */
  1490.         p += 24;                  /* short name? */
  1491.  
  1492.         if(namelen > (int)finfo->complete_path_size-1)
  1493.           namelen = finfo->complete_path_size-1;
  1494.  
  1495.         memcpy (finfo->complete_path, p, namelen);
  1496.         finfo->complete_path[namelen] = '\0';
  1497.         finfo->len = namelen;
  1498.       }
  1499.  
  1500.       break;
  1501.  
  1502.     default:
  1503.  
  1504.       if (finfo != NULL)
  1505.       {
  1506.         /* I have to set times to 0 here, because I do not
  1507.            have specs about this for all info levels. */
  1508.         finfo->ctime = finfo->mtime = finfo->atime = 0;
  1509.       }
  1510.  
  1511.       LOG (("Unknown long filename format %ld\n", level));
  1512.  
  1513.       result = p + WVAL (p, 0);
  1514.  
  1515.       break;
  1516.   }
  1517.  
  1518.   return result;
  1519. }
  1520.  
  1521. static int
  1522. smb_proc_readdir_long (struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry)
  1523. {
  1524.   int max_matches = 512; /* this should actually be based on the max_xmit value */
  1525.  
  1526.   /* NT uses 260, OS/2 uses 2. Both accept 1. */
  1527.   int info_level = server->protocol < PROTOCOL_NT1 ? 1 : 260;
  1528.  
  1529.   char *p;
  1530.   int i;
  1531.   int first;
  1532.   int total_count = 0;
  1533.   struct smb_dirent *current_entry;
  1534.  
  1535.   char *resp_data;
  1536.   char *resp_param;
  1537.   int resp_data_len = 0;
  1538.   int resp_param_len = 0;
  1539.  
  1540.   int attribute = aSYSTEM | aHIDDEN | aDIR;
  1541.   int result;
  1542.   int error = 0;
  1543.  
  1544.   int ff_searchcount;
  1545.   int ff_eos = 0;
  1546.   int ff_dir_handle = 0;
  1547.   int ff_resume_key = 0;
  1548.   int loop_count = 0;
  1549.  
  1550.   unsigned char *outbuf = server->packet;
  1551.  
  1552.   int dirlen = strlen (path) + 2 + 1;
  1553.   char *mask;
  1554.   int masklen;
  1555.  
  1556.   ENTER();
  1557.  
  1558.   /* ZZZ experimental 'max_matches' adjustment */
  1559.   /*
  1560.   if(info_level == 260)
  1561.     max_matches = server->max_xmit / 360;
  1562.   else
  1563.     max_matches = server->max_xmit / 40;
  1564.   */
  1565.  
  1566.   SHOWVALUE(server->max_xmit);
  1567.   SHOWVALUE(max_matches);
  1568.  
  1569.   mask = malloc (dirlen);
  1570.   if (mask == NULL)
  1571.   {
  1572.     LOG (("Memory allocation failed\n"));
  1573.     error = (-ENOMEM);
  1574.     SHOWVALUE(error);
  1575.     goto out;
  1576.   }
  1577.  
  1578.   strcpy (mask, path);
  1579.   strcat (mask, "\\*");
  1580.   masklen = strlen (mask);
  1581.  
  1582.   LOG (("SMB call lreaddir %ld @ %ld\n", cache_size, fpos));
  1583.   LOG (("          mask = %s\n", mask));
  1584.  
  1585.   resp_param = NULL;
  1586.   resp_data = NULL;
  1587.  
  1588.  retry:
  1589.  
  1590.   first = 1;
  1591.   total_count = 0;
  1592.   current_entry = entry;
  1593.  
  1594.   while (ff_eos == 0)
  1595.   {
  1596.     loop_count++;
  1597.     if (loop_count > 200)
  1598.     {
  1599.       LOG (("smb_proc_readdir_long: Looping in FIND_NEXT???\n"));
  1600.       error = -EIO;
  1601.       SHOWVALUE(error);
  1602.       break;
  1603.     }
  1604.  
  1605.     memset (outbuf, 0, 39);
  1606.  
  1607.     smb_setup_header (server, SMBtrans2, 15, 5 + 12 + masklen + 1);
  1608.  
  1609.     WSET (outbuf, smb_tpscnt, 12 + masklen + 1);
  1610.     WSET (outbuf, smb_tdscnt, 0);
  1611.     WSET (outbuf, smb_mprcnt, 10);
  1612.     WSET (outbuf, smb_mdrcnt, server->max_xmit);
  1613.     WSET (outbuf, smb_msrcnt, 0);
  1614.     WSET (outbuf, smb_flags, 0);
  1615.     DSET (outbuf, smb_timeout, 0);
  1616.     WSET (outbuf, smb_pscnt, WVAL (outbuf, smb_tpscnt));
  1617.     WSET (outbuf, smb_psoff, ((SMB_BUF (outbuf) + 3) - outbuf) - 4);
  1618.     WSET (outbuf, smb_dscnt, 0);
  1619.     WSET (outbuf, smb_dsoff, 0);
  1620.     WSET (outbuf, smb_suwcnt, 1);
  1621.     WSET (outbuf, smb_setup0, first == 1 ? TRANSACT2_FINDFIRST : TRANSACT2_FINDNEXT);
  1622.  
  1623.     p = SMB_BUF (outbuf);
  1624.     (*p++) = 0;   /* put in a null smb_name */
  1625.     (*p++) = 'D';
  1626.     (*p++) = ' '; /* this was added because OS/2 does it */
  1627.  
  1628.     if (first != 0)
  1629.     {
  1630.       LOG (("first match\n"));
  1631.       WSET (p, 0, attribute);   /* attribute */
  1632.       WSET (p, 2, max_matches); /* max count */
  1633.       WSET (p, 4, 8 + 4 + 2);   /* resume required + close on end + continue */
  1634.       WSET (p, 6, info_level);
  1635.       DSET (p, 8, 0);
  1636.     }
  1637.     else
  1638.     {
  1639.       LOG (("next match; ff_dir_handle=0x%lx ff_resume_key=%ld mask='%s'\n", ff_dir_handle, ff_resume_key, mask));
  1640.       WSET (p, 0, ff_dir_handle);
  1641.       WSET (p, 2, max_matches); /* max count */
  1642.       WSET (p, 4, info_level);
  1643.       DSET (p, 6, ff_resume_key);
  1644.       WSET (p, 10, 8 + 4 + 2);  /* resume required + close on end + continue */
  1645.     }
  1646.  
  1647.     p += 12;
  1648.  
  1649.     if(masklen > 0)
  1650.       memcpy (p, mask, masklen);
  1651.  
  1652.     p += masklen;
  1653.     (*p++) = 0;
  1654.     (*p) = 0;
  1655.  
  1656.     result = smb_trans2_request (server, &resp_data_len, &resp_param_len, &resp_data, &resp_param);
  1657.  
  1658.     LOG (("smb_proc_readdir_long: smb_trans2_request returns %ld\n", result));
  1659.  
  1660.     if (result < 0)
  1661.     {
  1662.       if (smb_retry (server))
  1663.         goto retry;
  1664.  
  1665.       LOG (("smb_proc_readdir_long: got error from trans2_request\n"));
  1666.       error = result;
  1667.       SHOWVALUE(error);
  1668.       break;
  1669.     }
  1670.  
  1671.     /* Apparently, there is a bug in Windows 95 and friends which
  1672.        causes the directory read attempt to fail if you're asking
  1673.        for too much data too fast... */
  1674.     if(server->rcls == ERRSRV && server->err == ERRerror)
  1675.     {
  1676.       SHOWMSG("ouch; delaying and retrying");
  1677.  
  1678.       Delay(TICKS_PER_SECOND / 5);
  1679.  
  1680.       continue;
  1681.     }
  1682.  
  1683.     if (server->rcls != 0)
  1684.     {
  1685.       LOG (("server->rcls = %ld err = %ld\n",server->rcls, server->err));
  1686.       error = smb_errno (server->rcls, server->err);
  1687.       SHOWVALUE(error);
  1688.       break;
  1689.     }
  1690.  
  1691.     /* ZZZ bail out if this is empty. */
  1692.     if (resp_param == NULL)
  1693.       break;
  1694.  
  1695.     /* parse out some important return info */
  1696.     p = resp_param;
  1697.     if (first != 0)
  1698.     {
  1699.       ff_dir_handle = WVAL (p, 0);
  1700.       ff_searchcount = WVAL (p, 2);
  1701.       ff_eos = WVAL (p, 4);
  1702.     }
  1703.     else
  1704.     {
  1705.       ff_searchcount = WVAL (p, 0);
  1706.       ff_eos = WVAL (p, 2);
  1707.     }
  1708.  
  1709.     LOG (("received %ld entries (eos=%ld)\n",ff_searchcount, ff_eos));
  1710.     if (ff_searchcount == 0)
  1711.       break;
  1712.  
  1713.     /* ZZZ bail out if this is empty. */
  1714.     if (resp_data == NULL)
  1715.       break;
  1716.  
  1717.     /* point to the data bytes */
  1718.     p = resp_data;
  1719.  
  1720.     /* Now we are ready to parse smb directory entries. */
  1721.     for (i = 0; i < ff_searchcount; i++)
  1722.     {
  1723.       if(i == ff_searchcount - 1)
  1724.       {
  1725.         char * last_name;
  1726.         int len;
  1727.  
  1728.         ff_resume_key = DVAL(p, 0);
  1729.  
  1730.         smb_get_dirent_name(p,info_level,&last_name,&len);
  1731.         if(len > 0)
  1732.         {
  1733.           #if DEBUG
  1734.           {
  1735.             char buffer[SMB_MAXNAMELEN+1];
  1736.  
  1737.             memcpy(buffer,last_name,len);
  1738.             buffer[len] = '\0';
  1739.  
  1740.             LOG(("last name = '%s'\n",buffer));
  1741.           }
  1742.           #endif /* DEBUG */
  1743.  
  1744.           if(len + 1 > dirlen)
  1745.           {
  1746.             D(("increasing mask; old value = %ld new value = %ld",dirlen,len+1));
  1747.  
  1748.             if(mask != NULL)
  1749.               free (mask);
  1750.  
  1751.             dirlen = len + 1;
  1752.             SHOWVALUE(dirlen);
  1753.  
  1754.             mask = malloc (dirlen);
  1755.             if (mask == NULL)
  1756.             {
  1757.               LOG (("smb_proc_readdir_long: Memory allocation failed\n"));
  1758.  
  1759.               error = -ENOMEM;
  1760.  
  1761.               SHOWVALUE(error);
  1762.  
  1763.               goto fail;
  1764.             }
  1765.           }
  1766.  
  1767.           memcpy (mask, last_name, len);
  1768.           mask[len] = '\0';
  1769.           masklen = len;
  1770.         }
  1771.         else
  1772.         {
  1773.           masklen = 0;
  1774.         }
  1775.       }
  1776.  
  1777.       if (total_count < fpos)
  1778.       {
  1779.         p = smb_decode_long_dirent (p, NULL, info_level);
  1780.  
  1781.         LOG (("smb_proc_readdir: skipped entry; total_count = %ld, i = %ld, fpos = %ld\n",total_count, i, fpos));
  1782.       }
  1783.       else if (total_count >= fpos + cache_size)
  1784.       {
  1785.         p = smb_decode_long_dirent (p, NULL, info_level);
  1786.  
  1787.         LOG (("smb_proc_readdir: skipped entry; total_count = %ld, i = %ld, fpos = %ld\n",total_count, i, fpos));
  1788.  
  1789.         continue;
  1790.       }
  1791.       else
  1792.       {
  1793.         p = smb_decode_long_dirent (p, current_entry, info_level);
  1794.  
  1795.         current_entry += 1;
  1796.       }
  1797.  
  1798.       total_count += 1;
  1799.     }
  1800.  
  1801.     SHOWVALUE(ff_resume_key);
  1802.  
  1803.     if (resp_data != NULL)
  1804.     {
  1805.       free (resp_data);
  1806.       resp_data = NULL;
  1807.     }
  1808.  
  1809.     if (resp_param != NULL)
  1810.     {
  1811.       free (resp_param);
  1812.       resp_param = NULL;
  1813.     }
  1814.  
  1815.     first = 0;
  1816.  
  1817.     if (ff_searchcount > 0)
  1818.       loop_count = 0;
  1819.   }
  1820.  
  1821.  fail:
  1822.  
  1823.   /* finished: not needed any more */
  1824.   if (mask != NULL)
  1825.     free (mask);
  1826.  
  1827.   if (resp_data != NULL)
  1828.     free (resp_data);
  1829.  
  1830.   if (resp_param != NULL)
  1831.     free (resp_param);
  1832.  
  1833.  out:
  1834.  
  1835.   if(error < 0)
  1836.   {
  1837.     RETURN(error);
  1838.     return(error);
  1839.   }
  1840.   else
  1841.   {
  1842.     RETURN (total_count - fpos);
  1843.     return (total_count - fpos);
  1844.   }
  1845. }
  1846.  
  1847. int
  1848. smb_proc_readdir (struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry)
  1849. {
  1850.   int result;
  1851.  
  1852.   if (server->protocol >= PROTOCOL_LANMAN2)
  1853.     result = smb_proc_readdir_long (server, path, fpos, cache_size, entry);
  1854.   else
  1855.     result = smb_proc_readdir_short (server, path, fpos, cache_size, entry);
  1856.  
  1857.   return result;
  1858. }
  1859.  
  1860. int
  1861. smb_proc_getattr_core (struct smb_server *server, const char *path, int len, struct smb_dirent *entry)
  1862. {
  1863.   int result;
  1864.   char *p;
  1865.   char *buf = server->packet;
  1866.  
  1867.   LOG (("smb_proc_getattr: %s\n", path));
  1868.  
  1869.  retry:
  1870.  
  1871.   p = smb_setup_header (server, SMBgetatr, 0, 2 + len);
  1872.   smb_encode_ascii (p, path, len);
  1873.  
  1874.   if ((result = smb_request_ok (server, SMBgetatr, 10, 0)) < 0)
  1875.   {
  1876.     if (smb_retry (server))
  1877.       goto retry;
  1878.  
  1879.     goto out;
  1880.   }
  1881.  
  1882.   entry->attr = WVAL (buf, smb_vwv0);
  1883.  
  1884.   /* The server only tells us 1 time */
  1885.   entry->ctime = entry->atime = entry->mtime = local2utc (DVAL (buf, smb_vwv1));
  1886.  
  1887.   entry->size = DVAL (buf, smb_vwv3);
  1888.  
  1889.  out:
  1890.  
  1891.   return result;
  1892. }
  1893.  
  1894. /* smb_proc_getattrE: entry->fid must be valid */
  1895. int
  1896. smb_proc_getattrE (struct smb_server *server, struct smb_dirent *entry)
  1897. {
  1898.   char *buf = server->packet;
  1899.   int result;
  1900.  
  1901.   smb_setup_header_exclusive (server, SMBgetattrE, 1, 0);
  1902.   WSET (buf, smb_vwv0, entry->fileid);
  1903.  
  1904.   if ((result = smb_request_ok (server, SMBgetattrE, 11, 0)) < 0)
  1905.     goto out;
  1906.  
  1907.   entry->ctime = date_dos2unix (WVAL (buf, smb_vwv1), WVAL (buf, smb_vwv0));
  1908.   entry->atime = date_dos2unix (WVAL (buf, smb_vwv3), WVAL (buf, smb_vwv2));
  1909.   entry->mtime = date_dos2unix (WVAL (buf, smb_vwv5), WVAL (buf, smb_vwv4));
  1910.   entry->size = DVAL (buf, smb_vwv6);
  1911.   entry->attr = WVAL (buf, smb_vwv10);
  1912.  
  1913.  out:
  1914.  
  1915.   return result;
  1916. }
  1917.  
  1918. /* In core protocol, there is only 1 time to be set, we use
  1919.    entry->mtime, to make touch work. */
  1920. int
  1921. smb_proc_setattr_core (struct smb_server *server, const char *path, int len, struct smb_dirent *new_finfo)
  1922. {
  1923.   char *p;
  1924.   char *buf = server->packet;
  1925.   int result;
  1926.   int local_time;
  1927.  
  1928.  retry:
  1929.  
  1930.   LOG (("smb_proc_setattr_core\n"));
  1931.  
  1932.   p = smb_setup_header (server, SMBsetatr, 8, 4 + len);
  1933.   WSET (buf, smb_vwv0, new_finfo->attr);
  1934.   local_time = utc2local (new_finfo->mtime);
  1935.   DSET (buf, smb_vwv1, local_time);
  1936.   p = smb_encode_ascii (p, path, len);
  1937.   (void) smb_encode_ascii (p, "", 0);
  1938.  
  1939.   if ((result = smb_request_ok (server, SMBsetatr, 0, 0)) < 0)
  1940.   {
  1941.     if (smb_retry (server))
  1942.       goto retry;
  1943.   }
  1944.  
  1945.   return result;
  1946. }
  1947.  
  1948. /* smb_proc_setattrE: we do not retry here, because we rely on fid,
  1949.    which would not be valid after a retry. */
  1950. int
  1951. smb_proc_setattrE (struct smb_server *server, word fid, struct smb_dirent *new_entry)
  1952. {
  1953.   char *buf = server->packet;
  1954.   word date, time_value;
  1955.   int result;
  1956.  
  1957.   LOG (("smb_proc_setattrE\n"));
  1958.  
  1959.   smb_setup_header_exclusive (server, SMBsetattrE, 7, 0);
  1960.  
  1961.   WSET (buf, smb_vwv0, fid);
  1962.  
  1963.   date_unix2dos (new_entry->ctime, &time_value, &date);
  1964.   WSET (buf, smb_vwv1, date);
  1965.   WSET (buf, smb_vwv2, time_value);
  1966.  
  1967.   date_unix2dos (new_entry->atime, &time_value, &date);
  1968.   WSET (buf, smb_vwv3, date);
  1969.   WSET (buf, smb_vwv4, time_value);
  1970.  
  1971.   date_unix2dos (new_entry->mtime, &time_value, &date);
  1972.   WSET (buf, smb_vwv5, date);
  1973.   WSET (buf, smb_vwv6, time_value);
  1974.  
  1975.   result = smb_request_ok_unlock (server, SMBsetattrE, 0, 0);
  1976.  
  1977.   return result;
  1978. }
  1979.  
  1980. int
  1981. smb_proc_dskattr (struct smb_server *server, struct smb_dskattr *attr)
  1982. {
  1983.   int error;
  1984.   char *p;
  1985.  
  1986.  retry:
  1987.  
  1988.   smb_setup_header (server, SMBdskattr, 0, 0);
  1989.  
  1990.   if ((error = smb_request_ok (server, SMBdskattr, 5, 0)) < 0)
  1991.   {
  1992.     if (smb_retry (server))
  1993.       goto retry;
  1994.  
  1995.     goto out;
  1996.   }
  1997.  
  1998.   p = SMB_VWV (server->packet);
  1999.   p = smb_decode_word (p, &attr->total);
  2000.   p = smb_decode_word (p, &attr->allocblocks);
  2001.   p = smb_decode_word (p, &attr->blocksize);
  2002.   (void) smb_decode_word (p, &attr->free);
  2003.  
  2004.  out:
  2005.  
  2006.   return error;
  2007. }
  2008.  
  2009. /*****************************************************************************
  2010.  *
  2011.  *  Mount/umount operations.
  2012.  *
  2013.  ****************************************************************************/
  2014. struct smb_prots
  2015. {
  2016.   enum smb_protocol prot;
  2017.   const char *name;
  2018. };
  2019.  
  2020. /* smb_proc_reconnect: We expect the server to be locked, so that you
  2021.    can call the routine from within smb_retry. The socket must be
  2022.    created, like after a user-level socket()-call. It may not be
  2023.    connected. */
  2024. static int
  2025. smb_proc_reconnect (struct smb_server *server)
  2026. {
  2027.   static const struct smb_prots prots[] =
  2028.   {
  2029.     {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
  2030.     {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
  2031.     {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
  2032.     {PROTOCOL_LANMAN1, "LANMAN1.0"},
  2033.     {PROTOCOL_LANMAN2, "LM1.2X002"},
  2034.     {PROTOCOL_NT1, "NT LM 0.12"},
  2035.     {PROTOCOL_NT1, "NT LANMAN 1.0"},
  2036.  
  2037.     {-1, NULL}
  2038.   };
  2039.  
  2040.   char dev[] = "A:";
  2041.   int i, plength;
  2042.   int max_xmit = 1024; /* Space needed for first request. */
  2043.   int given_max_xmit = server->mount_data.max_xmit;
  2044.   int result;
  2045.   word any_word;
  2046.   byte *p;
  2047.   unsigned char password[24];
  2048.   int password_len;
  2049.   unsigned char nt_password[24];
  2050.   int nt_password_len;
  2051.   unsigned char full_share[SMB_MAXNAMELEN+1];
  2052.   int full_share_len;
  2053.   byte *packet;
  2054.  
  2055.   if (server->max_recv <= 0)
  2056.     server->max_recv = given_max_xmit > 8000 ? given_max_xmit : 8000;
  2057.  
  2058.   if ((result = smb_connect (server)) < 0)
  2059.   {
  2060.     LOG (("smb_proc_reconnect: could not smb_connect\n"));
  2061.     goto fail;
  2062.   }
  2063.  
  2064.   /* Here we assume that the connection is valid */
  2065.   server->state = CONN_VALID;
  2066.  
  2067.   if (server->packet != NULL)
  2068.     free (server->packet);
  2069.  
  2070.   server->packet = malloc (server->max_recv);
  2071.  
  2072.   if (server->packet == NULL)
  2073.   {
  2074.     LOG (("smb_proc_connect: No memory! Bailing out.\n"));
  2075.     result = -ENOMEM;
  2076.     goto fail;
  2077.   }
  2078.  
  2079.   packet = server->packet;
  2080.  
  2081.   server->max_xmit = max_xmit;
  2082.  
  2083.   /* Start with an RFC1002 session request packet. */
  2084.   p = packet + 4;
  2085.  
  2086.   p = smb_name_mangle (p, server->mount_data.server_name);
  2087.   p = smb_name_mangle (p, server->mount_data.client_name);
  2088.  
  2089.   smb_encode_smb_length (packet, (byte *) p - (byte *) (packet));
  2090.  
  2091.   packet[0] = 0x81; /* SESSION REQUEST */
  2092.  
  2093.   if ((result = smb_request (server)) < 0)
  2094.   {
  2095.     LOG (("smb_proc_connect: Failed to send SESSION REQUEST.\n"));
  2096.     goto fail;
  2097.   }
  2098.  
  2099.   if (packet[0] != 0x82)
  2100.   {
  2101.     LOG (("smb_proc_connect: Did not receive positive response (err = %lx)\n",packet[0]));
  2102.  
  2103.     #if DEBUG
  2104.     {
  2105.       smb_dump_packet (packet);
  2106.     }
  2107.     #endif /* DEBUG */
  2108.  
  2109.     result = -EIO;
  2110.     goto fail;
  2111.   }
  2112.  
  2113.   LOG (("smb_proc_connect: Passed SESSION REQUEST.\n"));
  2114.  
  2115.   /* Now we are ready to send a SMB Negotiate Protocol packet. */
  2116.   memset (packet, 0, SMB_HEADER_LEN);
  2117.  
  2118.   plength = 0;
  2119.   for (i = 0; prots[i].name != NULL; i++)
  2120.     plength += strlen (prots[i].name) + 2;
  2121.  
  2122.   smb_setup_header (server, SMBnegprot, 0, plength);
  2123.  
  2124.   p = SMB_BUF (packet);
  2125.  
  2126.   for (i = 0; prots[i].name != NULL; i++)
  2127.     p = smb_encode_dialect (p, prots[i].name, strlen (prots[i].name));
  2128.  
  2129.   LOG (("smb_proc_connect: Request SMBnegprot...\n"));
  2130.   if ((result = smb_request_ok (server, SMBnegprot, 1, -1)) < 0)
  2131.   {
  2132.     LOG (("smb_proc_connect: Failure requesting SMBnegprot\n"));
  2133.     goto fail;
  2134.   }
  2135.  
  2136.   LOG (("Verified!\n"));
  2137.  
  2138.   p = SMB_VWV (packet);
  2139.   p = smb_decode_word (p, &any_word);
  2140.   i = any_word;
  2141.  
  2142.   server->protocol = prots[i].prot;
  2143.  
  2144.   LOG (("smb_proc_connect: Server wants %s protocol.\n",prots[i].name));
  2145.  
  2146.   if (server->protocol > PROTOCOL_LANMAN1)
  2147.   {
  2148.     int user_len = strlen (server->mount_data.username)+1;
  2149.  
  2150.     LOG (("smb_proc_connect: password = %s\n",server->mount_data.password));
  2151.     LOG (("smb_proc_connect: usernam = %s\n",server->mount_data.username));
  2152.     LOG (("smb_proc_connect: blkmode = %ld\n",WVAL (packet, smb_vwv5)));
  2153.  
  2154.     if (server->protocol >= PROTOCOL_NT1)
  2155.     {
  2156.       server->maxxmt = DVAL (packet, smb_vwv3 + 1);
  2157.       server->blkmode = DVAL (packet, smb_vwv9 + 1);
  2158.       server->sesskey = DVAL (packet, smb_vwv7 + 1);
  2159.  
  2160.       server->security_mode = BVAL(packet, smb_vwv1);
  2161.  
  2162.       memcpy(server->crypt_key,SMB_BUF(packet),8);
  2163.     }
  2164.     else
  2165.     {
  2166.       server->maxxmt = WVAL (packet, smb_vwv2);
  2167.       server->blkmode = WVAL (packet, smb_vwv5);
  2168.       server->sesskey = DVAL (packet, smb_vwv6);
  2169.  
  2170.       server->security_mode = BVAL(packet, smb_vwv1);
  2171.  
  2172.       memcpy(server->crypt_key,SMB_BUF(packet),8);
  2173.     }
  2174.  
  2175.     SHOWVALUE(server->security_mode);
  2176.  
  2177.     if(server->security_mode & 2)
  2178.     {
  2179.       SHOWMSG("encrypted passwords required");
  2180.  
  2181.       memset(password,0,sizeof(password));
  2182.       strlcpy(password,server->mount_data.password,sizeof(password));
  2183.  
  2184.       smb_encrypt(password,server->crypt_key,password);
  2185.       password_len = 24;
  2186.  
  2187.       PRINTHEADER();
  2188.       PRINTF(("password: "));
  2189.       for(i = 0 ; i < 24 ; i++)
  2190.         PRINTF(("%02lx ",password[i]));
  2191.       PRINTF(("\n"));
  2192.  
  2193.       memset(nt_password,0,sizeof(nt_password));
  2194.       strlcpy(nt_password,server->mount_data.password,sizeof(nt_password));
  2195.  
  2196.       smb_nt_encrypt(nt_password,server->crypt_key,nt_password);
  2197.       nt_password_len = 24;
  2198.  
  2199.       PRINTHEADER();
  2200.       PRINTF(("nt_password: "));
  2201.       for(i = 0 ; i < 24 ; i++)
  2202.         PRINTF(("%02lx ",nt_password[i]));
  2203.       PRINTF(("\n"));
  2204.  
  2205.       PRINTHEADER();
  2206.       PRINTF(("crypt_key: "));
  2207.       for(i = 0 ; i < 8 ; i++)
  2208.         PRINTF(("%02lx ",server->crypt_key[i]));
  2209.       PRINTF(("\n"));
  2210.     }
  2211.     else
  2212.     {
  2213.       SHOWMSG("plain text passwords sufficient");
  2214.  
  2215.       password_len = strlen(server->mount_data.password)+1;
  2216.       nt_password_len = 0;
  2217.     }
  2218.  
  2219.     /* If in share level security then don't send a password now */
  2220.     if((server->security_mode & 1) == 0)
  2221.     {
  2222.       SHOWMSG("share level security; zapping passwords");
  2223.       strcpy(password,"");
  2224.       password_len = 0;
  2225.  
  2226.       strcpy(nt_password,"");
  2227.       nt_password_len = 0;
  2228.     }
  2229.  
  2230.     SHOWVALUE(password_len);
  2231.     SHOWVALUE(nt_password_len);
  2232.  
  2233.     LOG (("smb_proc_connect: workgroup = %s\n", server->mount_data.workgroup_name));
  2234.     if (server->protocol >= PROTOCOL_NT1)
  2235.     {
  2236.       char *OS_id = "AmigaOS";
  2237.       char *client_id = "smbfs";
  2238.  
  2239.       SHOWMSG("server->protocol >= PROTOCOL_NT1");
  2240.  
  2241.       smb_setup_header (server, SMBsesssetupX, 13, user_len + password_len + nt_password_len + strlen (server->mount_data.workgroup_name)+1 + strlen (OS_id)+1 + strlen (client_id)+1);
  2242.  
  2243.       WSET (packet, smb_vwv0, 0xff);
  2244.       WSET (packet, smb_vwv2, given_max_xmit);
  2245.       WSET (packet, smb_vwv3, 2);
  2246.       WSET (packet, smb_vwv4, 0); /* server->pid */
  2247.       DSET (packet, smb_vwv5, server->sesskey);
  2248.       WSET (packet, smb_vwv7, password_len);
  2249.       WSET (packet, smb_vwv8, nt_password_len);
  2250.  
  2251.       p = SMB_BUF (packet);
  2252.  
  2253.       if(nt_password_len != 0)
  2254.       {
  2255.         SHOWMSG("adding encrypted passwords");
  2256.  
  2257.         memcpy (p, password, password_len);
  2258.         p += password_len;
  2259.  
  2260.         memcpy (p, nt_password, nt_password_len);
  2261.         p += nt_password_len;
  2262.       }
  2263.       else
  2264.       {
  2265.         SHOWMSG("adding plain text password");
  2266.  
  2267.         memcpy (p, server->mount_data.password, password_len);
  2268.         p += password_len;
  2269.       }
  2270.  
  2271.       memcpy (p, server->mount_data.username, user_len);
  2272.       p += user_len;
  2273.  
  2274.       strcpy (p, server->mount_data.workgroup_name);
  2275.       p += strlen (p) + 1;
  2276.  
  2277.       strcpy (p, OS_id);
  2278.       p += strlen (p) + 1;
  2279.  
  2280.       strcpy (p, client_id);
  2281.     }
  2282.     else
  2283.     {
  2284.       smb_setup_header (server, SMBsesssetupX, 10, user_len + password_len);
  2285.  
  2286.       WSET (packet, smb_vwv0, 0xff);
  2287.       WSET (packet, smb_vwv1, 0);
  2288.       WSET (packet, smb_vwv2, given_max_xmit);
  2289.       WSET (packet, smb_vwv3, 2);
  2290.       WSET (packet, smb_vwv4, 0); /* server->pid */
  2291.       DSET (packet, smb_vwv5, server->sesskey);
  2292.       WSET (packet, smb_vwv7, password_len);
  2293.       WSET (packet, smb_vwv8, 0);
  2294.       WSET (packet, smb_vwv9, 0);
  2295.  
  2296.       p = SMB_BUF (packet);
  2297.       memcpy (p, server->mount_data.password, password_len);
  2298.       p += password_len;
  2299.       memcpy (p, server->mount_data.username, user_len);
  2300.     }
  2301.  
  2302.     if ((result = smb_request_ok (server, SMBsesssetupX, 3, 0)) < 0)
  2303.     {
  2304.       LOG (("smb_proc_connect: SMBsessetupX failed\n"));
  2305.       goto fail;
  2306.     }
  2307.  
  2308.     smb_decode_word (packet + 32, &(server->server_uid));
  2309.   }
  2310.   else
  2311.   {
  2312.     server->maxxmt = 0;
  2313.     server->blkmode = 0;
  2314.     server->sesskey = 0;
  2315.  
  2316.     password_len = strlen(server->mount_data.password)+1;
  2317.  
  2318.     nt_password_len = 0;
  2319.   }
  2320.  
  2321.   if(nt_password_len > 0)
  2322.   {
  2323.     strlcpy(full_share,"//",sizeof(full_share));
  2324.     strlcat(full_share,server->mount_data.server_name,sizeof(full_share));
  2325.     strlcat(full_share,"/",sizeof(full_share));
  2326.     strlcat(full_share,server->mount_data.service,sizeof(full_share));
  2327.  
  2328.     full_share_len = strlen(full_share);
  2329.  
  2330.     for(i = 0 ; i < full_share_len ; i++)
  2331.     {
  2332.       if(full_share[i] == '/')
  2333.         full_share[i] = '\\';
  2334.     }
  2335.  
  2336.     StringToUpper(full_share);
  2337.  
  2338.     SHOWSTRING(full_share);
  2339.  
  2340.     memset (packet, 0, SMB_HEADER_LEN);
  2341.  
  2342.     smb_setup_header (server, SMBtconX, 4, password_len + full_share_len+1 + strlen(dev)+1);
  2343.  
  2344.     WSET (packet, smb_vwv0, 0xFF);
  2345.     WSET (packet, smb_vwv3, password_len);
  2346.  
  2347.     p = SMB_BUF (packet);
  2348.  
  2349.     if(nt_password_len > 0)
  2350.       memcpy(p,password,password_len);
  2351.     else
  2352.       memcpy (p, server->mount_data.password, password_len);
  2353.  
  2354.     p += password_len;
  2355.  
  2356.     memcpy(p,full_share,full_share_len+1);
  2357.     p += full_share_len+1;
  2358.  
  2359.     strcpy(p,dev);
  2360.  
  2361.     BSET(packet,smb_rcls,1);
  2362.  
  2363.     if ((result = smb_request_ok (server, SMBtconX, 3, 0)) < 0)
  2364.     {
  2365.       SHOWVALUE(SMB_WCT(packet));
  2366.  
  2367.       LOG (("smb_proc_connect: SMBtconX not verified.\n"));
  2368.       goto fail;
  2369.     }
  2370.  
  2371.     SHOWVALUE(SMB_WCT(packet));
  2372.  
  2373.     /* Changed, max_xmit hasn't been updated if a tconX message was send instead of tcon. */
  2374.     if (server->maxxmt)
  2375.       server->max_xmit = server->maxxmt;
  2376.  
  2377.     server->tid = WVAL(packet,smb_tid);
  2378.   }
  2379.   else
  2380.   {
  2381.     /* Fine! We have a connection, send a tcon message. */
  2382.     smb_setup_header (server, SMBtcon, 0, 6 + strlen (server->mount_data.service) + strlen (server->mount_data.password) + strlen (dev));
  2383.  
  2384.     p = SMB_BUF (packet);
  2385.     p = smb_encode_ascii (p, server->mount_data.service, strlen (server->mount_data.service));
  2386.     p = smb_encode_ascii (p, server->mount_data.password, strlen (server->mount_data.password));
  2387.     (void) smb_encode_ascii (p, dev, strlen (dev));
  2388.  
  2389.     if ((result = smb_request_ok (server, SMBtcon, 2, 0)) < 0)
  2390.     {
  2391.       LOG (("smb_proc_connect: SMBtcon not verified.\n"));
  2392.       goto fail;
  2393.     }
  2394.  
  2395.     LOG (("OK! Managed to set up SMBtcon!\n"));
  2396.  
  2397.     p = SMB_VWV (packet);
  2398.     p = smb_decode_word (p, &server->max_xmit);
  2399.  
  2400.     SHOWVALUE(server->max_xmit);
  2401.  
  2402.     /* Added by Brian Willette - We were ignoring the server's initial
  2403.        maxbuf value */
  2404.     if (server->maxxmt != 0 && server->max_xmit > server->maxxmt)
  2405.       server->max_xmit = server->maxxmt;
  2406.  
  2407.     (void) smb_decode_word (p, &server->tid);
  2408.   }
  2409.  
  2410.   SHOWVALUE(server->max_xmit);
  2411.  
  2412.   /* Changed, max_xmit hasn't been updated if a tconX message was send instead of tcon. */
  2413.   if (server->max_xmit > given_max_xmit)
  2414.     server->max_xmit = given_max_xmit;
  2415.  
  2416.   /* Ok, everything is fine. max_xmit does not include
  2417.      the TCP-SMB header of 4 bytes. */
  2418.   if (server->max_xmit < 65535 - 4)
  2419.     server->max_xmit += 4;
  2420.  
  2421.   LOG (("max_xmit = %ld, tid = %ld\n", server->max_xmit, server->tid));
  2422.  
  2423.   LOG (("smb_proc_connect: Normal exit\n"));
  2424.  
  2425.   return 0;
  2426.  
  2427.  fail:
  2428.  
  2429.   server->state = CONN_INVALID;
  2430.  
  2431.   return result;
  2432. }
  2433.  
  2434. /* smb_proc_reconnect: server->packet is allocated with
  2435.    server->max_xmit bytes if and only if we return >= 0 */
  2436. int
  2437. smb_proc_connect (struct smb_server *server)
  2438. {
  2439.   int result;
  2440.  
  2441.   result = smb_proc_reconnect (server);
  2442.  
  2443.   if ((result < 0) && (server->packet != NULL))
  2444.   {
  2445.     free (server->packet);
  2446.     server->packet = NULL;
  2447.   }
  2448.  
  2449.   return result;
  2450. }
  2451.  
  2452. /* error code stuff - put together by Merik Karman
  2453.    merik@blackadder.dsh.oz.au */
  2454. typedef struct
  2455. {
  2456.   char *name;
  2457.   int code;
  2458.   char *message;
  2459. } err_code_struct;
  2460.  
  2461. /* Dos Error Messages */
  2462. static const err_code_struct dos_msgs[] =
  2463. {
  2464.   {"ERRbadfunc", 1, "Invalid function"},
  2465.   {"ERRbadfile", 2, "File not found"},
  2466.   {"ERRbadpath", 3, "Directory invalid"},
  2467.   {"ERRnofids", 4, "No file descriptors available"},
  2468.   {"ERRnoaccess", 5, "Access denied"},
  2469.   {"ERRbadfid", 6, "Invalid file handle"},
  2470.   {"ERRbadmcb", 7, "Memory control blocks destroyed"},
  2471.   {"ERRnomem", 8, "Insufficient server memory to perform the requested function"},
  2472.   {"ERRbadmem", 9, "Invalid memory block address"},
  2473.   {"ERRbadenv", 10, "Invalid environment"},
  2474.   {"ERRbadformat", 11, "Invalid format"},
  2475.   {"ERRbadaccess", 12, "Invalid open mode"},
  2476.   {"ERRbaddata", 13, "Invalid data"},
  2477.   {"ERR", 14, "reserved"},
  2478.   {"ERRbaddrive", 15, "Invalid drive specified"},
  2479.   {"ERRremcd", 16, "A Delete Directory request attempted  to  remove  the  server's  current directory"},
  2480.   {"ERRdiffdevice", 17, "Not same device"},
  2481.   {"ERRnofiles", 18, "A File Search command can find no more files matching the specified criteria"},
  2482.   {"ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing  FIDs  on the file"},
  2483.   {"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"},
  2484.   {"ERRfilexists", 80, "The file named in a Create Directory, Make  New  File  or  Link  request already exists"},
  2485.   {"ERRbadpipe", 230, "Pipe invalid"},
  2486.   {"ERRpipebusy", 231, "All instances of the requested pipe are busy"},
  2487.   {"ERRpipeclosing", 232, "Pipe close in progress"},
  2488.   {"ERRnotconnected", 233, "No process on other end of pipe"},
  2489.   {"ERRmoredata", 234, "There is more data to be returned"},
  2490.  
  2491.   {NULL, -1, NULL}
  2492. };
  2493.  
  2494. /* Server Error Messages */
  2495. static const err_code_struct server_msgs[] =
  2496. {
  2497.   {"ERRerror", 1, "Non-specific error code"},
  2498.   {"ERRbadpw", 2, "Bad password - name/password pair in a Tree Connect or Session Setup are invalid"},
  2499.   {"ERRbadtype", 3, "reserved"},
  2500.   {"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"},
  2501.   {"ERRinvnid", 5, "The tree ID (TID) specified in a command was invalid"},
  2502.   {"ERRinvnetname", 6, "Invalid network name in tree connect"},
  2503.   {"ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection"},
  2504.   {"ERRqfull", 49, "Print queue full (files) -- returned by open print file"},
  2505.   {"ERRqtoobig", 50, "Print queue full -- no space"},
  2506.   {"ERRqeof", 51, "EOF on print queue dump"},
  2507.   {"ERRinvpfid", 52, "Invalid print file FID"},
  2508.   {"ERRsmbcmd", 64, "The server did not recognize the command received"},
  2509.   {"ERRsrverror", 65, "The server encountered an internal error, e.g., system file unavailable"},
  2510.   {"ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid  combination of values"},
  2511.   {"ERRreserved", 68, "reserved"},
  2512.   {"ERRbadpermits", 69, "The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute"},
  2513.   {"ERRreserved", 70, "reserved"},
  2514.   {"ERRsetattrmode", 71, "The attribute mode in the Set File Attribute request is invalid"},
  2515.   {"ERRpaused", 81, "Server is paused"},
  2516.   {"ERRmsgoff", 82, "Not receiving messages"},
  2517.   {"ERRnoroom", 83, "No room to buffer message"},
  2518.   {"ERRrmuns", 87, "Too many remote user names"},
  2519.   {"ERRtimeout", 88, "Operation timed out"},
  2520.   {"ERRnoresource", 89, "No resources currently available for request"},
  2521.   {"ERRtoomanyuids", 90, "Too many UIDs active on this session"},
  2522.   {"ERRbaduid", 91, "The UID is not known as a valid ID on this session"},
  2523.   {"ERRusempx", 250, "Temp unable to support Raw, use MPX mode"},
  2524.   {"ERRusestd", 251, "Temp unable to support Raw, use standard read/write"},
  2525.   {"ERRcontmpx", 252, "Continue in MPX mode"},
  2526.   {"ERRreserved", 253, "reserved"},
  2527.   {"ERRreserved", 254, "reserved"},
  2528.   {"ERRnosupport", 0xFFFF, "Function not supported"},
  2529.  
  2530.   {NULL, -1, NULL}
  2531. };
  2532.  
  2533. /* Hard Error Messages */
  2534. static const err_code_struct hard_msgs[] =
  2535. {
  2536.   {"ERRnowrite", 19, "Attempt to write on write-protected diskette"},
  2537.   {"ERRbadunit", 20, "Unknown unit"},
  2538.   {"ERRnotready", 21, "Drive not ready"},
  2539.   {"ERRbadcmd", 22, "Unknown command"},
  2540.   {"ERRdata", 23, "Data error (CRC)"},
  2541.   {"ERRbadreq", 24, "Bad request structure length"},
  2542.   {"ERRseek", 25, "Seek error"},
  2543.   {"ERRbadmedia", 26, "Unknown media type"},
  2544.   {"ERRbadsector", 27, "Sector not found"},
  2545.   {"ERRnopaper", 28, "Printer out of paper"},
  2546.   {"ERRwrite", 29, "Write fault"},
  2547.   {"ERRread", 30, "Read fault"},
  2548.   {"ERRgeneral", 31, "General failure"},
  2549.   {"ERRbadshare", 32, "A open conflicts with an existing open"},
  2550.   {"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"},
  2551.   {"ERRwrongdisk", 34, "The wrong disk was found in a drive"},
  2552.   {"ERRFCBUnavail", 35, "No FCBs are available to process request"},
  2553.   {"ERRsharebufexc", 36, "A sharing buffer has been exceeded"},
  2554.  
  2555.   {NULL, -1, NULL}
  2556. };
  2557.  
  2558. typedef struct
  2559. {
  2560.   int code;
  2561.   char *class;
  2562.   const err_code_struct *err_msgs;
  2563. } err_class_struct;
  2564.  
  2565. static const err_class_struct err_classes[] =
  2566. {
  2567.   { 0, "SUCCESS", NULL },
  2568.   { 0x01, "ERRDOS", dos_msgs },
  2569.   { 0x02, "ERRSRV", server_msgs },
  2570.   { 0x03, "ERRHRD", hard_msgs },
  2571.   { 0x04, "ERRXOS", NULL },
  2572.   { 0xE1, "ERRRMX1", NULL },
  2573.   { 0xE2, "ERRRMX2", NULL },
  2574.   { 0xE3, "ERRRMX3", NULL },
  2575.   { 0xFF, "ERRCMD", NULL },
  2576.  
  2577.   { -1, NULL, NULL }
  2578. };
  2579.  
  2580. static void
  2581. smb_printerr (int class, int num)
  2582. {
  2583.   int i, j;
  2584.   err_code_struct *err;
  2585.  
  2586.   for (i = 0; err_classes[i].class; i++)
  2587.   {
  2588.     if (err_classes[i].code != class)
  2589.       continue;
  2590.  
  2591.     if (!err_classes[i].err_msgs)
  2592.     {
  2593.       ReportError("%s - %ld.", err_classes[i].class, num);
  2594.  
  2595.       LOG (("%s - %ld\n", err_classes[i].class, num));
  2596.       return;
  2597.     }
  2598.  
  2599.     err = (err_code_struct *)err_classes[i].err_msgs;
  2600.  
  2601.     for (j = 0; err[j].name; j++)
  2602.     {
  2603.       if (num != err[j].code)
  2604.         continue;
  2605.  
  2606.       ReportError ("%s - %s (%s).", err_classes[i].class, err[j].name, err[j].message);
  2607.  
  2608.       LOG (("%s - %s (%s)\n",err_classes[i].class, err[j].name,err[j].message));
  2609.       return;
  2610.     }
  2611.   }
  2612.  
  2613.   ReportError ("Unknown error - (%ld, %ld).", class, num);
  2614.  
  2615.   LOG (("Unknown error - (%ld, %ld)\n", class, num));
  2616. }
  2617.