root/src/vfs/smbfs/smbfs.c

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

DEFINITIONS

This source file includes following definitions.
  1. smbfs_set_debugf
  2. free_after
  3. smbfs_auth_free
  4. smbfs_auth_free_all
  5. smbfs_auth_cmp_host_and_share
  6. smbfs_auth_cmp_host
  7. smbfs_auth_add
  8. smbfs_auth_remove
  9. smbfs_bucket_set_authinfo
  10. smbfs_set_debug
  11. smbfs_init
  12. smbfs_fill_names
  13. smbfs_read
  14. smbfs_write
  15. smbfs_close
  16. smbfs_errno
  17. smbfs_new_dir_entry
  18. smbfs_browsing_helper
  19. smbfs_loaddir_helper
  20. smbfs_convert_path
  21. smbfs_srv_browsing_helper
  22. smbfs_reconnect
  23. smbfs_send
  24. smbfs_chkpath
  25. smbfs_fs
  26. smbfs_loaddir
  27. smbfs_free_dir
  28. smbfs_readdir
  29. smbfs_closedir
  30. smbfs_chmod
  31. smbfs_chown
  32. smbfs_utime
  33. smbfs_readlink
  34. smbfs_symlink
  35. smbfs_do_connect
  36. smbfs_get_master_browser
  37. smbfs_free_bucket
  38. smbfs_get_free_bucket
  39. smbfs_open_link
  40. smbfs_get_path
  41. is_error
  42. smbfs_opendir
  43. smbfs_fake_server_stat
  44. smbfs_fake_share_stat
  45. smbfs_get_remote_stat
  46. smbfs_search_dir_entry
  47. smbfs_get_stat_info
  48. smbfs_chdir
  49. smbfs_loaddir_by_name
  50. smbfs_stat
  51. smbfs_lseek
  52. smbfs_mknod
  53. smbfs_mkdir
  54. smbfs_rmdir
  55. smbfs_link
  56. smbfs_free
  57. smbfs_forget
  58. smbfs_setctl
  59. smbfs_open_readwrite
  60. smbfs_open
  61. smbfs_unlink
  62. smbfs_rename
  63. smbfs_fstat
  64. smbfs_nothingisopen
  65. vfs_smb_authinfo_new
  66. vfs_init_smbfs

   1 /*
   2    Virtual File System: Midnight Commander file system.
   3 
   4    Copyright (C) 1999-2020
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Wayne Roberts <wroberts1@home.com>, 1997
   9    Andrew V. Samoilov <sav@bcs.zp.ua> 2002, 2003
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  25  */
  26 
  27 /**
  28  * \file
  29  * \brief Source: Virtual File System: smb file system
  30  * \author Wayne Roberts <wroberts1@home.com>
  31  * \author Andrew V. Samoilov <sav@bcs.zp.ua>
  32  * \date 1997, 2002, 2003
  33  *
  34  * Namespace: exports init_smbfs, smbfs_set_debug()
  35  */
  36 
  37 #include <config.h>
  38 
  39 #include <stdio.h>
  40 #include <sys/types.h>
  41 #include <string.h>             /* memset() */
  42 
  43 #undef USE_NCURSES              /* Don't include *curses.h */
  44 #undef USE_NCURSESW
  45 
  46 #include <string.h>
  47 
  48 #include "lib/global.h"
  49 #include "lib/strutil.h"
  50 #include "lib/util.h"
  51 #include "lib/widget.h"         /* message() */
  52 
  53 #undef  PACKAGE_BUGREPORT
  54 #undef  PACKAGE_NAME
  55 #undef  PACKAGE_STRING
  56 #undef  PACKAGE_TARNAME
  57 #undef  PACKAGE_VERSION
  58 
  59 #include "helpers/include/config.h"
  60 /* don't load crap in "samba/include/includes.h" we don't use and which 
  61    conflicts with definitions in other includes */
  62 #undef HAVE_LIBREADLINE
  63 #define NO_CONFIG_H
  64 #undef VERSION
  65 
  66 #include "helpers/include/includes.h"
  67 
  68 #include "lib/vfs/vfs.h"
  69 #include "lib/vfs/xdirentry.h"  /* vfs_s_subclass */
  70 #include "lib/vfs/netutil.h"
  71 #include "lib/vfs/utilvfs.h"
  72 
  73 #include "smbfs.h"
  74 
  75 /*** global variables ****************************************************************************/
  76 
  77 extern int DEBUGLEVEL;
  78 extern pstring myhostname;
  79 extern struct in_addr ipzero;
  80 extern pstring global_myname;
  81 extern pstring debugf;
  82 extern FILE *dbf;
  83 
  84 /*** file scope macro definitions ****************************************************************/
  85 
  86 #define SMBFS_MAX_CONNECTIONS 16
  87 
  88 #define HEADER_LEN      6
  89 
  90 #define CNV_LANG(s) dos_to_unix(s,False)
  91 #define GNAL_VNC(s) unix_to_dos(s,False)
  92 
  93 #define smbfs_lstat smbfs_stat  /* no symlinks on smb filesystem? */
  94 
  95 /*** file scope type declarations ****************************************************************/
  96 
  97 typedef struct _smbfs_connection smbfs_connection;
  98 
  99 typedef struct
 100 {
 101     struct cli_state *cli;
 102     int fnum;
 103     off_t nread;
 104     uint16 attr;
 105 } smbfs_handle;
 106 
 107 typedef struct dir_entry
 108 {
 109     char *text;
 110     struct dir_entry *next;
 111     struct stat my_stat;
 112     int merrno;
 113 } dir_entry;
 114 
 115 typedef struct
 116 {
 117     gboolean server_list;
 118     char *dirname;
 119     char *path;                 /* the dir originally passed to smbfs_opendir */
 120     smbfs_connection *conn;
 121     dir_entry *entries;
 122     dir_entry *current;
 123 } opendir_info;
 124 
 125 /*** file scope variables ************************************************************************/
 126 
 127 static const char *const IPC = "IPC$";
 128 static const char *const URL_HEADER = "smb" VFS_PATH_URL_DELIMITER;
 129 
 130 static int my_errno;
 131 static uint32 err;
 132 
 133 /* stuff that is same with each connection */
 134 
 135 static mode_t myumask = 0755;
 136 static int smbfs_open_connections = 0;
 137 static gboolean got_user = FALSE;
 138 static gboolean got_pass = FALSE;
 139 static pstring password;
 140 static pstring username;
 141 
 142 static struct vfs_s_subclass smbfs_subclass;
 143 static struct vfs_class *vfs_smbfs_ops = VFS_CLASS (&smbfs_subclass);
 144 
 145 static struct _smbfs_connection
 146 {
 147     struct cli_state *cli;
 148     struct in_addr dest_ip;
 149     BOOL have_ip;
 150     char *host;                 /* server name */
 151     char *service;              /* share name */
 152     char *domain;
 153     char *user;
 154     char *home;
 155     char *password;
 156     int port;
 157     int name_type;
 158     time_t last_use;
 159 } smbfs_connections[SMBFS_MAX_CONNECTIONS];
 160 /* unique to each connection */
 161 
 162 static smbfs_connection *current_bucket;
 163 
 164 static GSList *auth_list;
 165 
 166 static opendir_info *previous_info, *current_info, *current_share_info, *current_server_info;
 167 
 168 static gboolean first_direntry;
 169 
 170 /* stat a single file, smbfs_get_remote_stat callback  */
 171 static dir_entry *single_entry;
 172 
 173 /*** file scope functions ************************************************************************/
 174 /* --------------------------------------------------------------------------------------------- */
 175 
 176 /* modifies *share */
 177 static struct cli_state *smbfs_do_connect (const char *server, char *share);
 178 
 179 /* --------------------------------------------------------------------------------------------- */
 180 
 181 static void
 182 smbfs_set_debugf (const char *filename)
     /* [previous][next][first][last][top][bottom][index][help]  */
 183 {
 184     if (DEBUGLEVEL > 0)
 185     {
 186         FILE *outfile = fopen (filename, "w");
 187         if (outfile)
 188         {
 189             setup_logging ("", True);   /* No needs for timestamp for each message */
 190             dbf = outfile;
 191             setbuf (dbf, NULL);
 192             pstrcpy (debugf, filename);
 193         }
 194     }
 195 }
 196 
 197 /* --------------------------------------------------------------------------------------------- */
 198 /* this function allows you to write:
 199  * char *s = g_strdup("hello, world");
 200  * s = free_after(g_strconcat(s, s, (char *)0), s);
 201  */
 202 
 203 static inline char *
 204 free_after (char *result, char *string_to_free)
     /* [previous][next][first][last][top][bottom][index][help]  */
 205 {
 206     g_free (string_to_free);
 207     return result;
 208 }
 209 
 210 /* --------------------------------------------------------------------------------------------- */
 211 
 212 static void
 213 smbfs_auth_free (struct smb_authinfo const *a)
     /* [previous][next][first][last][top][bottom][index][help]  */
 214 {
 215     g_free (a->host);
 216     g_free (a->share);
 217     g_free (a->domain);
 218     g_free (a->user);
 219     wipe_password (a->password);
 220 }
 221 
 222 /* --------------------------------------------------------------------------------------------- */
 223 
 224 static void
 225 smbfs_auth_free_all (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 226 {
 227     g_clear_slist (&auth_list, (GDestroyNotify) smbfs_auth_free);
 228 }
 229 
 230 /* --------------------------------------------------------------------------------------------- */
 231 
 232 static gint
 233 smbfs_auth_cmp_host_and_share (gconstpointer _a, gconstpointer _b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 234 {
 235     struct smb_authinfo const *a = (struct smb_authinfo const *) _a;
 236     struct smb_authinfo const *b = (struct smb_authinfo const *) _b;
 237 
 238     if (!a->host || !a->share || !b->host || !b->share)
 239         return 1;
 240     if (strcmp (a->host, b->host) != 0)
 241         return 1;
 242     if (strcmp (a->share, b->share) != 0)
 243         return 1;
 244     return 0;
 245 }
 246 
 247 /* --------------------------------------------------------------------------------------------- */
 248 
 249 static gint
 250 smbfs_auth_cmp_host (gconstpointer _a, gconstpointer _b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 251 {
 252     struct smb_authinfo const *a = (struct smb_authinfo const *) _a;
 253     struct smb_authinfo const *b = (struct smb_authinfo const *) _b;
 254 
 255     if (!a->host || !b->host)
 256         return 1;
 257     if (strcmp (a->host, b->host) != 0)
 258         return 1;
 259     if (strcmp (a->share, IPC) != 0)
 260         return 1;
 261     return 0;
 262 }
 263 
 264 /* --------------------------------------------------------------------------------------------- */
 265 
 266 static void
 267 smbfs_auth_add (const char *host, const char *share, const char *domain,
     /* [previous][next][first][last][top][bottom][index][help]  */
 268                 const char *user, const char *pass)
 269 {
 270     struct smb_authinfo *auth;
 271 
 272     auth = vfs_smb_authinfo_new (host, share, domain, user, pass);
 273 
 274     if (auth != NULL)
 275         auth_list = g_slist_prepend (auth_list, auth);
 276 }
 277 
 278 /* --------------------------------------------------------------------------------------------- */
 279 
 280 static void
 281 smbfs_auth_remove (const char *host, const char *share)
     /* [previous][next][first][last][top][bottom][index][help]  */
 282 {
 283     struct smb_authinfo data;
 284     struct smb_authinfo *auth;
 285     GSList *list;
 286 
 287     data.host = g_strdup (host);
 288     data.share = g_strdup (share);
 289     list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host_and_share);
 290     g_free (data.host);
 291     g_free (data.share);
 292     if (!list)
 293         return;
 294     auth = list->data;
 295     auth_list = g_slist_remove (auth_list, auth);
 296     smbfs_auth_free (auth);
 297 }
 298 
 299 /* --------------------------------------------------------------------------------------------- */
 300 /* Set authentication information in bucket. Return 1 if successful, else 0 */
 301 /* Information in auth_list overrides user if pass is NULL. */
 302 /* bucket->host and bucket->service must be valid. */
 303 
 304 static int
 305 smbfs_bucket_set_authinfo (smbfs_connection * bucket,
     /* [previous][next][first][last][top][bottom][index][help]  */
 306                            const char *domain, const char *user, const char *pass,
 307                            int fallback_to_host)
 308 {
 309     struct smb_authinfo data;
 310     struct smb_authinfo *auth;
 311     GSList *list;
 312 
 313     if (domain && user && pass)
 314     {
 315         g_free (bucket->domain);
 316         g_free (bucket->user);
 317         g_free (bucket->password);
 318         bucket->domain = g_strdup (domain);
 319         bucket->user = g_strdup (user);
 320         bucket->password = g_strdup (pass);
 321         smbfs_auth_remove (bucket->host, bucket->service);
 322         smbfs_auth_add (bucket->host, bucket->service, domain, user, pass);
 323         return 1;
 324     }
 325 
 326     data.host = bucket->host;
 327     data.share = bucket->service;
 328     list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host_and_share);
 329     if (!list && fallback_to_host)
 330         list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host);
 331     if (list)
 332     {
 333         auth = list->data;
 334         bucket->domain = g_strdup (auth->domain);
 335         bucket->user = g_strdup (auth->user);
 336         bucket->password = g_strdup (auth->password);
 337         return 1;
 338     }
 339 
 340     if (got_pass)
 341     {
 342         bucket->domain = g_strdup (lp_workgroup ());
 343         bucket->user = g_strdup (got_user ? username : user);
 344         bucket->password = g_strdup (password);
 345         return 1;
 346     }
 347 
 348     auth = vfs_smb_get_authinfo (bucket->host,
 349                                  bucket->service, (domain ? domain : lp_workgroup ()), user);
 350     if (auth)
 351     {
 352         g_free (bucket->domain);
 353         g_free (bucket->user);
 354         g_free (bucket->password);
 355         bucket->domain = g_strdup (auth->domain);
 356         bucket->user = g_strdup (auth->user);
 357         bucket->password = g_strdup (auth->password);
 358         smbfs_auth_remove (bucket->host, bucket->service);
 359         auth_list = g_slist_prepend (auth_list, auth);
 360         return 1;
 361     }
 362     return 0;
 363 }
 364 
 365 /* --------------------------------------------------------------------------------------------- */
 366 
 367 void
 368 smbfs_set_debug (int arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 369 {
 370     DEBUGLEVEL = arg;
 371 }
 372 
 373 /* --------------------------------------------------------------------------------------------- */
 374 /********************** The callbacks ******************************/
 375 
 376 static int
 377 smbfs_init (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 378 {
 379     const char *servicesf = CONFIGDIR PATH_SEP_STR "smb.conf";
 380 
 381     /*  DEBUGLEVEL = 4; */
 382 
 383     TimeInit ();
 384     charset_initialise ();
 385 
 386     DEBUG (3, ("smbfs_init(%s)\n", me->name));
 387 
 388     if (!get_myname (myhostname, NULL))
 389         DEBUG (0, ("Failed to get my hostname.\n"));
 390 
 391     if (!lp_load (servicesf, True, False, False))
 392         DEBUG (0, ("Cannot load %s - run testparm to debug it\n", servicesf));
 393 
 394     codepage_initialise (lp_client_code_page ());
 395 
 396     load_interfaces ();
 397 
 398     myumask = umask (0);
 399     umask (myumask);
 400     myumask = ~myumask;
 401 
 402     if (getenv ("USER"))
 403     {
 404         char *p;
 405 
 406         pstrcpy (username, getenv ("USER"));
 407         got_user = TRUE;
 408         DEBUG (3, ("smbfs_init(): $USER:%s\n", username));
 409         if ((p = strchr (username, '%')))
 410         {
 411             *p = 0;
 412             pstrcpy (password, p + 1);
 413             got_pass = TRUE;
 414             memset (strchr (getenv ("USER"), '%') + 1, 'X', strlen (password));
 415             DEBUG (3, ("smbfs_init(): $USER%%pass: %s%%%s\n", username, password));
 416         }
 417         strupper (username);
 418     }
 419     if (getenv ("PASSWD"))
 420     {
 421         pstrcpy (password, getenv ("PASSWD"));
 422         got_pass = TRUE;
 423     }
 424     return 1;
 425 }
 426 
 427 /* --------------------------------------------------------------------------------------------- */
 428 
 429 static void
 430 smbfs_fill_names (struct vfs_class *me, fill_names_f func)
     /* [previous][next][first][last][top][bottom][index][help]  */
 431 {
 432     size_t i;
 433     char *path;
 434 
 435     (void) me;
 436 
 437     for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
 438     {
 439         if (smbfs_connections[i].cli)
 440         {
 441             path = g_strconcat (URL_HEADER,
 442                                 smbfs_connections[i].user, "@",
 443                                 smbfs_connections[i].host,
 444                                 "/", smbfs_connections[i].service, (char *) NULL);
 445             (*func) (path);
 446             g_free (path);
 447         }
 448     }
 449 }
 450 
 451 /* --------------------------------------------------------------------------------------------- */
 452 /* does same as do_get() in client.c */
 453 /* called from vfs.c:1080, count = buffer size */
 454 
 455 static ssize_t
 456 smbfs_read (void *data, char *buffer, size_t count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 457 {
 458     smbfs_handle *info = (smbfs_handle *) data;
 459     ssize_t n;
 460 
 461     DEBUG (3, ("smbfs_read(fnum:%d, nread:%d, count:%zu)\n", info->fnum, (int) info->nread, count));
 462     n = cli_read (info->cli, info->fnum, buffer, info->nread, count);
 463     if (n > 0)
 464         info->nread += n;
 465     return n;
 466 }
 467 
 468 /* --------------------------------------------------------------------------------------------- */
 469 
 470 static ssize_t
 471 smbfs_write (void *data, const char *buf, size_t nbyte)
     /* [previous][next][first][last][top][bottom][index][help]  */
 472 {
 473     smbfs_handle *info = (smbfs_handle *) data;
 474     ssize_t n;
 475 
 476     DEBUG (3, ("smbfs_write(fnum:%d, nread:%d, nbyte:%zu)\n",
 477                info->fnum, (int) info->nread, nbyte));
 478     n = cli_write (info->cli, info->fnum, 0, buf, info->nread, nbyte);
 479     if (n > 0)
 480         info->nread += n;
 481     return n;
 482 }
 483 
 484 /* --------------------------------------------------------------------------------------------- */
 485 
 486 static int
 487 smbfs_close (void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 488 {
 489     smbfs_handle *info = (smbfs_handle *) data;
 490     DEBUG (3, ("smbfs_close(fnum:%d)\n", info->fnum));
 491 
 492     /* FIXME: Why too different cli have the same outbuf
 493      * if file is copied to share
 494      */
 495     if (info->cli->outbuf == NULL)
 496     {
 497         my_errno = EINVAL;
 498         return -1;
 499     }
 500 #if 0
 501     /* if imlementing archive_level:    add rname to smbfs_handle */
 502     if (archive_level >= 2 && (inf->attr & aARCH))
 503     {
 504         cli_setatr (info->cli, rname, info->attr & ~(uint16) aARCH, 0);
 505     }
 506 #endif
 507     return (cli_close (info->cli, info->fnum) == True) ? 0 : -1;
 508 }
 509 
 510 /* --------------------------------------------------------------------------------------------- */
 511 
 512 static int
 513 smbfs_errno (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 514 {
 515     (void) me;
 516 
 517     DEBUG (3, ("smbfs_errno: %s\n", unix_error_string (my_errno)));
 518     return my_errno;
 519 }
 520 
 521 /* --------------------------------------------------------------------------------------------- */
 522 
 523 static dir_entry *
 524 smbfs_new_dir_entry (const char *name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 525 {
 526     static int inode_counter;
 527     dir_entry *new_entry;
 528     new_entry = g_new0 (dir_entry, 1);
 529     new_entry->text = dos_to_unix (g_strdup (name), 1);
 530 
 531     if (first_direntry)
 532     {
 533         current_info->entries = new_entry;
 534         first_direntry = FALSE;
 535     }
 536     else
 537     {
 538         current_info->current->next = new_entry;
 539     }
 540     current_info->current = new_entry;
 541     new_entry->my_stat.st_ino = inode_counter++;
 542 
 543     return new_entry;
 544 }
 545 
 546 /* --------------------------------------------------------------------------------------------- */
 547 /* browse for shares on server */
 548 
 549 static void
 550 smbfs_browsing_helper (const char *name, uint32 type, const char *comment, void *state)
     /* [previous][next][first][last][top][bottom][index][help]  */
 551 {
 552     const char *typestr = "";
 553     dir_entry *new_entry = smbfs_new_dir_entry (name);
 554 
 555     (void) state;
 556 
 557     switch (type)
 558     {
 559     case STYPE_DISKTREE:
 560         typestr = "Disk";
 561         /*      show this as dir        */
 562         new_entry->my_stat.st_mode =
 563             (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
 564         break;
 565     case STYPE_PRINTQ:
 566         typestr = "Printer";
 567         break;
 568     case STYPE_DEVICE:
 569         typestr = "Device";
 570         break;
 571     case STYPE_IPC:
 572         typestr = "IPC";
 573         break;
 574     default:
 575         break;
 576     }
 577     DEBUG (3, ("\t%-15.15s%-10.10s%s\n", name, typestr, comment));
 578 }
 579 
 580 /* --------------------------------------------------------------------------------------------- */
 581 
 582 static void
 583 smbfs_loaddir_helper (file_info * finfo, const char *mask, void *entry)
     /* [previous][next][first][last][top][bottom][index][help]  */
 584 {
 585     dir_entry *new_entry = (dir_entry *) entry;
 586     time_t t = finfo->mtime;    /* the time is assumed to be passed as GMT */
 587 
 588     (void) mask;
 589 
 590 #if 0                           /* I want to see dot files */
 591     if (finfo->mode & aHIDDEN)
 592         return;                 /* don't bother with hidden files, "~$" screws up mc */
 593 #endif
 594     if (!entry)
 595         new_entry = smbfs_new_dir_entry (finfo->name);
 596 
 597     new_entry->my_stat.st_size = finfo->size;
 598     new_entry->my_stat.st_mtime = finfo->mtime;
 599     new_entry->my_stat.st_atime = finfo->atime;
 600     new_entry->my_stat.st_ctime = finfo->ctime;
 601     new_entry->my_stat.st_uid = finfo->uid;
 602     new_entry->my_stat.st_gid = finfo->gid;
 603 
 604     new_entry->my_stat.st_mode =        /*  rw-rw-rw */
 605         S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
 606 
 607     /*  if (finfo->mode & aVOLID);   nothing similar in real world */
 608     if (finfo->mode & aDIR)
 609         new_entry->my_stat.st_mode |=   /* drwxrwxrwx */
 610             S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
 611     else
 612         new_entry->my_stat.st_mode |= S_IFREG;  /* if not dir, regular file? */
 613     /*  if (finfo->mode & aARCH);   DOS archive     */
 614     /*  if (finfo->mode & aHIDDEN); like a dot file? */
 615     /*  if (finfo->mode & aSYSTEM); like a kernel? */
 616     if (finfo->mode & aRONLY)
 617         new_entry->my_stat.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
 618     new_entry->my_stat.st_mode &= myumask;
 619 
 620     DEBUG (entry ? 3 : 6, ("  %-30s%7.7s%8.0f  %s",
 621                            CNV_LANG (finfo->name),
 622                            attrib_string (finfo->mode),
 623                            (double) finfo->size, asctime (LocalTime (&t))));
 624 }
 625 
 626 /* --------------------------------------------------------------------------------------------- */
 627 /* takes "/foo/bar/file" and gives malloced "\\foo\\bar\\file" */
 628 
 629 static char *
 630 smbfs_convert_path (const char *remote_file, gboolean trailing_asterik)
     /* [previous][next][first][last][top][bottom][index][help]  */
 631 {
 632     const char *p, *my_remote;
 633     char *result;
 634 
 635     my_remote = remote_file;
 636     if (strncmp (my_remote, URL_HEADER, HEADER_LEN) == 0)
 637     {                           /* if passed directly */
 638         my_remote += HEADER_LEN;
 639         if (*my_remote == '/')  /* from server browsing */
 640             my_remote++;
 641         p = strchr (my_remote, '/');
 642         if (p)
 643             my_remote = p + 1;  /* advance to end of server name */
 644     }
 645 
 646     if (*my_remote == '/')
 647         my_remote++;            /* strip off leading '/' */
 648     p = strchr (my_remote, '/');
 649     if (p)
 650         my_remote = p;          /* strip off share/service name */
 651     /* create remote filename as understood by smb clientgen */
 652     result = g_strconcat (my_remote, trailing_asterik ? "/*" : "", (char *) NULL);
 653     unix_to_dos (result, /* inplace = */ 1);    /* code page conversion */
 654     str_replace (result, '/', '\\');
 655     return result;
 656 }
 657 
 658 /* --------------------------------------------------------------------------------------------- */
 659 
 660 static void
 661 smbfs_srv_browsing_helper (const char *name, uint32 m, const char *comment, void *state)
     /* [previous][next][first][last][top][bottom][index][help]  */
 662 {
 663     dir_entry *new_entry = smbfs_new_dir_entry (name);
 664 
 665     (void) m;
 666     (void) state;
 667 
 668     /* show this as dir */
 669     new_entry->my_stat.st_mode =
 670         (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
 671 
 672     DEBUG (3, ("\t%-16.16s     %s\n", name, comment));
 673 }
 674 
 675 /* --------------------------------------------------------------------------------------------- */
 676 
 677 static BOOL
 678 smbfs_reconnect (smbfs_connection * conn, int *retries)
     /* [previous][next][first][last][top][bottom][index][help]  */
 679 {
 680     char *host;
 681     DEBUG (3, ("RECONNECT\n"));
 682 
 683     if (*(conn->host) == 0)
 684         host = g_strdup (conn->cli->desthost);  /* server browsing */
 685     else
 686         host = g_strdup (conn->host);
 687 
 688     cli_shutdown (conn->cli);
 689 
 690     if (!(conn->cli = smbfs_do_connect (host, conn->service)))
 691     {
 692         message (D_ERROR, MSG_ERROR, _("reconnect to %s failed"), conn->host);
 693         g_free (host);
 694         return False;
 695     }
 696     g_free (host);
 697     if (++(*retries) == 2)
 698         return False;
 699     return True;
 700 }
 701 
 702 /* --------------------------------------------------------------------------------------------- */
 703 
 704 static BOOL
 705 smbfs_send (struct cli_state *cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
 706 {
 707     size_t len;
 708     size_t nwritten = 0;
 709     ssize_t ret;
 710 
 711     len = smb_len (cli->outbuf) + 4;
 712 
 713     while (nwritten < len)
 714     {
 715         ret = write_socket (cli->fd, cli->outbuf + nwritten, len - nwritten);
 716         if (ret <= 0)
 717         {
 718             if (errno == EPIPE)
 719                 return False;
 720         }
 721         else
 722             nwritten += ret;
 723     }
 724 
 725     return True;
 726 }
 727 
 728 /* --------------------------------------------------------------------------------------------- */
 729 /****************************************************************************
 730 See if server has cut us off by checking for EPIPE when writing.
 731 Taken from cli_chkpath()
 732 ****************************************************************************/
 733 
 734 static BOOL
 735 smbfs_chkpath (struct cli_state *cli, const char *path, BOOL send_only)
     /* [previous][next][first][last][top][bottom][index][help]  */
 736 {
 737     fstring path2;
 738     char *p;
 739 
 740     fstrcpy (path2, path);
 741     unix_to_dos (path2, 1);
 742     trim_string (path2, NULL, "\\");
 743     if (!*path2)
 744         *path2 = '\\';
 745 
 746     memset (cli->outbuf, '\0', smb_size);
 747     set_message (cli->outbuf, 0, 4 + strlen (path2), True);
 748     SCVAL (cli->outbuf, smb_com, SMBchkpth);
 749     SSVAL (cli->outbuf, smb_tid, cli->cnum);
 750 
 751     cli->rap_error = 0;
 752     cli->nt_error = 0;
 753     SSVAL (cli->outbuf, smb_pid, cli->pid);
 754     SSVAL (cli->outbuf, smb_uid, cli->vuid);
 755     SSVAL (cli->outbuf, smb_mid, cli->mid);
 756     if (cli->protocol > PROTOCOL_CORE)
 757     {
 758         SCVAL (cli->outbuf, smb_flg, 0x8);
 759         SSVAL (cli->outbuf, smb_flg2, 0x1);
 760     }
 761 
 762     p = smb_buf (cli->outbuf);
 763     *p++ = 4;
 764     fstrcpy (p, path2);
 765 
 766     if (!smbfs_send (cli))
 767     {
 768         DEBUG (3, ("smbfs_chkpath: couldnt send\n"));
 769         return False;
 770     }
 771     if (send_only)
 772     {
 773         client_receive_smb (cli->fd, cli->inbuf, cli->timeout);
 774         DEBUG (3, ("smbfs_chkpath: send only OK\n"));
 775         return True;            /* just testing for EPIPE */
 776     }
 777     if (!client_receive_smb (cli->fd, cli->inbuf, cli->timeout))
 778     {
 779         DEBUG (3, ("smbfs_chkpath: receive error\n"));
 780         return False;
 781     }
 782     if ((my_errno = cli_error (cli, NULL, NULL, NULL)))
 783     {
 784         if (my_errno == 20 || my_errno == 13)
 785             return True;        /* ignore if 'not a directory' error */
 786         DEBUG (3, ("smbfs_chkpath: cli_error: %s\n", unix_error_string (my_errno)));
 787         return False;
 788     }
 789 
 790     return True;
 791 }
 792 
 793 /* --------------------------------------------------------------------------------------------- */
 794 
 795 #if 1
 796 static int
 797 smbfs_fs (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 798 {
 799     const char *p = text;
 800     int count = 0;
 801 
 802     while ((p = strchr (p, '/')) != NULL)
 803     {
 804         count++;
 805         p++;
 806     }
 807     if (count == 1)
 808         return strlen (text);
 809     return count;
 810 }
 811 #endif
 812 
 813 /* --------------------------------------------------------------------------------------------- */
 814 
 815 static int
 816 smbfs_loaddir (opendir_info * smbfs_info)
     /* [previous][next][first][last][top][bottom][index][help]  */
 817 {
 818     uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
 819     int servlen = strlen (smbfs_info->conn->service);
 820     const char *info_dirname = smbfs_info->dirname;
 821     char *my_dirname;
 822 
 823     DEBUG (3, ("smbfs_loaddir: dirname:%s\n", info_dirname));
 824     first_direntry = TRUE;
 825 
 826     if (current_info)
 827     {
 828         DEBUG (3, ("smbfs_loaddir: new:'%s', cached:'%s'\n", info_dirname, current_info->dirname));
 829         /* if new desired dir is longer than cached in current_info */
 830         if (smbfs_fs (info_dirname) > smbfs_fs (current_info->dirname))
 831         {
 832             DEBUG (3, ("saving to previous_info\n"));
 833             previous_info = current_info;
 834         }
 835     }
 836 
 837     current_info = smbfs_info;
 838 
 839     if (strcmp (info_dirname, "/") == 0)
 840     {
 841         if (!strcmp (smbfs_info->path, URL_HEADER))
 842         {
 843             DEBUG (6, ("smbfs_loaddir: browsing %s\n", IPC));
 844             /* browse for servers */
 845             if (!cli_NetServerEnum
 846                 (smbfs_info->conn->cli, smbfs_info->conn->domain,
 847                  SV_TYPE_ALL, smbfs_srv_browsing_helper, NULL))
 848                 return 0;
 849             else
 850                 current_server_info = smbfs_info;
 851             smbfs_info->server_list = TRUE;
 852         }
 853         else
 854         {
 855             /* browse for shares */
 856             if (cli_RNetShareEnum (smbfs_info->conn->cli, smbfs_browsing_helper, NULL) < 1)
 857                 return 0;
 858             else
 859                 current_share_info = smbfs_info;
 860         }
 861         goto done;
 862     }
 863 
 864     /* do regular directory listing */
 865     if (strncmp (smbfs_info->conn->service, info_dirname + 1, servlen) == 0)
 866     {
 867         /* strip share name from dir */
 868         my_dirname = g_strdup (info_dirname + servlen);
 869         *my_dirname = '/';
 870         my_dirname = free_after (smbfs_convert_path (my_dirname, TRUE), my_dirname);
 871     }
 872     else
 873         my_dirname = smbfs_convert_path (info_dirname, TRUE);
 874 
 875     DEBUG (6, ("smbfs_loaddir: service: %s\n", smbfs_info->conn->service));
 876     DEBUG (6, ("smbfs_loaddir: cli->share: %s\n", smbfs_info->conn->cli->share));
 877     DEBUG (6, ("smbfs_loaddir: calling cli_list with mask %s\n", my_dirname));
 878     /* do file listing: cli_list returns number of files */
 879     if (cli_list (smbfs_info->conn->cli, my_dirname, attribute, smbfs_loaddir_helper, NULL) < 0)
 880     {
 881         /* cli_list returns -1 if directory empty or cannot read socket */
 882         my_errno = cli_error (smbfs_info->conn->cli, NULL, &err, NULL);
 883         g_free (my_dirname);
 884         return 0;
 885     }
 886     if (*(my_dirname) == 0)
 887         smbfs_info->dirname = smbfs_info->conn->service;
 888     g_free (my_dirname);
 889     /*      do_dskattr();   */
 890 
 891   done:
 892     /*      current_info->parent = smbfs_info->dirname;     */
 893 
 894     smbfs_info->current = smbfs_info->entries;
 895     return 1;                   /* 1 = ok */
 896 }
 897 
 898 /* --------------------------------------------------------------------------------------------- */
 899 
 900 #ifdef SMBFS_FREE_DIR
 901 static void
 902 smbfs_free_dir (dir_entry * de)
     /* [previous][next][first][last][top][bottom][index][help]  */
 903 {
 904     if (!de)
 905         return;
 906 
 907     smbfs_free_dir (de->next);
 908     g_free (de->text);
 909     g_free (de);
 910 }
 911 #endif
 912 
 913 /* --------------------------------------------------------------------------------------------- */
 914 /* The readdir routine loads the complete directory */
 915 /* It's too slow to ask the server each time */
 916 /* It now also sends the complete lstat information for each file */
 917 
 918 static struct vfs_dirent *
 919 smbfs_readdir (void *info)
     /* [previous][next][first][last][top][bottom][index][help]  */
 920 {
 921     struct vfs_dirent *dirent;
 922     opendir_info *smbfs_info = (opendir_info *) info;
 923 
 924     DEBUG (4, ("smbfs_readdir(%s)\n", smbfs_info->dirname));
 925 
 926     if (!smbfs_info->entries)
 927         if (!smbfs_loaddir (smbfs_info))
 928             return NULL;
 929 
 930     if (smbfs_info->current == 0)
 931     {                           /* reached end of dir entries */
 932         DEBUG (3, ("smbfs_readdir: smbfs_info->current = 0\n"));
 933 #ifdef  SMBFS_FREE_DIR
 934         smbfs_free_dir (smbfs_info->entries);
 935         smbfs_info->entries = 0;
 936 #endif
 937         return NULL;
 938     }
 939 
 940     dirent = vfs_dirent_init (NULL, smbfs_info->current->text, 0);      /* FIXME: inode */
 941 
 942     smbfs_info->current = smbfs_info->current->next;
 943 
 944     return dirent;
 945 }
 946 
 947 /* --------------------------------------------------------------------------------------------- */
 948 
 949 static int
 950 smbfs_closedir (void *info)
     /* [previous][next][first][last][top][bottom][index][help]  */
 951 {
 952     opendir_info *smbfs_info = (opendir_info *) info;
 953     /*    dir_entry *p, *q; */
 954 
 955     DEBUG (3, ("smbfs_closedir(%s)\n", smbfs_info->dirname));
 956     /*      CLOSE HERE */
 957 
 958     /*    for (p = smbfs_info->entries; p;){
 959        q = p;
 960        p = p->next;
 961        g_free (q->text);
 962        g_free (q);
 963        }
 964        g_free (info);       */
 965     return 0;
 966 }
 967 
 968 /* --------------------------------------------------------------------------------------------- */
 969 
 970 static int
 971 smbfs_chmod (const vfs_path_t * vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 972 {
 973     const vfs_path_element_t *path_element;
 974 
 975     path_element = vfs_path_get_by_index (vpath, -1);
 976     DEBUG (3, ("smbfs_chmod(path:%s, mode:%d)\n", path_element->path, (int) mode));
 977     /*      my_errno = EOPNOTSUPP;
 978        return -1;   *//* cannot chmod on smb filesystem */
 979     return 0;                   /* make mc happy */
 980 }
 981 
 982 /* --------------------------------------------------------------------------------------------- */
 983 
 984 static int
 985 smbfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help]  */
 986 {
 987     const vfs_path_element_t *path_element;
 988 
 989     path_element = vfs_path_get_by_index (vpath, -1);
 990     DEBUG (3,
 991            ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path_element->path, (int) owner,
 992             (int) group));
 993     my_errno = EOPNOTSUPP;      /* ready for your labotomy? */
 994     return -1;
 995 }
 996 
 997 /* --------------------------------------------------------------------------------------------- */
 998 
 999 static int
1000 smbfs_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
     /* [previous][next][first][last][top][bottom][index][help]  */
1001 {
1002     const vfs_path_element_t *path_element;
1003 
1004     (void) times;
1005 
1006     path_element = vfs_path_get_by_index (vpath, -1);
1007 #ifdef HAVE_UTIMENSAT
1008     DEBUG (3, ("smbfs_utimensat(path:%s)\n", path_element->path));
1009 #else
1010     DEBUG (3, ("smbfs_utime(path:%s)\n", path_element->path));
1011 #endif
1012     my_errno = EOPNOTSUPP;
1013     return -1;
1014 }
1015 
1016 /* --------------------------------------------------------------------------------------------- */
1017 
1018 static int
1019 smbfs_readlink (const vfs_path_t * vpath, char *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
1020 {
1021     const vfs_path_element_t *path_element;
1022 
1023     path_element = vfs_path_get_by_index (vpath, -1);
1024     DEBUG (3, ("smbfs_readlink(path:%s, buf:%s, size:%zu)\n", path_element->path, buf, size));
1025     my_errno = EOPNOTSUPP;
1026     return -1;                  /* no symlinks on smb filesystem? */
1027 }
1028 
1029 /* --------------------------------------------------------------------------------------------- */
1030 
1031 static int
1032 smbfs_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1033 {
1034     const vfs_path_element_t *path_element1;
1035     const vfs_path_element_t *path_element2;
1036 
1037     path_element1 = vfs_path_get_by_index (vpath1, -1);
1038     path_element2 = vfs_path_get_by_index (vpath2, -1);
1039     DEBUG (3, ("smbfs_symlink(n1:%s, n2:%s)\n", path_element1->path, path_element2->path));
1040     my_errno = EOPNOTSUPP;
1041     return -1;                  /* no symlinks on smb filesystem? */
1042 }
1043 
1044 /* --------------------------------------------------------------------------------------------- */
1045 /*****************************************************
1046         return a connection to a SMB server
1047         current_bucket needs to be set before calling
1048 *******************************************************/
1049 
1050 static struct cli_state *
1051 smbfs_do_connect (const char *server, char *share)
     /* [previous][next][first][last][top][bottom][index][help]  */
1052 {
1053     struct cli_state *c;
1054     struct nmb_name called, calling;
1055     struct in_addr ip;
1056 
1057     DEBUG (3, ("smbfs_do_connect(%s, %s)\n", server, share));
1058     if (*share == '\\')
1059     {
1060         server = share + 2;
1061         share = strchr (server, '\\');
1062         if (!share)
1063             return NULL;
1064         *share = 0;
1065         share++;
1066     }
1067 
1068     make_nmb_name (&calling, global_myname, 0x0);
1069     make_nmb_name (&called, server, current_bucket->name_type);
1070 
1071     for (;;)
1072     {
1073 
1074         ip = (current_bucket->have_ip) ? current_bucket->dest_ip : ipzero;
1075 
1076         /* have to open a new connection */
1077         if (!(c = cli_initialise (NULL)))
1078         {
1079             my_errno = ENOMEM;
1080             return NULL;
1081         }
1082 
1083         pwd_init (&(c->pwd));   /* should be moved into cli_initialise()? */
1084         pwd_set_cleartext (&(c->pwd), current_bucket->password);
1085 
1086         if ((cli_set_port (c, current_bucket->port) == 0) || !cli_connect (c, server, &ip))
1087         {
1088             DEBUG (1, ("Connection to %s failed\n", server));
1089             break;
1090         }
1091 
1092         if (!cli_session_request (c, &calling, &called))
1093         {
1094             my_errno = cli_error (c, NULL, &err, NULL);
1095             DEBUG (1, ("session request to %s failed\n", called.name));
1096             cli_shutdown (c);
1097             if (strcmp (called.name, "*SMBSERVER"))
1098             {
1099                 make_nmb_name (&called, "*SMBSERVER", 0x20);
1100                 continue;
1101             }
1102             return NULL;
1103         }
1104 
1105         DEBUG (3, (" session request ok\n"));
1106 
1107         if (!cli_negprot (c))
1108         {
1109             DEBUG (1, ("protocol negotiation failed\n"));
1110             break;
1111         }
1112 
1113         if (!cli_session_setup (c, current_bucket->user,
1114                                 current_bucket->password, strlen (current_bucket->password),
1115                                 current_bucket->password, strlen (current_bucket->password),
1116                                 current_bucket->domain))
1117         {
1118             DEBUG (1, ("session setup failed: %s\n", cli_errstr (c)));
1119             smbfs_auth_remove (server, share);
1120             break;
1121         }
1122 
1123         if (*c->server_domain || *c->server_os || *c->server_type)
1124             DEBUG (5, ("Domain=[%s] OS=[%s] Server=[%s]\n",
1125                        c->server_domain, c->server_os, c->server_type));
1126 
1127         DEBUG (3, (" session setup ok\n"));
1128 
1129         if (!cli_send_tconX (c, share, "?????",
1130                              current_bucket->password, strlen (current_bucket->password) + 1))
1131         {
1132             DEBUG (1, ("%s: tree connect failed: %s\n", share, cli_errstr (c)));
1133             break;
1134         }
1135 
1136         DEBUG (3, (" tconx ok\n"));
1137 
1138         my_errno = 0;
1139         return c;
1140     }
1141 
1142     my_errno = cli_error (c, NULL, &err, NULL);
1143     cli_shutdown (c);
1144     return NULL;
1145 
1146 }
1147 
1148 /* --------------------------------------------------------------------------------------------- */
1149 
1150 static int
1151 smbfs_get_master_browser (char **host)
     /* [previous][next][first][last][top][bottom][index][help]  */
1152 {
1153     static char so_broadcast[] = "SO_BROADCAST";
1154     int count;
1155     struct in_addr *ip_list, bcast_addr;
1156 
1157     /* does port = 137 for win95 master browser? */
1158     int fd = open_socket_in (SOCK_DGRAM, 0, 3,
1159                              interpret_addr (lp_socket_address ()), True);
1160     if (fd == -1)
1161         return 0;
1162     set_socket_options (fd, so_broadcast);
1163     ip_list = iface_bcast (ipzero);
1164     bcast_addr = *ip_list;
1165     if ((ip_list = name_query (fd, "\01\02__MSBROWSE__\02", 1, True,
1166                                True, bcast_addr, &count, NULL)))
1167     {
1168         if (!count)
1169             return 0;
1170         /* just return first master browser */
1171         *host = g_strdup (inet_ntoa (ip_list[0]));
1172         return 1;
1173     }
1174     return 0;
1175 }
1176 
1177 /* --------------------------------------------------------------------------------------------- */
1178 
1179 static void
1180 smbfs_free_bucket (smbfs_connection * bucket)
     /* [previous][next][first][last][top][bottom][index][help]  */
1181 {
1182     g_free (bucket->host);
1183     g_free (bucket->service);
1184     g_free (bucket->domain);
1185     g_free (bucket->user);
1186     wipe_password (bucket->password);
1187     g_free (bucket->home);
1188     memset (bucket, 0, sizeof (smbfs_connection));
1189 }
1190 
1191 /* --------------------------------------------------------------------------------------------- */
1192 
1193 static smbfs_connection *
1194 smbfs_get_free_bucket (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1195 {
1196     int i;
1197 
1198     for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1199         if (!smbfs_connections[i].cli)
1200             return &smbfs_connections[i];
1201 
1202     {                           /* search for most dormant connection */
1203         int oldest = 0;         /* index */
1204         time_t oldest_time = smbfs_connections[0].last_use;
1205         for (i = 1; i < SMBFS_MAX_CONNECTIONS; i++)
1206         {
1207             if (smbfs_connections[i].last_use < oldest_time)
1208             {
1209                 oldest_time = smbfs_connections[i].last_use;
1210                 oldest = i;
1211             }
1212         }
1213         cli_shutdown (smbfs_connections[oldest].cli);
1214         smbfs_free_bucket (&smbfs_connections[oldest]);
1215         return &smbfs_connections[oldest];
1216     }
1217 
1218     /* This can't happend, since we have checked for max connections before */
1219     vfs_die ("Internal error: smbfs_get_free_bucket");
1220     return 0;                   /* shut up, stupid gcc */
1221 }
1222 
1223 /* --------------------------------------------------------------------------------------------- */
1224 /* This routine keeps track of open connections */
1225 /* Returns a connected socket to host */
1226 
1227 static smbfs_connection *
1228 smbfs_open_link (char *host, char *path, const char *user, int *port, char *this_pass)
     /* [previous][next][first][last][top][bottom][index][help]  */
1229 {
1230     int i;
1231     smbfs_connection *bucket;
1232     pstring service;
1233     struct in_addr *dest_ip = NULL;
1234 
1235     DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host, path));
1236 
1237     if (strcmp (host, path) == 0)       /* if host & path are same: */
1238         pstrcpy (service, IPC); /* setup for browse */
1239     else
1240     {                           /* get share name from path, path starts with server name */
1241         char *p;
1242         if ((p = strchr (path, '/')))   /* get share aka                            */
1243             pstrcpy (service, ++p);     /* service name from path               */
1244         else
1245             pstrcpy (service, "");
1246         /* now check for trailing directory/filenames   */
1247         p = strchr (service, '/');
1248         if (p)
1249             *p = 0;             /* cut off dir/files: sharename only */
1250         if (!*service)
1251             pstrcpy (service, IPC);     /* setup for browse */
1252         DEBUG (6, ("smbfs_open_link: service from path:%s\n", service));
1253     }
1254 
1255     if (got_user)
1256         user = username;        /* global from getenv */
1257 
1258     /* Is the link actually open? */
1259     for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1260     {
1261         if (!smbfs_connections[i].cli)
1262             continue;
1263         if ((strcmp (host, smbfs_connections[i].host) == 0) &&
1264             (strcmp (user, smbfs_connections[i].user) == 0) &&
1265             (strcmp (service, smbfs_connections[i].service) == 0))
1266         {
1267             int retries = 0;
1268             BOOL inshare = (*host != 0 && *path != 0 && strchr (path, '/'));
1269             /* check if this connection has died */
1270             while (!smbfs_chkpath (smbfs_connections[i].cli, "\\", !inshare))
1271             {
1272                 if (!smbfs_reconnect (&smbfs_connections[i], &retries))
1273                     return 0;
1274             }
1275             DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i));
1276             current_bucket = &smbfs_connections[i];
1277             smbfs_connections[i].last_use = time (NULL);
1278             return &smbfs_connections[i];
1279         }
1280         /* connection not found, find if we have ip for new connection */
1281         if (strcmp (host, smbfs_connections[i].host) == 0)
1282             dest_ip = &smbfs_connections[i].cli->dest_ip;
1283     }
1284 
1285     /* make new connection */
1286     bucket = smbfs_get_free_bucket ();
1287     bucket->name_type = 0x20;
1288     bucket->home = 0;
1289     bucket->port = *port;
1290     bucket->have_ip = False;
1291     if (dest_ip)
1292     {
1293         bucket->have_ip = True;
1294         bucket->dest_ip = *dest_ip;
1295     }
1296     current_bucket = bucket;
1297 
1298     bucket->user = g_strdup (user);
1299     bucket->service = g_strdup (service);
1300 
1301     if (!(*host))
1302     {                           /* if blank host name, browse for servers */
1303         if (!smbfs_get_master_browser (&host))  /* set host to ip of master browser */
1304             return 0;           /* could not find master browser? */
1305         g_free (host);
1306         bucket->host = g_strdup ("");   /* blank host means master browser */
1307     }
1308     else
1309         bucket->host = g_strdup (host);
1310 
1311     if (!smbfs_bucket_set_authinfo (bucket, 0,  /* domain currently not used */
1312                                     user, this_pass, 1))
1313         return 0;
1314 
1315     /* connect to share */
1316     while (!(bucket->cli = smbfs_do_connect (host, service)))
1317     {
1318 
1319         if (my_errno != EPERM)
1320             return 0;
1321         message (D_ERROR, MSG_ERROR, "%s", _("Authentication failed"));
1322 
1323         /* authentication failed, try again */
1324         smbfs_auth_remove (bucket->host, bucket->service);
1325         if (!smbfs_bucket_set_authinfo (bucket, bucket->domain, bucket->user, 0, 0))
1326             return 0;
1327 
1328     }
1329 
1330     smbfs_open_connections++;
1331     DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n", smbfs_open_connections));
1332     return bucket;
1333 }
1334 
1335 /* --------------------------------------------------------------------------------------------- */
1336 
1337 static char *
1338 smbfs_get_path (smbfs_connection ** sc, const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1339 {
1340     char *remote_path = NULL;
1341     vfs_path_element_t *url;
1342     const vfs_path_element_t *path_element;
1343     const char *path;
1344 
1345     path_element = vfs_path_get_by_index (vpath, -1);
1346     path = path_element->path;
1347 
1348     DEBUG (3, ("smbfs_get_path(%s)\n", path));
1349 
1350     if (path_element->class != vfs_smbfs_ops)
1351         return NULL;
1352 
1353     while (*path == '/')        /* '/' leading server name */
1354         path++;                 /* probably came from server browsing */
1355 
1356     url = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1357 
1358     if (url != NULL)
1359     {
1360         *sc = smbfs_open_link (url->host, url->path, url->user, &url->port, url->password);
1361         wipe_password (url->password);
1362 
1363         if (*sc != NULL)
1364             remote_path = g_strdup (url->path);
1365 
1366         vfs_path_element_free (url);
1367     }
1368 
1369     if (remote_path == NULL)
1370         return NULL;
1371 
1372     /* NOTE: tildes are deprecated. See ftpfs.c */
1373     {
1374         int f = strcmp (remote_path, "/~") ? 0 : 1;
1375 
1376         if (f != 0 || strncmp (remote_path, "/~/", 3) == 0)
1377         {
1378             char *s;
1379 
1380             s = mc_build_filename ((*sc)->home, remote_path + 3 - f, (char *) NULL);
1381             g_free (remote_path);
1382             remote_path = s;
1383         }
1384     }
1385 
1386     return remote_path;
1387 }
1388 
1389 /* --------------------------------------------------------------------------------------------- */
1390 
1391 #if 0
1392 static int
1393 is_error (int result, int errno_num)
     /* [previous][next][first][last][top][bottom][index][help]  */
1394 {
1395     if (!(result == -1))
1396         return my_errno = 0;
1397     else
1398         my_errno = errno_num;
1399     return 1;
1400 }
1401 #endif
1402 
1403 /* --------------------------------------------------------------------------------------------- */
1404 
1405 static void *
1406 smbfs_opendir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1407 {
1408     opendir_info *smbfs_info;
1409     smbfs_connection *sc;
1410     char *remote_dir;
1411     const vfs_path_element_t *path_element;
1412 
1413     path_element = vfs_path_get_by_index (vpath, -1);
1414     DEBUG (3, ("smbfs_opendir(dirname:%s)\n", path_element->path));
1415 
1416     if (!(remote_dir = smbfs_get_path (&sc, vpath)))
1417         return NULL;
1418 
1419     /* FIXME: where freed? */
1420     smbfs_info = g_new (opendir_info, 1);
1421     smbfs_info->server_list = FALSE;
1422     smbfs_info->path = g_strdup (path_element->path);   /* keep original */
1423     smbfs_info->dirname = remote_dir;
1424     smbfs_info->conn = sc;
1425     smbfs_info->entries = 0;
1426     smbfs_info->current = 0;
1427 
1428     return smbfs_info;
1429 }
1430 
1431 /* --------------------------------------------------------------------------------------------- */
1432 
1433 static int
1434 smbfs_fake_server_stat (const char *server_url, const char *path, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1435 {
1436     dir_entry *dentry;
1437     const char *p;
1438 
1439     (void) server_url;
1440 
1441     if ((p = strrchr (path, '/')))
1442         path = p + 1;           /* advance until last '/' */
1443 
1444     if (!current_info->entries)
1445     {
1446         if (!smbfs_loaddir (current_info))      /* browse host */
1447             return -1;
1448     }
1449 
1450     if (current_info->server_list == True)
1451     {
1452         dentry = current_info->entries;
1453         DEBUG (4, ("fake stat for SERVER \"%s\"\n", path));
1454         while (dentry)
1455         {
1456             if (strcmp (dentry->text, path) == 0)
1457             {
1458                 DEBUG (4, ("smbfs_fake_server_stat: %s:%4o\n",
1459                            dentry->text, (unsigned int) dentry->my_stat.st_mode));
1460                 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1461                 return 0;
1462             }
1463             dentry = dentry->next;
1464         }
1465     }
1466     my_errno = ENOENT;
1467     return -1;
1468 }
1469 
1470 /* --------------------------------------------------------------------------------------------- */
1471 
1472 static int
1473 smbfs_fake_share_stat (const char *server_url, const char *path, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1474 {
1475     dir_entry *dentry;
1476     if (strlen (path) < strlen (server_url))
1477         return -1;
1478 
1479     if (!current_share_info)
1480     {                           /* Server was not stat()ed */
1481         /* Make sure there is such share at server */
1482         smbfs_connection *sc;
1483         char *p;
1484         vfs_path_t *vpath;
1485 
1486         vpath = vfs_path_from_str (path);
1487         p = smbfs_get_path (&sc, vpath);
1488         vfs_path_free (vpath);
1489 
1490         if (p != NULL)
1491         {
1492             memset (buf, 0, sizeof (*buf));
1493             /*      show this as dir        */
1494             buf->st_mode =
1495                 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
1496             g_free (p);
1497             return 0;
1498         }
1499         return -1;
1500     }
1501 
1502     path += strlen (server_url);        /* we only want share name */
1503     path++;
1504 
1505     if (*path == '/')           /* '/' leading server name */
1506         path++;                 /* probably came from server browsing */
1507 
1508     if (!current_share_info->entries)
1509     {
1510         if (!smbfs_loaddir (current_share_info))        /* browse host */
1511             return -1;
1512     }
1513     dentry = current_share_info->entries;
1514     DEBUG (3, ("smbfs_fake_share_stat: %s on %s\n", path, server_url));
1515     while (dentry)
1516     {
1517         if (strcmp (dentry->text, path) == 0)
1518         {
1519             DEBUG (6, ("smbfs_fake_share_stat: %s:%4o\n",
1520                        dentry->text, (unsigned int) dentry->my_stat.st_mode));
1521             memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1522             return 0;
1523         }
1524         dentry = dentry->next;
1525     }
1526     my_errno = ENOENT;
1527     return -1;
1528 }
1529 
1530 /* --------------------------------------------------------------------------------------------- */
1531 /* stat a single file */
1532 
1533 static int
1534 smbfs_get_remote_stat (smbfs_connection * sc, const char *path, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1535 {
1536     uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
1537     char *mypath;
1538 
1539     DEBUG (3, ("smbfs_get_remote_stat(): mypath:%s\n", path));
1540 
1541     mypath = smbfs_convert_path (path, FALSE);
1542 
1543 #if 0                           /* single_entry is never free()d now.  And only my_stat is used */
1544     single_entry = g_new (dir_entry, 1);
1545 
1546     single_entry->text = dos_to_unix (g_strdup (finfo->name), 1);
1547 
1548     single_entry->next = 0;
1549 #endif
1550     if (!single_entry)
1551         single_entry = g_new0 (dir_entry, 1);
1552 
1553     if (cli_list (sc->cli, mypath, attribute, smbfs_loaddir_helper, single_entry) < 1)
1554     {
1555         my_errno = ENOENT;
1556         g_free (mypath);
1557         return -1;              /* cli_list returns number of files */
1558     }
1559 
1560     memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
1561 
1562     /* don't free here, use for smbfs_fstat() */
1563     /*      g_free(single_entry->text);
1564        g_free(single_entry);        */
1565     g_free (mypath);
1566     return 0;
1567 }
1568 
1569 /* --------------------------------------------------------------------------------------------- */
1570 
1571 static int
1572 smbfs_search_dir_entry (dir_entry * dentry, const char *text, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1573 {
1574     while (dentry)
1575     {
1576         if (strcmp (text, dentry->text) == 0)
1577         {
1578             memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1579             memcpy (&single_entry->my_stat, &dentry->my_stat, sizeof (struct stat));
1580             return 0;
1581         }
1582         dentry = dentry->next;
1583     }
1584     return -1;
1585 }
1586 
1587 /* --------------------------------------------------------------------------------------------- */
1588 
1589 static int
1590 smbfs_get_stat_info (smbfs_connection * sc, const char *path, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1591 {
1592     char *p;
1593 #if 0
1594     dir_entry *dentry = current_info->entries;
1595 #endif
1596     const char *mypath = path;
1597 
1598     mypath++;                   /* cut off leading '/' */
1599     if ((p = strrchr (mypath, '/')))
1600         mypath = p + 1;         /* advance until last file/dir name */
1601     DEBUG (3, ("smbfs_get_stat_info: mypath:%s, current_info->dirname:%s\n",
1602                mypath, current_info->dirname));
1603 #if 0
1604     if (!dentry)
1605     {
1606         DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1607                    current_info->dirname, path));
1608         return -1;
1609     }
1610 #endif
1611     if (!single_entry)          /* when found, this will be written too */
1612         single_entry = g_new (dir_entry, 1);
1613     if (smbfs_search_dir_entry (current_info->entries, mypath, buf) == 0)
1614     {
1615         return 0;
1616     }
1617     /* now try to identify mypath as PARENT dir */
1618     {
1619         char *mdp;
1620         char *mydir;
1621         mdp = mydir = g_strdup (current_info->dirname);
1622         if ((p = strrchr (mydir, '/')))
1623             *p = 0;             /* advance util last '/' */
1624         if ((p = strrchr (mydir, '/')))
1625             mydir = p + 1;      /* advance util last '/' */
1626         if (strcmp (mydir, mypath) == 0)
1627         {                       /* fake a stat for ".." */
1628             memset (buf, 0, sizeof (struct stat));
1629             buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1630             memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1631             g_free (mdp);
1632             DEBUG (1, ("        PARENT:found in %s\n", current_info->dirname));
1633             return 0;
1634         }
1635         g_free (mdp);
1636     }
1637     /* now try to identify as CURRENT dir? */
1638     {
1639         char *dnp = current_info->dirname;
1640         DEBUG (6, ("smbfs_get_stat_info: is %s current dir? this dir is: %s\n",
1641                    mypath, current_info->dirname));
1642         if (*dnp == '/')
1643             dnp++;
1644         else
1645         {
1646             return -1;
1647         }
1648         if (strcmp (mypath, dnp) == 0)
1649         {
1650             memset (buf, 0, sizeof (struct stat));
1651             buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1652             memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1653             DEBUG (1, ("        CURRENT:found in %s\n", current_info->dirname));
1654             return 0;
1655         }
1656     }
1657     DEBUG (3, ("'%s' not found in current_info '%s'\n", path, current_info->dirname));
1658     /* try to find this in the PREVIOUS listing */
1659     if (previous_info)
1660     {
1661         if (smbfs_search_dir_entry (previous_info->entries, mypath, buf) == 0)
1662             return 0;
1663         DEBUG (3, ("'%s' not found in previous_info '%s'\n", path, previous_info->dirname));
1664     }
1665     /* try to find this in the SHARE listing */
1666     if (current_share_info)
1667     {
1668         if (smbfs_search_dir_entry (current_share_info->entries, mypath, buf) == 0)
1669             return 0;
1670         DEBUG (3, ("'%s' not found in share_info '%s'\n", path, current_share_info->dirname));
1671     }
1672     /* try to find this in the SERVER listing */
1673     if (current_server_info)
1674     {
1675         if (smbfs_search_dir_entry (current_server_info->entries, mypath, buf) == 0)
1676             return 0;
1677         DEBUG (3, ("'%s' not found in server_info '%s'\n", path, current_server_info->dirname));
1678     }
1679     /* nothing found. get stat file info from server */
1680     return smbfs_get_remote_stat (sc, path, buf);
1681 }
1682 
1683 /* --------------------------------------------------------------------------------------------- */
1684 
1685 static int
1686 smbfs_chdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1687 {
1688     char *remote_dir;
1689     smbfs_connection *sc;
1690     const vfs_path_element_t *path_element;
1691 
1692     path_element = vfs_path_get_by_index (vpath, -1);
1693     DEBUG (3, ("smbfs_chdir(path:%s)\n", path_element->path));
1694     if (!(remote_dir = smbfs_get_path (&sc, vpath)))
1695         return -1;
1696     g_free (remote_dir);
1697 
1698     return 0;
1699 }
1700 
1701 /* --------------------------------------------------------------------------------------------- */
1702 
1703 static int
1704 smbfs_loaddir_by_name (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1705 {
1706     void *info;
1707     char *mypath, *p;
1708     const vfs_path_element_t *path_element;
1709 
1710     path_element = vfs_path_get_by_index (vpath, -1);
1711     mypath = g_strdup (path_element->path);
1712     p = strrchr (mypath, '/');
1713 
1714     if (p > mypath)
1715         *p = 0;
1716     DEBUG (6, ("smbfs_loaddir_by_name(%s)\n", mypath));
1717     smbfs_chdir (vpath);
1718     info = smbfs_opendir (vpath);
1719     g_free (mypath);
1720     if (!info)
1721         return -1;
1722     smbfs_readdir (info);
1723     smbfs_loaddir (info);
1724     return 0;
1725 }
1726 
1727 /* --------------------------------------------------------------------------------------------- */
1728 
1729 static int
1730 smbfs_stat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1731 {
1732     smbfs_connection *sc;
1733     pstring server_url;
1734     char *service, *pp, *at;
1735     const char *p;
1736     const vfs_path_element_t *path_element;
1737 
1738     path_element = vfs_path_get_by_index (vpath, -1);
1739     DEBUG (3, ("smbfs_stat(path:%s)\n", path_element->path));
1740 
1741     if (!current_info)
1742     {
1743         DEBUG (1, ("current_info = NULL: "));
1744         if (smbfs_loaddir_by_name (vpath) < 0)
1745             return -1;
1746     }
1747 
1748     /* check if stating server */
1749     p = path_element->path;
1750     if (path_element->class != vfs_smbfs_ops)
1751         return -1;
1752 
1753     while (*p == '/')           /* '/' leading server name */
1754         p++;                    /* probably came from server browsing */
1755 
1756     pp = strchr (p, '/');       /* advance past next '/' */
1757     at = strchr (p, '@');
1758     pstrcpy (server_url, URL_HEADER);
1759     if (at && at < pp)
1760     {                           /* user@server */
1761         char *z = &(server_url[sizeof (server_url) - 1]);
1762         const char *s = p;
1763 
1764         at = &(server_url[HEADER_LEN]) + (at - p + 1);
1765         if (z > at)
1766             z = at;
1767         at = &(server_url[HEADER_LEN]);
1768         while (at < z)
1769             *at++ = *s++;
1770         *z = 0;
1771     }
1772     pstrcat (server_url, current_bucket->host);
1773 
1774     if (!pp)
1775     {
1776         if (!current_info->server_list)
1777         {
1778             if (smbfs_loaddir_by_name (vpath) < 0)
1779                 return -1;
1780         }
1781         return smbfs_fake_server_stat (server_url, path_element->path, buf);
1782     }
1783 
1784     if (!strchr (++pp, '/'))
1785     {
1786         return smbfs_fake_share_stat (server_url, path_element->path, buf);
1787     }
1788 
1789     /* stating inside share at this point */
1790     if (!(service = smbfs_get_path (&sc, vpath)))       /* connects if necessary */
1791         return -1;
1792     {
1793         int hostlen = strlen (current_bucket->host);
1794         char *ppp = service + strlen (service) - hostlen;
1795         char *sp = server_url + strlen (server_url) - hostlen;
1796 
1797         if (strcmp (sp, ppp) == 0)
1798         {
1799             /* make server name appear as directory */
1800             DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1801             memset (buf, 0, sizeof (struct stat));
1802             buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1803             g_free (service);
1804             return 0;
1805         }
1806     }
1807     /* check if current_info is in share requested */
1808     p = service;
1809     pp = strchr (p, '/');
1810     if (pp)
1811     {
1812         p = ++pp;               /* advance past server name */
1813         pp = strchr (p, '/');
1814     }
1815     if (pp)
1816         *pp = 0;                /* cut off everthing after service name */
1817     else
1818         p = IPC;                /* browsing for services */
1819     pp = current_info->dirname;
1820     if (*pp == '/')
1821         pp++;
1822     if (strncmp (p, pp, strlen (p)) != 0)
1823     {
1824         DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p, pp));
1825         if (smbfs_loaddir_by_name (vpath) < 0)
1826         {
1827             g_free (service);
1828             return -1;
1829         }
1830         DEBUG (6, ("loaded dir: '%s'\n", current_info->dirname));
1831     }
1832     g_free (service);
1833     /* stat dirs & files under shares now */
1834     return smbfs_get_stat_info (sc, path_element->path, buf);
1835 }
1836 
1837 /* --------------------------------------------------------------------------------------------- */
1838 
1839 static off_t
1840 smbfs_lseek (void *data, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
1841 {
1842     smbfs_handle *info = (smbfs_handle *) data;
1843     size_t size;
1844 
1845     DEBUG (3,
1846            ("smbfs_lseek(info->nread => %d, offset => %d, whence => %d) \n",
1847             (int) info->nread, (int) offset, whence));
1848 
1849     switch (whence)
1850     {
1851     case SEEK_SET:
1852         info->nread = offset;
1853         break;
1854     case SEEK_CUR:
1855         info->nread += offset;
1856         break;
1857     case SEEK_END:
1858         if (!cli_qfileinfo (info->cli, info->fnum,
1859                             NULL, &size, NULL, NULL, NULL,
1860                             NULL, NULL) &&
1861             !cli_getattrE (info->cli, info->fnum, NULL, &size, NULL, NULL, NULL))
1862         {
1863             errno = EINVAL;
1864             return -1;
1865         }
1866         info->nread = size + offset;
1867         break;
1868     default:
1869         break;
1870     }
1871 
1872     return info->nread;
1873 }
1874 
1875 /* --------------------------------------------------------------------------------------------- */
1876 
1877 static int
1878 smbfs_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help]  */
1879 {
1880     const vfs_path_element_t *path_element;
1881 
1882     path_element = vfs_path_get_by_index (vpath, -1);
1883     DEBUG (3,
1884            ("smbfs_mknod(path:%s, mode:%d, dev:%u)\n", path_element->path, (int) mode,
1885             (unsigned int) dev));
1886     my_errno = EOPNOTSUPP;
1887     return -1;
1888 }
1889 
1890 /* --------------------------------------------------------------------------------------------- */
1891 
1892 static int
1893 smbfs_mkdir (const vfs_path_t * vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
1894 {
1895     smbfs_connection *sc;
1896     char *remote_file;
1897     char *cpath;
1898     const vfs_path_element_t *path_element;
1899 
1900     path_element = vfs_path_get_by_index (vpath, -1);
1901     DEBUG (3, ("smbfs_mkdir(path:%s, mode:%d)\n", path_element->path, (int) mode));
1902     if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
1903         return -1;
1904     g_free (remote_file);
1905     cpath = smbfs_convert_path (path_element->path, FALSE);
1906 
1907     if (!cli_mkdir (sc->cli, cpath))
1908     {
1909         my_errno = cli_error (sc->cli, NULL, &err, NULL);
1910         message (D_ERROR, MSG_ERROR, _("Error %s creating directory %s"),
1911                  cli_errstr (sc->cli), CNV_LANG (cpath));
1912         g_free (cpath);
1913         return -1;
1914     }
1915     g_free (cpath);
1916     return 0;
1917 }
1918 
1919 /* --------------------------------------------------------------------------------------------- */
1920 
1921 static int
1922 smbfs_rmdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1923 {
1924     smbfs_connection *sc;
1925     char *remote_file;
1926     char *cpath;
1927     const vfs_path_element_t *path_element;
1928 
1929     path_element = vfs_path_get_by_index (vpath, -1);
1930     DEBUG (3, ("smbfs_rmdir(path:%s)\n", path_element->path));
1931     if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
1932         return -1;
1933     g_free (remote_file);
1934     cpath = smbfs_convert_path (path_element->path, FALSE);
1935 
1936     if (!cli_rmdir (sc->cli, cpath))
1937     {
1938         my_errno = cli_error (sc->cli, NULL, &err, NULL);
1939         message (D_ERROR, MSG_ERROR, _("Error %s removing directory %s"),
1940                  cli_errstr (sc->cli), CNV_LANG (cpath));
1941         g_free (cpath);
1942         return -1;
1943     }
1944 
1945     g_free (cpath);
1946     return 0;
1947 }
1948 
1949 /* --------------------------------------------------------------------------------------------- */
1950 
1951 static int
1952 smbfs_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1953 {
1954     const vfs_path_element_t *path_element1;
1955     const vfs_path_element_t *path_element2;
1956 
1957     path_element1 = vfs_path_get_by_index (vpath1, -1);
1958     path_element2 = vfs_path_get_by_index (vpath2, -1);
1959     DEBUG (3, ("smbfs_link(p1:%s, p2:%s)\n", path_element1->path, path_element2->path));
1960     my_errno = EOPNOTSUPP;
1961     return -1;
1962 }
1963 
1964 /* --------------------------------------------------------------------------------------------- */
1965 
1966 static void
1967 smbfs_free (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
1968 {
1969     DEBUG (3, ("smbfs_free(%p)\n", id));
1970     smbfs_auth_free_all ();
1971 }
1972 
1973 /* --------------------------------------------------------------------------------------------- */
1974 /* Gives up on a socket and reopens the connection, the child own the socket
1975  * now
1976  */
1977 
1978 static void
1979 smbfs_forget (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1980 {
1981     const vfs_path_element_t *path_element;
1982     vfs_path_element_t *p;
1983     const char *path;
1984 
1985     path_element = vfs_path_get_by_index (vpath, -1);
1986     if (path_element->class != vfs_smbfs_ops)
1987         return;
1988 
1989     path = path_element->path;
1990 
1991     DEBUG (3, ("smbfs_forget(path:%s)\n", path));
1992 
1993     while (*path == '/')        /* '/' leading server name */
1994         path++;                 /* probably came from server browsing */
1995 
1996     p = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1997     if (p != NULL)
1998     {
1999         size_t i;
2000 
2001         for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
2002         {
2003             if (smbfs_connections[i].cli
2004                 && (strcmp (p->host, smbfs_connections[i].host) == 0)
2005                 && (strcmp (p->user, smbfs_connections[i].user) == 0)
2006                 && (p->port == smbfs_connections[i].port))
2007             {
2008 
2009                 /* close socket: the child owns it now */
2010                 cli_shutdown (smbfs_connections[i].cli);
2011 
2012                 /* reopen the connection */
2013                 smbfs_connections[i].cli = smbfs_do_connect (p->host, smbfs_connections[i].service);
2014             }
2015         }
2016 
2017         vfs_path_element_free (p);
2018     }
2019 }
2020 
2021 /* --------------------------------------------------------------------------------------------- */
2022 
2023 static int
2024 smbfs_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
2025 {
2026     const vfs_path_element_t *path_element;
2027 
2028     (void) arg;
2029 
2030     path_element = vfs_path_get_by_index (vpath, -1);
2031     DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path_element->path, ctlop));
2032     switch (ctlop)
2033     {
2034     case VFS_SETCTL_FORGET:
2035         smbfs_forget (vpath);
2036         break;
2037     case VFS_SETCTL_LOGFILE:
2038         smbfs_set_debugf ((const char *) arg);
2039         break;
2040     default:
2041         break;
2042     }
2043     return 0;
2044 }
2045 
2046 /* --------------------------------------------------------------------------------------------- */
2047 
2048 static smbfs_handle *
2049 smbfs_open_readwrite (smbfs_handle * remote_handle, char *rname, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2050 {
2051     size_t size;
2052 
2053     (void) mode;
2054 
2055     if (flags & O_TRUNC)        /* if it exists truncate to zero */
2056         DEBUG (3, ("smbfs_open: O_TRUNC\n"));
2057 
2058     remote_handle->fnum =
2059 #if 1                           /* Don't play with flags, it is cli_open() headache */
2060         cli_open (remote_handle->cli, rname, flags, DENY_NONE);
2061 #else /* What's a reasons to has this code ? */
2062         cli_open (remote_handle->cli, rname, ((flags & O_CREAT)
2063                                               || (flags ==
2064                                                   (O_WRONLY | O_APPEND))) ?
2065                   flags : O_RDONLY, DENY_NONE);
2066 #endif
2067     if (remote_handle->fnum == -1)
2068     {
2069         message (D_ERROR, MSG_ERROR, _("%s opening remote file %s"),
2070                  cli_errstr (remote_handle->cli), CNV_LANG (rname));
2071         DEBUG (1, ("smbfs_open(rname:%s) error:%s\n", rname, cli_errstr (remote_handle->cli)));
2072         my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2073         return NULL;
2074     }
2075 
2076     if (flags & O_CREAT)
2077         return remote_handle;
2078 
2079     if (!cli_qfileinfo (remote_handle->cli, remote_handle->fnum,
2080                         &remote_handle->attr, &size, NULL, NULL, NULL, NULL,
2081                         NULL)
2082         && !cli_getattrE (remote_handle->cli, remote_handle->fnum,
2083                           &remote_handle->attr, &size, NULL, NULL, NULL))
2084     {
2085         message (D_ERROR, MSG_ERROR, "getattrib: %s", cli_errstr (remote_handle->cli));
2086         DEBUG (1, ("smbfs_open(rname:%s) getattrib:%s\n", rname, cli_errstr (remote_handle->cli)));
2087         my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2088         cli_close (remote_handle->cli, remote_handle->fnum);
2089         return NULL;
2090     }
2091 
2092     if ((flags == (O_WRONLY | O_APPEND))        /* file.c:copy_file_file() -> do_append */
2093         && smbfs_lseek (remote_handle, 0, SEEK_END) == -1)
2094     {
2095         cli_close (remote_handle->cli, remote_handle->fnum);
2096         return NULL;
2097     }
2098 
2099     return remote_handle;
2100 }
2101 
2102 /* --------------------------------------------------------------------------------------------- */
2103 
2104 static void *
2105 smbfs_open (const vfs_path_t * vpath, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2106 {
2107     char *remote_file;
2108     void *ret;
2109     smbfs_connection *sc;
2110     smbfs_handle *remote_handle;
2111     const vfs_path_element_t *path_element;
2112 
2113     path_element = vfs_path_get_by_index (vpath, -1);
2114     DEBUG (3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", path_element->path, flags, mode));
2115 
2116     if (!(remote_file = smbfs_get_path (&sc, vpath)))
2117         return 0;
2118 
2119     remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2120 
2121     remote_handle = g_new (smbfs_handle, 2);
2122     remote_handle->cli = sc->cli;
2123     remote_handle->nread = 0;
2124 
2125     ret = smbfs_open_readwrite (remote_handle, remote_file, flags, mode);
2126 
2127     g_free (remote_file);
2128     if (!ret)
2129         g_free (remote_handle);
2130 
2131     return ret;
2132 }
2133 
2134 /* --------------------------------------------------------------------------------------------- */
2135 
2136 static int
2137 smbfs_unlink (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
2138 {
2139     smbfs_connection *sc;
2140     char *remote_file;
2141 
2142     if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
2143         return -1;
2144 
2145     remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2146 
2147     if (!cli_unlink (sc->cli, remote_file))
2148     {
2149         message (D_ERROR, MSG_ERROR, _("%s removing remote file %s"),
2150                  cli_errstr (sc->cli), CNV_LANG (remote_file));
2151         g_free (remote_file);
2152         return -1;
2153     }
2154     g_free (remote_file);
2155     return 0;
2156 }
2157 
2158 /* --------------------------------------------------------------------------------------------- */
2159 
2160 static int
2161 smbfs_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
2162 {
2163     smbfs_connection *sc;
2164     char *ra, *rb;
2165     int retval;
2166 
2167     if ((ra = smbfs_get_path (&sc, vpath1)) == 0)
2168         return -1;
2169 
2170     if ((rb = smbfs_get_path (&sc, vpath2)) == 0)
2171     {
2172         g_free (ra);
2173         return -1;
2174     }
2175 
2176     ra = free_after (smbfs_convert_path (ra, FALSE), ra);
2177     rb = free_after (smbfs_convert_path (rb, FALSE), rb);
2178 
2179     retval = cli_rename (sc->cli, ra, rb);
2180 
2181     g_free (ra);
2182     g_free (rb);
2183 
2184     if (!retval)
2185     {
2186         message (D_ERROR, MSG_ERROR, _("%s renaming files\n"), cli_errstr (sc->cli));
2187         return -1;
2188     }
2189     return 0;
2190 }
2191 
2192 /* --------------------------------------------------------------------------------------------- */
2193 
2194 static int
2195 smbfs_fstat (void *data, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
2196 {
2197     smbfs_handle *remote_handle = (smbfs_handle *) data;
2198 
2199     DEBUG (3, ("smbfs_fstat(fnum:%d)\n", remote_handle->fnum));
2200 
2201     /* use left over from previous smbfs_get_remote_stat, if available */
2202     if (single_entry)
2203         memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
2204     else
2205     {                           /* single_entry not set up: bug */
2206         my_errno = EFAULT;
2207         return -EFAULT;
2208     }
2209     return 0;
2210 }
2211 
2212 /* --------------------------------------------------------------------------------------------- */
2213 
2214 static gboolean
2215 smbfs_nothingisopen (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
2216 {
2217     /* FIXME */
2218     (void) id;
2219 
2220     return TRUE;
2221 }
2222 
2223 /* --------------------------------------------------------------------------------------------- */
2224 /*** public functions ****************************************************************************/
2225 /* --------------------------------------------------------------------------------------------- */
2226 
2227 smb_authinfo *
2228 vfs_smb_authinfo_new (const char *host, const char *share, const char *domain,
     /* [previous][next][first][last][top][bottom][index][help]  */
2229                       const char *user, const char *pass)
2230 {
2231     smb_authinfo *auth;
2232 
2233     auth = g_try_new (struct smb_authinfo, 1);
2234 
2235     if (auth != NULL)
2236     {
2237         auth->host = g_strdup (host);
2238         auth->share = g_strdup (share);
2239         auth->domain = g_strdup (domain);
2240         auth->user = g_strdup (user);
2241         auth->password = g_strdup (pass);
2242     }
2243 
2244     return auth;
2245 }
2246 
2247 /* --------------------------------------------------------------------------------------------- */
2248 
2249 void
2250 vfs_init_smbfs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2251 {
2252     tcp_init ();
2253 
2254     /* NULLize vfs_s_subclass members */
2255     memset (&smbfs_subclass, 0, sizeof (smbfs_subclass));
2256 
2257     vfs_init_class (vfs_smbfs_ops, "smbfs", VFSF_NOLINKS, "smb");
2258     vfs_smbfs_ops->init = smbfs_init;
2259     vfs_smbfs_ops->fill_names = smbfs_fill_names;
2260     vfs_smbfs_ops->open = smbfs_open;
2261     vfs_smbfs_ops->close = smbfs_close;
2262     vfs_smbfs_ops->read = smbfs_read;
2263     vfs_smbfs_ops->write = smbfs_write;
2264     vfs_smbfs_ops->opendir = smbfs_opendir;
2265     vfs_smbfs_ops->readdir = smbfs_readdir;
2266     vfs_smbfs_ops->closedir = smbfs_closedir;
2267     vfs_smbfs_ops->stat = smbfs_stat;
2268     vfs_smbfs_ops->lstat = smbfs_lstat;
2269     vfs_smbfs_ops->fstat = smbfs_fstat;
2270     vfs_smbfs_ops->chmod = smbfs_chmod;
2271     vfs_smbfs_ops->chown = smbfs_chown;
2272     vfs_smbfs_ops->utime = smbfs_utime;
2273     vfs_smbfs_ops->readlink = smbfs_readlink;
2274     vfs_smbfs_ops->symlink = smbfs_symlink;
2275     vfs_smbfs_ops->link = smbfs_link;
2276     vfs_smbfs_ops->unlink = smbfs_unlink;
2277     vfs_smbfs_ops->rename = smbfs_rename;
2278     vfs_smbfs_ops->chdir = smbfs_chdir;
2279     vfs_smbfs_ops->ferrno = smbfs_errno;
2280     vfs_smbfs_ops->lseek = smbfs_lseek;
2281     vfs_smbfs_ops->mknod = smbfs_mknod;
2282     vfs_smbfs_ops->free = smbfs_free;
2283     vfs_smbfs_ops->mkdir = smbfs_mkdir;
2284     vfs_smbfs_ops->rmdir = smbfs_rmdir;
2285     vfs_smbfs_ops->setctl = smbfs_setctl;
2286     vfs_smbfs_ops->nothingisopen = smbfs_nothingisopen;
2287     vfs_register_class (vfs_smbfs_ops);
2288 }
2289 
2290 /* --------------------------------------------------------------------------------------------- */

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