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 void *
 919 smbfs_readdir (void *info)
     /* [previous][next][first][last][top][bottom][index][help]  */
 920 {
 921     static union vfs_dirent smbfs_readdir_data;
 922     static char *const dirent_dest = smbfs_readdir_data.dent.d_name;
 923     opendir_info *smbfs_info = (opendir_info *) info;
 924 
 925     DEBUG (4, ("smbfs_readdir(%s)\n", smbfs_info->dirname));
 926 
 927     if (!smbfs_info->entries)
 928         if (!smbfs_loaddir (smbfs_info))
 929             return NULL;
 930 
 931     if (smbfs_info->current == 0)
 932     {                           /* reached end of dir entries */
 933         DEBUG (3, ("smbfs_readdir: smbfs_info->current = 0\n"));
 934 #ifdef  SMBFS_FREE_DIR
 935         smbfs_free_dir (smbfs_info->entries);
 936         smbfs_info->entries = 0;
 937 #endif
 938         return NULL;
 939     }
 940     g_strlcpy (dirent_dest, smbfs_info->current->text, MC_MAXPATHLEN);
 941     smbfs_info->current = smbfs_info->current->next;
 942 
 943     return &smbfs_readdir_data;
 944 }
 945 
 946 /* --------------------------------------------------------------------------------------------- */
 947 
 948 static int
 949 smbfs_closedir (void *info)
     /* [previous][next][first][last][top][bottom][index][help]  */
 950 {
 951     opendir_info *smbfs_info = (opendir_info *) info;
 952     /*    dir_entry *p, *q; */
 953 
 954     DEBUG (3, ("smbfs_closedir(%s)\n", smbfs_info->dirname));
 955     /*      CLOSE HERE */
 956 
 957     /*    for (p = smbfs_info->entries; p;){
 958        q = p;
 959        p = p->next;
 960        g_free (q->text);
 961        g_free (q);
 962        }
 963        g_free (info);       */
 964     return 0;
 965 }
 966 
 967 /* --------------------------------------------------------------------------------------------- */
 968 
 969 static int
 970 smbfs_chmod (const vfs_path_t * vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 971 {
 972     const vfs_path_element_t *path_element;
 973 
 974     path_element = vfs_path_get_by_index (vpath, -1);
 975     DEBUG (3, ("smbfs_chmod(path:%s, mode:%d)\n", path_element->path, (int) mode));
 976     /*      my_errno = EOPNOTSUPP;
 977        return -1;   *//* cannot chmod on smb filesystem */
 978     return 0;                   /* make mc happy */
 979 }
 980 
 981 /* --------------------------------------------------------------------------------------------- */
 982 
 983 static int
 984 smbfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help]  */
 985 {
 986     const vfs_path_element_t *path_element;
 987 
 988     path_element = vfs_path_get_by_index (vpath, -1);
 989     DEBUG (3,
 990            ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path_element->path, (int) owner,
 991             (int) group));
 992     my_errno = EOPNOTSUPP;      /* ready for your labotomy? */
 993     return -1;
 994 }
 995 
 996 /* --------------------------------------------------------------------------------------------- */
 997 
 998 static int
 999 smbfs_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
     /* [previous][next][first][last][top][bottom][index][help]  */
1000 {
1001     const vfs_path_element_t *path_element;
1002 
1003     (void) times;
1004 
1005     path_element = vfs_path_get_by_index (vpath, -1);
1006 #ifdef HAVE_UTIMENSAT
1007     DEBUG (3, ("smbfs_utimensat(path:%s)\n", path_element->path));
1008 #else
1009     DEBUG (3, ("smbfs_utime(path:%s)\n", path_element->path));
1010 #endif
1011     my_errno = EOPNOTSUPP;
1012     return -1;
1013 }
1014 
1015 /* --------------------------------------------------------------------------------------------- */
1016 
1017 static int
1018 smbfs_readlink (const vfs_path_t * vpath, char *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
1019 {
1020     const vfs_path_element_t *path_element;
1021 
1022     path_element = vfs_path_get_by_index (vpath, -1);
1023     DEBUG (3, ("smbfs_readlink(path:%s, buf:%s, size:%zu)\n", path_element->path, buf, size));
1024     my_errno = EOPNOTSUPP;
1025     return -1;                  /* no symlinks on smb filesystem? */
1026 }
1027 
1028 /* --------------------------------------------------------------------------------------------- */
1029 
1030 static int
1031 smbfs_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1032 {
1033     const vfs_path_element_t *path_element1;
1034     const vfs_path_element_t *path_element2;
1035 
1036     path_element1 = vfs_path_get_by_index (vpath1, -1);
1037     path_element2 = vfs_path_get_by_index (vpath2, -1);
1038     DEBUG (3, ("smbfs_symlink(n1:%s, n2:%s)\n", path_element1->path, path_element2->path));
1039     my_errno = EOPNOTSUPP;
1040     return -1;                  /* no symlinks on smb filesystem? */
1041 }
1042 
1043 /* --------------------------------------------------------------------------------------------- */
1044 /*****************************************************
1045         return a connection to a SMB server
1046         current_bucket needs to be set before calling
1047 *******************************************************/
1048 
1049 static struct cli_state *
1050 smbfs_do_connect (const char *server, char *share)
     /* [previous][next][first][last][top][bottom][index][help]  */
1051 {
1052     struct cli_state *c;
1053     struct nmb_name called, calling;
1054     struct in_addr ip;
1055 
1056     DEBUG (3, ("smbfs_do_connect(%s, %s)\n", server, share));
1057     if (*share == '\\')
1058     {
1059         server = share + 2;
1060         share = strchr (server, '\\');
1061         if (!share)
1062             return NULL;
1063         *share = 0;
1064         share++;
1065     }
1066 
1067     make_nmb_name (&calling, global_myname, 0x0);
1068     make_nmb_name (&called, server, current_bucket->name_type);
1069 
1070     for (;;)
1071     {
1072 
1073         ip = (current_bucket->have_ip) ? current_bucket->dest_ip : ipzero;
1074 
1075         /* have to open a new connection */
1076         if (!(c = cli_initialise (NULL)))
1077         {
1078             my_errno = ENOMEM;
1079             return NULL;
1080         }
1081 
1082         pwd_init (&(c->pwd));   /* should be moved into cli_initialise()? */
1083         pwd_set_cleartext (&(c->pwd), current_bucket->password);
1084 
1085         if ((cli_set_port (c, current_bucket->port) == 0) || !cli_connect (c, server, &ip))
1086         {
1087             DEBUG (1, ("Connection to %s failed\n", server));
1088             break;
1089         }
1090 
1091         if (!cli_session_request (c, &calling, &called))
1092         {
1093             my_errno = cli_error (c, NULL, &err, NULL);
1094             DEBUG (1, ("session request to %s failed\n", called.name));
1095             cli_shutdown (c);
1096             if (strcmp (called.name, "*SMBSERVER"))
1097             {
1098                 make_nmb_name (&called, "*SMBSERVER", 0x20);
1099                 continue;
1100             }
1101             return NULL;
1102         }
1103 
1104         DEBUG (3, (" session request ok\n"));
1105 
1106         if (!cli_negprot (c))
1107         {
1108             DEBUG (1, ("protocol negotiation failed\n"));
1109             break;
1110         }
1111 
1112         if (!cli_session_setup (c, current_bucket->user,
1113                                 current_bucket->password, strlen (current_bucket->password),
1114                                 current_bucket->password, strlen (current_bucket->password),
1115                                 current_bucket->domain))
1116         {
1117             DEBUG (1, ("session setup failed: %s\n", cli_errstr (c)));
1118             smbfs_auth_remove (server, share);
1119             break;
1120         }
1121 
1122         if (*c->server_domain || *c->server_os || *c->server_type)
1123             DEBUG (5, ("Domain=[%s] OS=[%s] Server=[%s]\n",
1124                        c->server_domain, c->server_os, c->server_type));
1125 
1126         DEBUG (3, (" session setup ok\n"));
1127 
1128         if (!cli_send_tconX (c, share, "?????",
1129                              current_bucket->password, strlen (current_bucket->password) + 1))
1130         {
1131             DEBUG (1, ("%s: tree connect failed: %s\n", share, cli_errstr (c)));
1132             break;
1133         }
1134 
1135         DEBUG (3, (" tconx ok\n"));
1136 
1137         my_errno = 0;
1138         return c;
1139     }
1140 
1141     my_errno = cli_error (c, NULL, &err, NULL);
1142     cli_shutdown (c);
1143     return NULL;
1144 
1145 }
1146 
1147 /* --------------------------------------------------------------------------------------------- */
1148 
1149 static int
1150 smbfs_get_master_browser (char **host)
     /* [previous][next][first][last][top][bottom][index][help]  */
1151 {
1152     static char so_broadcast[] = "SO_BROADCAST";
1153     int count;
1154     struct in_addr *ip_list, bcast_addr;
1155 
1156     /* does port = 137 for win95 master browser? */
1157     int fd = open_socket_in (SOCK_DGRAM, 0, 3,
1158                              interpret_addr (lp_socket_address ()), True);
1159     if (fd == -1)
1160         return 0;
1161     set_socket_options (fd, so_broadcast);
1162     ip_list = iface_bcast (ipzero);
1163     bcast_addr = *ip_list;
1164     if ((ip_list = name_query (fd, "\01\02__MSBROWSE__\02", 1, True,
1165                                True, bcast_addr, &count, NULL)))
1166     {
1167         if (!count)
1168             return 0;
1169         /* just return first master browser */
1170         *host = g_strdup (inet_ntoa (ip_list[0]));
1171         return 1;
1172     }
1173     return 0;
1174 }
1175 
1176 /* --------------------------------------------------------------------------------------------- */
1177 
1178 static void
1179 smbfs_free_bucket (smbfs_connection * bucket)
     /* [previous][next][first][last][top][bottom][index][help]  */
1180 {
1181     g_free (bucket->host);
1182     g_free (bucket->service);
1183     g_free (bucket->domain);
1184     g_free (bucket->user);
1185     wipe_password (bucket->password);
1186     g_free (bucket->home);
1187     memset (bucket, 0, sizeof (smbfs_connection));
1188 }
1189 
1190 /* --------------------------------------------------------------------------------------------- */
1191 
1192 static smbfs_connection *
1193 smbfs_get_free_bucket (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1194 {
1195     int i;
1196 
1197     for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1198         if (!smbfs_connections[i].cli)
1199             return &smbfs_connections[i];
1200 
1201     {                           /* search for most dormant connection */
1202         int oldest = 0;         /* index */
1203         time_t oldest_time = smbfs_connections[0].last_use;
1204         for (i = 1; i < SMBFS_MAX_CONNECTIONS; i++)
1205         {
1206             if (smbfs_connections[i].last_use < oldest_time)
1207             {
1208                 oldest_time = smbfs_connections[i].last_use;
1209                 oldest = i;
1210             }
1211         }
1212         cli_shutdown (smbfs_connections[oldest].cli);
1213         smbfs_free_bucket (&smbfs_connections[oldest]);
1214         return &smbfs_connections[oldest];
1215     }
1216 
1217     /* This can't happend, since we have checked for max connections before */
1218     vfs_die ("Internal error: smbfs_get_free_bucket");
1219     return 0;                   /* shut up, stupid gcc */
1220 }
1221 
1222 /* --------------------------------------------------------------------------------------------- */
1223 /* This routine keeps track of open connections */
1224 /* Returns a connected socket to host */
1225 
1226 static smbfs_connection *
1227 smbfs_open_link (char *host, char *path, const char *user, int *port, char *this_pass)
     /* [previous][next][first][last][top][bottom][index][help]  */
1228 {
1229     int i;
1230     smbfs_connection *bucket;
1231     pstring service;
1232     struct in_addr *dest_ip = NULL;
1233 
1234     DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host, path));
1235 
1236     if (strcmp (host, path) == 0)       /* if host & path are same: */
1237         pstrcpy (service, IPC); /* setup for browse */
1238     else
1239     {                           /* get share name from path, path starts with server name */
1240         char *p;
1241         if ((p = strchr (path, '/')))   /* get share aka                            */
1242             pstrcpy (service, ++p);     /* service name from path               */
1243         else
1244             pstrcpy (service, "");
1245         /* now check for trailing directory/filenames   */
1246         p = strchr (service, '/');
1247         if (p)
1248             *p = 0;             /* cut off dir/files: sharename only */
1249         if (!*service)
1250             pstrcpy (service, IPC);     /* setup for browse */
1251         DEBUG (6, ("smbfs_open_link: service from path:%s\n", service));
1252     }
1253 
1254     if (got_user)
1255         user = username;        /* global from getenv */
1256 
1257     /* Is the link actually open? */
1258     for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1259     {
1260         if (!smbfs_connections[i].cli)
1261             continue;
1262         if ((strcmp (host, smbfs_connections[i].host) == 0) &&
1263             (strcmp (user, smbfs_connections[i].user) == 0) &&
1264             (strcmp (service, smbfs_connections[i].service) == 0))
1265         {
1266             int retries = 0;
1267             BOOL inshare = (*host != 0 && *path != 0 && strchr (path, '/'));
1268             /* check if this connection has died */
1269             while (!smbfs_chkpath (smbfs_connections[i].cli, "\\", !inshare))
1270             {
1271                 if (!smbfs_reconnect (&smbfs_connections[i], &retries))
1272                     return 0;
1273             }
1274             DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i));
1275             current_bucket = &smbfs_connections[i];
1276             smbfs_connections[i].last_use = time (NULL);
1277             return &smbfs_connections[i];
1278         }
1279         /* connection not found, find if we have ip for new connection */
1280         if (strcmp (host, smbfs_connections[i].host) == 0)
1281             dest_ip = &smbfs_connections[i].cli->dest_ip;
1282     }
1283 
1284     /* make new connection */
1285     bucket = smbfs_get_free_bucket ();
1286     bucket->name_type = 0x20;
1287     bucket->home = 0;
1288     bucket->port = *port;
1289     bucket->have_ip = False;
1290     if (dest_ip)
1291     {
1292         bucket->have_ip = True;
1293         bucket->dest_ip = *dest_ip;
1294     }
1295     current_bucket = bucket;
1296 
1297     bucket->user = g_strdup (user);
1298     bucket->service = g_strdup (service);
1299 
1300     if (!(*host))
1301     {                           /* if blank host name, browse for servers */
1302         if (!smbfs_get_master_browser (&host))  /* set host to ip of master browser */
1303             return 0;           /* could not find master browser? */
1304         g_free (host);
1305         bucket->host = g_strdup ("");   /* blank host means master browser */
1306     }
1307     else
1308         bucket->host = g_strdup (host);
1309 
1310     if (!smbfs_bucket_set_authinfo (bucket, 0,  /* domain currently not used */
1311                                     user, this_pass, 1))
1312         return 0;
1313 
1314     /* connect to share */
1315     while (!(bucket->cli = smbfs_do_connect (host, service)))
1316     {
1317 
1318         if (my_errno != EPERM)
1319             return 0;
1320         message (D_ERROR, MSG_ERROR, "%s", _("Authentication failed"));
1321 
1322         /* authentication failed, try again */
1323         smbfs_auth_remove (bucket->host, bucket->service);
1324         if (!smbfs_bucket_set_authinfo (bucket, bucket->domain, bucket->user, 0, 0))
1325             return 0;
1326 
1327     }
1328 
1329     smbfs_open_connections++;
1330     DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n", smbfs_open_connections));
1331     return bucket;
1332 }
1333 
1334 /* --------------------------------------------------------------------------------------------- */
1335 
1336 static char *
1337 smbfs_get_path (smbfs_connection ** sc, const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1338 {
1339     char *remote_path = NULL;
1340     vfs_path_element_t *url;
1341     const vfs_path_element_t *path_element;
1342     const char *path;
1343 
1344     path_element = vfs_path_get_by_index (vpath, -1);
1345     path = path_element->path;
1346 
1347     DEBUG (3, ("smbfs_get_path(%s)\n", path));
1348 
1349     if (path_element->class != vfs_smbfs_ops)
1350         return NULL;
1351 
1352     while (*path == '/')        /* '/' leading server name */
1353         path++;                 /* probably came from server browsing */
1354 
1355     url = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1356 
1357     if (url != NULL)
1358     {
1359         *sc = smbfs_open_link (url->host, url->path, url->user, &url->port, url->password);
1360         wipe_password (url->password);
1361 
1362         if (*sc != NULL)
1363             remote_path = g_strdup (url->path);
1364 
1365         vfs_path_element_free (url);
1366     }
1367 
1368     if (remote_path == NULL)
1369         return NULL;
1370 
1371     /* NOTE: tildes are deprecated. See ftpfs.c */
1372     {
1373         int f = strcmp (remote_path, "/~") ? 0 : 1;
1374 
1375         if (f != 0 || strncmp (remote_path, "/~/", 3) == 0)
1376         {
1377             char *s;
1378 
1379             s = mc_build_filename ((*sc)->home, remote_path + 3 - f, (char *) NULL);
1380             g_free (remote_path);
1381             remote_path = s;
1382         }
1383     }
1384 
1385     return remote_path;
1386 }
1387 
1388 /* --------------------------------------------------------------------------------------------- */
1389 
1390 #if 0
1391 static int
1392 is_error (int result, int errno_num)
     /* [previous][next][first][last][top][bottom][index][help]  */
1393 {
1394     if (!(result == -1))
1395         return my_errno = 0;
1396     else
1397         my_errno = errno_num;
1398     return 1;
1399 }
1400 #endif
1401 
1402 /* --------------------------------------------------------------------------------------------- */
1403 
1404 static void *
1405 smbfs_opendir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1406 {
1407     opendir_info *smbfs_info;
1408     smbfs_connection *sc;
1409     char *remote_dir;
1410     const vfs_path_element_t *path_element;
1411 
1412     path_element = vfs_path_get_by_index (vpath, -1);
1413     DEBUG (3, ("smbfs_opendir(dirname:%s)\n", path_element->path));
1414 
1415     if (!(remote_dir = smbfs_get_path (&sc, vpath)))
1416         return NULL;
1417 
1418     /* FIXME: where freed? */
1419     smbfs_info = g_new (opendir_info, 1);
1420     smbfs_info->server_list = FALSE;
1421     smbfs_info->path = g_strdup (path_element->path);   /* keep original */
1422     smbfs_info->dirname = remote_dir;
1423     smbfs_info->conn = sc;
1424     smbfs_info->entries = 0;
1425     smbfs_info->current = 0;
1426 
1427     return smbfs_info;
1428 }
1429 
1430 /* --------------------------------------------------------------------------------------------- */
1431 
1432 static int
1433 smbfs_fake_server_stat (const char *server_url, const char *path, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1434 {
1435     dir_entry *dentry;
1436     const char *p;
1437 
1438     (void) server_url;
1439 
1440     if ((p = strrchr (path, '/')))
1441         path = p + 1;           /* advance until last '/' */
1442 
1443     if (!current_info->entries)
1444     {
1445         if (!smbfs_loaddir (current_info))      /* browse host */
1446             return -1;
1447     }
1448 
1449     if (current_info->server_list == True)
1450     {
1451         dentry = current_info->entries;
1452         DEBUG (4, ("fake stat for SERVER \"%s\"\n", path));
1453         while (dentry)
1454         {
1455             if (strcmp (dentry->text, path) == 0)
1456             {
1457                 DEBUG (4, ("smbfs_fake_server_stat: %s:%4o\n",
1458                            dentry->text, (unsigned int) dentry->my_stat.st_mode));
1459                 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1460                 return 0;
1461             }
1462             dentry = dentry->next;
1463         }
1464     }
1465     my_errno = ENOENT;
1466     return -1;
1467 }
1468 
1469 /* --------------------------------------------------------------------------------------------- */
1470 
1471 static int
1472 smbfs_fake_share_stat (const char *server_url, const char *path, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1473 {
1474     dir_entry *dentry;
1475     if (strlen (path) < strlen (server_url))
1476         return -1;
1477 
1478     if (!current_share_info)
1479     {                           /* Server was not stat()ed */
1480         /* Make sure there is such share at server */
1481         smbfs_connection *sc;
1482         char *p;
1483         vfs_path_t *vpath;
1484 
1485         vpath = vfs_path_from_str (path);
1486         p = smbfs_get_path (&sc, vpath);
1487         vfs_path_free (vpath);
1488 
1489         if (p != NULL)
1490         {
1491             memset (buf, 0, sizeof (*buf));
1492             /*      show this as dir        */
1493             buf->st_mode =
1494                 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
1495             g_free (p);
1496             return 0;
1497         }
1498         return -1;
1499     }
1500 
1501     path += strlen (server_url);        /* we only want share name */
1502     path++;
1503 
1504     if (*path == '/')           /* '/' leading server name */
1505         path++;                 /* probably came from server browsing */
1506 
1507     if (!current_share_info->entries)
1508     {
1509         if (!smbfs_loaddir (current_share_info))        /* browse host */
1510             return -1;
1511     }
1512     dentry = current_share_info->entries;
1513     DEBUG (3, ("smbfs_fake_share_stat: %s on %s\n", path, server_url));
1514     while (dentry)
1515     {
1516         if (strcmp (dentry->text, path) == 0)
1517         {
1518             DEBUG (6, ("smbfs_fake_share_stat: %s:%4o\n",
1519                        dentry->text, (unsigned int) dentry->my_stat.st_mode));
1520             memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1521             return 0;
1522         }
1523         dentry = dentry->next;
1524     }
1525     my_errno = ENOENT;
1526     return -1;
1527 }
1528 
1529 /* --------------------------------------------------------------------------------------------- */
1530 /* stat a single file */
1531 
1532 static int
1533 smbfs_get_remote_stat (smbfs_connection * sc, const char *path, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1534 {
1535     uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
1536     char *mypath;
1537 
1538     DEBUG (3, ("smbfs_get_remote_stat(): mypath:%s\n", path));
1539 
1540     mypath = smbfs_convert_path (path, FALSE);
1541 
1542 #if 0                           /* single_entry is never free()d now.  And only my_stat is used */
1543     single_entry = g_new (dir_entry, 1);
1544 
1545     single_entry->text = dos_to_unix (g_strdup (finfo->name), 1);
1546 
1547     single_entry->next = 0;
1548 #endif
1549     if (!single_entry)
1550         single_entry = g_new0 (dir_entry, 1);
1551 
1552     if (cli_list (sc->cli, mypath, attribute, smbfs_loaddir_helper, single_entry) < 1)
1553     {
1554         my_errno = ENOENT;
1555         g_free (mypath);
1556         return -1;              /* cli_list returns number of files */
1557     }
1558 
1559     memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
1560 
1561     /* don't free here, use for smbfs_fstat() */
1562     /*      g_free(single_entry->text);
1563        g_free(single_entry);        */
1564     g_free (mypath);
1565     return 0;
1566 }
1567 
1568 /* --------------------------------------------------------------------------------------------- */
1569 
1570 static int
1571 smbfs_search_dir_entry (dir_entry * dentry, const char *text, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1572 {
1573     while (dentry)
1574     {
1575         if (strcmp (text, dentry->text) == 0)
1576         {
1577             memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1578             memcpy (&single_entry->my_stat, &dentry->my_stat, sizeof (struct stat));
1579             return 0;
1580         }
1581         dentry = dentry->next;
1582     }
1583     return -1;
1584 }
1585 
1586 /* --------------------------------------------------------------------------------------------- */
1587 
1588 static int
1589 smbfs_get_stat_info (smbfs_connection * sc, const char *path, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1590 {
1591     char *p;
1592 #if 0
1593     dir_entry *dentry = current_info->entries;
1594 #endif
1595     const char *mypath = path;
1596 
1597     mypath++;                   /* cut off leading '/' */
1598     if ((p = strrchr (mypath, '/')))
1599         mypath = p + 1;         /* advance until last file/dir name */
1600     DEBUG (3, ("smbfs_get_stat_info: mypath:%s, current_info->dirname:%s\n",
1601                mypath, current_info->dirname));
1602 #if 0
1603     if (!dentry)
1604     {
1605         DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1606                    current_info->dirname, path));
1607         return -1;
1608     }
1609 #endif
1610     if (!single_entry)          /* when found, this will be written too */
1611         single_entry = g_new (dir_entry, 1);
1612     if (smbfs_search_dir_entry (current_info->entries, mypath, buf) == 0)
1613     {
1614         return 0;
1615     }
1616     /* now try to identify mypath as PARENT dir */
1617     {
1618         char *mdp;
1619         char *mydir;
1620         mdp = mydir = g_strdup (current_info->dirname);
1621         if ((p = strrchr (mydir, '/')))
1622             *p = 0;             /* advance util last '/' */
1623         if ((p = strrchr (mydir, '/')))
1624             mydir = p + 1;      /* advance util last '/' */
1625         if (strcmp (mydir, mypath) == 0)
1626         {                       /* fake a stat for ".." */
1627             memset (buf, 0, sizeof (struct stat));
1628             buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1629             memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1630             g_free (mdp);
1631             DEBUG (1, ("        PARENT:found in %s\n", current_info->dirname));
1632             return 0;
1633         }
1634         g_free (mdp);
1635     }
1636     /* now try to identify as CURRENT dir? */
1637     {
1638         char *dnp = current_info->dirname;
1639         DEBUG (6, ("smbfs_get_stat_info: is %s current dir? this dir is: %s\n",
1640                    mypath, current_info->dirname));
1641         if (*dnp == '/')
1642             dnp++;
1643         else
1644         {
1645             return -1;
1646         }
1647         if (strcmp (mypath, dnp) == 0)
1648         {
1649             memset (buf, 0, sizeof (struct stat));
1650             buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1651             memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1652             DEBUG (1, ("        CURRENT:found in %s\n", current_info->dirname));
1653             return 0;
1654         }
1655     }
1656     DEBUG (3, ("'%s' not found in current_info '%s'\n", path, current_info->dirname));
1657     /* try to find this in the PREVIOUS listing */
1658     if (previous_info)
1659     {
1660         if (smbfs_search_dir_entry (previous_info->entries, mypath, buf) == 0)
1661             return 0;
1662         DEBUG (3, ("'%s' not found in previous_info '%s'\n", path, previous_info->dirname));
1663     }
1664     /* try to find this in the SHARE listing */
1665     if (current_share_info)
1666     {
1667         if (smbfs_search_dir_entry (current_share_info->entries, mypath, buf) == 0)
1668             return 0;
1669         DEBUG (3, ("'%s' not found in share_info '%s'\n", path, current_share_info->dirname));
1670     }
1671     /* try to find this in the SERVER listing */
1672     if (current_server_info)
1673     {
1674         if (smbfs_search_dir_entry (current_server_info->entries, mypath, buf) == 0)
1675             return 0;
1676         DEBUG (3, ("'%s' not found in server_info '%s'\n", path, current_server_info->dirname));
1677     }
1678     /* nothing found. get stat file info from server */
1679     return smbfs_get_remote_stat (sc, path, buf);
1680 }
1681 
1682 /* --------------------------------------------------------------------------------------------- */
1683 
1684 static int
1685 smbfs_chdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1686 {
1687     char *remote_dir;
1688     smbfs_connection *sc;
1689     const vfs_path_element_t *path_element;
1690 
1691     path_element = vfs_path_get_by_index (vpath, -1);
1692     DEBUG (3, ("smbfs_chdir(path:%s)\n", path_element->path));
1693     if (!(remote_dir = smbfs_get_path (&sc, vpath)))
1694         return -1;
1695     g_free (remote_dir);
1696 
1697     return 0;
1698 }
1699 
1700 /* --------------------------------------------------------------------------------------------- */
1701 
1702 static int
1703 smbfs_loaddir_by_name (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1704 {
1705     void *info;
1706     char *mypath, *p;
1707     const vfs_path_element_t *path_element;
1708 
1709     path_element = vfs_path_get_by_index (vpath, -1);
1710     mypath = g_strdup (path_element->path);
1711     p = strrchr (mypath, '/');
1712 
1713     if (p > mypath)
1714         *p = 0;
1715     DEBUG (6, ("smbfs_loaddir_by_name(%s)\n", mypath));
1716     smbfs_chdir (vpath);
1717     info = smbfs_opendir (vpath);
1718     g_free (mypath);
1719     if (!info)
1720         return -1;
1721     smbfs_readdir (info);
1722     smbfs_loaddir (info);
1723     return 0;
1724 }
1725 
1726 /* --------------------------------------------------------------------------------------------- */
1727 
1728 static int
1729 smbfs_stat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
1730 {
1731     smbfs_connection *sc;
1732     pstring server_url;
1733     char *service, *pp, *at;
1734     const char *p;
1735     const vfs_path_element_t *path_element;
1736 
1737     path_element = vfs_path_get_by_index (vpath, -1);
1738     DEBUG (3, ("smbfs_stat(path:%s)\n", path_element->path));
1739 
1740     if (!current_info)
1741     {
1742         DEBUG (1, ("current_info = NULL: "));
1743         if (smbfs_loaddir_by_name (vpath) < 0)
1744             return -1;
1745     }
1746 
1747     /* check if stating server */
1748     p = path_element->path;
1749     if (path_element->class != vfs_smbfs_ops)
1750         return -1;
1751 
1752     while (*p == '/')           /* '/' leading server name */
1753         p++;                    /* probably came from server browsing */
1754 
1755     pp = strchr (p, '/');       /* advance past next '/' */
1756     at = strchr (p, '@');
1757     pstrcpy (server_url, URL_HEADER);
1758     if (at && at < pp)
1759     {                           /* user@server */
1760         char *z = &(server_url[sizeof (server_url) - 1]);
1761         const char *s = p;
1762 
1763         at = &(server_url[HEADER_LEN]) + (at - p + 1);
1764         if (z > at)
1765             z = at;
1766         at = &(server_url[HEADER_LEN]);
1767         while (at < z)
1768             *at++ = *s++;
1769         *z = 0;
1770     }
1771     pstrcat (server_url, current_bucket->host);
1772 
1773     if (!pp)
1774     {
1775         if (!current_info->server_list)
1776         {
1777             if (smbfs_loaddir_by_name (vpath) < 0)
1778                 return -1;
1779         }
1780         return smbfs_fake_server_stat (server_url, path_element->path, buf);
1781     }
1782 
1783     if (!strchr (++pp, '/'))
1784     {
1785         return smbfs_fake_share_stat (server_url, path_element->path, buf);
1786     }
1787 
1788     /* stating inside share at this point */
1789     if (!(service = smbfs_get_path (&sc, vpath)))       /* connects if necessary */
1790         return -1;
1791     {
1792         int hostlen = strlen (current_bucket->host);
1793         char *ppp = service + strlen (service) - hostlen;
1794         char *sp = server_url + strlen (server_url) - hostlen;
1795 
1796         if (strcmp (sp, ppp) == 0)
1797         {
1798             /* make server name appear as directory */
1799             DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1800             memset (buf, 0, sizeof (struct stat));
1801             buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1802             g_free (service);
1803             return 0;
1804         }
1805     }
1806     /* check if current_info is in share requested */
1807     p = service;
1808     pp = strchr (p, '/');
1809     if (pp)
1810     {
1811         p = ++pp;               /* advance past server name */
1812         pp = strchr (p, '/');
1813     }
1814     if (pp)
1815         *pp = 0;                /* cut off everthing after service name */
1816     else
1817         p = IPC;                /* browsing for services */
1818     pp = current_info->dirname;
1819     if (*pp == '/')
1820         pp++;
1821     if (strncmp (p, pp, strlen (p)) != 0)
1822     {
1823         DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p, pp));
1824         if (smbfs_loaddir_by_name (vpath) < 0)
1825         {
1826             g_free (service);
1827             return -1;
1828         }
1829         DEBUG (6, ("loaded dir: '%s'\n", current_info->dirname));
1830     }
1831     g_free (service);
1832     /* stat dirs & files under shares now */
1833     return smbfs_get_stat_info (sc, path_element->path, buf);
1834 }
1835 
1836 /* --------------------------------------------------------------------------------------------- */
1837 
1838 static off_t
1839 smbfs_lseek (void *data, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
1840 {
1841     smbfs_handle *info = (smbfs_handle *) data;
1842     size_t size;
1843 
1844     DEBUG (3,
1845            ("smbfs_lseek(info->nread => %d, offset => %d, whence => %d) \n",
1846             (int) info->nread, (int) offset, whence));
1847 
1848     switch (whence)
1849     {
1850     case SEEK_SET:
1851         info->nread = offset;
1852         break;
1853     case SEEK_CUR:
1854         info->nread += offset;
1855         break;
1856     case SEEK_END:
1857         if (!cli_qfileinfo (info->cli, info->fnum,
1858                             NULL, &size, NULL, NULL, NULL,
1859                             NULL, NULL) &&
1860             !cli_getattrE (info->cli, info->fnum, NULL, &size, NULL, NULL, NULL))
1861         {
1862             errno = EINVAL;
1863             return -1;
1864         }
1865         info->nread = size + offset;
1866         break;
1867     default:
1868         break;
1869     }
1870 
1871     return info->nread;
1872 }
1873 
1874 /* --------------------------------------------------------------------------------------------- */
1875 
1876 static int
1877 smbfs_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help]  */
1878 {
1879     const vfs_path_element_t *path_element;
1880 
1881     path_element = vfs_path_get_by_index (vpath, -1);
1882     DEBUG (3,
1883            ("smbfs_mknod(path:%s, mode:%d, dev:%u)\n", path_element->path, (int) mode,
1884             (unsigned int) dev));
1885     my_errno = EOPNOTSUPP;
1886     return -1;
1887 }
1888 
1889 /* --------------------------------------------------------------------------------------------- */
1890 
1891 static int
1892 smbfs_mkdir (const vfs_path_t * vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
1893 {
1894     smbfs_connection *sc;
1895     char *remote_file;
1896     char *cpath;
1897     const vfs_path_element_t *path_element;
1898 
1899     path_element = vfs_path_get_by_index (vpath, -1);
1900     DEBUG (3, ("smbfs_mkdir(path:%s, mode:%d)\n", path_element->path, (int) mode));
1901     if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
1902         return -1;
1903     g_free (remote_file);
1904     cpath = smbfs_convert_path (path_element->path, FALSE);
1905 
1906     if (!cli_mkdir (sc->cli, cpath))
1907     {
1908         my_errno = cli_error (sc->cli, NULL, &err, NULL);
1909         message (D_ERROR, MSG_ERROR, _("Error %s creating directory %s"),
1910                  cli_errstr (sc->cli), CNV_LANG (cpath));
1911         g_free (cpath);
1912         return -1;
1913     }
1914     g_free (cpath);
1915     return 0;
1916 }
1917 
1918 /* --------------------------------------------------------------------------------------------- */
1919 
1920 static int
1921 smbfs_rmdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1922 {
1923     smbfs_connection *sc;
1924     char *remote_file;
1925     char *cpath;
1926     const vfs_path_element_t *path_element;
1927 
1928     path_element = vfs_path_get_by_index (vpath, -1);
1929     DEBUG (3, ("smbfs_rmdir(path:%s)\n", path_element->path));
1930     if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
1931         return -1;
1932     g_free (remote_file);
1933     cpath = smbfs_convert_path (path_element->path, FALSE);
1934 
1935     if (!cli_rmdir (sc->cli, cpath))
1936     {
1937         my_errno = cli_error (sc->cli, NULL, &err, NULL);
1938         message (D_ERROR, MSG_ERROR, _("Error %s removing directory %s"),
1939                  cli_errstr (sc->cli), CNV_LANG (cpath));
1940         g_free (cpath);
1941         return -1;
1942     }
1943 
1944     g_free (cpath);
1945     return 0;
1946 }
1947 
1948 /* --------------------------------------------------------------------------------------------- */
1949 
1950 static int
1951 smbfs_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1952 {
1953     const vfs_path_element_t *path_element1;
1954     const vfs_path_element_t *path_element2;
1955 
1956     path_element1 = vfs_path_get_by_index (vpath1, -1);
1957     path_element2 = vfs_path_get_by_index (vpath2, -1);
1958     DEBUG (3, ("smbfs_link(p1:%s, p2:%s)\n", path_element1->path, path_element2->path));
1959     my_errno = EOPNOTSUPP;
1960     return -1;
1961 }
1962 
1963 /* --------------------------------------------------------------------------------------------- */
1964 
1965 static void
1966 smbfs_free (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
1967 {
1968     DEBUG (3, ("smbfs_free(%p)\n", id));
1969     smbfs_auth_free_all ();
1970 }
1971 
1972 /* --------------------------------------------------------------------------------------------- */
1973 /* Gives up on a socket and reopens the connection, the child own the socket
1974  * now
1975  */
1976 
1977 static void
1978 smbfs_forget (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1979 {
1980     const vfs_path_element_t *path_element;
1981     vfs_path_element_t *p;
1982     const char *path;
1983 
1984     path_element = vfs_path_get_by_index (vpath, -1);
1985     if (path_element->class != vfs_smbfs_ops)
1986         return;
1987 
1988     path = path_element->path;
1989 
1990     DEBUG (3, ("smbfs_forget(path:%s)\n", path));
1991 
1992     while (*path == '/')        /* '/' leading server name */
1993         path++;                 /* probably came from server browsing */
1994 
1995     p = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1996     if (p != NULL)
1997     {
1998         size_t i;
1999 
2000         for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
2001         {
2002             if (smbfs_connections[i].cli
2003                 && (strcmp (p->host, smbfs_connections[i].host) == 0)
2004                 && (strcmp (p->user, smbfs_connections[i].user) == 0)
2005                 && (p->port == smbfs_connections[i].port))
2006             {
2007 
2008                 /* close socket: the child owns it now */
2009                 cli_shutdown (smbfs_connections[i].cli);
2010 
2011                 /* reopen the connection */
2012                 smbfs_connections[i].cli = smbfs_do_connect (p->host, smbfs_connections[i].service);
2013             }
2014         }
2015 
2016         vfs_path_element_free (p);
2017     }
2018 }
2019 
2020 /* --------------------------------------------------------------------------------------------- */
2021 
2022 static int
2023 smbfs_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
2024 {
2025     const vfs_path_element_t *path_element;
2026 
2027     (void) arg;
2028 
2029     path_element = vfs_path_get_by_index (vpath, -1);
2030     DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path_element->path, ctlop));
2031     switch (ctlop)
2032     {
2033     case VFS_SETCTL_FORGET:
2034         smbfs_forget (vpath);
2035         break;
2036     case VFS_SETCTL_LOGFILE:
2037         smbfs_set_debugf ((const char *) arg);
2038         break;
2039     default:
2040         break;
2041     }
2042     return 0;
2043 }
2044 
2045 /* --------------------------------------------------------------------------------------------- */
2046 
2047 static smbfs_handle *
2048 smbfs_open_readwrite (smbfs_handle * remote_handle, char *rname, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2049 {
2050     size_t size;
2051 
2052     (void) mode;
2053 
2054     if (flags & O_TRUNC)        /* if it exists truncate to zero */
2055         DEBUG (3, ("smbfs_open: O_TRUNC\n"));
2056 
2057     remote_handle->fnum =
2058 #if 1                           /* Don't play with flags, it is cli_open() headache */
2059         cli_open (remote_handle->cli, rname, flags, DENY_NONE);
2060 #else /* What's a reasons to has this code ? */
2061         cli_open (remote_handle->cli, rname, ((flags & O_CREAT)
2062                                               || (flags ==
2063                                                   (O_WRONLY | O_APPEND))) ?
2064                   flags : O_RDONLY, DENY_NONE);
2065 #endif
2066     if (remote_handle->fnum == -1)
2067     {
2068         message (D_ERROR, MSG_ERROR, _("%s opening remote file %s"),
2069                  cli_errstr (remote_handle->cli), CNV_LANG (rname));
2070         DEBUG (1, ("smbfs_open(rname:%s) error:%s\n", rname, cli_errstr (remote_handle->cli)));
2071         my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2072         return NULL;
2073     }
2074 
2075     if (flags & O_CREAT)
2076         return remote_handle;
2077 
2078     if (!cli_qfileinfo (remote_handle->cli, remote_handle->fnum,
2079                         &remote_handle->attr, &size, NULL, NULL, NULL, NULL,
2080                         NULL)
2081         && !cli_getattrE (remote_handle->cli, remote_handle->fnum,
2082                           &remote_handle->attr, &size, NULL, NULL, NULL))
2083     {
2084         message (D_ERROR, MSG_ERROR, "getattrib: %s", cli_errstr (remote_handle->cli));
2085         DEBUG (1, ("smbfs_open(rname:%s) getattrib:%s\n", rname, cli_errstr (remote_handle->cli)));
2086         my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2087         cli_close (remote_handle->cli, remote_handle->fnum);
2088         return NULL;
2089     }
2090 
2091     if ((flags == (O_WRONLY | O_APPEND))        /* file.c:copy_file_file() -> do_append */
2092         && smbfs_lseek (remote_handle, 0, SEEK_END) == -1)
2093     {
2094         cli_close (remote_handle->cli, remote_handle->fnum);
2095         return NULL;
2096     }
2097 
2098     return remote_handle;
2099 }
2100 
2101 /* --------------------------------------------------------------------------------------------- */
2102 
2103 static void *
2104 smbfs_open (const vfs_path_t * vpath, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2105 {
2106     char *remote_file;
2107     void *ret;
2108     smbfs_connection *sc;
2109     smbfs_handle *remote_handle;
2110     const vfs_path_element_t *path_element;
2111 
2112     path_element = vfs_path_get_by_index (vpath, -1);
2113     DEBUG (3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", path_element->path, flags, mode));
2114 
2115     if (!(remote_file = smbfs_get_path (&sc, vpath)))
2116         return 0;
2117 
2118     remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2119 
2120     remote_handle = g_new (smbfs_handle, 2);
2121     remote_handle->cli = sc->cli;
2122     remote_handle->nread = 0;
2123 
2124     ret = smbfs_open_readwrite (remote_handle, remote_file, flags, mode);
2125 
2126     g_free (remote_file);
2127     if (!ret)
2128         g_free (remote_handle);
2129 
2130     return ret;
2131 }
2132 
2133 /* --------------------------------------------------------------------------------------------- */
2134 
2135 static int
2136 smbfs_unlink (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
2137 {
2138     smbfs_connection *sc;
2139     char *remote_file;
2140 
2141     if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
2142         return -1;
2143 
2144     remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2145 
2146     if (!cli_unlink (sc->cli, remote_file))
2147     {
2148         message (D_ERROR, MSG_ERROR, _("%s removing remote file %s"),
2149                  cli_errstr (sc->cli), CNV_LANG (remote_file));
2150         g_free (remote_file);
2151         return -1;
2152     }
2153     g_free (remote_file);
2154     return 0;
2155 }
2156 
2157 /* --------------------------------------------------------------------------------------------- */
2158 
2159 static int
2160 smbfs_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
2161 {
2162     smbfs_connection *sc;
2163     char *ra, *rb;
2164     int retval;
2165 
2166     if ((ra = smbfs_get_path (&sc, vpath1)) == 0)
2167         return -1;
2168 
2169     if ((rb = smbfs_get_path (&sc, vpath2)) == 0)
2170     {
2171         g_free (ra);
2172         return -1;
2173     }
2174 
2175     ra = free_after (smbfs_convert_path (ra, FALSE), ra);
2176     rb = free_after (smbfs_convert_path (rb, FALSE), rb);
2177 
2178     retval = cli_rename (sc->cli, ra, rb);
2179 
2180     g_free (ra);
2181     g_free (rb);
2182 
2183     if (!retval)
2184     {
2185         message (D_ERROR, MSG_ERROR, _("%s renaming files\n"), cli_errstr (sc->cli));
2186         return -1;
2187     }
2188     return 0;
2189 }
2190 
2191 /* --------------------------------------------------------------------------------------------- */
2192 
2193 static int
2194 smbfs_fstat (void *data, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
2195 {
2196     smbfs_handle *remote_handle = (smbfs_handle *) data;
2197 
2198     DEBUG (3, ("smbfs_fstat(fnum:%d)\n", remote_handle->fnum));
2199 
2200     /* use left over from previous smbfs_get_remote_stat, if available */
2201     if (single_entry)
2202         memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
2203     else
2204     {                           /* single_entry not set up: bug */
2205         my_errno = EFAULT;
2206         return -EFAULT;
2207     }
2208     return 0;
2209 }
2210 
2211 /* --------------------------------------------------------------------------------------------- */
2212 
2213 static gboolean
2214 smbfs_nothingisopen (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
2215 {
2216     /* FIXME */
2217     (void) id;
2218 
2219     return TRUE;
2220 }
2221 
2222 /* --------------------------------------------------------------------------------------------- */
2223 /*** public functions ****************************************************************************/
2224 /* --------------------------------------------------------------------------------------------- */
2225 
2226 smb_authinfo *
2227 vfs_smb_authinfo_new (const char *host, const char *share, const char *domain,
     /* [previous][next][first][last][top][bottom][index][help]  */
2228                       const char *user, const char *pass)
2229 {
2230     smb_authinfo *auth;
2231 
2232     auth = g_try_new (struct smb_authinfo, 1);
2233 
2234     if (auth != NULL)
2235     {
2236         auth->host = g_strdup (host);
2237         auth->share = g_strdup (share);
2238         auth->domain = g_strdup (domain);
2239         auth->user = g_strdup (user);
2240         auth->password = g_strdup (pass);
2241     }
2242 
2243     return auth;
2244 }
2245 
2246 /* --------------------------------------------------------------------------------------------- */
2247 
2248 void
2249 vfs_init_smbfs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2250 {
2251     tcp_init ();
2252 
2253     /* NULLize vfs_s_subclass members */
2254     memset (&smbfs_subclass, 0, sizeof (smbfs_subclass));
2255 
2256     vfs_init_class (vfs_smbfs_ops, "smbfs", VFSF_NOLINKS, "smb");
2257     vfs_smbfs_ops->init = smbfs_init;
2258     vfs_smbfs_ops->fill_names = smbfs_fill_names;
2259     vfs_smbfs_ops->open = smbfs_open;
2260     vfs_smbfs_ops->close = smbfs_close;
2261     vfs_smbfs_ops->read = smbfs_read;
2262     vfs_smbfs_ops->write = smbfs_write;
2263     vfs_smbfs_ops->opendir = smbfs_opendir;
2264     vfs_smbfs_ops->readdir = smbfs_readdir;
2265     vfs_smbfs_ops->closedir = smbfs_closedir;
2266     vfs_smbfs_ops->stat = smbfs_stat;
2267     vfs_smbfs_ops->lstat = smbfs_lstat;
2268     vfs_smbfs_ops->fstat = smbfs_fstat;
2269     vfs_smbfs_ops->chmod = smbfs_chmod;
2270     vfs_smbfs_ops->chown = smbfs_chown;
2271     vfs_smbfs_ops->utime = smbfs_utime;
2272     vfs_smbfs_ops->readlink = smbfs_readlink;
2273     vfs_smbfs_ops->symlink = smbfs_symlink;
2274     vfs_smbfs_ops->link = smbfs_link;
2275     vfs_smbfs_ops->unlink = smbfs_unlink;
2276     vfs_smbfs_ops->rename = smbfs_rename;
2277     vfs_smbfs_ops->chdir = smbfs_chdir;
2278     vfs_smbfs_ops->ferrno = smbfs_errno;
2279     vfs_smbfs_ops->lseek = smbfs_lseek;
2280     vfs_smbfs_ops->mknod = smbfs_mknod;
2281     vfs_smbfs_ops->free = smbfs_free;
2282     vfs_smbfs_ops->mkdir = smbfs_mkdir;
2283     vfs_smbfs_ops->rmdir = smbfs_rmdir;
2284     vfs_smbfs_ops->setctl = smbfs_setctl;
2285     vfs_smbfs_ops->nothingisopen = smbfs_nothingisopen;
2286     vfs_register_class (vfs_smbfs_ops);
2287 }
2288 
2289 /* --------------------------------------------------------------------------------------------- */

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