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

  1. /*
  2.  * $Id: smb_abstraction.c,v 1.51 2004/05/18 08:39:13 obarthel Exp $
  3.  *
  4.  * :ts=8
  5.  *
  6.  * Name: smb_abstraction.c
  7.  * Description: Smb abstraction layer.
  8.  * Author: Christian Starkjohann <cs@hal.kph.tuwien.ac.at>
  9.  * Date: 1996-12-31
  10.  * Copyright: GNU-GPL
  11.  *
  12.  * Modified for use with AmigaOS by Olaf Barthel <olsen@sourcery.han.de>
  13.  */
  14.  
  15. #include "smbfs.h"
  16.  
  17. /*****************************************************************************/
  18.  
  19. #include <smb/smb_fs.h>
  20. #include <smb/smb.h>
  21. #include <smb/smbno.h>
  22.  
  23. /*****************************************************************************/
  24.  
  25. #define ATTR_CACHE_TIME     5   /* cache attributes for this time */
  26. #define DIR_CACHE_TIME      5   /* cache directories for this time */
  27. #define DIRCACHE_SIZE       170
  28. #define DOS_PATHSEP         '\\'
  29.  
  30. /*****************************************************************************/
  31.  
  32. typedef struct dircache
  33. {
  34.   int base;
  35.   int len;
  36.   int eof;                      /* cache end is eof */
  37.   long created_at;              /* for invalidation */
  38.   struct smba_file *cache_for;  /* owner of this cache */
  39.   int cache_size;
  40.   struct smb_dirent cache[1];
  41. } dircache_t;
  42.  
  43. /* opaque structures for server and files: */
  44. struct smba_server
  45. {
  46.   struct smb_server server;
  47.   struct MinList open_files;
  48.   dircache_t * dircache;
  49.   unsigned supports_E:1;
  50.   unsigned supports_E_known:1;
  51. };
  52.  
  53. struct smba_file
  54. {
  55.   struct MinNode node;
  56.   struct smba_server *server;
  57.   struct smb_dirent dirent;
  58.   long attr_time;               /* time when dirent was read */
  59.   dircache_t *dircache;         /* content cache for directories */
  60.   unsigned attr_dirty:1;        /* attribute cache is dirty */
  61.   unsigned is_valid:1;          /* server was down, entry removed, ... */
  62. };
  63.  
  64. /*****************************************************************************/
  65.  
  66. #include "smb_abstraction.h"
  67.  
  68. /*****************************************************************************/
  69.  
  70. static int smba_connect(smba_connect_parameters_t *p, unsigned int ip_addr, int use_E, char *workgroup_name, int cache_size, smba_server_t **result);
  71. static INLINE int make_open(smba_file_t *f, int need_fid);
  72. static int write_attr(smba_file_t *f);
  73. static void invalidate_dircache(struct smba_server *server, char *path);
  74. static void close_path(smba_server_t *s, char *path);
  75. static void smba_cleanup_dircache(struct smba_server *server);
  76. static int smba_setup_dircache(struct smba_server *server, int cache_size);
  77. static int extract_service (char *service, char *server, size_t server_size, char *share, size_t share_size);
  78.  
  79. /*****************************************************************************/
  80.  
  81. static int
  82. smba_connect (smba_connect_parameters_t * p, unsigned int ip_addr, int use_E, char * workgroup_name, int cache_size, smba_server_t ** result)
  83. {
  84.   smba_server_t *res;
  85.   struct smb_mount_data data;
  86.   int errnum;
  87.   char hostname[MAXHOSTNAMELEN], *s;
  88.   struct servent * servent;
  89.  
  90.   (*result) = NULL;
  91.  
  92.   res = malloc (sizeof(*res));
  93.   if(res == NULL)
  94.   {
  95.     ReportError("Not enough memory.");
  96.     errnum = -ENOMEM;
  97.     goto error_occured;
  98.   }
  99.  
  100.   memset (res, 0, sizeof(*res));
  101.   memset (&data, 0, sizeof (data));
  102.   memset (hostname, 0, sizeof (hostname));
  103.  
  104.   errnum = smba_setup_dircache (res,cache_size);
  105.   if(errnum < 0)
  106.   {
  107.     ReportError("Directory cache initialization failed (%ld, %s).",-errnum,amitcp_strerror(-errnum));
  108.     goto error_occured;
  109.   }
  110.  
  111.   strlcpy(data.workgroup_name,workgroup_name,sizeof(data.workgroup_name));
  112.  
  113.   res->server.abstraction = res;
  114.  
  115.   gethostname (hostname, MAXHOSTNAMELEN);
  116.  
  117.   if ((s = strchr (hostname, '.')) != NULL)
  118.     (*s) = '\0';
  119.  
  120.   data.addr.sin_family = AF_INET;
  121.   data.addr.sin_addr.s_addr = ip_addr;
  122.  
  123.   servent = getservbyname("netbios-ssn","tcp");
  124.   if(servent != NULL)
  125.     data.addr.sin_port = htons (servent->s_port);
  126.   else
  127.     data.addr.sin_port = htons (SMB_PORT);
  128.  
  129.   data.fd = socket (AF_INET, SOCK_STREAM, 0);
  130.   if (data.fd < 0)
  131.   {
  132.     errnum = (-errno);
  133.     ReportError("socket() call failed (%ld, %s).", errno, amitcp_strerror (errno));
  134.     goto error_occured;
  135.   }
  136.  
  137.   strlcpy (data.service, p->service, sizeof(data.service));
  138.   StringToUpper (data.service);
  139.   strlcpy (data.username, p->username, sizeof(data.username));
  140.   strlcpy (data.password, p->password, sizeof(data.password));
  141.  
  142.   if (p->max_xmit > 0)
  143.     data.max_xmit = p->max_xmit;
  144.   else
  145.     data.max_xmit = 65530 /*8300*/;
  146.  
  147.   strlcpy (data.server_name, p->server_name, sizeof(data.server_name));
  148.   strlcpy (data.client_name, p->client_name, sizeof(data.client_name));
  149.  
  150.   if (data.server_name[0] == '\0')
  151.   {
  152.     if (strlen (p->server_ipname) > 16)
  153.     {
  154.       errnum = -ENAMETOOLONG;
  155.       ReportError("Server name '%s' is too long for NetBIOS (max %ld characters).",p->server_ipname,16);
  156.       goto error_occured;
  157.     }
  158.  
  159.     strlcpy (data.server_name, p->server_ipname, sizeof(data.server_name));
  160.   }
  161.  
  162.   StringToUpper (data.server_name);
  163.  
  164.   if (data.client_name[0] == '\0')
  165.   {
  166.     if (strlen (hostname) > 16)
  167.     {
  168.       errnum = -ENAMETOOLONG;
  169.       ReportError("Local host name '%s' is too long for NetBIOS (max %ld characters).", hostname, 16);
  170.       goto error_occured;
  171.     }
  172.  
  173.     strlcpy (data.client_name, hostname, sizeof(data.client_name));
  174.     StringToUpper (data.client_name);
  175.   }
  176.  
  177.   res->server.mount_data = data;
  178.  
  179.   NewList((struct List *)&res->open_files);
  180.  
  181.   if ((errnum = smb_proc_connect (&res->server)) < 0)
  182.   {
  183.     ReportError("Cannot connect to server (%ld, %s).", -errnum,amitcp_strerror(-errnum));
  184.     goto error_occured;
  185.   }
  186.  
  187.   if (!use_E)
  188.     res->supports_E_known = 1;
  189.  
  190.   (*result) = res;
  191.  
  192.   return 0;
  193.  
  194.  error_occured:
  195.  
  196.   if(res != NULL)
  197.   {
  198.     smba_cleanup_dircache (res);
  199.     free (res);
  200.   }
  201.  
  202.   return errnum;
  203. }
  204.  
  205. /*****************************************************************************/
  206.  
  207. void
  208. smba_disconnect (smba_server_t * server)
  209. {
  210.   CloseSocket (server->server.mount_data.fd);
  211.  
  212.   smba_cleanup_dircache(server);
  213.  
  214.   free (server);
  215. }
  216.  
  217. /*****************************************************************************/
  218.  
  219. static INLINE int
  220. make_open (smba_file_t * f, int need_fid)
  221. {
  222.   int errnum = 0;
  223.   smba_server_t *s;
  224.  
  225.   if (!f->is_valid || (need_fid && !f->dirent.opened))
  226.   {
  227.     s = f->server;
  228.  
  229.     if (!f->is_valid || f->attr_time == -1 || GetCurrentTime() - f->attr_time > ATTR_CACHE_TIME)
  230.     {
  231.       if ((errnum = smb_proc_getattr_core (&s->server, f->dirent.complete_path, f->dirent.len, &f->dirent)) < 0)
  232.         goto error_occured;
  233.     }
  234.  
  235.     if ((f->dirent.attr & aDIR) == 0) /* a regular file */
  236.     {
  237.       if (need_fid || !s->supports_E_known || s->supports_E)
  238.       {
  239.         LOG (("opening file %s\n", f->dirent.complete_path));
  240.         if ((errnum = smb_proc_open (&s->server, f->dirent.complete_path, f->dirent.len, &f->dirent)) < 0)
  241.           goto error_occured;
  242.  
  243.         if (s->supports_E || !s->supports_E_known)
  244.         {
  245.           if (smb_proc_getattrE (&s->server, &f->dirent) < 0)
  246.           {
  247.             if (!s->supports_E_known)
  248.             {
  249.               s->supports_E_known = 1;
  250.               s->supports_E = 0;
  251.             } /* ignore errors here */
  252.           }
  253.           else
  254.           {
  255.             s->supports_E_known = 1;
  256.             s->supports_E = 1;
  257.           }
  258.         }
  259.       }
  260.     }
  261.     else
  262.     {
  263.       /* don't open directory, initialize directory cache */
  264.       if (f->dircache != NULL)
  265.       {
  266.         f->dircache->cache_for = NULL;
  267.         f->dircache->len = 0;
  268.         f->dircache = NULL;
  269.       }
  270.     }
  271.  
  272.     f->attr_time = GetCurrentTime();
  273.     f->is_valid = 1;
  274.   }
  275.  
  276.  error_occured:
  277.  
  278.   return errnum;
  279. }
  280.  
  281. /*****************************************************************************/
  282.  
  283. int
  284. smba_open (smba_server_t * s, char *name, size_t name_size, smba_file_t ** file)
  285. {
  286.   smba_file_t *f;
  287.   int errnum;
  288.  
  289.   (*file) = NULL;
  290.  
  291.   f = malloc (sizeof(*f));
  292.   if(f == NULL)
  293.   {
  294.     errnum = -ENOMEM;
  295.     goto error_occured;
  296.   }
  297.  
  298.   memset(f,0,sizeof(*f));
  299.  
  300.   f->dirent.complete_path = name;
  301.   f->dirent.complete_path_size = name_size;
  302.   f->dirent.len = strlen (name);
  303.   f->server = s;
  304.  
  305.   errnum = make_open (f, 0);
  306.   if (errnum < 0)
  307.     goto error_occured;
  308.  
  309.   AddTail ((struct List *)&s->open_files, (struct Node *)f);
  310.  
  311.   (*file) = f;
  312.  
  313.   return 0;
  314.  
  315.  error_occured:
  316.  
  317.   if (f != NULL)
  318.     free (f);
  319.  
  320.   return errnum;
  321. }
  322.  
  323. /*****************************************************************************/
  324.  
  325. static int
  326. write_attr (smba_file_t * f)
  327. {
  328.   int errnum;
  329.  
  330.   LOG (("file %s\n", f->dirent.complete_path));
  331.  
  332.   errnum = make_open (f, 0);
  333.   if (errnum < 0)
  334.     goto out;
  335.  
  336.   if (f->dirent.opened && f->server->supports_E)
  337.     errnum = smb_proc_setattrE (&f->server->server, f->dirent.fileid, &f->dirent);
  338.   else
  339.     errnum = smb_proc_setattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent);
  340.  
  341.   if (errnum < 0)
  342.     f->attr_time = -1;
  343.   else
  344.     f->attr_dirty = 0;
  345.  
  346.  out:
  347.  
  348.   return errnum;
  349. }
  350.  
  351. /*****************************************************************************/
  352.  
  353. void
  354. smba_close (smba_file_t * f)
  355. {
  356.   if(f->node.mln_Succ != NULL || f->node.mln_Pred != NULL)
  357.     Remove((struct Node *)f);
  358.  
  359.   if(f->attr_dirty)
  360.     write_attr(f);
  361.  
  362.   if (f->dirent.opened)
  363.   {
  364.     LOG (("closing file %s\n", f->dirent.complete_path));
  365.     smb_proc_close (&f->server->server, f->dirent.fileid, f->dirent.mtime);
  366.   }
  367.  
  368.   if (f->dircache != NULL)
  369.   {
  370.     f->dircache->cache_for = NULL;
  371.     f->dircache->len = 0;
  372.     f->dircache = NULL;
  373.   }
  374.  
  375.   free (f);
  376. }
  377.  
  378. /*****************************************************************************/
  379.  
  380. int
  381. smba_read (smba_file_t * f, char *data, long len, long offset)
  382. {
  383.   int maxsize, count, totalcount, result;
  384.   int bytes_read = 0;
  385.   char *rpos;
  386.  
  387.   result = make_open (f, 1);
  388.   if (result < 0)
  389.     goto out;
  390.  
  391.   D(("read %ld bytes from offset %ld",len,offset));
  392.  
  393.   if (f->server->server.blkmode & 1)
  394.   {
  395.     SHOWVALUE(f->server->server.max_xmit);
  396.  
  397.     if(len <= 65535)
  398.     {
  399.       result = smb_proc_read_raw (&f->server->server, &f->dirent, offset, len, data);
  400.  
  401.       LOG (("smb_proc_read_raw(%s)->%ld\n", f->dirent.complete_path, result));
  402.     }
  403.     else if (len > 0)
  404.     {
  405.       int n;
  406.  
  407.       totalcount = 0;
  408.  
  409.       do
  410.       {
  411.         n = min(len,65535);
  412.  
  413.         result = smb_proc_read_raw (&f->server->server, &f->dirent, offset, n, data);
  414.         if(result <= 0)
  415.         {
  416.           D(("!!! wanted to read %ld bytes, got %ld",n,result));
  417.           totalcount = -1;
  418.           break;
  419.         }
  420.  
  421.         data += result;
  422.         offset += result;
  423.         len -= result;
  424.         totalcount += result;
  425.  
  426.         if(result < n)
  427.         {
  428.           D(("read returned fewer characters than expected (%ld < %ld)",result,n));
  429.           break;
  430.         }
  431.       }
  432.       while(len > 0);
  433.  
  434.       if(totalcount != -1)
  435.       {
  436.         result = totalcount;
  437.         goto out;
  438.       }
  439.     }
  440.   }
  441.  
  442.   if (result <= 0)
  443.   {
  444.     totalcount = len;
  445.     rpos = data;
  446.  
  447.     maxsize = f->server->server.max_xmit - SMB_HEADER_LEN - 5 * 2 - 5;
  448.  
  449.     do
  450.     {
  451.       count = totalcount > maxsize ? maxsize : totalcount;
  452.  
  453.       result = smb_proc_read (&f->server->server, &f->dirent, offset, count, rpos, 0);
  454.       if (result <= 0)
  455.         break;
  456.  
  457.       bytes_read += result;
  458.       totalcount -= result;
  459.       offset += result;
  460.       rpos += result;
  461.  
  462.       if(result < count)
  463.       {
  464.         D(("read returned fewer characters than expected (%ld < %ld)",result,count));
  465.         break;
  466.       }
  467.     }
  468.     while (totalcount > 0);
  469.  
  470.     if(result >= 0)
  471.       result = bytes_read;
  472.   }
  473.  
  474.  out:
  475.  
  476.   return result;
  477. }
  478.  
  479. /*****************************************************************************/
  480.  
  481. int
  482. smba_write (smba_file_t * f, char *data, long len, long offset)
  483. {
  484.   int newlen, maxsize, totalcount, count, result;
  485.  
  486.   if ((result = make_open (f, 1)) < 0)
  487.     return result;
  488.  
  489.   /* Calculate maximum number of bytes that could be tranfered with
  490.      a single SMBwrite packet... */
  491.   maxsize = f->server->server.max_xmit - (SMB_HEADER_LEN + 5 * sizeof (word) + 5) - 4;
  492.  
  493.   if (len <= maxsize)
  494.   {
  495.     /* Use a single SMBwrite packet whenever possible instead of a SMBwritebraw
  496.        because that requires two packets to be send. */
  497.     result = smb_proc_write (&f->server->server, &f->dirent, offset, len, data);
  498.   }
  499.   else
  500.   {
  501.     /* Added by Brian Willette - We were always checking bit 2 here, but
  502.        according to the documentation I have, the newer versions of SMB put
  503.        the SMB_RAW_WRITE AND SMB_RAW_READ capability in bit 1 */
  504.     if ((f->server->server.protocol >= PROTOCOL_NT1
  505.         && f->server->server.blkmode & 1)
  506.         || (f->server->server.protocol < PROTOCOL_NT1
  507.            && f->server->server.blkmode & 2))
  508.     {
  509.       long maxxmit;
  510.       int n;
  511.  
  512.       totalcount = 0;
  513.  
  514.       /* Try to send the maximum number of bytes with the two SMBwritebraw packets. */
  515.       maxxmit = 2 * f->server->server.max_xmit - (SMB_HEADER_LEN + 12 * sizeof (word) + 4) - 8;
  516.  
  517.       /* If the number of bytes that should be transfered exceed the number of
  518.          bytes that could be transfered by a single call to smb_proc_write_raw,
  519.          the data is transfered as before: Only by the second packet, this
  520.          prevents the CPU from copying the data into the transferbuffer. */
  521.       if (maxxmit < len)
  522.         maxxmit = f->server->server.max_xmit - 4;
  523.  
  524.       do
  525.       {
  526.         n = min(len,maxxmit);
  527.  
  528.         if (n <= maxsize)
  529.         {
  530.           /* Use a single SMBwrite packet whenever possible instead of a
  531.              SMBwritebraw because that requires two packets to be send. */
  532.           result = smb_proc_write (&f->server->server, &f->dirent, offset, n, data);
  533.         }
  534.         else
  535.         {
  536.           result = smb_proc_write_raw (&f->server->server, &f->dirent, offset, n, data);
  537.         }
  538.  
  539.         if(result <= 0)
  540.         {
  541.           totalcount = -1;
  542.           break;
  543.         }
  544.  
  545.         data += result;
  546.         offset += result;
  547.         len -= result;
  548.         totalcount += result;
  549.  
  550.         if(result < n)
  551.           break;
  552.       }
  553.       while(len > 0);
  554.  
  555.       if(totalcount != -1)
  556.       {
  557.         len = totalcount;
  558.         goto out;
  559.       }
  560.     }
  561.     if (result <= 0)
  562.     {
  563.       /* Failed to use the SMBwritebraw packet, fallback to SMBwrite... */
  564.       totalcount = len;
  565.       len = 0;
  566.  
  567.       do
  568.       {
  569.         count = totalcount > maxsize ? maxsize : totalcount;
  570.         result = smb_proc_write (&f->server->server, &f->dirent, offset, count, data);
  571.         if (result < 0)
  572.           break;
  573.  
  574.         totalcount -= result;
  575.         offset += result;
  576.         data += result;
  577.         len += result;
  578.  
  579.         if(result < count)
  580.           break;
  581.       }
  582.       while (totalcount > 0);
  583.     }
  584.   }
  585.  
  586.  out:
  587.  
  588.   if (result < 0)
  589.   {
  590.     f->attr_time = -1;
  591.     return result;
  592.   }
  593.  
  594.   f->dirent.mtime = GetCurrentTime();
  595.  
  596.   newlen = f->dirent.size;
  597.  
  598.   if (offset + len > newlen)
  599.     newlen = offset + len;
  600.  
  601.   f->dirent.size = newlen;
  602.   return len;
  603. }
  604.  
  605. /*****************************************************************************/
  606.  
  607. long
  608. smba_seek (smba_file_t *f, long offset, long mode, off_t * new_position_ptr)
  609. {
  610.    long result;
  611.  
  612.    D(("seek %ld bytes from position %s",offset,mode > 0 ? (mode == 2 ? "SEEK_END" : "SEEK_CUR") : "SEEK_SET"));
  613.  
  614.    if ((result = make_open (f, 1)) >= 0)
  615.       result = smb_proc_lseek (&f->server->server, &f->dirent, offset, mode, new_position_ptr);
  616.  
  617.    return result;
  618. }
  619.  
  620. /*****************************************************************************/
  621.  
  622. /* perform a single record-lock */
  623. int
  624. smba_lockrec (smba_file_t *f, long offset, long len, long mode, int unlocked, long timeout)
  625. {
  626.    int errnum;
  627.    struct smb_lkrng *rec_lock;
  628.  
  629.    if ((errnum = make_open (f, 1)) >= 0)
  630.    {
  631.       if (unlocked)
  632.         mode |= 2;
  633.  
  634.       rec_lock = malloc (sizeof (struct smb_lkrng));
  635.       if (rec_lock != NULL)
  636.       {
  637.          rec_lock->offset = offset,
  638.          rec_lock->len = len;
  639.  
  640.          errnum = smb_proc_lockingX (&f->server->server, &f->dirent, rec_lock, 1, mode, timeout);
  641.  
  642.          free (rec_lock);
  643.       }
  644.       else
  645.       {
  646.          errnum = -ENOMEM;
  647.       }
  648.    }
  649.  
  650.    return errnum;
  651. }
  652.  
  653. /*****************************************************************************/
  654.  
  655. int
  656. smba_getattr (smba_file_t * f, smba_stat_t * data)
  657. {
  658.   long now = GetCurrentTime();
  659.   int errnum;
  660.  
  661.   errnum = make_open (f, 0);
  662.   if (errnum < 0)
  663.     goto out;
  664.  
  665.   if (f->attr_time == -1 || (now - f->attr_time) > ATTR_CACHE_TIME)
  666.   {
  667.     LOG (("file %s\n", f->dirent.complete_path));
  668.  
  669.     if (f->dirent.opened && f->server->supports_E)
  670.       errnum = smb_proc_getattrE (&f->server->server, &f->dirent);
  671.     else
  672.       errnum = smb_proc_getattr_core (&f->server->server, f->dirent.complete_path, f->dirent.len, &f->dirent);
  673.  
  674.     if (errnum >= 0)
  675.       f->attr_time = now;
  676.   }
  677.  
  678.   data->is_dir = (f->dirent.attr & aDIR) != 0;
  679.   data->is_wp = (f->dirent.attr & aRONLY) != 0;
  680.   data->is_hidden = (f->dirent.attr & aHIDDEN) != 0;
  681.   data->is_system = (f->dirent.attr & aSYSTEM) != 0;
  682.   data->is_archive = (f->dirent.attr & aARCH) != 0;
  683.  
  684.   data->size = f->dirent.size;
  685.   data->atime = f->dirent.atime;
  686.   data->ctime = f->dirent.ctime;
  687.   data->mtime = f->dirent.mtime;
  688.  
  689.  out:
  690.  
  691.   return errnum;
  692. }
  693.  
  694. /*****************************************************************************/
  695.  
  696. int
  697. smba_setattr (smba_file_t * f, smba_stat_t * data)
  698. {
  699.   int errnum;
  700.  
  701.   if (data->atime != -1)
  702.     f->dirent.atime = data->atime;
  703.  
  704.   if (data->ctime != -1)
  705.     f->dirent.ctime = data->ctime;
  706.  
  707.   if (data->mtime != -1)
  708.     f->dirent.mtime = data->mtime;
  709.  
  710.   if (data->is_wp)
  711.     f->dirent.attr |= aRONLY;
  712.   else
  713.     f->dirent.attr &= ~aRONLY;
  714.  
  715.   if (data->is_archive)
  716.     f->dirent.attr |= aARCH;
  717.   else
  718.     f->dirent.attr &= ~aARCH;
  719.  
  720.   if (data->is_system)
  721.     f->dirent.attr |= aSYSTEM;
  722.   else
  723.     f->dirent.attr &= ~aSYSTEM;
  724.  
  725.   f->attr_dirty = 1;
  726.  
  727.   if ((errnum = write_attr (f)) < 0)
  728.     goto error_occured;
  729.  
  730.   if (data->size != -1 &&
  731.       data->size != (int)f->dirent.size)
  732.   {
  733.     if ((errnum = make_open (f, 1)) < 0)
  734.       goto error_occured;
  735.  
  736.     if ((errnum = smb_proc_trunc (&f->server->server, f->dirent.fileid, data->size)) < 0)
  737.       goto error_occured;
  738.  
  739.     f->dirent.size = data->size;
  740.   }
  741.  
  742.  error_occured:
  743.  
  744.   return errnum;
  745. }
  746.  
  747. /*****************************************************************************/
  748.  
  749. int
  750. smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback)
  751. {
  752.   int cache_index, rval, o, eof, count = 0;
  753.   long now = GetCurrentTime();
  754.   smba_stat_t data;
  755.  
  756.   rval = make_open (f, 0);
  757.   if (rval < 0)
  758.     goto out;
  759.  
  760.   if (f->dircache == NULL) /* get a cache */
  761.   {
  762.     dircache_t * dircache = f->server->dircache;
  763.  
  764.     if (dircache->cache_for != NULL)
  765.       dircache->cache_for->dircache = NULL;  /* steal it */
  766.  
  767.     dircache->eof = dircache->len = dircache->base = 0;
  768.     dircache->cache_for = f;
  769.  
  770.     f->dircache = dircache;
  771.  
  772.     LOG (("stealing cache\n"));
  773.   }
  774.   else
  775.   {
  776.     if ((now - f->dircache->created_at) >= DIR_CACHE_TIME)
  777.     {
  778.       f->dircache->eof = f->dircache->len = f->dircache->base = 0;
  779.  
  780.       LOG (("cache outdated\n"));
  781.     }
  782.   }
  783.  
  784.   for (cache_index = offs ; ; cache_index++)
  785.   {
  786.     if (cache_index < f->dircache->base  /* fill cache if necessary */
  787.      || cache_index >= f->dircache->base + f->dircache->len)
  788.     {
  789.       if (cache_index >= f->dircache->base + f->dircache->len && f->dircache->eof)
  790.         break; /* nothing more to read */
  791.  
  792.       LOG (("cachefill for %s\n", f->dirent.complete_path));
  793.       LOG (("\tbase was: %ld, len was: %ld, newbase=%ld\n", f->dircache->base, f->dircache->len, cache_index));
  794.  
  795.       f->dircache->len = 0;
  796.       f->dircache->base = cache_index;
  797.  
  798.       rval = smb_proc_readdir (&f->server->server, f->dirent.complete_path, cache_index, f->dircache->cache_size, f->dircache->cache);
  799.       if (rval <= 0)
  800.         break;
  801.  
  802.       /* Avoid some hits if restart/retry occured. Should fix the real root
  803.          of this problem really, but I am not bored enough atm. -Piru
  804.          ZZZ this needs further investigation. */
  805.       if (f->dircache == NULL)
  806.       {
  807.         LOG (("lost dircache due to an error, bailing out!\n"));
  808.         rval = -1;
  809.         break;
  810.       }
  811.  
  812.       f->dircache->len = rval;
  813.       f->dircache->eof = (rval < f->dircache->cache_size);
  814.       f->dircache->created_at = now;
  815.  
  816.       LOG (("cachefill with %ld entries\n", rval));
  817.     }
  818.  
  819.     o = cache_index - f->dircache->base;
  820.     eof = (o >= (f->dircache->len - 1) && f->dircache->eof);
  821.     count++;
  822.  
  823.     LOG (("delivering '%s', cache_index=%ld, eof=%ld\n", f->dircache->cache[o].complete_path, cache_index, eof));
  824.  
  825.     data.is_dir = (f->dircache->cache[o].attr & aDIR) != 0;
  826.     data.is_wp = (f->dircache->cache[o].attr & aRONLY) != 0;
  827.     data.is_hidden = (f->dircache->cache[o].attr & aHIDDEN) != 0;
  828.     data.is_system = (f->dircache->cache[o].attr & aSYSTEM) != 0;
  829.     data.is_archive = (f->dircache->cache[o].attr & aARCH) != 0;
  830.     data.size = f->dircache->cache[o].size;
  831.     data.atime = f->dircache->cache[o].atime;
  832.     data.ctime = f->dircache->cache[o].ctime;
  833.     data.mtime = f->dircache->cache[o].mtime;
  834.  
  835.     if ((*callback) (d, cache_index, cache_index + 1, f->dircache->cache[o].complete_path, eof, &data))
  836.       break;
  837.   }
  838.  
  839.  out:
  840.  
  841.   if (rval < 0)
  842.     return rval;
  843.   else
  844.     return count;
  845. }
  846.  
  847. /*****************************************************************************/
  848.  
  849. static void
  850. invalidate_dircache (struct smba_server * server, char * path)
  851. {
  852.   dircache_t * dircache = server->dircache;
  853.   char other_path[SMB_MAXNAMELEN + 1];
  854.  
  855.   ENTER();
  856.  
  857.   if(path != NULL)
  858.   {
  859.     int len,i;
  860.  
  861.     strlcpy(other_path,path,sizeof(other_path));
  862.  
  863.     len = strlen(other_path);
  864.     for(i = len-1 ; i >= 0 ; i--)
  865.     {
  866.       if(i == 0)
  867.       {
  868.         other_path[0] = DOS_PATHSEP;
  869.         other_path[1] = '\0';
  870.       }
  871.       else if (other_path[i] == DOS_PATHSEP)
  872.       {
  873.         other_path[i] = '\0';
  874.         break;
  875.       }
  876.     }
  877.   }
  878.   else
  879.   {
  880.     other_path[0] = '\0';
  881.   }
  882.  
  883.   SHOWSTRING(other_path);
  884.  
  885.   if(dircache->cache_for != NULL)
  886.     SHOWSTRING(dircache->cache_for->dirent.complete_path);
  887.   else
  888.     SHOWMSG("-- directory cache is empty --");
  889.  
  890.   if(path == NULL || (dircache->cache_for != NULL && CompareNames(other_path,dircache->cache_for->dirent.complete_path) == SAME))
  891.   {
  892.     SHOWMSG("clearing directory cache");
  893.  
  894.     dircache->eof = dircache->len = dircache->base = 0;
  895.     if(dircache->cache_for != NULL)
  896.     {
  897.       dircache->cache_for->dircache = NULL;
  898.       dircache->cache_for = NULL;
  899.     }
  900.   }
  901.  
  902.   LEAVE();
  903. }
  904.  
  905. /*****************************************************************************/
  906.  
  907. int
  908. smba_create (smba_file_t * dir, const char *name, smba_stat_t * attr)
  909. {
  910.   struct smb_dirent entry;
  911.   char *path;
  912.   int errnum;
  913.  
  914.   errnum = make_open (dir, 0);
  915.   if (errnum < 0)
  916.     goto out;
  917.  
  918.   memset (&entry, 0, sizeof (entry));
  919.  
  920.   if (attr->is_wp)
  921.     entry.attr |= aRONLY;
  922.  
  923.   if (attr->is_archive)
  924.     entry.attr |= aARCH;
  925.  
  926.   if (attr->is_system)
  927.     entry.attr |= aSYSTEM;
  928.  
  929.   entry.atime = entry.mtime = entry.ctime = GetCurrentTime();
  930.  
  931.   path = malloc (strlen (name) + dir->dirent.len + 2);
  932.   if(path == NULL)
  933.   {
  934.     errnum = -ENOMEM;
  935.     goto out;
  936.   }
  937.  
  938.   memcpy (path, dir->dirent.complete_path, dir->dirent.len);
  939.   path[dir->dirent.len] = DOS_PATHSEP;
  940.   strcpy (&path[dir->dirent.len + 1], name);
  941.  
  942.   errnum = smb_proc_create (&dir->server->server, path, strlen (path), &entry);
  943.   if(errnum >= 0)
  944.     invalidate_dircache (dir->server, path);
  945.  
  946.   free (path);
  947.  
  948.  out:
  949.  
  950.   return errnum;
  951. }
  952.  
  953. /*****************************************************************************/
  954.  
  955. int
  956. smba_mkdir (smba_file_t * dir, const char *name)
  957. {
  958.   char *path;
  959.   int errnum;
  960.  
  961.   errnum = make_open (dir, 0);
  962.   if (errnum < 0)
  963.     goto out;
  964.  
  965.   path = malloc (strlen (name) + dir->dirent.len + 2);
  966.   if(path == NULL)
  967.   {
  968.     errnum = -ENOMEM;
  969.     goto out;
  970.   }
  971.  
  972.   memcpy (path, dir->dirent.complete_path, dir->dirent.len);
  973.   path[dir->dirent.len] = DOS_PATHSEP;
  974.   strcpy (&path[dir->dirent.len + 1], name);
  975.  
  976.   errnum = smb_proc_mkdir (&dir->server->server, path, strlen (path));
  977.   if(errnum >= 0)
  978.     invalidate_dircache (dir->server, path);
  979.  
  980.   free (path);
  981.  
  982.  out:
  983.  
  984.   return errnum;
  985. }
  986.  
  987. /*****************************************************************************/
  988.  
  989. static void
  990. close_path (smba_server_t * s, char *path)
  991. {
  992.   smba_file_t *p;
  993.  
  994.   for (p = (smba_file_t *)s->open_files.mlh_Head;
  995.        p->node.mln_Succ != NULL;
  996.        p = (smba_file_t *)p->node.mln_Succ)
  997.   {
  998.     if (p->is_valid && CompareNames(p->dirent.complete_path, path) == SAME)
  999.     {
  1000.       if (p->dirent.opened)
  1001.         smb_proc_close (&s->server, p->dirent.fileid, p->dirent.mtime);
  1002.  
  1003.       p->dirent.opened = 0;
  1004.       p->is_valid = 0;
  1005.     }
  1006.   }
  1007. }
  1008.  
  1009. /*****************************************************************************/
  1010.  
  1011. int
  1012. smba_remove (smba_server_t * s, char *path)
  1013. {
  1014.   int result;
  1015.  
  1016.   close_path (s, path);
  1017.  
  1018.   result = smb_proc_unlink (&s->server, path, strlen (path));
  1019.   if(result >= 0)
  1020.     invalidate_dircache (s, path);
  1021.  
  1022.   return result;
  1023. }
  1024.  
  1025. /*****************************************************************************/
  1026.  
  1027. int
  1028. smba_rmdir (smba_server_t * s, char *path)
  1029. {
  1030.   int result;
  1031.  
  1032.   close_path (s, path);
  1033.  
  1034.   result = smb_proc_rmdir (&s->server, path, strlen (path));
  1035.   if(result >= 0)
  1036.     invalidate_dircache (s, path);
  1037.  
  1038.   return result;
  1039. }
  1040.  
  1041. /*****************************************************************************/
  1042.  
  1043. int
  1044. smba_rename (smba_server_t * s, char *from, char *to)
  1045. {
  1046.   int result;
  1047.  
  1048.   close_path (s, from);
  1049.  
  1050.   result = smb_proc_mv (&s->server, from, strlen (from), to, strlen (to));
  1051.   if(result >= 0)
  1052.     invalidate_dircache (s, from);
  1053.  
  1054.   return result;
  1055. }
  1056.  
  1057. /*****************************************************************************/
  1058.  
  1059. int
  1060. smba_statfs (smba_server_t * s, long *bsize, long *blocks, long *bfree)
  1061. {
  1062.   struct smb_dskattr dskattr;
  1063.   int errnum;
  1064.  
  1065.   errnum = smb_proc_dskattr (&s->server, &dskattr);
  1066.   if (errnum < 0)
  1067.     goto out;
  1068.  
  1069.   (*bsize) = dskattr.blocksize * dskattr.allocblocks;
  1070.   (*blocks) = dskattr.total;
  1071.   (*bfree) = dskattr.free;
  1072.  
  1073.  out:
  1074.  
  1075.   return errnum;
  1076. }
  1077.  
  1078. /*****************************************************************************/
  1079.  
  1080. void
  1081. smb_invalidate_all_inodes (struct smb_server *server)
  1082. {
  1083.   smba_file_t *f;
  1084.  
  1085.   invalidate_dircache (server->abstraction, NULL);
  1086.  
  1087.   for (f = (smba_file_t *)server->abstraction->open_files.mlh_Head;
  1088.        f->node.mln_Succ != NULL;
  1089.        f = (smba_file_t *)f->node.mln_Succ)
  1090.   {
  1091.     f->dirent.opened = 0;
  1092.     f->is_valid = 0;
  1093.   }
  1094. }
  1095.  
  1096. /*****************************************************************************/
  1097.  
  1098. static void
  1099. smba_cleanup_dircache(struct smba_server * server)
  1100. {
  1101.   dircache_t * the_dircache = server->dircache;
  1102.  
  1103.   if(the_dircache != NULL)
  1104.   {
  1105.     int i;
  1106.  
  1107.     for (i = 0; i < the_dircache->cache_size; i++)
  1108.     {
  1109.       if(the_dircache->cache[i].complete_path != NULL)
  1110.         free(the_dircache->cache[i].complete_path);
  1111.     }
  1112.  
  1113.     free(the_dircache);
  1114.     server->dircache = NULL;
  1115.   }
  1116. }
  1117.  
  1118. static int
  1119. smba_setup_dircache (struct smba_server * server,int cache_size)
  1120. {
  1121.   dircache_t * the_dircache;
  1122.   int error = (-ENOMEM);
  1123.   int i;
  1124.  
  1125.   the_dircache = malloc(sizeof(*the_dircache) + (cache_size-1) * sizeof(the_dircache->cache));
  1126.   if(the_dircache == NULL)
  1127.     goto out;
  1128.  
  1129.   memset(the_dircache,0,sizeof(*the_dircache));
  1130.   the_dircache->cache_size = cache_size;
  1131.  
  1132.   for (i = 0; i < the_dircache->cache_size; i++)
  1133.   {
  1134.     the_dircache->cache[i].complete_path = malloc (SMB_MAXNAMELEN + 1);
  1135.     if(the_dircache->cache[i].complete_path == NULL)
  1136.       goto out;
  1137.  
  1138.     the_dircache->cache[i].complete_path_size = SMB_MAXNAMELEN + 1;
  1139.   }
  1140.  
  1141.   server->dircache = the_dircache;
  1142.  
  1143.   error = 0;
  1144.  
  1145.  out:
  1146.  
  1147.   if(error < 0)
  1148.   {
  1149.     if(the_dircache != NULL)
  1150.     {
  1151.       for (i = 0; i < the_dircache->cache_size; i++)
  1152.       {
  1153.         if(the_dircache->cache[i].complete_path != NULL)
  1154.           free(the_dircache->cache[i].complete_path);
  1155.       }
  1156.  
  1157.       free(the_dircache);
  1158.     }
  1159.   }
  1160.  
  1161.   return(error);
  1162. }
  1163.  
  1164. /*****************************************************************************/
  1165.  
  1166. static int
  1167. extract_service (char *service, char *server, size_t server_size, char *share, size_t share_size)
  1168. {
  1169.   char *share_start;
  1170.   char *root_start;
  1171.   char *complete_service;
  1172.   char * service_copy;
  1173.   int result = 0;
  1174.  
  1175.   service_copy = malloc(strlen(service)+1);
  1176.   if(service_copy == NULL)
  1177.   {
  1178.     result = -ENOMEM;
  1179.     ReportError("Not enough memory.");
  1180.     goto out;
  1181.   }
  1182.  
  1183.   strcpy (service_copy, service);
  1184.   complete_service = service_copy;
  1185.  
  1186.   if (strlen (complete_service) < 4 || complete_service[0] != '/')
  1187.   {
  1188.     result = -EINVAL;
  1189.     ReportError("Invalid service name '%s'.",complete_service);
  1190.     goto out;
  1191.   }
  1192.  
  1193.   while (complete_service[0] == '/')
  1194.     complete_service += 1;
  1195.  
  1196.   share_start = strchr (complete_service, '/');
  1197.   if (share_start == NULL)
  1198.   {
  1199.     result = -EINVAL;
  1200.     ReportError("Invalid share name '%s'.",complete_service);
  1201.     goto out;
  1202.   }
  1203.  
  1204.   (*share_start++) = '\0';
  1205.   root_start = strchr (share_start, '/');
  1206.  
  1207.   if (root_start != NULL)
  1208.     (*root_start) = '\0';
  1209.  
  1210.   if ((strlen (complete_service) > 63) || (strlen (share_start) > 63))
  1211.   {
  1212.     result = -ENAMETOOLONG;
  1213.     ReportError("Server or share name is too long in '%s' (max %ld characters).",service,63);
  1214.     goto out;
  1215.   }
  1216.  
  1217.   strlcpy (server, complete_service, server_size);
  1218.   strlcpy (share, share_start, share_size);
  1219.  
  1220.  out:
  1221.  
  1222.   if(service_copy != NULL)
  1223.     free(service_copy);
  1224.  
  1225.   return(result);
  1226. }
  1227.  
  1228. int
  1229. smba_start(char * service,char *opt_workgroup,char *opt_username,char *opt_password,char *opt_clientname,char *opt_servername,int opt_cachesize,smba_server_t ** result)
  1230. {
  1231.   smba_connect_parameters_t par;
  1232.   smba_server_t *the_server = NULL;
  1233.   int i;
  1234.   struct hostent *h;
  1235.   int max_xmit = -1;
  1236.   int use_extended = 0;
  1237.   char server_name[17], client_name[17];
  1238.   char username[64], password[64];
  1239.   char workgroup[20];
  1240.   char server[64], share[64];
  1241.   unsigned int ipAddr;
  1242.   int error;
  1243.  
  1244.   (*result) = NULL;
  1245.   (*username) = (*password) = (*server_name) = (*client_name) = '\0';
  1246.  
  1247.   error = extract_service (service, server, sizeof(server), share, sizeof(share));
  1248.   if(error < 0)
  1249.     goto out;
  1250.  
  1251.   ipAddr = inet_addr (server);
  1252.   if (ipAddr == INADDR_NONE) /* name was given, not numeric */
  1253.   {
  1254.     int lookup_error;
  1255.  
  1256.     h = gethostbyname (server);
  1257.     lookup_error = h_errno;
  1258.  
  1259.     if (h != NULL)
  1260.     {
  1261.       ipAddr = ((struct in_addr *)(h->h_addr))->s_addr;
  1262.     }
  1263.     else if (BroadcastNameQuery(server,"",(UBYTE *)&ipAddr) != 0)
  1264.     {
  1265.       ReportError("Unknown host '%s' (%ld, %s).",server,lookup_error,host_strerror(lookup_error));
  1266.       error = (-ENOENT);
  1267.       goto out;
  1268.     }
  1269.   }
  1270.   else
  1271.   {
  1272.     char hostName[MAXHOSTNAMELEN+1];
  1273.  
  1274.     h = gethostbyaddr ((char *) &ipAddr, sizeof (ipAddr), AF_INET);
  1275.     if (h == NULL)
  1276.     {
  1277.       ReportError("Unknown host '%s' (%ld, %s).",server,h_errno,host_strerror(errno));
  1278.       error = (-ENOENT);
  1279.       goto out;
  1280.     }
  1281.  
  1282.     /* Brian Willette: Now we will set the server name to the dns
  1283.        hostname, hopefully this will be the same as the netbios name for
  1284.        the server.
  1285.        We do this because the user supplied no hostname, and we
  1286.        need one for netbios, this is the best guess choice we have
  1287.        NOTE: If the names are different between DNS and netbios on
  1288.        the windows side, the user MUST use the -s option. */
  1289.     for (i = 0; h->h_name[i] != '.' && h->h_name[i] != '\0' && i < 255; i++)
  1290.       hostName[i] = h->h_name[i];
  1291.  
  1292.     hostName[i] = '\0';
  1293.  
  1294.     /* Make sure the hostname is 16 characters or less (for Netbios) */
  1295.     if (strlen (hostName) > 16)
  1296.     {
  1297.       ReportError("Server host name '%s' is too long (max %ld characters).", hostName, 16);
  1298.       error = (-ENAMETOOLONG);
  1299.       goto out;
  1300.     }
  1301.  
  1302.     strlcpy (server_name, hostName, sizeof(server_name));
  1303.   }
  1304.  
  1305.   if(opt_password != NULL)
  1306.   {
  1307.     if(strlen(opt_password) >= sizeof(password))
  1308.     {
  1309.       ReportError("Password is too long (max %ld characters).", sizeof(password)-1);
  1310.       error = (-ENAMETOOLONG);
  1311.       goto out;
  1312.     }
  1313.  
  1314.     strlcpy(password,opt_password,sizeof(password));
  1315.   }
  1316.  
  1317.   if(strlen(opt_username) >= sizeof(username))
  1318.   {
  1319.     ReportError("User name '%s' is too long (max %ld characters).", username,sizeof(username)-1);
  1320.     error = (-ENAMETOOLONG);
  1321.     goto out;
  1322.   }
  1323.  
  1324.   strlcpy(username,opt_username,sizeof(username));
  1325.   StringToUpper(username);
  1326.  
  1327.   if (strlen(opt_workgroup) > 15)
  1328.   {
  1329.     ReportError("Workgroup/domain name '%s' is too long (max %ld characters).", opt_workgroup,15);
  1330.     error = (-ENAMETOOLONG);
  1331.     goto out;
  1332.   }
  1333.  
  1334.   strlcpy (workgroup, opt_workgroup, sizeof(workgroup));
  1335.   StringToUpper (workgroup);
  1336.  
  1337.   if(opt_servername != NULL)
  1338.   {
  1339.     if (strlen (opt_servername) > 16)
  1340.     {
  1341.       ReportError("Server name '%s' is too long (max %ld characters).", opt_servername,16);
  1342.       error = (-ENAMETOOLONG);
  1343.       goto out;
  1344.     }
  1345.  
  1346.     strlcpy (server_name, opt_servername, sizeof(server_name));
  1347.   }
  1348.  
  1349.   if(opt_clientname != NULL)
  1350.   {
  1351.     if (strlen (opt_clientname) > 16)
  1352.     {
  1353.       ReportError("Client name '%s' is too long (max %ld characters).", opt_clientname,16);
  1354.       error = (-ENAMETOOLONG);
  1355.       goto out;
  1356.     }
  1357.  
  1358.     strlcpy (client_name, opt_clientname, sizeof(client_name));
  1359.   }
  1360.  
  1361.   if(opt_cachesize < 1)
  1362.     opt_cachesize = DIRCACHE_SIZE;
  1363.   else if (opt_cachesize < 10)
  1364.     opt_cachesize = 10;
  1365.  
  1366.   strlcpy(par.server_ipname,server,sizeof(par.server_ipname));
  1367.   par.server_name = server_name;
  1368.   par.client_name = client_name;
  1369.  
  1370.   strlcpy(par.service,share,sizeof(par.service));
  1371.   par.username = username;
  1372.   par.password = password;
  1373.   par.max_xmit = max_xmit;
  1374.  
  1375.   error = smba_connect (&par, ipAddr, use_extended, workgroup, opt_cachesize, &the_server);
  1376.   if(error < 0)
  1377.   {
  1378.     ReportError("Could not connect to server (%ld, %s).",-error,amitcp_strerror(-error));
  1379.     goto out;
  1380.   }
  1381.  
  1382.   (*result) = the_server;
  1383.  
  1384.   error = 0;
  1385.  
  1386.  out:
  1387.  
  1388.   return(error);
  1389. }
  1390.  
  1391. /*****************************************************************************/
  1392.  
  1393. int
  1394. smba_get_dircache_size(struct smba_server * server)
  1395. {
  1396.   int result;
  1397.  
  1398.   result = server->dircache->cache_size;
  1399.  
  1400.   return(result);
  1401. }
  1402.  
  1403. /*****************************************************************************/
  1404.  
  1405. int
  1406. smba_change_dircache_size(struct smba_server * server,int cache_size)
  1407. {
  1408.   dircache_t * new_cache;
  1409.   dircache_t * the_dircache = server->dircache;
  1410.   int result;
  1411.   int i;
  1412.  
  1413.   result = the_dircache->cache_size;
  1414.  
  1415.   if(cache_size < 10)
  1416.     cache_size = 10;
  1417.  
  1418.   if(cache_size == the_dircache->cache_size)
  1419.     goto out;
  1420.  
  1421.   new_cache = malloc(sizeof(*new_cache) + (cache_size-1) * sizeof(new_cache->cache));
  1422.   if(new_cache == NULL)
  1423.     goto out;
  1424.  
  1425.   memset(new_cache,0,sizeof(*new_cache));
  1426.   new_cache->cache_size = cache_size;
  1427.  
  1428.   /* If the new cache is to be larger than the old one,
  1429.      allocate additional file name slots. */
  1430.   if(cache_size > the_dircache->cache_size)
  1431.   {
  1432.     for(i = the_dircache->cache_size ; i < cache_size ; i++)
  1433.     {
  1434.       new_cache->cache[i].complete_path = malloc (SMB_MAXNAMELEN + 1);
  1435.       if(new_cache->cache[i].complete_path == NULL)
  1436.       {
  1437.         int j;
  1438.  
  1439.         for(j = the_dircache->cache_size ; j < i ; j++)
  1440.           free(new_cache->cache[j].complete_path);
  1441.  
  1442.         free(new_cache);
  1443.  
  1444.         goto out;
  1445.       }
  1446.  
  1447.       new_cache->cache[i].complete_path_size = SMB_MAXNAMELEN + 1;
  1448.     }
  1449.  
  1450.     /* Reuse the file name buffers allocated for
  1451.        the old cache. */
  1452.     for(i = 0 ; i < the_dircache->cache_size ; i++)
  1453.     {
  1454.       new_cache->cache[i].complete_path = the_dircache->cache[i].complete_path;
  1455.       new_cache->cache[i].complete_path_size = the_dircache->cache[i].complete_path_size;
  1456.  
  1457.       the_dircache->cache[i].complete_path = NULL;
  1458.     }
  1459.   }
  1460.   else
  1461.   {
  1462.     /* Reuse the file name buffers allocated for
  1463.        the old cache. */
  1464.     for(i = 0 ; i < cache_size ; i++)
  1465.     {
  1466.       new_cache->cache[i].complete_path = the_dircache->cache[i].complete_path;
  1467.       new_cache->cache[i].complete_path_size = the_dircache->cache[i].complete_path_size;
  1468.       the_dircache->cache[i].complete_path = NULL;
  1469.     }
  1470.   }
  1471.  
  1472.   invalidate_dircache(server, NULL);
  1473.  
  1474.   for (i = 0; i < the_dircache->cache_size; i++)
  1475.   {
  1476.     if(the_dircache->cache[i].complete_path != NULL)
  1477.       free(the_dircache->cache[i].complete_path);
  1478.   }
  1479.  
  1480.   free(the_dircache);
  1481.  
  1482.   server->dircache = new_cache;
  1483.   result = cache_size;
  1484.  
  1485.  out:
  1486.  
  1487.   return(result);
  1488. }
  1489.