Update copyright years.
[midnight-commander.git] / src / vfs / smbfs / smbfs.c
bloba13f5fe8e3ba6fccba5cd9e9b28baba3caf933bc
1 /*
2 Virtual File System: Midnight Commander file system.
4 Copyright (C) 1999-2016
5 Free Software Foundation, Inc.
7 Written by:
8 Wayne Roberts <wroberts1@home.com>, 1997
9 Andrew V. Samoilov <sav@bcs.zp.ua> 2002, 2003
11 This file is part of the Midnight Commander.
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.
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.
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/>.
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
34 * Namespace: exports init_smbfs, smbfs_set_debug()
37 #include <config.h>
39 #include <stdio.h>
40 #include <sys/types.h>
42 #undef USE_NCURSES /* Don't include *curses.h */
43 #undef USE_NCURSESW
45 #include <string.h>
47 #include "lib/global.h"
48 #include "lib/strutil.h"
49 #include "lib/util.h"
50 #include "lib/widget.h" /* message() */
52 #undef PACKAGE_BUGREPORT
53 #undef PACKAGE_NAME
54 #undef PACKAGE_STRING
55 #undef PACKAGE_TARNAME
56 #undef PACKAGE_VERSION
58 #include "helpers/include/config.h"
59 /* don't load crap in "samba/include/includes.h" we don't use and which
60 conflicts with definitions in other includes */
61 #undef HAVE_LIBREADLINE
62 #define NO_CONFIG_H
63 #undef VERSION
65 #include "helpers/include/includes.h"
67 #include "lib/vfs/vfs.h"
68 #include "lib/vfs/netutil.h"
69 #include "lib/vfs/utilvfs.h"
71 #include "smbfs.h"
73 /*** global variables ****************************************************************************/
75 extern int DEBUGLEVEL;
76 extern pstring myhostname;
77 extern struct in_addr ipzero;
78 extern pstring global_myname;
79 extern pstring debugf;
80 extern FILE *dbf;
82 /*** file scope macro definitions ****************************************************************/
84 #define SMBFS_MAX_CONNECTIONS 16
86 #define HEADER_LEN 6
88 #define CNV_LANG(s) dos_to_unix(s,False)
89 #define GNAL_VNC(s) unix_to_dos(s,False)
91 #define smbfs_lstat smbfs_stat /* no symlinks on smb filesystem? */
93 /*** file scope type declarations ****************************************************************/
95 typedef struct _smbfs_connection smbfs_connection;
97 typedef struct
99 struct cli_state *cli;
100 int fnum;
101 off_t nread;
102 uint16 attr;
103 } smbfs_handle;
105 typedef struct dir_entry
107 char *text;
108 struct dir_entry *next;
109 struct stat my_stat;
110 int merrno;
111 } dir_entry;
113 typedef struct
115 gboolean server_list;
116 char *dirname;
117 char *path; /* the dir originally passed to smbfs_opendir */
118 smbfs_connection *conn;
119 dir_entry *entries;
120 dir_entry *current;
121 } opendir_info;
123 /*** file scope variables ************************************************************************/
125 static const char *const IPC = "IPC$";
126 static const char *const URL_HEADER = "smb" VFS_PATH_URL_DELIMITER;
128 static int my_errno;
129 static uint32 err;
131 /* stuff that is same with each connection */
133 static mode_t myumask = 0755;
134 static int smbfs_open_connections = 0;
135 static gboolean got_user = FALSE;
136 static gboolean got_pass = FALSE;
137 static pstring password;
138 static pstring username;
139 static struct vfs_class vfs_smbfs_ops;
141 static struct _smbfs_connection
143 struct cli_state *cli;
144 struct in_addr dest_ip;
145 BOOL have_ip;
146 char *host; /* server name */
147 char *service; /* share name */
148 char *domain;
149 char *user;
150 char *home;
151 char *password;
152 int port;
153 int name_type;
154 time_t last_use;
155 } smbfs_connections[SMBFS_MAX_CONNECTIONS];
156 /* unique to each connection */
158 static smbfs_connection *current_bucket;
160 static GSList *auth_list;
162 static opendir_info *previous_info, *current_info, *current_share_info, *current_server_info;
164 static gboolean first_direntry;
166 /* stat a single file, smbfs_get_remote_stat callback */
167 static dir_entry *single_entry;
169 /*** file scope functions ************************************************************************/
170 /* --------------------------------------------------------------------------------------------- */
172 /* modifies *share */
173 static struct cli_state *smbfs_do_connect (const char *server, char *share);
175 /* --------------------------------------------------------------------------------------------- */
177 static void
178 smbfs_set_debugf (const char *filename)
180 if (DEBUGLEVEL > 0)
182 FILE *outfile = fopen (filename, "w");
183 if (outfile)
185 setup_logging ("", True); /* No needs for timestamp for each message */
186 dbf = outfile;
187 setbuf (dbf, NULL);
188 pstrcpy (debugf, filename);
193 /* --------------------------------------------------------------------------------------------- */
194 /* this function allows you to write:
195 * char *s = g_strdup("hello, world");
196 * s = free_after(g_strconcat(s, s, (char *)0), s);
199 static inline char *
200 free_after (char *result, char *string_to_free)
202 g_free (string_to_free);
203 return result;
206 /* --------------------------------------------------------------------------------------------- */
208 static void
209 smbfs_auth_free (struct smb_authinfo const *a)
211 g_free (a->host);
212 g_free (a->share);
213 g_free (a->domain);
214 g_free (a->user);
215 wipe_password (a->password);
218 /* --------------------------------------------------------------------------------------------- */
220 static void
221 smbfs_auth_free_all (void)
223 if (auth_list)
225 g_slist_foreach (auth_list, (GFunc) smbfs_auth_free, 0);
226 g_slist_free (auth_list);
227 auth_list = 0;
231 /* --------------------------------------------------------------------------------------------- */
233 static gint
234 smbfs_auth_cmp_host_and_share (gconstpointer _a, gconstpointer _b)
236 struct smb_authinfo const *a = (struct smb_authinfo const *) _a;
237 struct smb_authinfo const *b = (struct smb_authinfo const *) _b;
239 if (!a->host || !a->share || !b->host || !b->share)
240 return 1;
241 if (strcmp (a->host, b->host) != 0)
242 return 1;
243 if (strcmp (a->share, b->share) != 0)
244 return 1;
245 return 0;
248 /* --------------------------------------------------------------------------------------------- */
250 static gint
251 smbfs_auth_cmp_host (gconstpointer _a, gconstpointer _b)
253 struct smb_authinfo const *a = (struct smb_authinfo const *) _a;
254 struct smb_authinfo const *b = (struct smb_authinfo const *) _b;
256 if (!a->host || !b->host)
257 return 1;
258 if (strcmp (a->host, b->host) != 0)
259 return 1;
260 if (strcmp (a->share, IPC) != 0)
261 return 1;
262 return 0;
265 /* --------------------------------------------------------------------------------------------- */
267 static void
268 smbfs_auth_add (const char *host, const char *share, const char *domain,
269 const char *user, const char *pass)
271 struct smb_authinfo *auth;
273 auth = vfs_smb_authinfo_new (host, share, domain, user, pass);
275 if (auth != NULL)
276 auth_list = g_slist_prepend (auth_list, auth);
279 /* --------------------------------------------------------------------------------------------- */
281 static void
282 smbfs_auth_remove (const char *host, const char *share)
284 struct smb_authinfo data;
285 struct smb_authinfo *auth;
286 GSList *list;
288 data.host = g_strdup (host);
289 data.share = g_strdup (share);
290 list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host_and_share);
291 g_free (data.host);
292 g_free (data.share);
293 if (!list)
294 return;
295 auth = list->data;
296 auth_list = g_slist_remove (auth_list, auth);
297 smbfs_auth_free (auth);
300 /* --------------------------------------------------------------------------------------------- */
301 /* Set authentication information in bucket. Return 1 if successful, else 0 */
302 /* Information in auth_list overrides user if pass is NULL. */
303 /* bucket->host and bucket->service must be valid. */
305 static int
306 smbfs_bucket_set_authinfo (smbfs_connection * bucket,
307 const char *domain, const char *user, const char *pass,
308 int fallback_to_host)
310 struct smb_authinfo data;
311 struct smb_authinfo *auth;
312 GSList *list;
314 if (domain && user && pass)
316 g_free (bucket->domain);
317 g_free (bucket->user);
318 g_free (bucket->password);
319 bucket->domain = g_strdup (domain);
320 bucket->user = g_strdup (user);
321 bucket->password = g_strdup (pass);
322 smbfs_auth_remove (bucket->host, bucket->service);
323 smbfs_auth_add (bucket->host, bucket->service, domain, user, pass);
324 return 1;
327 data.host = bucket->host;
328 data.share = bucket->service;
329 list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host_and_share);
330 if (!list && fallback_to_host)
331 list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host);
332 if (list)
334 auth = list->data;
335 bucket->domain = g_strdup (auth->domain);
336 bucket->user = g_strdup (auth->user);
337 bucket->password = g_strdup (auth->password);
338 return 1;
341 if (got_pass)
343 bucket->domain = g_strdup (lp_workgroup ());
344 bucket->user = g_strdup (got_user ? username : user);
345 bucket->password = g_strdup (password);
346 return 1;
349 auth = vfs_smb_get_authinfo (bucket->host,
350 bucket->service, (domain ? domain : lp_workgroup ()), user);
351 if (auth)
353 g_free (bucket->domain);
354 g_free (bucket->user);
355 g_free (bucket->password);
356 bucket->domain = g_strdup (auth->domain);
357 bucket->user = g_strdup (auth->user);
358 bucket->password = g_strdup (auth->password);
359 smbfs_auth_remove (bucket->host, bucket->service);
360 auth_list = g_slist_prepend (auth_list, auth);
361 return 1;
363 return 0;
366 /* --------------------------------------------------------------------------------------------- */
368 void
369 smbfs_set_debug (int arg)
371 DEBUGLEVEL = arg;
374 /* --------------------------------------------------------------------------------------------- */
375 /********************** The callbacks ******************************/
377 static int
378 smbfs_init (struct vfs_class *me)
380 const char *servicesf = CONFIGDIR PATH_SEP_STR "smb.conf";
382 /* DEBUGLEVEL = 4; */
384 TimeInit ();
385 charset_initialise ();
387 DEBUG (3, ("smbfs_init(%s)\n", me->name));
389 if (!get_myname (myhostname, NULL))
390 DEBUG (0, ("Failed to get my hostname.\n"));
392 if (!lp_load (servicesf, True, False, False))
393 DEBUG (0, ("Cannot load %s - run testparm to debug it\n", servicesf));
395 codepage_initialise (lp_client_code_page ());
397 load_interfaces ();
399 myumask = umask (0);
400 umask (myumask);
401 myumask = ~myumask;
403 if (getenv ("USER"))
405 char *p;
407 pstrcpy (username, getenv ("USER"));
408 got_user = TRUE;
409 DEBUG (3, ("smbfs_init(): $USER:%s\n", username));
410 if ((p = strchr (username, '%')))
412 *p = 0;
413 pstrcpy (password, p + 1);
414 got_pass = TRUE;
415 memset (strchr (getenv ("USER"), '%') + 1, 'X', strlen (password));
416 DEBUG (3, ("smbfs_init(): $USER%%pass: %s%%%s\n", username, password));
418 strupper (username);
420 if (getenv ("PASSWD"))
422 pstrcpy (password, getenv ("PASSWD"));
423 got_pass = TRUE;
425 return 1;
428 /* --------------------------------------------------------------------------------------------- */
430 static void
431 smbfs_fill_names (struct vfs_class *me, fill_names_f func)
433 size_t i;
434 char *path;
436 (void) me;
438 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
440 if (smbfs_connections[i].cli)
442 path = g_strconcat (URL_HEADER,
443 smbfs_connections[i].user, "@",
444 smbfs_connections[i].host,
445 "/", smbfs_connections[i].service, (char *) NULL);
446 (*func) (path);
447 g_free (path);
452 /* --------------------------------------------------------------------------------------------- */
453 /* does same as do_get() in client.c */
454 /* called from vfs.c:1080, count = buffer size */
456 static ssize_t
457 smbfs_read (void *data, char *buffer, size_t count)
459 smbfs_handle *info = (smbfs_handle *) data;
460 ssize_t n;
462 DEBUG (3, ("smbfs_read(fnum:%d, nread:%d, count:%zu)\n", info->fnum, (int) info->nread, count));
463 n = cli_read (info->cli, info->fnum, buffer, info->nread, count);
464 if (n > 0)
465 info->nread += n;
466 return n;
469 /* --------------------------------------------------------------------------------------------- */
471 static ssize_t
472 smbfs_write (void *data, const char *buf, size_t nbyte)
474 smbfs_handle *info = (smbfs_handle *) data;
475 ssize_t n;
477 DEBUG (3, ("smbfs_write(fnum:%d, nread:%d, nbyte:%zu)\n",
478 info->fnum, (int) info->nread, nbyte));
479 n = cli_write (info->cli, info->fnum, 0, buf, info->nread, nbyte);
480 if (n > 0)
481 info->nread += n;
482 return n;
485 /* --------------------------------------------------------------------------------------------- */
487 static int
488 smbfs_close (void *data)
490 smbfs_handle *info = (smbfs_handle *) data;
491 DEBUG (3, ("smbfs_close(fnum:%d)\n", info->fnum));
493 /* FIXME: Why too different cli have the same outbuf
494 * if file is copied to share
496 if (info->cli->outbuf == NULL)
498 my_errno = EINVAL;
499 return -1;
501 #if 0
502 /* if imlementing archive_level: add rname to smbfs_handle */
503 if (archive_level >= 2 && (inf->attr & aARCH))
505 cli_setatr (info->cli, rname, info->attr & ~(uint16) aARCH, 0);
507 #endif
508 return (cli_close (info->cli, info->fnum) == True) ? 0 : -1;
511 /* --------------------------------------------------------------------------------------------- */
513 static int
514 smbfs_errno (struct vfs_class *me)
516 (void) me;
518 DEBUG (3, ("smbfs_errno: %s\n", unix_error_string (my_errno)));
519 return my_errno;
522 /* --------------------------------------------------------------------------------------------- */
524 static dir_entry *
525 smbfs_new_dir_entry (const char *name)
527 static int inode_counter;
528 dir_entry *new_entry;
529 new_entry = g_new0 (dir_entry, 1);
530 new_entry->text = dos_to_unix (g_strdup (name), 1);
532 if (first_direntry)
534 current_info->entries = new_entry;
535 first_direntry = FALSE;
537 else
539 current_info->current->next = new_entry;
541 current_info->current = new_entry;
542 new_entry->my_stat.st_ino = inode_counter++;
544 return new_entry;
547 /* --------------------------------------------------------------------------------------------- */
548 /* browse for shares on server */
550 static void
551 smbfs_browsing_helper (const char *name, uint32 type, const char *comment, void *state)
553 const char *typestr = "";
554 dir_entry *new_entry = smbfs_new_dir_entry (name);
556 (void) state;
558 switch (type)
560 case STYPE_DISKTREE:
561 typestr = "Disk";
562 /* show this as dir */
563 new_entry->my_stat.st_mode =
564 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
565 break;
566 case STYPE_PRINTQ:
567 typestr = "Printer";
568 break;
569 case STYPE_DEVICE:
570 typestr = "Device";
571 break;
572 case STYPE_IPC:
573 typestr = "IPC";
574 break;
575 default:
576 break;
578 DEBUG (3, ("\t%-15.15s%-10.10s%s\n", name, typestr, comment));
581 /* --------------------------------------------------------------------------------------------- */
583 static void
584 smbfs_loaddir_helper (file_info * finfo, const char *mask, void *entry)
586 dir_entry *new_entry = (dir_entry *) entry;
587 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
589 (void) mask;
591 #if 0 /* I want to see dot files */
592 if (finfo->mode & aHIDDEN)
593 return; /* don't bother with hidden files, "~$" screws up mc */
594 #endif
595 if (!entry)
596 new_entry = smbfs_new_dir_entry (finfo->name);
598 new_entry->my_stat.st_size = finfo->size;
599 new_entry->my_stat.st_mtime = finfo->mtime;
600 new_entry->my_stat.st_atime = finfo->atime;
601 new_entry->my_stat.st_ctime = finfo->ctime;
602 new_entry->my_stat.st_uid = finfo->uid;
603 new_entry->my_stat.st_gid = finfo->gid;
605 new_entry->my_stat.st_mode = /* rw-rw-rw */
606 S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
608 /* if (finfo->mode & aVOLID); nothing similar in real world */
609 if (finfo->mode & aDIR)
610 new_entry->my_stat.st_mode |= /* drwxrwxrwx */
611 S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
612 else
613 new_entry->my_stat.st_mode |= S_IFREG; /* if not dir, regular file? */
614 /* if (finfo->mode & aARCH); DOS archive */
615 /* if (finfo->mode & aHIDDEN); like a dot file? */
616 /* if (finfo->mode & aSYSTEM); like a kernel? */
617 if (finfo->mode & aRONLY)
618 new_entry->my_stat.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
619 new_entry->my_stat.st_mode &= myumask;
621 DEBUG (entry ? 3 : 6, (" %-30s%7.7s%8.0f %s",
622 CNV_LANG (finfo->name),
623 attrib_string (finfo->mode),
624 (double) finfo->size, asctime (LocalTime (&t))));
627 /* --------------------------------------------------------------------------------------------- */
628 /* takes "/foo/bar/file" and gives malloced "\\foo\\bar\\file" */
630 static char *
631 smbfs_convert_path (const char *remote_file, gboolean trailing_asterik)
633 const char *p, *my_remote;
634 char *result;
636 my_remote = remote_file;
637 if (strncmp (my_remote, URL_HEADER, HEADER_LEN) == 0)
638 { /* if passed directly */
639 my_remote += HEADER_LEN;
640 if (*my_remote == '/') /* from server browsing */
641 my_remote++;
642 p = strchr (my_remote, '/');
643 if (p)
644 my_remote = p + 1; /* advance to end of server name */
647 if (*my_remote == '/')
648 my_remote++; /* strip off leading '/' */
649 p = strchr (my_remote, '/');
650 if (p)
651 my_remote = p; /* strip off share/service name */
652 /* create remote filename as understood by smb clientgen */
653 result = g_strconcat (my_remote, trailing_asterik ? "/*" : "", (char *) NULL);
654 unix_to_dos (result, /* inplace = */ 1); /* code page conversion */
655 str_replace (result, '/', '\\');
656 return result;
659 /* --------------------------------------------------------------------------------------------- */
661 static void
662 smbfs_srv_browsing_helper (const char *name, uint32 m, const char *comment, void *state)
664 dir_entry *new_entry = smbfs_new_dir_entry (name);
666 (void) m;
667 (void) state;
669 /* show this as dir */
670 new_entry->my_stat.st_mode =
671 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
673 DEBUG (3, ("\t%-16.16s %s\n", name, comment));
676 /* --------------------------------------------------------------------------------------------- */
678 static BOOL
679 smbfs_reconnect (smbfs_connection * conn, int *retries)
681 char *host;
682 DEBUG (3, ("RECONNECT\n"));
684 if (*(conn->host) == 0)
685 host = g_strdup (conn->cli->desthost); /* server browsing */
686 else
687 host = g_strdup (conn->host);
689 cli_shutdown (conn->cli);
691 if (!(conn->cli = smbfs_do_connect (host, conn->service)))
693 message (D_ERROR, MSG_ERROR, _("reconnect to %s failed"), conn->host);
694 g_free (host);
695 return False;
697 g_free (host);
698 if (++(*retries) == 2)
699 return False;
700 return True;
703 /* --------------------------------------------------------------------------------------------- */
705 static BOOL
706 smbfs_send (struct cli_state *cli)
708 size_t len;
709 size_t nwritten = 0;
710 ssize_t ret;
712 len = smb_len (cli->outbuf) + 4;
714 while (nwritten < len)
716 ret = write_socket (cli->fd, cli->outbuf + nwritten, len - nwritten);
717 if (ret <= 0)
719 if (errno == EPIPE)
720 return False;
722 else
723 nwritten += ret;
726 return True;
729 /* --------------------------------------------------------------------------------------------- */
730 /****************************************************************************
731 See if server has cut us off by checking for EPIPE when writing.
732 Taken from cli_chkpath()
733 ****************************************************************************/
735 static BOOL
736 smbfs_chkpath (struct cli_state *cli, const char *path, BOOL send_only)
738 fstring path2;
739 char *p;
741 fstrcpy (path2, path);
742 unix_to_dos (path2, 1);
743 trim_string (path2, NULL, "\\");
744 if (!*path2)
745 *path2 = '\\';
747 memset (cli->outbuf, '\0', smb_size);
748 set_message (cli->outbuf, 0, 4 + strlen (path2), True);
749 SCVAL (cli->outbuf, smb_com, SMBchkpth);
750 SSVAL (cli->outbuf, smb_tid, cli->cnum);
752 cli->rap_error = 0;
753 cli->nt_error = 0;
754 SSVAL (cli->outbuf, smb_pid, cli->pid);
755 SSVAL (cli->outbuf, smb_uid, cli->vuid);
756 SSVAL (cli->outbuf, smb_mid, cli->mid);
757 if (cli->protocol > PROTOCOL_CORE)
759 SCVAL (cli->outbuf, smb_flg, 0x8);
760 SSVAL (cli->outbuf, smb_flg2, 0x1);
763 p = smb_buf (cli->outbuf);
764 *p++ = 4;
765 fstrcpy (p, path2);
767 if (!smbfs_send (cli))
769 DEBUG (3, ("smbfs_chkpath: couldnt send\n"));
770 return False;
772 if (send_only)
774 client_receive_smb (cli->fd, cli->inbuf, cli->timeout);
775 DEBUG (3, ("smbfs_chkpath: send only OK\n"));
776 return True; /* just testing for EPIPE */
778 if (!client_receive_smb (cli->fd, cli->inbuf, cli->timeout))
780 DEBUG (3, ("smbfs_chkpath: receive error\n"));
781 return False;
783 if ((my_errno = cli_error (cli, NULL, NULL, NULL)))
785 if (my_errno == 20 || my_errno == 13)
786 return True; /* ignore if 'not a directory' error */
787 DEBUG (3, ("smbfs_chkpath: cli_error: %s\n", unix_error_string (my_errno)));
788 return False;
791 return True;
794 /* --------------------------------------------------------------------------------------------- */
796 #if 1
797 static int
798 smbfs_fs (const char *text)
800 const char *p = text;
801 int count = 0;
803 while ((p = strchr (p, '/')) != NULL)
805 count++;
806 p++;
808 if (count == 1)
809 return strlen (text);
810 return count;
812 #endif
814 /* --------------------------------------------------------------------------------------------- */
816 static int
817 smbfs_loaddir (opendir_info * smbfs_info)
819 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
820 int servlen = strlen (smbfs_info->conn->service);
821 const char *info_dirname = smbfs_info->dirname;
822 char *my_dirname;
824 DEBUG (3, ("smbfs_loaddir: dirname:%s\n", info_dirname));
825 first_direntry = TRUE;
827 if (current_info)
829 DEBUG (3, ("smbfs_loaddir: new:'%s', cached:'%s'\n", info_dirname, current_info->dirname));
830 /* if new desired dir is longer than cached in current_info */
831 if (smbfs_fs (info_dirname) > smbfs_fs (current_info->dirname))
833 DEBUG (3, ("saving to previous_info\n"));
834 previous_info = current_info;
838 current_info = smbfs_info;
840 if (strcmp (info_dirname, "/") == 0)
842 if (!strcmp (smbfs_info->path, URL_HEADER))
844 DEBUG (6, ("smbfs_loaddir: browsing %s\n", IPC));
845 /* browse for servers */
846 if (!cli_NetServerEnum
847 (smbfs_info->conn->cli, smbfs_info->conn->domain,
848 SV_TYPE_ALL, smbfs_srv_browsing_helper, NULL))
849 return 0;
850 else
851 current_server_info = smbfs_info;
852 smbfs_info->server_list = TRUE;
854 else
856 /* browse for shares */
857 if (cli_RNetShareEnum (smbfs_info->conn->cli, smbfs_browsing_helper, NULL) < 1)
858 return 0;
859 else
860 current_share_info = smbfs_info;
862 goto done;
865 /* do regular directory listing */
866 if (strncmp (smbfs_info->conn->service, info_dirname + 1, servlen) == 0)
868 /* strip share name from dir */
869 my_dirname = g_strdup (info_dirname + servlen);
870 *my_dirname = '/';
871 my_dirname = free_after (smbfs_convert_path (my_dirname, TRUE), my_dirname);
873 else
874 my_dirname = smbfs_convert_path (info_dirname, TRUE);
876 DEBUG (6, ("smbfs_loaddir: service: %s\n", smbfs_info->conn->service));
877 DEBUG (6, ("smbfs_loaddir: cli->share: %s\n", smbfs_info->conn->cli->share));
878 DEBUG (6, ("smbfs_loaddir: calling cli_list with mask %s\n", my_dirname));
879 /* do file listing: cli_list returns number of files */
880 if (cli_list (smbfs_info->conn->cli, my_dirname, attribute, smbfs_loaddir_helper, NULL) < 0)
882 /* cli_list returns -1 if directory empty or cannot read socket */
883 my_errno = cli_error (smbfs_info->conn->cli, NULL, &err, NULL);
884 g_free (my_dirname);
885 return 0;
887 if (*(my_dirname) == 0)
888 smbfs_info->dirname = smbfs_info->conn->service;
889 g_free (my_dirname);
890 /* do_dskattr(); */
892 done:
893 /* current_info->parent = smbfs_info->dirname; */
895 smbfs_info->current = smbfs_info->entries;
896 return 1; /* 1 = ok */
899 /* --------------------------------------------------------------------------------------------- */
901 #ifdef SMBFS_FREE_DIR
902 static void
903 smbfs_free_dir (dir_entry * de)
905 if (!de)
906 return;
908 smbfs_free_dir (de->next);
909 g_free (de->text);
910 g_free (de);
912 #endif
914 /* --------------------------------------------------------------------------------------------- */
915 /* The readdir routine loads the complete directory */
916 /* It's too slow to ask the server each time */
917 /* It now also sends the complete lstat information for each file */
919 static void *
920 smbfs_readdir (void *info)
922 static union vfs_dirent smbfs_readdir_data;
923 static char *const dirent_dest = smbfs_readdir_data.dent.d_name;
924 opendir_info *smbfs_info = (opendir_info *) info;
926 DEBUG (4, ("smbfs_readdir(%s)\n", smbfs_info->dirname));
928 if (!smbfs_info->entries)
929 if (!smbfs_loaddir (smbfs_info))
930 return NULL;
932 if (smbfs_info->current == 0)
933 { /* reached end of dir entries */
934 DEBUG (3, ("smbfs_readdir: smbfs_info->current = 0\n"));
935 #ifdef SMBFS_FREE_DIR
936 smbfs_free_dir (smbfs_info->entries);
937 smbfs_info->entries = 0;
938 #endif
939 return NULL;
941 g_strlcpy (dirent_dest, smbfs_info->current->text, MC_MAXPATHLEN);
942 smbfs_info->current = smbfs_info->current->next;
944 return &smbfs_readdir_data;
947 /* --------------------------------------------------------------------------------------------- */
949 static int
950 smbfs_closedir (void *info)
952 opendir_info *smbfs_info = (opendir_info *) info;
953 /* dir_entry *p, *q; */
955 DEBUG (3, ("smbfs_closedir(%s)\n", smbfs_info->dirname));
956 /* CLOSE HERE */
958 /* for (p = smbfs_info->entries; p;){
959 q = p;
960 p = p->next;
961 g_free (q->text);
962 g_free (q);
964 g_free (info); */
965 return 0;
968 /* --------------------------------------------------------------------------------------------- */
970 static int
971 smbfs_chmod (const vfs_path_t * vpath, mode_t mode)
973 const vfs_path_element_t *path_element;
975 path_element = vfs_path_get_by_index (vpath, -1);
976 DEBUG (3, ("smbfs_chmod(path:%s, mode:%d)\n", path_element->path, (int) mode));
977 /* my_errno = EOPNOTSUPP;
978 return -1; *//* cannot chmod on smb filesystem */
979 return 0; /* make mc happy */
982 /* --------------------------------------------------------------------------------------------- */
984 static int
985 smbfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
987 const vfs_path_element_t *path_element;
989 path_element = vfs_path_get_by_index (vpath, -1);
990 DEBUG (3, ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path_element->path, owner, group));
991 my_errno = EOPNOTSUPP; /* ready for your labotomy? */
992 return -1;
995 /* --------------------------------------------------------------------------------------------- */
997 static int
998 smbfs_utime (const vfs_path_t * vpath, struct utimbuf *times)
1000 const vfs_path_element_t *path_element;
1002 (void) times;
1004 path_element = vfs_path_get_by_index (vpath, -1);
1005 DEBUG (3, ("smbfs_utime(path:%s)\n", path_element->path));
1006 my_errno = EOPNOTSUPP;
1007 return -1;
1010 /* --------------------------------------------------------------------------------------------- */
1012 static int
1013 smbfs_readlink (const vfs_path_t * vpath, char *buf, size_t size)
1015 const vfs_path_element_t *path_element;
1017 path_element = vfs_path_get_by_index (vpath, -1);
1018 DEBUG (3, ("smbfs_readlink(path:%s, buf:%s, size:%zu)\n", path_element->path, buf, size));
1019 my_errno = EOPNOTSUPP;
1020 return -1; /* no symlinks on smb filesystem? */
1023 /* --------------------------------------------------------------------------------------------- */
1025 static int
1026 smbfs_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
1028 const vfs_path_element_t *path_element1;
1029 const vfs_path_element_t *path_element2;
1031 path_element1 = vfs_path_get_by_index (vpath1, -1);
1032 path_element2 = vfs_path_get_by_index (vpath2, -1);
1033 DEBUG (3, ("smbfs_symlink(n1:%s, n2:%s)\n", path_element1->path, path_element2->path));
1034 my_errno = EOPNOTSUPP;
1035 return -1; /* no symlinks on smb filesystem? */
1038 /* --------------------------------------------------------------------------------------------- */
1039 /*****************************************************
1040 return a connection to a SMB server
1041 current_bucket needs to be set before calling
1042 *******************************************************/
1044 static struct cli_state *
1045 smbfs_do_connect (const char *server, char *share)
1047 struct cli_state *c;
1048 struct nmb_name called, calling;
1049 struct in_addr ip;
1051 DEBUG (3, ("smbfs_do_connect(%s, %s)\n", server, share));
1052 if (*share == '\\')
1054 server = share + 2;
1055 share = strchr (server, '\\');
1056 if (!share)
1057 return NULL;
1058 *share = 0;
1059 share++;
1062 make_nmb_name (&calling, global_myname, 0x0);
1063 make_nmb_name (&called, server, current_bucket->name_type);
1065 for (;;)
1068 ip = (current_bucket->have_ip) ? current_bucket->dest_ip : ipzero;
1070 /* have to open a new connection */
1071 if (!(c = cli_initialise (NULL)))
1073 my_errno = ENOMEM;
1074 return NULL;
1077 pwd_init (&(c->pwd)); /* should be moved into cli_initialise()? */
1078 pwd_set_cleartext (&(c->pwd), current_bucket->password);
1080 if ((cli_set_port (c, current_bucket->port) == 0) || !cli_connect (c, server, &ip))
1082 DEBUG (1, ("Connection to %s failed\n", server));
1083 break;
1086 if (!cli_session_request (c, &calling, &called))
1088 my_errno = cli_error (c, NULL, &err, NULL);
1089 DEBUG (1, ("session request to %s failed\n", called.name));
1090 cli_shutdown (c);
1091 if (strcmp (called.name, "*SMBSERVER"))
1093 make_nmb_name (&called, "*SMBSERVER", 0x20);
1094 continue;
1096 return NULL;
1099 DEBUG (3, (" session request ok\n"));
1101 if (!cli_negprot (c))
1103 DEBUG (1, ("protocol negotiation failed\n"));
1104 break;
1107 if (!cli_session_setup (c, current_bucket->user,
1108 current_bucket->password, strlen (current_bucket->password),
1109 current_bucket->password, strlen (current_bucket->password),
1110 current_bucket->domain))
1112 DEBUG (1, ("session setup failed: %s\n", cli_errstr (c)));
1113 smbfs_auth_remove (server, share);
1114 break;
1117 if (*c->server_domain || *c->server_os || *c->server_type)
1118 DEBUG (5, ("Domain=[%s] OS=[%s] Server=[%s]\n",
1119 c->server_domain, c->server_os, c->server_type));
1121 DEBUG (3, (" session setup ok\n"));
1123 if (!cli_send_tconX (c, share, "?????",
1124 current_bucket->password, strlen (current_bucket->password) + 1))
1126 DEBUG (1, ("%s: tree connect failed: %s\n", share, cli_errstr (c)));
1127 break;
1130 DEBUG (3, (" tconx ok\n"));
1132 my_errno = 0;
1133 return c;
1136 my_errno = cli_error (c, NULL, &err, NULL);
1137 cli_shutdown (c);
1138 return NULL;
1142 /* --------------------------------------------------------------------------------------------- */
1144 static int
1145 smbfs_get_master_browser (char **host)
1147 static char so_broadcast[] = "SO_BROADCAST";
1148 int count;
1149 struct in_addr *ip_list, bcast_addr;
1151 /* does port = 137 for win95 master browser? */
1152 int fd = open_socket_in (SOCK_DGRAM, 0, 3,
1153 interpret_addr (lp_socket_address ()), True);
1154 if (fd == -1)
1155 return 0;
1156 set_socket_options (fd, so_broadcast);
1157 ip_list = iface_bcast (ipzero);
1158 bcast_addr = *ip_list;
1159 if ((ip_list = name_query (fd, "\01\02__MSBROWSE__\02", 1, True,
1160 True, bcast_addr, &count, NULL)))
1162 if (!count)
1163 return 0;
1164 /* just return first master browser */
1165 *host = g_strdup (inet_ntoa (ip_list[0]));
1166 return 1;
1168 return 0;
1171 /* --------------------------------------------------------------------------------------------- */
1173 static void
1174 smbfs_free_bucket (smbfs_connection * bucket)
1176 g_free (bucket->host);
1177 g_free (bucket->service);
1178 g_free (bucket->domain);
1179 g_free (bucket->user);
1180 wipe_password (bucket->password);
1181 g_free (bucket->home);
1182 memset (bucket, 0, sizeof (smbfs_connection));
1185 /* --------------------------------------------------------------------------------------------- */
1187 static smbfs_connection *
1188 smbfs_get_free_bucket (void)
1190 int i;
1192 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1193 if (!smbfs_connections[i].cli)
1194 return &smbfs_connections[i];
1196 { /* search for most dormant connection */
1197 int oldest = 0; /* index */
1198 time_t oldest_time = smbfs_connections[0].last_use;
1199 for (i = 1; i < SMBFS_MAX_CONNECTIONS; i++)
1201 if (smbfs_connections[i].last_use < oldest_time)
1203 oldest_time = smbfs_connections[i].last_use;
1204 oldest = i;
1207 cli_shutdown (smbfs_connections[oldest].cli);
1208 smbfs_free_bucket (&smbfs_connections[oldest]);
1209 return &smbfs_connections[oldest];
1212 /* This can't happend, since we have checked for max connections before */
1213 vfs_die ("Internal error: smbfs_get_free_bucket");
1214 return 0; /* shut up, stupid gcc */
1217 /* --------------------------------------------------------------------------------------------- */
1218 /* This routine keeps track of open connections */
1219 /* Returns a connected socket to host */
1221 static smbfs_connection *
1222 smbfs_open_link (char *host, char *path, const char *user, int *port, char *this_pass)
1224 int i;
1225 smbfs_connection *bucket;
1226 pstring service;
1227 struct in_addr *dest_ip = NULL;
1229 DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host, path));
1231 if (strcmp (host, path) == 0) /* if host & path are same: */
1232 pstrcpy (service, IPC); /* setup for browse */
1233 else
1234 { /* get share name from path, path starts with server name */
1235 char *p;
1236 if ((p = strchr (path, '/'))) /* get share aka */
1237 pstrcpy (service, ++p); /* service name from path */
1238 else
1239 pstrcpy (service, "");
1240 /* now check for trailing directory/filenames */
1241 p = strchr (service, '/');
1242 if (p)
1243 *p = 0; /* cut off dir/files: sharename only */
1244 if (!*service)
1245 pstrcpy (service, IPC); /* setup for browse */
1246 DEBUG (6, ("smbfs_open_link: service from path:%s\n", service));
1249 if (got_user)
1250 user = username; /* global from getenv */
1252 /* Is the link actually open? */
1253 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1255 if (!smbfs_connections[i].cli)
1256 continue;
1257 if ((strcmp (host, smbfs_connections[i].host) == 0) &&
1258 (strcmp (user, smbfs_connections[i].user) == 0) &&
1259 (strcmp (service, smbfs_connections[i].service) == 0))
1261 int retries = 0;
1262 BOOL inshare = (*host != 0 && *path != 0 && strchr (path, '/'));
1263 /* check if this connection has died */
1264 while (!smbfs_chkpath (smbfs_connections[i].cli, "\\", !inshare))
1266 if (!smbfs_reconnect (&smbfs_connections[i], &retries))
1267 return 0;
1269 DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i));
1270 current_bucket = &smbfs_connections[i];
1271 smbfs_connections[i].last_use = time (NULL);
1272 return &smbfs_connections[i];
1274 /* connection not found, find if we have ip for new connection */
1275 if (strcmp (host, smbfs_connections[i].host) == 0)
1276 dest_ip = &smbfs_connections[i].cli->dest_ip;
1279 /* make new connection */
1280 bucket = smbfs_get_free_bucket ();
1281 bucket->name_type = 0x20;
1282 bucket->home = 0;
1283 bucket->port = *port;
1284 bucket->have_ip = False;
1285 if (dest_ip)
1287 bucket->have_ip = True;
1288 bucket->dest_ip = *dest_ip;
1290 current_bucket = bucket;
1292 bucket->user = g_strdup (user);
1293 bucket->service = g_strdup (service);
1295 if (!(*host))
1296 { /* if blank host name, browse for servers */
1297 if (!smbfs_get_master_browser (&host)) /* set host to ip of master browser */
1298 return 0; /* could not find master browser? */
1299 g_free (host);
1300 bucket->host = g_strdup (""); /* blank host means master browser */
1302 else
1303 bucket->host = g_strdup (host);
1305 if (!smbfs_bucket_set_authinfo (bucket, 0, /* domain currently not used */
1306 user, this_pass, 1))
1307 return 0;
1309 /* connect to share */
1310 while (!(bucket->cli = smbfs_do_connect (host, service)))
1313 if (my_errno != EPERM)
1314 return 0;
1315 message (D_ERROR, MSG_ERROR, _("Authentication failed"));
1317 /* authentication failed, try again */
1318 smbfs_auth_remove (bucket->host, bucket->service);
1319 if (!smbfs_bucket_set_authinfo (bucket, bucket->domain, bucket->user, 0, 0))
1320 return 0;
1324 smbfs_open_connections++;
1325 DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n", smbfs_open_connections));
1326 return bucket;
1329 /* --------------------------------------------------------------------------------------------- */
1331 static char *
1332 smbfs_get_path (smbfs_connection ** sc, const vfs_path_t * vpath)
1334 char *remote_path = NULL;
1335 vfs_path_element_t *url;
1336 const vfs_path_element_t *path_element;
1337 const char *path;
1339 path_element = vfs_path_get_by_index (vpath, -1);
1340 path = path_element->path;
1342 DEBUG (3, ("smbfs_get_path(%s)\n", path));
1344 if (path_element->class != &vfs_smbfs_ops)
1345 return NULL;
1347 while (*path == '/') /* '/' leading server name */
1348 path++; /* probably came from server browsing */
1350 url = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1352 if (url != NULL)
1354 *sc = smbfs_open_link (url->host, url->path, url->user, &url->port, url->password);
1355 wipe_password (url->password);
1357 if (*sc != NULL)
1358 remote_path = g_strdup (url->path);
1360 vfs_path_element_free (url);
1363 if (remote_path == NULL)
1364 return NULL;
1366 /* NOTE: tildes are deprecated. See ftpfs.c */
1368 int f = strcmp (remote_path, "/~") ? 0 : 1;
1370 if (f != 0 || strncmp (remote_path, "/~/", 3) == 0)
1372 char *s;
1374 s = mc_build_filename ((*sc)->home, remote_path + 3 - f, NULL);
1375 g_free (remote_path);
1376 remote_path = s;
1380 return remote_path;
1383 /* --------------------------------------------------------------------------------------------- */
1385 #if 0
1386 static int
1387 is_error (int result, int errno_num)
1389 if (!(result == -1))
1390 return my_errno = 0;
1391 else
1392 my_errno = errno_num;
1393 return 1;
1395 #endif
1397 /* --------------------------------------------------------------------------------------------- */
1399 static void *
1400 smbfs_opendir (const vfs_path_t * vpath)
1402 opendir_info *smbfs_info;
1403 smbfs_connection *sc;
1404 char *remote_dir;
1405 const vfs_path_element_t *path_element;
1407 path_element = vfs_path_get_by_index (vpath, -1);
1408 DEBUG (3, ("smbfs_opendir(dirname:%s)\n", path_element->path));
1410 if (!(remote_dir = smbfs_get_path (&sc, vpath)))
1411 return NULL;
1413 /* FIXME: where freed? */
1414 smbfs_info = g_new (opendir_info, 1);
1415 smbfs_info->server_list = FALSE;
1416 smbfs_info->path = g_strdup (path_element->path); /* keep original */
1417 smbfs_info->dirname = remote_dir;
1418 smbfs_info->conn = sc;
1419 smbfs_info->entries = 0;
1420 smbfs_info->current = 0;
1422 return smbfs_info;
1425 /* --------------------------------------------------------------------------------------------- */
1427 static int
1428 smbfs_fake_server_stat (const char *server_url, const char *path, struct stat *buf)
1430 dir_entry *dentry;
1431 const char *p;
1433 (void) server_url;
1435 if ((p = strrchr (path, '/')))
1436 path = p + 1; /* advance until last '/' */
1438 if (!current_info->entries)
1440 if (!smbfs_loaddir (current_info)) /* browse host */
1441 return -1;
1444 if (current_info->server_list == True)
1446 dentry = current_info->entries;
1447 DEBUG (4, ("fake stat for SERVER \"%s\"\n", path));
1448 while (dentry)
1450 if (strcmp (dentry->text, path) == 0)
1452 DEBUG (4, ("smbfs_fake_server_stat: %s:%4o\n",
1453 dentry->text, (int) dentry->my_stat.st_mode));
1454 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1455 return 0;
1457 dentry = dentry->next;
1460 my_errno = ENOENT;
1461 return -1;
1464 /* --------------------------------------------------------------------------------------------- */
1466 static int
1467 smbfs_fake_share_stat (const char *server_url, const char *path, struct stat *buf)
1469 dir_entry *dentry;
1470 if (strlen (path) < strlen (server_url))
1471 return -1;
1473 if (!current_share_info)
1474 { /* Server was not stat()ed */
1475 /* Make sure there is such share at server */
1476 smbfs_connection *sc;
1477 char *p;
1478 vfs_path_t *vpath;
1480 vpath = vfs_path_from_str (path);
1481 p = smbfs_get_path (&sc, vpath);
1482 vfs_path_free (vpath);
1484 if (p != NULL)
1486 memset (buf, 0, sizeof (*buf));
1487 /* show this as dir */
1488 buf->st_mode =
1489 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
1490 g_free (p);
1491 return 0;
1493 g_free (p);
1494 return -1;
1497 path += strlen (server_url); /* we only want share name */
1498 path++;
1500 if (*path == '/') /* '/' leading server name */
1501 path++; /* probably came from server browsing */
1503 if (!current_share_info->entries)
1505 if (!smbfs_loaddir (current_share_info)) /* browse host */
1506 return -1;
1508 dentry = current_share_info->entries;
1509 DEBUG (3, ("smbfs_fake_share_stat: %s on %s\n", path, server_url));
1510 while (dentry)
1512 if (strcmp (dentry->text, path) == 0)
1514 DEBUG (6, ("smbfs_fake_share_stat: %s:%4o\n",
1515 dentry->text, (int) dentry->my_stat.st_mode));
1516 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1517 return 0;
1519 dentry = dentry->next;
1521 my_errno = ENOENT;
1522 return -1;
1525 /* --------------------------------------------------------------------------------------------- */
1526 /* stat a single file */
1528 static int
1529 smbfs_get_remote_stat (smbfs_connection * sc, const char *path, struct stat *buf)
1531 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
1532 char *mypath;
1534 DEBUG (3, ("smbfs_get_remote_stat(): mypath:%s\n", path));
1536 mypath = smbfs_convert_path (path, FALSE);
1538 #if 0 /* single_entry is never free()d now. And only my_stat is used */
1539 single_entry = g_new (dir_entry, 1);
1541 single_entry->text = dos_to_unix (g_strdup (finfo->name), 1);
1543 single_entry->next = 0;
1544 #endif
1545 if (!single_entry)
1546 single_entry = g_new0 (dir_entry, 1);
1548 if (cli_list (sc->cli, mypath, attribute, smbfs_loaddir_helper, single_entry) < 1)
1550 my_errno = ENOENT;
1551 g_free (mypath);
1552 return -1; /* cli_list returns number of files */
1555 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
1557 /* don't free here, use for smbfs_fstat() */
1558 /* g_free(single_entry->text);
1559 g_free(single_entry); */
1560 g_free (mypath);
1561 return 0;
1564 /* --------------------------------------------------------------------------------------------- */
1566 static int
1567 smbfs_search_dir_entry (dir_entry * dentry, const char *text, struct stat *buf)
1569 while (dentry)
1571 if (strcmp (text, dentry->text) == 0)
1573 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1574 memcpy (&single_entry->my_stat, &dentry->my_stat, sizeof (struct stat));
1575 return 0;
1577 dentry = dentry->next;
1579 return -1;
1582 /* --------------------------------------------------------------------------------------------- */
1584 static int
1585 smbfs_get_stat_info (smbfs_connection * sc, const char *path, struct stat *buf)
1587 char *p;
1588 #if 0
1589 dir_entry *dentry = current_info->entries;
1590 #endif
1591 const char *mypath = path;
1593 mypath++; /* cut off leading '/' */
1594 if ((p = strrchr (mypath, '/')))
1595 mypath = p + 1; /* advance until last file/dir name */
1596 DEBUG (3, ("smbfs_get_stat_info: mypath:%s, current_info->dirname:%s\n",
1597 mypath, current_info->dirname));
1598 #if 0
1599 if (!dentry)
1601 DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1602 current_info->dirname, path));
1603 return -1;
1605 #endif
1606 if (!single_entry) /* when found, this will be written too */
1607 single_entry = g_new (dir_entry, 1);
1608 if (smbfs_search_dir_entry (current_info->entries, mypath, buf) == 0)
1610 return 0;
1612 /* now try to identify mypath as PARENT dir */
1614 char *mdp;
1615 char *mydir;
1616 mdp = mydir = g_strdup (current_info->dirname);
1617 if ((p = strrchr (mydir, '/')))
1618 *p = 0; /* advance util last '/' */
1619 if ((p = strrchr (mydir, '/')))
1620 mydir = p + 1; /* advance util last '/' */
1621 if (strcmp (mydir, mypath) == 0)
1622 { /* fake a stat for ".." */
1623 memset (buf, 0, sizeof (struct stat));
1624 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1625 memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1626 g_free (mdp);
1627 DEBUG (1, (" PARENT:found in %s\n", current_info->dirname));
1628 return 0;
1630 g_free (mdp);
1632 /* now try to identify as CURRENT dir? */
1634 char *dnp = current_info->dirname;
1635 DEBUG (6, ("smbfs_get_stat_info: is %s current dir? this dir is: %s\n",
1636 mypath, current_info->dirname));
1637 if (*dnp == '/')
1638 dnp++;
1639 else
1641 return -1;
1643 if (strcmp (mypath, dnp) == 0)
1645 memset (buf, 0, sizeof (struct stat));
1646 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1647 memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1648 DEBUG (1, (" CURRENT:found in %s\n", current_info->dirname));
1649 return 0;
1652 DEBUG (3, ("'%s' not found in current_info '%s'\n", path, current_info->dirname));
1653 /* try to find this in the PREVIOUS listing */
1654 if (previous_info)
1656 if (smbfs_search_dir_entry (previous_info->entries, mypath, buf) == 0)
1657 return 0;
1658 DEBUG (3, ("'%s' not found in previous_info '%s'\n", path, previous_info->dirname));
1660 /* try to find this in the SHARE listing */
1661 if (current_share_info)
1663 if (smbfs_search_dir_entry (current_share_info->entries, mypath, buf) == 0)
1664 return 0;
1665 DEBUG (3, ("'%s' not found in share_info '%s'\n", path, current_share_info->dirname));
1667 /* try to find this in the SERVER listing */
1668 if (current_server_info)
1670 if (smbfs_search_dir_entry (current_server_info->entries, mypath, buf) == 0)
1671 return 0;
1672 DEBUG (3, ("'%s' not found in server_info '%s'\n", path, current_server_info->dirname));
1674 /* nothing found. get stat file info from server */
1675 return smbfs_get_remote_stat (sc, path, buf);
1678 /* --------------------------------------------------------------------------------------------- */
1680 static int
1681 smbfs_chdir (const vfs_path_t * vpath)
1683 char *remote_dir;
1684 smbfs_connection *sc;
1685 const vfs_path_element_t *path_element;
1687 path_element = vfs_path_get_by_index (vpath, -1);
1688 DEBUG (3, ("smbfs_chdir(path:%s)\n", path_element->path));
1689 if (!(remote_dir = smbfs_get_path (&sc, vpath)))
1690 return -1;
1691 g_free (remote_dir);
1693 return 0;
1696 /* --------------------------------------------------------------------------------------------- */
1698 static int
1699 smbfs_loaddir_by_name (const vfs_path_t * vpath)
1701 void *info;
1702 char *mypath, *p;
1703 const vfs_path_element_t *path_element;
1705 path_element = vfs_path_get_by_index (vpath, -1);
1706 mypath = g_strdup (path_element->path);
1707 p = strrchr (mypath, '/');
1709 if (p > mypath)
1710 *p = 0;
1711 DEBUG (6, ("smbfs_loaddir_by_name(%s)\n", mypath));
1712 smbfs_chdir (vpath);
1713 info = smbfs_opendir (vpath);
1714 g_free (mypath);
1715 if (!info)
1716 return -1;
1717 smbfs_readdir (info);
1718 smbfs_loaddir (info);
1719 return 0;
1722 /* --------------------------------------------------------------------------------------------- */
1724 static int
1725 smbfs_stat (const vfs_path_t * vpath, struct stat *buf)
1727 smbfs_connection *sc;
1728 pstring server_url;
1729 char *service, *pp, *at;
1730 const char *p;
1731 const vfs_path_element_t *path_element;
1733 path_element = vfs_path_get_by_index (vpath, -1);
1734 DEBUG (3, ("smbfs_stat(path:%s)\n", path_element->path));
1736 if (!current_info)
1738 DEBUG (1, ("current_info = NULL: "));
1739 if (smbfs_loaddir_by_name (vpath) < 0)
1740 return -1;
1743 /* check if stating server */
1744 p = path_element->path;
1745 if (path_element->class != &vfs_smbfs_ops)
1746 return -1;
1748 while (*p == '/') /* '/' leading server name */
1749 p++; /* probably came from server browsing */
1751 pp = strchr (p, '/'); /* advance past next '/' */
1752 at = strchr (p, '@');
1753 pstrcpy (server_url, URL_HEADER);
1754 if (at && at < pp)
1755 { /* user@server */
1756 char *z = &(server_url[sizeof (server_url) - 1]);
1757 const char *s = p;
1759 at = &(server_url[HEADER_LEN]) + (at - p + 1);
1760 if (z > at)
1761 z = at;
1762 at = &(server_url[HEADER_LEN]);
1763 while (at < z)
1764 *at++ = *s++;
1765 *z = 0;
1767 pstrcat (server_url, current_bucket->host);
1769 if (!pp)
1771 if (!current_info->server_list)
1773 if (smbfs_loaddir_by_name (vpath) < 0)
1774 return -1;
1776 return smbfs_fake_server_stat (server_url, path_element->path, buf);
1779 if (!strchr (++pp, '/'))
1781 return smbfs_fake_share_stat (server_url, path_element->path, buf);
1784 /* stating inside share at this point */
1785 if (!(service = smbfs_get_path (&sc, vpath))) /* connects if necessary */
1786 return -1;
1788 int hostlen = strlen (current_bucket->host);
1789 char *ppp = service + strlen (service) - hostlen;
1790 char *sp = server_url + strlen (server_url) - hostlen;
1792 if (strcmp (sp, ppp) == 0)
1794 /* make server name appear as directory */
1795 DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1796 memset (buf, 0, sizeof (struct stat));
1797 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1798 g_free (service);
1799 return 0;
1802 /* check if current_info is in share requested */
1803 p = service;
1804 pp = strchr (p, '/');
1805 if (pp)
1807 p = ++pp; /* advance past server name */
1808 pp = strchr (p, '/');
1810 if (pp)
1811 *pp = 0; /* cut off everthing after service name */
1812 else
1813 p = IPC; /* browsing for services */
1814 pp = current_info->dirname;
1815 if (*pp == '/')
1816 pp++;
1817 if (strncmp (p, pp, strlen (p)) != 0)
1819 DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p, pp));
1820 if (smbfs_loaddir_by_name (vpath) < 0)
1822 g_free (service);
1823 return -1;
1825 DEBUG (6, ("loaded dir: '%s'\n", current_info->dirname));
1827 g_free (service);
1828 /* stat dirs & files under shares now */
1829 return smbfs_get_stat_info (sc, path_element->path, buf);
1832 /* --------------------------------------------------------------------------------------------- */
1834 static off_t
1835 smbfs_lseek (void *data, off_t offset, int whence)
1837 smbfs_handle *info = (smbfs_handle *) data;
1838 size_t size;
1840 DEBUG (3,
1841 ("smbfs_lseek(info->nread => %d, offset => %d, whence => %d) \n",
1842 (int) info->nread, (int) offset, whence));
1844 switch (whence)
1846 case SEEK_SET:
1847 info->nread = offset;
1848 break;
1849 case SEEK_CUR:
1850 info->nread += offset;
1851 break;
1852 case SEEK_END:
1853 if (!cli_qfileinfo (info->cli, info->fnum,
1854 NULL, &size, NULL, NULL, NULL,
1855 NULL, NULL) &&
1856 !cli_getattrE (info->cli, info->fnum, NULL, &size, NULL, NULL, NULL))
1858 errno = EINVAL;
1859 return -1;
1861 info->nread = size + offset;
1862 break;
1863 default:
1864 break;
1867 return info->nread;
1870 /* --------------------------------------------------------------------------------------------- */
1872 static int
1873 smbfs_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev)
1875 const vfs_path_element_t *path_element;
1877 path_element = vfs_path_get_by_index (vpath, -1);
1878 DEBUG (3,
1879 ("smbfs_mknod(path:%s, mode:%d, dev:%u)\n", path_element->path, mode,
1880 (unsigned int) dev));
1881 my_errno = EOPNOTSUPP;
1882 return -1;
1885 /* --------------------------------------------------------------------------------------------- */
1887 static int
1888 smbfs_mkdir (const vfs_path_t * vpath, mode_t mode)
1890 smbfs_connection *sc;
1891 char *remote_file;
1892 char *cpath;
1893 const vfs_path_element_t *path_element;
1895 path_element = vfs_path_get_by_index (vpath, -1);
1896 DEBUG (3, ("smbfs_mkdir(path:%s, mode:%d)\n", path_element->path, (int) mode));
1897 if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
1898 return -1;
1899 g_free (remote_file);
1900 cpath = smbfs_convert_path (path_element->path, FALSE);
1902 if (!cli_mkdir (sc->cli, cpath))
1904 my_errno = cli_error (sc->cli, NULL, &err, NULL);
1905 message (D_ERROR, MSG_ERROR, _("Error %s creating directory %s"),
1906 cli_errstr (sc->cli), CNV_LANG (cpath));
1907 g_free (cpath);
1908 return -1;
1910 g_free (cpath);
1911 return 0;
1914 /* --------------------------------------------------------------------------------------------- */
1916 static int
1917 smbfs_rmdir (const vfs_path_t * vpath)
1919 smbfs_connection *sc;
1920 char *remote_file;
1921 char *cpath;
1922 const vfs_path_element_t *path_element;
1924 path_element = vfs_path_get_by_index (vpath, -1);
1925 DEBUG (3, ("smbfs_rmdir(path:%s)\n", path_element->path));
1926 if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
1927 return -1;
1928 g_free (remote_file);
1929 cpath = smbfs_convert_path (path_element->path, FALSE);
1931 if (!cli_rmdir (sc->cli, cpath))
1933 my_errno = cli_error (sc->cli, NULL, &err, NULL);
1934 message (D_ERROR, MSG_ERROR, _("Error %s removing directory %s"),
1935 cli_errstr (sc->cli), CNV_LANG (cpath));
1936 g_free (cpath);
1937 return -1;
1940 g_free (cpath);
1941 return 0;
1944 /* --------------------------------------------------------------------------------------------- */
1946 static int
1947 smbfs_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
1949 const vfs_path_element_t *path_element1;
1950 const vfs_path_element_t *path_element2;
1952 path_element1 = vfs_path_get_by_index (vpath1, -1);
1953 path_element2 = vfs_path_get_by_index (vpath2, -1);
1954 DEBUG (3, ("smbfs_link(p1:%s, p2:%s)\n", path_element1->path, path_element2->path));
1955 my_errno = EOPNOTSUPP;
1956 return -1;
1959 /* --------------------------------------------------------------------------------------------- */
1961 static void
1962 smbfs_free (vfsid id)
1964 DEBUG (3, ("smbfs_free(%p)\n", id));
1965 smbfs_auth_free_all ();
1968 /* --------------------------------------------------------------------------------------------- */
1969 /* Gives up on a socket and reopens the connection, the child own the socket
1970 * now
1973 static void
1974 smbfs_forget (const vfs_path_t * vpath)
1976 const vfs_path_element_t *path_element;
1977 vfs_path_element_t *p;
1978 const char *path;
1980 path_element = vfs_path_get_by_index (vpath, -1);
1981 if (path_element->class != &vfs_smbfs_ops)
1982 return;
1984 path = path_element->path;
1986 DEBUG (3, ("smbfs_forget(path:%s)\n", path));
1988 while (*path == '/') /* '/' leading server name */
1989 path++; /* probably came from server browsing */
1991 p = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1992 if (p != NULL)
1994 size_t i;
1996 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1998 if (smbfs_connections[i].cli
1999 && (strcmp (p->host, smbfs_connections[i].host) == 0)
2000 && (strcmp (p->user, smbfs_connections[i].user) == 0)
2001 && (p->port == smbfs_connections[i].port))
2004 /* close socket: the child owns it now */
2005 cli_shutdown (smbfs_connections[i].cli);
2007 /* reopen the connection */
2008 smbfs_connections[i].cli = smbfs_do_connect (p->host, smbfs_connections[i].service);
2012 vfs_path_element_free (p);
2016 /* --------------------------------------------------------------------------------------------- */
2018 static int
2019 smbfs_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
2021 const vfs_path_element_t *path_element;
2023 (void) arg;
2025 path_element = vfs_path_get_by_index (vpath, -1);
2026 DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path_element->path, ctlop));
2027 switch (ctlop)
2029 case VFS_SETCTL_FORGET:
2030 smbfs_forget (vpath);
2031 break;
2032 case VFS_SETCTL_LOGFILE:
2033 smbfs_set_debugf ((const char *) arg);
2034 break;
2035 default:
2036 break;
2038 return 0;
2041 /* --------------------------------------------------------------------------------------------- */
2043 static smbfs_handle *
2044 smbfs_open_readwrite (smbfs_handle * remote_handle, char *rname, int flags, mode_t mode)
2046 size_t size;
2048 (void) mode;
2050 if (flags & O_TRUNC) /* if it exists truncate to zero */
2051 DEBUG (3, ("smbfs_open: O_TRUNC\n"));
2053 remote_handle->fnum =
2054 #if 1 /* Don't play with flags, it is cli_open() headache */
2055 cli_open (remote_handle->cli, rname, flags, DENY_NONE);
2056 #else /* What's a reasons to has this code ? */
2057 cli_open (remote_handle->cli, rname, ((flags & O_CREAT)
2058 || (flags ==
2059 (O_WRONLY | O_APPEND))) ?
2060 flags : O_RDONLY, DENY_NONE);
2061 #endif
2062 if (remote_handle->fnum == -1)
2064 message (D_ERROR, MSG_ERROR, _("%s opening remote file %s"),
2065 cli_errstr (remote_handle->cli), CNV_LANG (rname));
2066 DEBUG (1, ("smbfs_open(rname:%s) error:%s\n", rname, cli_errstr (remote_handle->cli)));
2067 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2068 return NULL;
2071 if (flags & O_CREAT)
2072 return remote_handle;
2074 if (!cli_qfileinfo (remote_handle->cli, remote_handle->fnum,
2075 &remote_handle->attr, &size, NULL, NULL, NULL, NULL,
2076 NULL)
2077 && !cli_getattrE (remote_handle->cli, remote_handle->fnum,
2078 &remote_handle->attr, &size, NULL, NULL, NULL))
2080 message (D_ERROR, MSG_ERROR, "getattrib: %s", cli_errstr (remote_handle->cli));
2081 DEBUG (1, ("smbfs_open(rname:%s) getattrib:%s\n", rname, cli_errstr (remote_handle->cli)));
2082 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2083 cli_close (remote_handle->cli, remote_handle->fnum);
2084 return NULL;
2087 if ((flags == (O_WRONLY | O_APPEND)) /* file.c:copy_file_file() -> do_append */
2088 && smbfs_lseek (remote_handle, 0, SEEK_END) == -1)
2090 cli_close (remote_handle->cli, remote_handle->fnum);
2091 return NULL;
2094 return remote_handle;
2097 /* --------------------------------------------------------------------------------------------- */
2099 static void *
2100 smbfs_open (const vfs_path_t * vpath, int flags, mode_t mode)
2102 char *remote_file;
2103 void *ret;
2104 smbfs_connection *sc;
2105 smbfs_handle *remote_handle;
2106 const vfs_path_element_t *path_element;
2108 path_element = vfs_path_get_by_index (vpath, -1);
2109 DEBUG (3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", path_element->path, flags, mode));
2111 if (!(remote_file = smbfs_get_path (&sc, vpath)))
2112 return 0;
2114 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2116 remote_handle = g_new (smbfs_handle, 2);
2117 remote_handle->cli = sc->cli;
2118 remote_handle->nread = 0;
2120 ret = smbfs_open_readwrite (remote_handle, remote_file, flags, mode);
2122 g_free (remote_file);
2123 if (!ret)
2124 g_free (remote_handle);
2126 return ret;
2129 /* --------------------------------------------------------------------------------------------- */
2131 static int
2132 smbfs_unlink (const vfs_path_t * vpath)
2134 smbfs_connection *sc;
2135 char *remote_file;
2137 if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
2138 return -1;
2140 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2142 if (!cli_unlink (sc->cli, remote_file))
2144 message (D_ERROR, MSG_ERROR, _("%s removing remote file %s"),
2145 cli_errstr (sc->cli), CNV_LANG (remote_file));
2146 g_free (remote_file);
2147 return -1;
2149 g_free (remote_file);
2150 return 0;
2153 /* --------------------------------------------------------------------------------------------- */
2155 static int
2156 smbfs_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
2158 smbfs_connection *sc;
2159 char *ra, *rb;
2160 int retval;
2162 if ((ra = smbfs_get_path (&sc, vpath1)) == 0)
2163 return -1;
2165 if ((rb = smbfs_get_path (&sc, vpath2)) == 0)
2167 g_free (ra);
2168 return -1;
2171 ra = free_after (smbfs_convert_path (ra, FALSE), ra);
2172 rb = free_after (smbfs_convert_path (rb, FALSE), rb);
2174 retval = cli_rename (sc->cli, ra, rb);
2176 g_free (ra);
2177 g_free (rb);
2179 if (!retval)
2181 message (D_ERROR, MSG_ERROR, _("%s renaming files\n"), cli_errstr (sc->cli));
2182 return -1;
2184 return 0;
2187 /* --------------------------------------------------------------------------------------------- */
2189 static int
2190 smbfs_fstat (void *data, struct stat *buf)
2192 smbfs_handle *remote_handle = (smbfs_handle *) data;
2194 DEBUG (3, ("smbfs_fstat(fnum:%d)\n", remote_handle->fnum));
2196 /* use left over from previous smbfs_get_remote_stat, if available */
2197 if (single_entry)
2198 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
2199 else
2200 { /* single_entry not set up: bug */
2201 my_errno = EFAULT;
2202 return -EFAULT;
2204 return 0;
2207 /* --------------------------------------------------------------------------------------------- */
2208 /*** public functions ****************************************************************************/
2209 /* --------------------------------------------------------------------------------------------- */
2211 smb_authinfo *
2212 vfs_smb_authinfo_new (const char *host, const char *share, const char *domain,
2213 const char *user, const char *pass)
2215 smb_authinfo *auth;
2217 auth = g_try_new (struct smb_authinfo, 1);
2219 if (auth != NULL)
2221 auth->host = g_strdup (host);
2222 auth->share = g_strdup (share);
2223 auth->domain = g_strdup (domain);
2224 auth->user = g_strdup (user);
2225 auth->password = g_strdup (pass);
2228 return auth;
2231 /* --------------------------------------------------------------------------------------------- */
2233 void
2234 init_smbfs (void)
2236 tcp_init ();
2238 vfs_smbfs_ops.name = "smbfs";
2239 vfs_smbfs_ops.prefix = "smb";
2240 vfs_smbfs_ops.flags = VFSF_NOLINKS;
2241 vfs_smbfs_ops.init = smbfs_init;
2242 vfs_smbfs_ops.fill_names = smbfs_fill_names;
2243 vfs_smbfs_ops.open = smbfs_open;
2244 vfs_smbfs_ops.close = smbfs_close;
2245 vfs_smbfs_ops.read = smbfs_read;
2246 vfs_smbfs_ops.write = smbfs_write;
2247 vfs_smbfs_ops.opendir = smbfs_opendir;
2248 vfs_smbfs_ops.readdir = smbfs_readdir;
2249 vfs_smbfs_ops.closedir = smbfs_closedir;
2250 vfs_smbfs_ops.stat = smbfs_stat;
2251 vfs_smbfs_ops.lstat = smbfs_lstat;
2252 vfs_smbfs_ops.fstat = smbfs_fstat;
2253 vfs_smbfs_ops.chmod = smbfs_chmod;
2254 vfs_smbfs_ops.chown = smbfs_chown;
2255 vfs_smbfs_ops.utime = smbfs_utime;
2256 vfs_smbfs_ops.readlink = smbfs_readlink;
2257 vfs_smbfs_ops.symlink = smbfs_symlink;
2258 vfs_smbfs_ops.link = smbfs_link;
2259 vfs_smbfs_ops.unlink = smbfs_unlink;
2260 vfs_smbfs_ops.rename = smbfs_rename;
2261 vfs_smbfs_ops.chdir = smbfs_chdir;
2262 vfs_smbfs_ops.ferrno = smbfs_errno;
2263 vfs_smbfs_ops.lseek = smbfs_lseek;
2264 vfs_smbfs_ops.mknod = smbfs_mknod;
2265 vfs_smbfs_ops.free = smbfs_free;
2266 vfs_smbfs_ops.mkdir = smbfs_mkdir;
2267 vfs_smbfs_ops.rmdir = smbfs_rmdir;
2268 vfs_smbfs_ops.setctl = smbfs_setctl;
2269 vfs_register_class (&vfs_smbfs_ops);
2272 /* --------------------------------------------------------------------------------------------- */