Code indentation.
[midnight-commander.git] / src / vfs / smbfs / smbfs.c
blobc3adf17f85a456b812bd266f629540e71b4c8fec
1 /*
2 Virtual File System: Midnight Commander file system.
4 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2011
5 The 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;
576 DEBUG (3, ("\t%-15.15s%-10.10s%s\n", name, typestr, comment));
579 /* --------------------------------------------------------------------------------------------- */
581 static void
582 smbfs_loaddir_helper (file_info * finfo, const char *mask, void *entry)
584 dir_entry *new_entry = (dir_entry *) entry;
585 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
587 (void) mask;
589 #if 0 /* I want to see dot files */
590 if (finfo->mode & aHIDDEN)
591 return; /* don't bother with hidden files, "~$" screws up mc */
592 #endif
593 if (!entry)
594 new_entry = smbfs_new_dir_entry (finfo->name);
596 new_entry->my_stat.st_size = finfo->size;
597 new_entry->my_stat.st_mtime = finfo->mtime;
598 new_entry->my_stat.st_atime = finfo->atime;
599 new_entry->my_stat.st_ctime = finfo->ctime;
600 new_entry->my_stat.st_uid = finfo->uid;
601 new_entry->my_stat.st_gid = finfo->gid;
603 new_entry->my_stat.st_mode = /* rw-rw-rw */
604 S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
606 /* if (finfo->mode & aVOLID); nothing similar in real world */
607 if (finfo->mode & aDIR)
608 new_entry->my_stat.st_mode |= /* drwxrwxrwx */
609 S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
610 else
611 new_entry->my_stat.st_mode |= S_IFREG; /* if not dir, regular file? */
612 /* if (finfo->mode & aARCH); DOS archive */
613 /* if (finfo->mode & aHIDDEN); like a dot file? */
614 /* if (finfo->mode & aSYSTEM); like a kernel? */
615 if (finfo->mode & aRONLY)
616 new_entry->my_stat.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
617 new_entry->my_stat.st_mode &= myumask;
619 DEBUG (entry ? 3 : 6, (" %-30s%7.7s%8.0f %s",
620 CNV_LANG (finfo->name),
621 attrib_string (finfo->mode),
622 (double) finfo->size, asctime (LocalTime (&t))));
625 /* --------------------------------------------------------------------------------------------- */
626 /* takes "/foo/bar/file" and gives malloced "\\foo\\bar\\file" */
628 static char *
629 smbfs_convert_path (const char *remote_file, gboolean trailing_asterik)
631 const char *p, *my_remote;
632 char *result;
634 my_remote = remote_file;
635 if (strncmp (my_remote, URL_HEADER, HEADER_LEN) == 0)
636 { /* if passed directly */
637 my_remote += HEADER_LEN;
638 if (*my_remote == '/') /* from server browsing */
639 my_remote++;
640 p = strchr (my_remote, '/');
641 if (p)
642 my_remote = p + 1; /* advance to end of server name */
645 if (*my_remote == '/')
646 my_remote++; /* strip off leading '/' */
647 p = strchr (my_remote, '/');
648 if (p)
649 my_remote = p; /* strip off share/service name */
650 /* create remote filename as understood by smb clientgen */
651 result = g_strconcat (my_remote, trailing_asterik ? "/*" : "", (char *) NULL);
652 unix_to_dos (result, /* inplace = */ 1); /* code page conversion */
653 str_replace (result, '/', '\\');
654 return result;
657 /* --------------------------------------------------------------------------------------------- */
659 static void
660 smbfs_srv_browsing_helper (const char *name, uint32 m, const char *comment, void *state)
662 dir_entry *new_entry = smbfs_new_dir_entry (name);
664 (void) m;
665 (void) state;
667 /* show this as dir */
668 new_entry->my_stat.st_mode =
669 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
671 DEBUG (3, ("\t%-16.16s %s\n", name, comment));
674 /* --------------------------------------------------------------------------------------------- */
676 static BOOL
677 smbfs_reconnect (smbfs_connection * conn, int *retries)
679 char *host;
680 DEBUG (3, ("RECONNECT\n"));
682 if (*(conn->host) == 0)
683 host = g_strdup (conn->cli->desthost); /* server browsing */
684 else
685 host = g_strdup (conn->host);
687 cli_shutdown (conn->cli);
689 if (!(conn->cli = smbfs_do_connect (host, conn->service)))
691 message (D_ERROR, MSG_ERROR, _("reconnect to %s failed"), conn->host);
692 g_free (host);
693 return False;
695 g_free (host);
696 if (++(*retries) == 2)
697 return False;
698 return True;
701 /* --------------------------------------------------------------------------------------------- */
703 static BOOL
704 smbfs_send (struct cli_state *cli)
706 size_t len;
707 size_t nwritten = 0;
708 ssize_t ret;
710 len = smb_len (cli->outbuf) + 4;
712 while (nwritten < len)
714 ret = write_socket (cli->fd, cli->outbuf + nwritten, len - nwritten);
715 if (ret <= 0)
717 if (errno == EPIPE)
718 return False;
720 else
721 nwritten += ret;
724 return True;
727 /* --------------------------------------------------------------------------------------------- */
728 /****************************************************************************
729 See if server has cut us off by checking for EPIPE when writing.
730 Taken from cli_chkpath()
731 ****************************************************************************/
733 static BOOL
734 smbfs_chkpath (struct cli_state *cli, const char *path, BOOL send_only)
736 fstring path2;
737 char *p;
739 fstrcpy (path2, path);
740 unix_to_dos (path2, 1);
741 trim_string (path2, NULL, "\\");
742 if (!*path2)
743 *path2 = '\\';
745 memset (cli->outbuf, '\0', smb_size);
746 set_message (cli->outbuf, 0, 4 + strlen (path2), True);
747 SCVAL (cli->outbuf, smb_com, SMBchkpth);
748 SSVAL (cli->outbuf, smb_tid, cli->cnum);
750 cli->rap_error = 0;
751 cli->nt_error = 0;
752 SSVAL (cli->outbuf, smb_pid, cli->pid);
753 SSVAL (cli->outbuf, smb_uid, cli->vuid);
754 SSVAL (cli->outbuf, smb_mid, cli->mid);
755 if (cli->protocol > PROTOCOL_CORE)
757 SCVAL (cli->outbuf, smb_flg, 0x8);
758 SSVAL (cli->outbuf, smb_flg2, 0x1);
761 p = smb_buf (cli->outbuf);
762 *p++ = 4;
763 fstrcpy (p, path2);
765 if (!smbfs_send (cli))
767 DEBUG (3, ("smbfs_chkpath: couldnt send\n"));
768 return False;
770 if (send_only)
772 client_receive_smb (cli->fd, cli->inbuf, cli->timeout);
773 DEBUG (3, ("smbfs_chkpath: send only OK\n"));
774 return True; /* just testing for EPIPE */
776 if (!client_receive_smb (cli->fd, cli->inbuf, cli->timeout))
778 DEBUG (3, ("smbfs_chkpath: receive error\n"));
779 return False;
781 if ((my_errno = cli_error (cli, NULL, NULL, NULL)))
783 if (my_errno == 20 || my_errno == 13)
784 return True; /* ignore if 'not a directory' error */
785 DEBUG (3, ("smbfs_chkpath: cli_error: %s\n", unix_error_string (my_errno)));
786 return False;
789 return True;
792 /* --------------------------------------------------------------------------------------------- */
794 #if 1
795 static int
796 smbfs_fs (const char *text)
798 const char *p = text;
799 int count = 0;
801 while ((p = strchr (p, '/')) != NULL)
803 count++;
804 p++;
806 if (count == 1)
807 return strlen (text);
808 return count;
810 #endif
812 /* --------------------------------------------------------------------------------------------- */
814 static int
815 smbfs_loaddir (opendir_info * smbfs_info)
817 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
818 int servlen = strlen (smbfs_info->conn->service);
819 const char *info_dirname = smbfs_info->dirname;
820 char *my_dirname;
822 DEBUG (3, ("smbfs_loaddir: dirname:%s\n", info_dirname));
823 first_direntry = TRUE;
825 if (current_info)
827 DEBUG (3, ("smbfs_loaddir: new:'%s', cached:'%s'\n", info_dirname, current_info->dirname));
828 /* if new desired dir is longer than cached in current_info */
829 if (smbfs_fs (info_dirname) > smbfs_fs (current_info->dirname))
831 DEBUG (3, ("saving to previous_info\n"));
832 previous_info = current_info;
836 current_info = smbfs_info;
838 if (strcmp (info_dirname, "/") == 0)
840 if (!strcmp (smbfs_info->path, URL_HEADER))
842 DEBUG (6, ("smbfs_loaddir: browsing %s\n", IPC));
843 /* browse for servers */
844 if (!cli_NetServerEnum
845 (smbfs_info->conn->cli, smbfs_info->conn->domain,
846 SV_TYPE_ALL, smbfs_srv_browsing_helper, NULL))
847 return 0;
848 else
849 current_server_info = smbfs_info;
850 smbfs_info->server_list = TRUE;
852 else
854 /* browse for shares */
855 if (cli_RNetShareEnum (smbfs_info->conn->cli, smbfs_browsing_helper, NULL) < 1)
856 return 0;
857 else
858 current_share_info = smbfs_info;
860 goto done;
863 /* do regular directory listing */
864 if (strncmp (smbfs_info->conn->service, info_dirname + 1, servlen) == 0)
866 /* strip share name from dir */
867 my_dirname = g_strdup (info_dirname + servlen);
868 *my_dirname = '/';
869 my_dirname = free_after (smbfs_convert_path (my_dirname, TRUE), my_dirname);
871 else
872 my_dirname = smbfs_convert_path (info_dirname, TRUE);
874 DEBUG (6, ("smbfs_loaddir: service: %s\n", smbfs_info->conn->service));
875 DEBUG (6, ("smbfs_loaddir: cli->share: %s\n", smbfs_info->conn->cli->share));
876 DEBUG (6, ("smbfs_loaddir: calling cli_list with mask %s\n", my_dirname));
877 /* do file listing: cli_list returns number of files */
878 if (cli_list (smbfs_info->conn->cli, my_dirname, attribute, smbfs_loaddir_helper, NULL) < 0)
880 /* cli_list returns -1 if directory empty or cannot read socket */
881 my_errno = cli_error (smbfs_info->conn->cli, NULL, &err, NULL);
882 g_free (my_dirname);
883 return 0;
885 if (*(my_dirname) == 0)
886 smbfs_info->dirname = smbfs_info->conn->service;
887 g_free (my_dirname);
888 /* do_dskattr(); */
890 done:
891 /* current_info->parent = smbfs_info->dirname; */
893 smbfs_info->current = smbfs_info->entries;
894 return 1; /* 1 = ok */
897 /* --------------------------------------------------------------------------------------------- */
899 #ifdef SMBFS_FREE_DIR
900 static void
901 smbfs_free_dir (dir_entry * de)
903 if (!de)
904 return;
906 smbfs_free_dir (de->next);
907 g_free (de->text);
908 g_free (de);
910 #endif
912 /* --------------------------------------------------------------------------------------------- */
913 /* The readdir routine loads the complete directory */
914 /* It's too slow to ask the server each time */
915 /* It now also sends the complete lstat information for each file */
917 static void *
918 smbfs_readdir (void *info)
920 static union vfs_dirent smbfs_readdir_data;
921 static char *const dirent_dest = smbfs_readdir_data.dent.d_name;
922 opendir_info *smbfs_info = (opendir_info *) info;
924 DEBUG (4, ("smbfs_readdir(%s)\n", smbfs_info->dirname));
926 if (!smbfs_info->entries)
927 if (!smbfs_loaddir (smbfs_info))
928 return NULL;
930 if (smbfs_info->current == 0)
931 { /* reached end of dir entries */
932 DEBUG (3, ("smbfs_readdir: smbfs_info->current = 0\n"));
933 #ifdef SMBFS_FREE_DIR
934 smbfs_free_dir (smbfs_info->entries);
935 smbfs_info->entries = 0;
936 #endif
937 return NULL;
939 g_strlcpy (dirent_dest, smbfs_info->current->text, MC_MAXPATHLEN);
940 smbfs_info->current = smbfs_info->current->next;
942 compute_namelen (&smbfs_readdir_data.dent);
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 = vfs_path_from_str (path);
1480 p = smbfs_get_path (&sc, vpath);
1481 vfs_path_free (vpath);
1483 g_free (p);
1484 if (p)
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 return 0;
1492 return -1;
1495 path += strlen (server_url); /* we only want share name */
1496 path++;
1498 if (*path == '/') /* '/' leading server name */
1499 path++; /* probably came from server browsing */
1501 if (!current_share_info->entries)
1503 if (!smbfs_loaddir (current_share_info)) /* browse host */
1504 return -1;
1506 dentry = current_share_info->entries;
1507 DEBUG (3, ("smbfs_fake_share_stat: %s on %s\n", path, server_url));
1508 while (dentry)
1510 if (strcmp (dentry->text, path) == 0)
1512 DEBUG (6, ("smbfs_fake_share_stat: %s:%4o\n",
1513 dentry->text, (int) dentry->my_stat.st_mode));
1514 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1515 return 0;
1517 dentry = dentry->next;
1519 my_errno = ENOENT;
1520 return -1;
1523 /* --------------------------------------------------------------------------------------------- */
1524 /* stat a single file */
1526 static int
1527 smbfs_get_remote_stat (smbfs_connection * sc, const char *path, struct stat *buf)
1529 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
1530 char *mypath;
1532 DEBUG (3, ("smbfs_get_remote_stat(): mypath:%s\n", path));
1534 mypath = smbfs_convert_path (path, FALSE);
1536 #if 0 /* single_entry is never free()d now. And only my_stat is used */
1537 single_entry = g_new (dir_entry, 1);
1539 single_entry->text = dos_to_unix (g_strdup (finfo->name), 1);
1541 single_entry->next = 0;
1542 #endif
1543 if (!single_entry)
1544 single_entry = g_new0 (dir_entry, 1);
1546 if (cli_list (sc->cli, mypath, attribute, smbfs_loaddir_helper, single_entry) < 1)
1548 my_errno = ENOENT;
1549 g_free (mypath);
1550 return -1; /* cli_list returns number of files */
1553 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
1555 /* don't free here, use for smbfs_fstat() */
1556 /* g_free(single_entry->text);
1557 g_free(single_entry); */
1558 g_free (mypath);
1559 return 0;
1562 /* --------------------------------------------------------------------------------------------- */
1564 static int
1565 smbfs_search_dir_entry (dir_entry * dentry, const char *text, struct stat *buf)
1567 while (dentry)
1569 if (strcmp (text, dentry->text) == 0)
1571 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1572 memcpy (&single_entry->my_stat, &dentry->my_stat, sizeof (struct stat));
1573 return 0;
1575 dentry = dentry->next;
1577 return -1;
1580 /* --------------------------------------------------------------------------------------------- */
1582 static int
1583 smbfs_get_stat_info (smbfs_connection * sc, const char *path, struct stat *buf)
1585 char *p;
1586 #if 0
1587 dir_entry *dentry = current_info->entries;
1588 #endif
1589 const char *mypath = path;
1591 mypath++; /* cut off leading '/' */
1592 if ((p = strrchr (mypath, '/')))
1593 mypath = p + 1; /* advance until last file/dir name */
1594 DEBUG (3, ("smbfs_get_stat_info: mypath:%s, current_info->dirname:%s\n",
1595 mypath, current_info->dirname));
1596 #if 0
1597 if (!dentry)
1599 DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1600 current_info->dirname, path));
1601 return -1;
1603 #endif
1604 if (!single_entry) /* when found, this will be written too */
1605 single_entry = g_new (dir_entry, 1);
1606 if (smbfs_search_dir_entry (current_info->entries, mypath, buf) == 0)
1608 return 0;
1610 /* now try to identify mypath as PARENT dir */
1612 char *mdp;
1613 char *mydir;
1614 mdp = mydir = g_strdup (current_info->dirname);
1615 if ((p = strrchr (mydir, '/')))
1616 *p = 0; /* advance util last '/' */
1617 if ((p = strrchr (mydir, '/')))
1618 mydir = p + 1; /* advance util last '/' */
1619 if (strcmp (mydir, mypath) == 0)
1620 { /* fake a stat for ".." */
1621 memset (buf, 0, sizeof (struct stat));
1622 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1623 memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1624 g_free (mdp);
1625 DEBUG (1, (" PARENT:found in %s\n", current_info->dirname));
1626 return 0;
1628 g_free (mdp);
1630 /* now try to identify as CURRENT dir? */
1632 char *dnp = current_info->dirname;
1633 DEBUG (6, ("smbfs_get_stat_info: is %s current dir? this dir is: %s\n",
1634 mypath, current_info->dirname));
1635 if (*dnp == '/')
1636 dnp++;
1637 else
1639 return -1;
1641 if (strcmp (mypath, dnp) == 0)
1643 memset (buf, 0, sizeof (struct stat));
1644 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1645 memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1646 DEBUG (1, (" CURRENT:found in %s\n", current_info->dirname));
1647 return 0;
1650 DEBUG (3, ("'%s' not found in current_info '%s'\n", path, current_info->dirname));
1651 /* try to find this in the PREVIOUS listing */
1652 if (previous_info)
1654 if (smbfs_search_dir_entry (previous_info->entries, mypath, buf) == 0)
1655 return 0;
1656 DEBUG (3, ("'%s' not found in previous_info '%s'\n", path, previous_info->dirname));
1658 /* try to find this in the SHARE listing */
1659 if (current_share_info)
1661 if (smbfs_search_dir_entry (current_share_info->entries, mypath, buf) == 0)
1662 return 0;
1663 DEBUG (3, ("'%s' not found in share_info '%s'\n", path, current_share_info->dirname));
1665 /* try to find this in the SERVER listing */
1666 if (current_server_info)
1668 if (smbfs_search_dir_entry (current_server_info->entries, mypath, buf) == 0)
1669 return 0;
1670 DEBUG (3, ("'%s' not found in server_info '%s'\n", path, current_server_info->dirname));
1672 /* nothing found. get stat file info from server */
1673 return smbfs_get_remote_stat (sc, path, buf);
1676 /* --------------------------------------------------------------------------------------------- */
1678 static int
1679 smbfs_chdir (const vfs_path_t * vpath)
1681 char *remote_dir;
1682 smbfs_connection *sc;
1683 const vfs_path_element_t *path_element;
1685 path_element = vfs_path_get_by_index (vpath, -1);
1686 DEBUG (3, ("smbfs_chdir(path:%s)\n", path_element->path));
1687 if (!(remote_dir = smbfs_get_path (&sc, vpath)))
1688 return -1;
1689 g_free (remote_dir);
1691 return 0;
1694 /* --------------------------------------------------------------------------------------------- */
1696 static int
1697 smbfs_loaddir_by_name (const vfs_path_t * vpath)
1699 void *info;
1700 char *mypath, *p;
1701 const vfs_path_element_t *path_element;
1703 path_element = vfs_path_get_by_index (vpath, -1);
1704 mypath = g_strdup (path_element->path);
1705 p = strrchr (mypath, '/');
1707 if (p > mypath)
1708 *p = 0;
1709 DEBUG (6, ("smbfs_loaddir_by_name(%s)\n", mypath));
1710 smbfs_chdir (vpath);
1711 info = smbfs_opendir (vpath);
1712 g_free (mypath);
1713 if (!info)
1714 return -1;
1715 smbfs_readdir (info);
1716 smbfs_loaddir (info);
1717 return 0;
1720 /* --------------------------------------------------------------------------------------------- */
1722 static int
1723 smbfs_stat (const vfs_path_t * vpath, struct stat *buf)
1725 smbfs_connection *sc;
1726 pstring server_url;
1727 char *service, *pp, *at;
1728 const char *p;
1729 const vfs_path_element_t *path_element;
1731 path_element = vfs_path_get_by_index (vpath, -1);
1732 DEBUG (3, ("smbfs_stat(path:%s)\n", path_element->path));
1734 if (!current_info)
1736 DEBUG (1, ("current_info = NULL: "));
1737 if (smbfs_loaddir_by_name (vpath) < 0)
1738 return -1;
1741 /* check if stating server */
1742 p = path_element->path;
1743 if (path_element->class != &vfs_smbfs_ops)
1744 return -1;
1746 while (*p == '/') /* '/' leading server name */
1747 p++; /* probably came from server browsing */
1749 pp = strchr (p, '/'); /* advance past next '/' */
1750 at = strchr (p, '@');
1751 pstrcpy (server_url, URL_HEADER);
1752 if (at && at < pp)
1753 { /* user@server */
1754 char *z = &(server_url[sizeof (server_url) - 1]);
1755 const char *s = p;
1757 at = &(server_url[HEADER_LEN]) + (at - p + 1);
1758 if (z > at)
1759 z = at;
1760 at = &(server_url[HEADER_LEN]);
1761 while (at < z)
1762 *at++ = *s++;
1763 *z = 0;
1765 pstrcat (server_url, current_bucket->host);
1767 if (!pp)
1769 if (!current_info->server_list)
1771 if (smbfs_loaddir_by_name (vpath) < 0)
1772 return -1;
1774 return smbfs_fake_server_stat (server_url, path_element->path, buf);
1777 if (!strchr (++pp, '/'))
1779 return smbfs_fake_share_stat (server_url, path_element->path, buf);
1782 /* stating inside share at this point */
1783 if (!(service = smbfs_get_path (&sc, vpath))) /* connects if necessary */
1784 return -1;
1786 int hostlen = strlen (current_bucket->host);
1787 char *ppp = service + strlen (service) - hostlen;
1788 char *sp = server_url + strlen (server_url) - hostlen;
1790 if (strcmp (sp, ppp) == 0)
1792 /* make server name appear as directory */
1793 DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1794 memset (buf, 0, sizeof (struct stat));
1795 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1796 g_free (service);
1797 return 0;
1800 /* check if current_info is in share requested */
1801 p = service;
1802 pp = strchr (p, '/');
1803 if (pp)
1805 p = ++pp; /* advance past server name */
1806 pp = strchr (p, '/');
1808 if (pp)
1809 *pp = 0; /* cut off everthing after service name */
1810 else
1811 p = IPC; /* browsing for services */
1812 pp = current_info->dirname;
1813 if (*pp == '/')
1814 pp++;
1815 if (strncmp (p, pp, strlen (p)) != 0)
1817 DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p, pp));
1818 if (smbfs_loaddir_by_name (vpath) < 0)
1820 g_free (service);
1821 return -1;
1823 DEBUG (6, ("loaded dir: '%s'\n", current_info->dirname));
1825 g_free (service);
1826 /* stat dirs & files under shares now */
1827 return smbfs_get_stat_info (sc, path_element->path, buf);
1830 /* --------------------------------------------------------------------------------------------- */
1832 static off_t
1833 smbfs_lseek (void *data, off_t offset, int whence)
1835 smbfs_handle *info = (smbfs_handle *) data;
1836 size_t size;
1838 DEBUG (3,
1839 ("smbfs_lseek(info->nread => %d, offset => %d, whence => %d) \n",
1840 (int) info->nread, (int) offset, whence));
1842 switch (whence)
1844 case SEEK_SET:
1845 info->nread = offset;
1846 break;
1847 case SEEK_CUR:
1848 info->nread += offset;
1849 break;
1850 case SEEK_END:
1851 if (!cli_qfileinfo (info->cli, info->fnum,
1852 NULL, &size, NULL, NULL, NULL,
1853 NULL, NULL) &&
1854 !cli_getattrE (info->cli, info->fnum, NULL, &size, NULL, NULL, NULL))
1856 errno = EINVAL;
1857 return -1;
1859 info->nread = size + offset;
1860 break;
1863 return info->nread;
1866 /* --------------------------------------------------------------------------------------------- */
1868 static int
1869 smbfs_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev)
1871 const vfs_path_element_t *path_element;
1873 path_element = vfs_path_get_by_index (vpath, -1);
1874 DEBUG (3,
1875 ("smbfs_mknod(path:%s, mode:%d, dev:%u)\n", path_element->path, mode,
1876 (unsigned int) dev));
1877 my_errno = EOPNOTSUPP;
1878 return -1;
1881 /* --------------------------------------------------------------------------------------------- */
1883 static int
1884 smbfs_mkdir (const vfs_path_t * vpath, mode_t mode)
1886 smbfs_connection *sc;
1887 char *remote_file;
1888 char *cpath;
1889 const vfs_path_element_t *path_element;
1891 path_element = vfs_path_get_by_index (vpath, -1);
1892 DEBUG (3, ("smbfs_mkdir(path:%s, mode:%d)\n", path_element->path, (int) mode));
1893 if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
1894 return -1;
1895 g_free (remote_file);
1896 cpath = smbfs_convert_path (path_element->path, FALSE);
1898 if (!cli_mkdir (sc->cli, cpath))
1900 my_errno = cli_error (sc->cli, NULL, &err, NULL);
1901 message (D_ERROR, MSG_ERROR, _("Error %s creating directory %s"),
1902 cli_errstr (sc->cli), CNV_LANG (cpath));
1903 g_free (cpath);
1904 return -1;
1906 g_free (cpath);
1907 return 0;
1910 /* --------------------------------------------------------------------------------------------- */
1912 static int
1913 smbfs_rmdir (const vfs_path_t * vpath)
1915 smbfs_connection *sc;
1916 char *remote_file;
1917 char *cpath;
1918 const vfs_path_element_t *path_element;
1920 path_element = vfs_path_get_by_index (vpath, -1);
1921 DEBUG (3, ("smbfs_rmdir(path:%s)\n", path_element->path));
1922 if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
1923 return -1;
1924 g_free (remote_file);
1925 cpath = smbfs_convert_path (path_element->path, FALSE);
1927 if (!cli_rmdir (sc->cli, cpath))
1929 my_errno = cli_error (sc->cli, NULL, &err, NULL);
1930 message (D_ERROR, MSG_ERROR, _("Error %s removing directory %s"),
1931 cli_errstr (sc->cli), CNV_LANG (cpath));
1932 g_free (cpath);
1933 return -1;
1936 g_free (cpath);
1937 return 0;
1940 /* --------------------------------------------------------------------------------------------- */
1942 static int
1943 smbfs_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
1945 const vfs_path_element_t *path_element1;
1946 const vfs_path_element_t *path_element2;
1948 path_element1 = vfs_path_get_by_index (vpath1, -1);
1949 path_element2 = vfs_path_get_by_index (vpath2, -1);
1950 DEBUG (3, ("smbfs_link(p1:%s, p2:%s)\n", path_element1->path, path_element2->path));
1951 my_errno = EOPNOTSUPP;
1952 return -1;
1955 /* --------------------------------------------------------------------------------------------- */
1957 static void
1958 smbfs_free (vfsid id)
1960 DEBUG (3, ("smbfs_free(%p)\n", id));
1961 smbfs_auth_free_all ();
1964 /* --------------------------------------------------------------------------------------------- */
1965 /* Gives up on a socket and reopens the connection, the child own the socket
1966 * now
1969 static void
1970 smbfs_forget (const vfs_path_t * vpath)
1972 const vfs_path_element_t *path_element;
1973 vfs_path_element_t *p;
1974 const char *path;
1976 path_element = vfs_path_get_by_index (vpath, -1);
1977 if (path_element->class != &vfs_smbfs_ops)
1978 return;
1980 path = path_element->path;
1982 DEBUG (3, ("smbfs_forget(path:%s)\n", path));
1984 while (*path == '/') /* '/' leading server name */
1985 path++; /* probably came from server browsing */
1987 p = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1988 if (p != NULL)
1990 size_t i;
1992 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1994 if (smbfs_connections[i].cli
1995 && (strcmp (p->host, smbfs_connections[i].host) == 0)
1996 && (strcmp (p->user, smbfs_connections[i].user) == 0)
1997 && (p->port == smbfs_connections[i].port))
2000 /* close socket: the child owns it now */
2001 cli_shutdown (smbfs_connections[i].cli);
2003 /* reopen the connection */
2004 smbfs_connections[i].cli = smbfs_do_connect (p->host, smbfs_connections[i].service);
2008 vfs_path_element_free (p);
2012 /* --------------------------------------------------------------------------------------------- */
2014 static int
2015 smbfs_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
2017 const vfs_path_element_t *path_element;
2019 (void) arg;
2021 path_element = vfs_path_get_by_index (vpath, -1);
2022 DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path_element->path, ctlop));
2023 switch (ctlop)
2025 case VFS_SETCTL_FORGET:
2026 smbfs_forget (vpath);
2027 break;
2028 case VFS_SETCTL_LOGFILE:
2029 smbfs_set_debugf ((const char *) arg);
2030 break;
2032 return 0;
2035 /* --------------------------------------------------------------------------------------------- */
2037 static smbfs_handle *
2038 smbfs_open_readwrite (smbfs_handle * remote_handle, char *rname, int flags, mode_t mode)
2040 size_t size;
2042 (void) mode;
2044 if (flags & O_TRUNC) /* if it exists truncate to zero */
2045 DEBUG (3, ("smbfs_open: O_TRUNC\n"));
2047 remote_handle->fnum =
2048 #if 1 /* Don't play with flags, it is cli_open() headache */
2049 cli_open (remote_handle->cli, rname, flags, DENY_NONE);
2050 #else /* What's a reasons to has this code ? */
2051 cli_open (remote_handle->cli, rname, ((flags & O_CREAT)
2052 || (flags ==
2053 (O_WRONLY | O_APPEND))) ?
2054 flags : O_RDONLY, DENY_NONE);
2055 #endif
2056 if (remote_handle->fnum == -1)
2058 message (D_ERROR, MSG_ERROR, _("%s opening remote file %s"),
2059 cli_errstr (remote_handle->cli), CNV_LANG (rname));
2060 DEBUG (1, ("smbfs_open(rname:%s) error:%s\n", rname, cli_errstr (remote_handle->cli)));
2061 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2062 return NULL;
2065 if (flags & O_CREAT)
2066 return remote_handle;
2068 if (!cli_qfileinfo (remote_handle->cli, remote_handle->fnum,
2069 &remote_handle->attr, &size, NULL, NULL, NULL, NULL,
2070 NULL)
2071 && !cli_getattrE (remote_handle->cli, remote_handle->fnum,
2072 &remote_handle->attr, &size, NULL, NULL, NULL))
2074 message (D_ERROR, MSG_ERROR, "getattrib: %s", cli_errstr (remote_handle->cli));
2075 DEBUG (1, ("smbfs_open(rname:%s) getattrib:%s\n", rname, cli_errstr (remote_handle->cli)));
2076 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2077 cli_close (remote_handle->cli, remote_handle->fnum);
2078 return NULL;
2081 if ((flags == (O_WRONLY | O_APPEND)) /* file.c:copy_file_file() -> do_append */
2082 && smbfs_lseek (remote_handle, 0, SEEK_END) == -1)
2084 cli_close (remote_handle->cli, remote_handle->fnum);
2085 return NULL;
2088 return remote_handle;
2091 /* --------------------------------------------------------------------------------------------- */
2093 static void *
2094 smbfs_open (const vfs_path_t * vpath, int flags, mode_t mode)
2096 char *remote_file;
2097 void *ret;
2098 smbfs_connection *sc;
2099 smbfs_handle *remote_handle;
2100 const vfs_path_element_t *path_element;
2102 path_element = vfs_path_get_by_index (vpath, -1);
2103 DEBUG (3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", path_element->path, flags, mode));
2105 if (!(remote_file = smbfs_get_path (&sc, vpath)))
2106 return 0;
2108 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2110 remote_handle = g_new (smbfs_handle, 2);
2111 remote_handle->cli = sc->cli;
2112 remote_handle->nread = 0;
2114 ret = smbfs_open_readwrite (remote_handle, remote_file, flags, mode);
2116 g_free (remote_file);
2117 if (!ret)
2118 g_free (remote_handle);
2120 return ret;
2123 /* --------------------------------------------------------------------------------------------- */
2125 static int
2126 smbfs_unlink (const vfs_path_t * vpath)
2128 smbfs_connection *sc;
2129 char *remote_file;
2131 if ((remote_file = smbfs_get_path (&sc, vpath)) == 0)
2132 return -1;
2134 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2136 if (!cli_unlink (sc->cli, remote_file))
2138 message (D_ERROR, MSG_ERROR, _("%s removing remote file %s"),
2139 cli_errstr (sc->cli), CNV_LANG (remote_file));
2140 g_free (remote_file);
2141 return -1;
2143 g_free (remote_file);
2144 return 0;
2147 /* --------------------------------------------------------------------------------------------- */
2149 static int
2150 smbfs_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
2152 smbfs_connection *sc;
2153 char *ra, *rb;
2154 int retval;
2156 if ((ra = smbfs_get_path (&sc, vpath1)) == 0)
2157 return -1;
2159 if ((rb = smbfs_get_path (&sc, vpath2)) == 0)
2161 g_free (ra);
2162 return -1;
2165 ra = free_after (smbfs_convert_path (ra, FALSE), ra);
2166 rb = free_after (smbfs_convert_path (rb, FALSE), rb);
2168 retval = cli_rename (sc->cli, ra, rb);
2170 g_free (ra);
2171 g_free (rb);
2173 if (!retval)
2175 message (D_ERROR, MSG_ERROR, _("%s renaming files\n"), cli_errstr (sc->cli));
2176 return -1;
2178 return 0;
2181 /* --------------------------------------------------------------------------------------------- */
2183 static int
2184 smbfs_fstat (void *data, struct stat *buf)
2186 smbfs_handle *remote_handle = (smbfs_handle *) data;
2188 DEBUG (3, ("smbfs_fstat(fnum:%d)\n", remote_handle->fnum));
2190 /* use left over from previous smbfs_get_remote_stat, if available */
2191 if (single_entry)
2192 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
2193 else
2194 { /* single_entry not set up: bug */
2195 my_errno = EFAULT;
2196 return -EFAULT;
2198 return 0;
2201 /* --------------------------------------------------------------------------------------------- */
2202 /*** public functions ****************************************************************************/
2203 /* --------------------------------------------------------------------------------------------- */
2205 smb_authinfo *
2206 vfs_smb_authinfo_new (const char *host, const char *share, const char *domain,
2207 const char *user, const char *pass)
2209 smb_authinfo *auth;
2211 auth = g_try_new (struct smb_authinfo, 1);
2213 if (auth != NULL)
2215 auth->host = g_strdup (host);
2216 auth->share = g_strdup (share);
2217 auth->domain = g_strdup (domain);
2218 auth->user = g_strdup (user);
2219 auth->password = g_strdup (pass);
2222 return auth;
2225 /* --------------------------------------------------------------------------------------------- */
2227 void
2228 init_smbfs (void)
2230 tcp_init ();
2232 vfs_smbfs_ops.name = "smbfs";
2233 vfs_smbfs_ops.prefix = "smb";
2234 vfs_smbfs_ops.flags = VFSF_NOLINKS;
2235 vfs_smbfs_ops.init = smbfs_init;
2236 vfs_smbfs_ops.fill_names = smbfs_fill_names;
2237 vfs_smbfs_ops.open = smbfs_open;
2238 vfs_smbfs_ops.close = smbfs_close;
2239 vfs_smbfs_ops.read = smbfs_read;
2240 vfs_smbfs_ops.write = smbfs_write;
2241 vfs_smbfs_ops.opendir = smbfs_opendir;
2242 vfs_smbfs_ops.readdir = smbfs_readdir;
2243 vfs_smbfs_ops.closedir = smbfs_closedir;
2244 vfs_smbfs_ops.stat = smbfs_stat;
2245 vfs_smbfs_ops.lstat = smbfs_lstat;
2246 vfs_smbfs_ops.fstat = smbfs_fstat;
2247 vfs_smbfs_ops.chmod = smbfs_chmod;
2248 vfs_smbfs_ops.chown = smbfs_chown;
2249 vfs_smbfs_ops.utime = smbfs_utime;
2250 vfs_smbfs_ops.readlink = smbfs_readlink;
2251 vfs_smbfs_ops.symlink = smbfs_symlink;
2252 vfs_smbfs_ops.link = smbfs_link;
2253 vfs_smbfs_ops.unlink = smbfs_unlink;
2254 vfs_smbfs_ops.rename = smbfs_rename;
2255 vfs_smbfs_ops.chdir = smbfs_chdir;
2256 vfs_smbfs_ops.ferrno = smbfs_errno;
2257 vfs_smbfs_ops.lseek = smbfs_lseek;
2258 vfs_smbfs_ops.mknod = smbfs_mknod;
2259 vfs_smbfs_ops.free = smbfs_free;
2260 vfs_smbfs_ops.mkdir = smbfs_mkdir;
2261 vfs_smbfs_ops.rmdir = smbfs_rmdir;
2262 vfs_smbfs_ops.setctl = smbfs_setctl;
2263 vfs_register_class (&vfs_smbfs_ops);
2266 /* --------------------------------------------------------------------------------------------- */