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

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