Updated Russian translation.
[midnight-commander.git] / lib / vfs / mc-vfs / smbfs.c
blob021f4ac3cb43c1e181f97374a70c661ff8af705f
1 /* Virtual File System: Midnight Commander file system.
3 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
4 Free Software Foundation, Inc.
6 Written by Wayne Roberts <wroberts1@home.com>, 1997
7 Andrew V. Samoilov <sav@bcs.zp.ua> 2002, 2003
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License
11 as published by the Free Software Foundation; either version 2 of
12 the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 /**
24 * \file
25 * \brief Source: Virtual File System: smb file system
26 * \author Wayne Roberts <wroberts1@home.com>
27 * \author Andrew V. Samoilov <sav@bcs.zp.ua>
28 * \date 1997, 2002, 2003
30 * Namespace: exports init_smbfs, smbfs_set_debug()
33 #include <config.h>
35 #include <stdio.h>
36 #include <sys/types.h>
38 #undef USE_NCURSES /* Don't include *curses.h */
39 #undef USE_NCURSESW
41 #include <string.h>
43 #include "lib/global.h"
44 #include "lib/strutil.h"
45 #include "lib/util.h"
46 #include "lib/widget.h" /* message() */
48 #undef PACKAGE_BUGREPORT
49 #undef PACKAGE_NAME
50 #undef PACKAGE_STRING
51 #undef PACKAGE_TARNAME
52 #undef PACKAGE_VERSION
54 #include "samba/include/config.h"
55 /* don't load crap in "samba/include/includes.h" we don't use and which
56 conflicts with definitions in other includes */
57 #undef HAVE_LIBREADLINE
58 #define NO_CONFIG_H
59 #undef VERSION
61 #include "samba/include/includes.h"
63 #include "vfs-impl.h"
64 #include "netutil.h"
65 #include "utilvfs.h"
66 #include "smbfs.h"
68 /*** global variables ****************************************************************************/
70 extern int DEBUGLEVEL;
71 extern pstring myhostname;
72 extern struct in_addr ipzero;
73 extern pstring global_myname;
74 extern pstring debugf;
75 extern FILE *dbf;
77 /*** file scope macro definitions ****************************************************************/
79 #define SMBFS_MAX_CONNECTIONS 16
81 #define HEADER_LEN 6
83 #define CNV_LANG(s) dos_to_unix(s,False)
84 #define GNAL_VNC(s) unix_to_dos(s,False)
86 /* Extract the hostname and username from the path */
87 /* path is in the form: [user@]hostname/share/remote-dir */
88 #define smbfs_get_host_and_username(path, host, user, port, pass) \
89 vfs_split_url (*path, host, user, port, pass, SMB_PORT, 0)
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:";
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 (struct vfs_class *me, const char *path, int mode)
973 (void) me;
975 DEBUG (3, ("smbfs_chmod(path:%s, mode:%d)\n", path, mode));
976 /* my_errno = EOPNOTSUPP;
977 return -1; *//* cannot chmod on smb filesystem */
978 return 0; /* make mc happy */
981 /* --------------------------------------------------------------------------------------------- */
983 static int
984 smbfs_chown (struct vfs_class *me, const char *path, uid_t owner, gid_t group)
986 (void) me;
988 DEBUG (3, ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path, owner, group));
989 my_errno = EOPNOTSUPP; /* ready for your labotomy? */
990 return -1;
993 /* --------------------------------------------------------------------------------------------- */
995 static int
996 smbfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
998 (void) me;
999 (void) times;
1001 DEBUG (3, ("smbfs_utime(path:%s)\n", path));
1002 my_errno = EOPNOTSUPP;
1003 return -1;
1006 /* --------------------------------------------------------------------------------------------- */
1008 static int
1009 smbfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
1011 (void) me;
1013 DEBUG (3, ("smbfs_readlink(path:%s, buf:%s, size:%zu)\n", path, buf, size));
1014 my_errno = EOPNOTSUPP;
1015 return -1; /* no symlinks on smb filesystem? */
1018 /* --------------------------------------------------------------------------------------------- */
1020 static int
1021 smbfs_symlink (struct vfs_class *me, const char *n1, const char *n2)
1023 (void) me;
1025 DEBUG (3, ("smbfs_symlink(n1:%s, n2:%s)\n", n1, n2));
1026 my_errno = EOPNOTSUPP;
1027 return -1; /* no symlinks on smb filesystem? */
1030 /* --------------------------------------------------------------------------------------------- */
1031 /*****************************************************
1032 return a connection to a SMB server
1033 current_bucket needs to be set before calling
1034 *******************************************************/
1036 static struct cli_state *
1037 smbfs_do_connect (const char *server, char *share)
1039 struct cli_state *c;
1040 struct nmb_name called, calling;
1041 struct in_addr ip;
1043 DEBUG (3, ("smbfs_do_connect(%s, %s)\n", server, share));
1044 if (*share == '\\')
1046 server = share + 2;
1047 share = strchr (server, '\\');
1048 if (!share)
1049 return NULL;
1050 *share = 0;
1051 share++;
1054 make_nmb_name (&calling, global_myname, 0x0);
1055 make_nmb_name (&called, server, current_bucket->name_type);
1057 for (;;)
1060 ip = (current_bucket->have_ip) ? current_bucket->dest_ip : ipzero;
1062 /* have to open a new connection */
1063 if (!(c = cli_initialise (NULL)))
1065 my_errno = ENOMEM;
1066 return NULL;
1069 pwd_init (&(c->pwd)); /* should be moved into cli_initialise()? */
1070 pwd_set_cleartext (&(c->pwd), current_bucket->password);
1072 if ((cli_set_port (c, current_bucket->port) == 0) || !cli_connect (c, server, &ip))
1074 DEBUG (1, ("Connection to %s failed\n", server));
1075 break;
1078 if (!cli_session_request (c, &calling, &called))
1080 my_errno = cli_error (c, NULL, &err, NULL);
1081 DEBUG (1, ("session request to %s failed\n", called.name));
1082 cli_shutdown (c);
1083 if (strcmp (called.name, "*SMBSERVER"))
1085 make_nmb_name (&called, "*SMBSERVER", 0x20);
1086 continue;
1088 return NULL;
1091 DEBUG (3, (" session request ok\n"));
1093 if (!cli_negprot (c))
1095 DEBUG (1, ("protocol negotiation failed\n"));
1096 break;
1099 if (!cli_session_setup (c, current_bucket->user,
1100 current_bucket->password, strlen (current_bucket->password),
1101 current_bucket->password, strlen (current_bucket->password),
1102 current_bucket->domain))
1104 DEBUG (1, ("session setup failed: %s\n", cli_errstr (c)));
1105 smbfs_auth_remove (server, share);
1106 break;
1109 if (*c->server_domain || *c->server_os || *c->server_type)
1110 DEBUG (5, ("Domain=[%s] OS=[%s] Server=[%s]\n",
1111 c->server_domain, c->server_os, c->server_type));
1113 DEBUG (3, (" session setup ok\n"));
1115 if (!cli_send_tconX (c, share, "?????",
1116 current_bucket->password, strlen (current_bucket->password) + 1))
1118 DEBUG (1, ("%s: tree connect failed: %s\n", share, cli_errstr (c)));
1119 break;
1122 DEBUG (3, (" tconx ok\n"));
1124 my_errno = 0;
1125 return c;
1128 my_errno = cli_error (c, NULL, &err, NULL);
1129 cli_shutdown (c);
1130 return NULL;
1134 /* --------------------------------------------------------------------------------------------- */
1136 static int
1137 smbfs_get_master_browser (char **host)
1139 static char so_broadcast[] = "SO_BROADCAST";
1140 int count;
1141 struct in_addr *ip_list, bcast_addr;
1143 /* does port = 137 for win95 master browser? */
1144 int fd = open_socket_in (SOCK_DGRAM, 0, 3,
1145 interpret_addr (lp_socket_address ()), True);
1146 if (fd == -1)
1147 return 0;
1148 set_socket_options (fd, so_broadcast);
1149 ip_list = iface_bcast (ipzero);
1150 bcast_addr = *ip_list;
1151 if ((ip_list = name_query (fd, "\01\02__MSBROWSE__\02", 1, True,
1152 True, bcast_addr, &count, NULL)))
1154 if (!count)
1155 return 0;
1156 /* just return first master browser */
1157 *host = g_strdup (inet_ntoa (ip_list[0]));
1158 return 1;
1160 return 0;
1163 /* --------------------------------------------------------------------------------------------- */
1165 static void
1166 smbfs_free_bucket (smbfs_connection * bucket)
1168 g_free (bucket->host);
1169 g_free (bucket->service);
1170 g_free (bucket->domain);
1171 g_free (bucket->user);
1172 wipe_password (bucket->password);
1173 g_free (bucket->home);
1174 memset (bucket, 0, sizeof (smbfs_connection));
1177 /* --------------------------------------------------------------------------------------------- */
1179 static smbfs_connection *
1180 smbfs_get_free_bucket (void)
1182 int i;
1184 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1185 if (!smbfs_connections[i].cli)
1186 return &smbfs_connections[i];
1188 { /* search for most dormant connection */
1189 int oldest = 0; /* index */
1190 time_t oldest_time = smbfs_connections[0].last_use;
1191 for (i = 1; i < SMBFS_MAX_CONNECTIONS; i++)
1193 if (smbfs_connections[i].last_use < oldest_time)
1195 oldest_time = smbfs_connections[i].last_use;
1196 oldest = i;
1199 cli_shutdown (smbfs_connections[oldest].cli);
1200 smbfs_free_bucket (&smbfs_connections[oldest]);
1201 return &smbfs_connections[oldest];
1204 /* This can't happend, since we have checked for max connections before */
1205 vfs_die ("Internal error: smbfs_get_free_bucket");
1206 return 0; /* shut up, stupid gcc */
1209 /* --------------------------------------------------------------------------------------------- */
1210 /* This routine keeps track of open connections */
1211 /* Returns a connected socket to host */
1213 static smbfs_connection *
1214 smbfs_open_link (char *host, char *path, const char *user, int *port, char *this_pass)
1216 int i;
1217 smbfs_connection *bucket;
1218 pstring service;
1219 struct in_addr *dest_ip = NULL;
1221 DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host, path));
1223 if (strcmp (host, path) == 0) /* if host & path are same: */
1224 pstrcpy (service, IPC); /* setup for browse */
1225 else
1226 { /* get share name from path, path starts with server name */
1227 char *p;
1228 if ((p = strchr (path, '/'))) /* get share aka */
1229 pstrcpy (service, ++p); /* service name from path */
1230 else
1231 pstrcpy (service, "");
1232 /* now check for trailing directory/filenames */
1233 p = strchr (service, '/');
1234 if (p)
1235 *p = 0; /* cut off dir/files: sharename only */
1236 if (!*service)
1237 pstrcpy (service, IPC); /* setup for browse */
1238 DEBUG (6, ("smbfs_open_link: service from path:%s\n", service));
1241 if (got_user)
1242 user = username; /* global from getenv */
1244 /* Is the link actually open? */
1245 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1247 if (!smbfs_connections[i].cli)
1248 continue;
1249 if ((strcmp (host, smbfs_connections[i].host) == 0) &&
1250 (strcmp (user, smbfs_connections[i].user) == 0) &&
1251 (strcmp (service, smbfs_connections[i].service) == 0))
1253 int retries = 0;
1254 BOOL inshare = (*host != 0 && *path != 0 && strchr (path, '/'));
1255 /* check if this connection has died */
1256 while (!smbfs_chkpath (smbfs_connections[i].cli, "\\", !inshare))
1258 if (!smbfs_reconnect (&smbfs_connections[i], &retries))
1259 return 0;
1261 DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i));
1262 current_bucket = &smbfs_connections[i];
1263 smbfs_connections[i].last_use = time (NULL);
1264 return &smbfs_connections[i];
1266 /* connection not found, find if we have ip for new connection */
1267 if (strcmp (host, smbfs_connections[i].host) == 0)
1268 dest_ip = &smbfs_connections[i].cli->dest_ip;
1271 /* make new connection */
1272 bucket = smbfs_get_free_bucket ();
1273 bucket->name_type = 0x20;
1274 bucket->home = 0;
1275 bucket->port = *port;
1276 bucket->have_ip = False;
1277 if (dest_ip)
1279 bucket->have_ip = True;
1280 bucket->dest_ip = *dest_ip;
1282 current_bucket = bucket;
1284 bucket->user = g_strdup (user);
1285 bucket->service = g_strdup (service);
1287 if (!(*host))
1288 { /* if blank host name, browse for servers */
1289 if (!smbfs_get_master_browser (&host)) /* set host to ip of master browser */
1290 return 0; /* could not find master browser? */
1291 g_free (host);
1292 bucket->host = g_strdup (""); /* blank host means master browser */
1294 else
1295 bucket->host = g_strdup (host);
1297 if (!smbfs_bucket_set_authinfo (bucket, 0, /* domain currently not used */
1298 user, this_pass, 1))
1299 return 0;
1301 /* connect to share */
1302 while (!(bucket->cli = smbfs_do_connect (host, service)))
1305 if (my_errno != EPERM)
1306 return 0;
1307 message (D_ERROR, MSG_ERROR, _("Authentication failed"));
1309 /* authentication failed, try again */
1310 smbfs_auth_remove (bucket->host, bucket->service);
1311 if (!smbfs_bucket_set_authinfo (bucket, bucket->domain, bucket->user, 0, 0))
1312 return 0;
1316 smbfs_open_connections++;
1317 DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n", smbfs_open_connections));
1318 return bucket;
1321 /* --------------------------------------------------------------------------------------------- */
1323 static char *
1324 smbfs_get_path (smbfs_connection ** sc, const char *path)
1326 char *user, *host, *remote_path, *pass;
1327 int port = SMB_PORT;
1329 DEBUG (3, ("smbfs_get_path(%s)\n", path));
1330 if (strncmp (path, URL_HEADER, HEADER_LEN))
1331 return NULL;
1332 path += HEADER_LEN;
1334 if (*path == '/') /* '/' leading server name */
1335 path++; /* probably came from server browsing */
1337 if ((remote_path = smbfs_get_host_and_username (&path, &host, &user, &port, &pass)))
1338 if ((*sc = smbfs_open_link (host, remote_path, user, &port, pass)) == NULL)
1340 g_free (remote_path);
1341 remote_path = NULL;
1343 g_free (host);
1344 g_free (user);
1345 if (pass)
1346 wipe_password (pass);
1348 if (!remote_path)
1349 return NULL;
1351 /* NOTE: tildes are deprecated. See ftpfs.c */
1353 int f = !strcmp (remote_path, "/~");
1354 if (f || !strncmp (remote_path, "/~/", 3))
1356 char *s;
1357 s = concat_dir_and_file ((*sc)->home, remote_path + 3 - f);
1358 g_free (remote_path);
1359 return s;
1362 return remote_path;
1365 /* --------------------------------------------------------------------------------------------- */
1367 #if 0
1368 static int
1369 is_error (int result, int errno_num)
1371 if (!(result == -1))
1372 return my_errno = 0;
1373 else
1374 my_errno = errno_num;
1375 return 1;
1377 #endif
1379 /* --------------------------------------------------------------------------------------------- */
1381 static void *
1382 smbfs_opendir (struct vfs_class *me, const char *dirname)
1384 opendir_info *smbfs_info;
1385 smbfs_connection *sc;
1386 char *remote_dir;
1388 (void) me;
1390 DEBUG (3, ("smbfs_opendir(dirname:%s)\n", dirname));
1392 if (!(remote_dir = smbfs_get_path (&sc, dirname)))
1393 return NULL;
1395 /* FIXME: where freed? */
1396 smbfs_info = g_new (opendir_info, 1);
1397 smbfs_info->server_list = FALSE;
1398 smbfs_info->path = g_strdup (dirname); /* keep original */
1399 smbfs_info->dirname = remote_dir;
1400 smbfs_info->conn = sc;
1401 smbfs_info->entries = 0;
1402 smbfs_info->current = 0;
1404 return smbfs_info;
1407 /* --------------------------------------------------------------------------------------------- */
1409 static int
1410 smbfs_fake_server_stat (const char *server_url, const char *path, struct stat *buf)
1412 dir_entry *dentry;
1413 const char *p;
1415 (void) server_url;
1417 if ((p = strrchr (path, '/')))
1418 path = p + 1; /* advance until last '/' */
1420 if (!current_info->entries)
1422 if (!smbfs_loaddir (current_info)) /* browse host */
1423 return -1;
1426 if (current_info->server_list == True)
1428 dentry = current_info->entries;
1429 DEBUG (4, ("fake stat for SERVER \"%s\"\n", path));
1430 while (dentry)
1432 if (strcmp (dentry->text, path) == 0)
1434 DEBUG (4, ("smbfs_fake_server_stat: %s:%4o\n",
1435 dentry->text, (int) dentry->my_stat.st_mode));
1436 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1437 return 0;
1439 dentry = dentry->next;
1442 my_errno = ENOENT;
1443 return -1;
1446 /* --------------------------------------------------------------------------------------------- */
1448 static int
1449 smbfs_fake_share_stat (const char *server_url, const char *path, struct stat *buf)
1451 dir_entry *dentry;
1452 if (strlen (path) < strlen (server_url))
1453 return -1;
1455 if (!current_share_info)
1456 { /* Server was not stat()ed */
1457 /* Make sure there is such share at server */
1458 smbfs_connection *sc;
1459 char *p;
1460 p = smbfs_get_path (&sc, path);
1461 g_free (p);
1462 if (p)
1464 memset (buf, 0, sizeof (*buf));
1465 /* show this as dir */
1466 buf->st_mode =
1467 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
1468 return 0;
1470 return -1;
1473 path += strlen (server_url); /* we only want share name */
1474 path++;
1476 if (*path == '/') /* '/' leading server name */
1477 path++; /* probably came from server browsing */
1479 if (!current_share_info->entries)
1481 if (!smbfs_loaddir (current_share_info)) /* browse host */
1482 return -1;
1484 dentry = current_share_info->entries;
1485 DEBUG (3, ("smbfs_fake_share_stat: %s on %s\n", path, server_url));
1486 while (dentry)
1488 if (strcmp (dentry->text, path) == 0)
1490 DEBUG (6, ("smbfs_fake_share_stat: %s:%4o\n",
1491 dentry->text, (int) dentry->my_stat.st_mode));
1492 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1493 return 0;
1495 dentry = dentry->next;
1497 my_errno = ENOENT;
1498 return -1;
1501 /* --------------------------------------------------------------------------------------------- */
1502 /* stat a single file */
1504 static int
1505 smbfs_get_remote_stat (smbfs_connection * sc, const char *path, struct stat *buf)
1507 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
1508 char *mypath;
1510 DEBUG (3, ("smbfs_get_remote_stat(): mypath:%s\n", path));
1512 mypath = smbfs_convert_path (path, FALSE);
1514 #if 0 /* single_entry is never free()d now. And only my_stat is used */
1515 single_entry = g_new (dir_entry, 1);
1517 single_entry->text = dos_to_unix (g_strdup (finfo->name), 1);
1519 single_entry->next = 0;
1520 #endif
1521 if (!single_entry)
1522 single_entry = g_new0 (dir_entry, 1);
1524 if (cli_list (sc->cli, mypath, attribute, smbfs_loaddir_helper, single_entry) < 1)
1526 my_errno = ENOENT;
1527 g_free (mypath);
1528 return -1; /* cli_list returns number of files */
1531 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
1533 /* don't free here, use for smbfs_fstat() */
1534 /* g_free(single_entry->text);
1535 g_free(single_entry); */
1536 g_free (mypath);
1537 return 0;
1540 /* --------------------------------------------------------------------------------------------- */
1542 static int
1543 smbfs_search_dir_entry (dir_entry * dentry, const char *text, struct stat *buf)
1545 while (dentry)
1547 if (strcmp (text, dentry->text) == 0)
1549 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1550 memcpy (&single_entry->my_stat, &dentry->my_stat, sizeof (struct stat));
1551 return 0;
1553 dentry = dentry->next;
1555 return -1;
1558 /* --------------------------------------------------------------------------------------------- */
1560 static int
1561 smbfs_get_stat_info (smbfs_connection * sc, const char *path, struct stat *buf)
1563 char *p;
1564 #if 0
1565 dir_entry *dentry = current_info->entries;
1566 #endif
1567 const char *mypath = path;
1569 mypath++; /* cut off leading '/' */
1570 if ((p = strrchr (mypath, '/')))
1571 mypath = p + 1; /* advance until last file/dir name */
1572 DEBUG (3, ("smbfs_get_stat_info: mypath:%s, current_info->dirname:%s\n",
1573 mypath, current_info->dirname));
1574 #if 0
1575 if (!dentry)
1577 DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1578 current_info->dirname, path));
1579 return -1;
1581 #endif
1582 if (!single_entry) /* when found, this will be written too */
1583 single_entry = g_new (dir_entry, 1);
1584 if (smbfs_search_dir_entry (current_info->entries, mypath, buf) == 0)
1586 return 0;
1588 /* now try to identify mypath as PARENT dir */
1590 char *mdp;
1591 char *mydir;
1592 mdp = mydir = g_strdup (current_info->dirname);
1593 if ((p = strrchr (mydir, '/')))
1594 *p = 0; /* advance util last '/' */
1595 if ((p = strrchr (mydir, '/')))
1596 mydir = p + 1; /* advance util last '/' */
1597 if (strcmp (mydir, mypath) == 0)
1598 { /* fake a stat for ".." */
1599 memset (buf, 0, sizeof (struct stat));
1600 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1601 memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1602 g_free (mdp);
1603 DEBUG (1, (" PARENT:found in %s\n", current_info->dirname));
1604 return 0;
1606 g_free (mdp);
1608 /* now try to identify as CURRENT dir? */
1610 char *dnp = current_info->dirname;
1611 DEBUG (6, ("smbfs_get_stat_info: is %s current dir? this dir is: %s\n",
1612 mypath, current_info->dirname));
1613 if (*dnp == '/')
1614 dnp++;
1615 else
1617 return -1;
1619 if (strcmp (mypath, dnp) == 0)
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 DEBUG (1, (" CURRENT:found in %s\n", current_info->dirname));
1625 return 0;
1628 DEBUG (3, ("'%s' not found in current_info '%s'\n", path, current_info->dirname));
1629 /* try to find this in the PREVIOUS listing */
1630 if (previous_info)
1632 if (smbfs_search_dir_entry (previous_info->entries, mypath, buf) == 0)
1633 return 0;
1634 DEBUG (3, ("'%s' not found in previous_info '%s'\n", path, previous_info->dirname));
1636 /* try to find this in the SHARE listing */
1637 if (current_share_info)
1639 if (smbfs_search_dir_entry (current_share_info->entries, mypath, buf) == 0)
1640 return 0;
1641 DEBUG (3, ("'%s' not found in share_info '%s'\n", path, current_share_info->dirname));
1643 /* try to find this in the SERVER listing */
1644 if (current_server_info)
1646 if (smbfs_search_dir_entry (current_server_info->entries, mypath, buf) == 0)
1647 return 0;
1648 DEBUG (3, ("'%s' not found in server_info '%s'\n", path, current_server_info->dirname));
1650 /* nothing found. get stat file info from server */
1651 return smbfs_get_remote_stat (sc, path, buf);
1654 /* --------------------------------------------------------------------------------------------- */
1656 static int
1657 smbfs_chdir (struct vfs_class *me, const char *path)
1659 char *remote_dir;
1660 smbfs_connection *sc;
1662 (void) me;
1664 DEBUG (3, ("smbfs_chdir(path:%s)\n", path));
1665 if (!(remote_dir = smbfs_get_path (&sc, path)))
1666 return -1;
1667 g_free (remote_dir);
1669 return 0;
1672 /* --------------------------------------------------------------------------------------------- */
1674 static int
1675 smbfs_loaddir_by_name (struct vfs_class *me, const char *path)
1677 void *info;
1678 char *mypath, *p;
1680 mypath = g_strdup (path);
1681 p = strrchr (mypath, '/');
1683 if (p > mypath)
1684 *p = 0;
1685 DEBUG (6, ("smbfs_loaddir_by_name(%s)\n", mypath));
1686 smbfs_chdir (me, mypath);
1687 info = smbfs_opendir (me, mypath);
1688 g_free (mypath);
1689 if (!info)
1690 return -1;
1691 smbfs_readdir (info);
1692 smbfs_loaddir (info);
1693 return 0;
1696 /* --------------------------------------------------------------------------------------------- */
1698 static int
1699 smbfs_stat (struct vfs_class *me, const char *path, struct stat *buf)
1701 smbfs_connection *sc;
1702 pstring server_url;
1703 char *service, *pp, *at;
1704 const char *p;
1706 DEBUG (3, ("smbfs_stat(path:%s)\n", path));
1708 if (!current_info)
1710 DEBUG (1, ("current_info = NULL: "));
1711 if (smbfs_loaddir_by_name (me, path) < 0)
1712 return -1;
1715 /* check if stating server */
1716 p = path;
1717 if (strncmp (p, URL_HEADER, HEADER_LEN))
1719 DEBUG (1, ("'%s' doesnt start with '%s' (length %d)\n", p, URL_HEADER, HEADER_LEN));
1720 return -1;
1723 p += HEADER_LEN;
1724 if (*p == '/')
1725 p++;
1727 pp = strchr (p, '/'); /* advance past next '/' */
1728 at = strchr (p, '@');
1729 pstrcpy (server_url, URL_HEADER);
1730 if (at && at < pp)
1731 { /* user@server */
1732 char *z = &(server_url[sizeof (server_url) - 1]);
1733 const char *s = p;
1735 at = &(server_url[HEADER_LEN]) + (at - p + 1);
1736 if (z > at)
1737 z = at;
1738 at = &(server_url[HEADER_LEN]);
1739 while (at < z)
1740 *at++ = *s++;
1741 *z = 0;
1743 pstrcat (server_url, current_bucket->host);
1745 if (!pp)
1747 if (!current_info->server_list)
1749 if (smbfs_loaddir_by_name (me, path) < 0)
1750 return -1;
1752 return smbfs_fake_server_stat (server_url, path, buf);
1755 if (!strchr (++pp, '/'))
1757 return smbfs_fake_share_stat (server_url, path, buf);
1760 /* stating inside share at this point */
1761 if (!(service = smbfs_get_path (&sc, path))) /* connects if necessary */
1762 return -1;
1764 int hostlen = strlen (current_bucket->host);
1765 char *ppp = service + strlen (service) - hostlen;
1766 char *sp = server_url + strlen (server_url) - hostlen;
1768 if (strcmp (sp, ppp) == 0)
1770 /* make server name appear as directory */
1771 DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1772 memset (buf, 0, sizeof (struct stat));
1773 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1774 g_free (service);
1775 return 0;
1778 /* check if current_info is in share requested */
1779 p = service;
1780 pp = strchr (p, '/');
1781 if (pp)
1783 p = ++pp; /* advance past server name */
1784 pp = strchr (p, '/');
1786 if (pp)
1787 *pp = 0; /* cut off everthing after service name */
1788 else
1789 p = IPC; /* browsing for services */
1790 pp = current_info->dirname;
1791 if (*pp == '/')
1792 pp++;
1793 if (strncmp (p, pp, strlen (p)) != 0)
1795 DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p, pp));
1796 if (smbfs_loaddir_by_name (me, path) < 0)
1798 g_free (service);
1799 return -1;
1801 DEBUG (6, ("loaded dir: '%s'\n", current_info->dirname));
1803 g_free (service);
1804 /* stat dirs & files under shares now */
1805 return smbfs_get_stat_info (sc, path, buf);
1808 /* --------------------------------------------------------------------------------------------- */
1810 static off_t
1811 smbfs_lseek (void *data, off_t offset, int whence)
1813 smbfs_handle *info = (smbfs_handle *) data;
1814 size_t size;
1816 DEBUG (3,
1817 ("smbfs_lseek(info->nread => %d, offset => %d, whence => %d) \n",
1818 (int) info->nread, (int) offset, whence));
1820 switch (whence)
1822 case SEEK_SET:
1823 info->nread = offset;
1824 break;
1825 case SEEK_CUR:
1826 info->nread += offset;
1827 break;
1828 case SEEK_END:
1829 if (!cli_qfileinfo (info->cli, info->fnum,
1830 NULL, &size, NULL, NULL, NULL,
1831 NULL, NULL) &&
1832 !cli_getattrE (info->cli, info->fnum, NULL, &size, NULL, NULL, NULL))
1834 errno = EINVAL;
1835 return -1;
1837 info->nread = size + offset;
1838 break;
1841 return info->nread;
1844 /* --------------------------------------------------------------------------------------------- */
1846 static int
1847 smbfs_mknod (struct vfs_class *me, const char *path, mode_t mode, dev_t dev)
1849 (void) me;
1851 DEBUG (3, ("smbfs_mknod(path:%s, mode:%d, dev:%u)\n", path, mode, (unsigned int) dev));
1852 my_errno = EOPNOTSUPP;
1853 return -1;
1856 /* --------------------------------------------------------------------------------------------- */
1858 static int
1859 smbfs_mkdir (struct vfs_class *me, const char *path, mode_t mode)
1861 smbfs_connection *sc;
1862 char *remote_file;
1863 char *cpath;
1865 (void) me;
1867 DEBUG (3, ("smbfs_mkdir(path:%s, mode:%d)\n", path, (int) mode));
1868 if ((remote_file = smbfs_get_path (&sc, path)) == 0)
1869 return -1;
1870 g_free (remote_file);
1871 cpath = smbfs_convert_path (path, FALSE);
1873 if (!cli_mkdir (sc->cli, cpath))
1875 my_errno = cli_error (sc->cli, NULL, &err, NULL);
1876 message (D_ERROR, MSG_ERROR, _("Error %s creating directory %s"),
1877 cli_errstr (sc->cli), CNV_LANG (cpath));
1878 g_free (cpath);
1879 return -1;
1881 g_free (cpath);
1882 return 0;
1885 /* --------------------------------------------------------------------------------------------- */
1887 static int
1888 smbfs_rmdir (struct vfs_class *me, const char *path)
1890 smbfs_connection *sc;
1891 char *remote_file;
1892 char *cpath;
1894 (void) me;
1896 DEBUG (3, ("smbfs_rmdir(path:%s)\n", path));
1897 if ((remote_file = smbfs_get_path (&sc, path)) == 0)
1898 return -1;
1899 g_free (remote_file);
1900 cpath = smbfs_convert_path (path, FALSE);
1902 if (!cli_rmdir (sc->cli, cpath))
1904 my_errno = cli_error (sc->cli, NULL, &err, NULL);
1905 message (D_ERROR, MSG_ERROR, _("Error %s removing directory %s"),
1906 cli_errstr (sc->cli), CNV_LANG (cpath));
1907 g_free (cpath);
1908 return -1;
1911 g_free (cpath);
1912 return 0;
1915 /* --------------------------------------------------------------------------------------------- */
1917 static int
1918 smbfs_link (struct vfs_class *me, const char *p1, const char *p2)
1920 (void) me;
1922 DEBUG (3, ("smbfs_link(p1:%s, p2:%s)\n", p1, p2));
1923 my_errno = EOPNOTSUPP;
1924 return -1;
1927 /* --------------------------------------------------------------------------------------------- */
1929 static void
1930 smbfs_free (vfsid id)
1932 DEBUG (3, ("smbfs_free(%p)\n", id));
1933 smbfs_auth_free_all ();
1936 /* --------------------------------------------------------------------------------------------- */
1937 /* Gives up on a socket and reopens the connection, the child own the socket
1938 * now
1941 static void
1942 smbfs_forget (const char *path)
1944 char *host, *user, *p;
1945 int port;
1947 if (strncmp (path, URL_HEADER, HEADER_LEN))
1948 return;
1950 DEBUG (3, ("smbfs_forget(path:%s)\n", path));
1952 path += 6;
1953 if (path[0] == '/' && path[1] == '/')
1954 path += 2;
1956 if ((p = smbfs_get_host_and_username (&path, &host, &user, &port, NULL)))
1958 size_t i;
1960 g_free (p);
1962 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1964 if (smbfs_connections[i].cli
1965 && (strcmp (host, smbfs_connections[i].host) == 0)
1966 && (strcmp (user, smbfs_connections[i].user) == 0)
1967 && (port == smbfs_connections[i].port))
1970 /* close socket: the child owns it now */
1971 cli_shutdown (smbfs_connections[i].cli);
1973 /* reopen the connection */
1974 smbfs_connections[i].cli = smbfs_do_connect (host, smbfs_connections[i].service);
1978 g_free (host);
1979 g_free (user);
1982 /* --------------------------------------------------------------------------------------------- */
1984 static int
1985 smbfs_setctl (struct vfs_class *me, const char *path, int ctlop, void *arg)
1987 (void) me;
1988 (void) arg;
1990 DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path, ctlop));
1991 switch (ctlop)
1993 case VFS_SETCTL_FORGET:
1994 smbfs_forget (path);
1995 break;
1996 case VFS_SETCTL_LOGFILE:
1997 smbfs_set_debugf ((const char *) arg);
1998 break;
2000 return 0;
2003 /* --------------------------------------------------------------------------------------------- */
2005 static smbfs_handle *
2006 smbfs_open_readwrite (smbfs_handle * remote_handle, char *rname, int flags, mode_t mode)
2008 size_t size;
2010 (void) mode;
2012 if (flags & O_TRUNC) /* if it exists truncate to zero */
2013 DEBUG (3, ("smbfs_open: O_TRUNC\n"));
2015 remote_handle->fnum =
2016 #if 1 /* Don't play with flags, it is cli_open() headache */
2017 cli_open (remote_handle->cli, rname, flags, DENY_NONE);
2018 #else /* What's a reasons to has this code ? */
2019 cli_open (remote_handle->cli, rname, ((flags & O_CREAT)
2020 || (flags ==
2021 (O_WRONLY | O_APPEND))) ?
2022 flags : O_RDONLY, DENY_NONE);
2023 #endif
2024 if (remote_handle->fnum == -1)
2026 message (D_ERROR, MSG_ERROR, _("%s opening remote file %s"),
2027 cli_errstr (remote_handle->cli), CNV_LANG (rname));
2028 DEBUG (1, ("smbfs_open(rname:%s) error:%s\n", rname, cli_errstr (remote_handle->cli)));
2029 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2030 return NULL;
2033 if (flags & O_CREAT)
2034 return remote_handle;
2036 if (!cli_qfileinfo (remote_handle->cli, remote_handle->fnum,
2037 &remote_handle->attr, &size, NULL, NULL, NULL, NULL,
2038 NULL)
2039 && !cli_getattrE (remote_handle->cli, remote_handle->fnum,
2040 &remote_handle->attr, &size, NULL, NULL, NULL))
2042 message (D_ERROR, MSG_ERROR, "getattrib: %s", cli_errstr (remote_handle->cli));
2043 DEBUG (1, ("smbfs_open(rname:%s) getattrib:%s\n", rname, cli_errstr (remote_handle->cli)));
2044 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2045 cli_close (remote_handle->cli, remote_handle->fnum);
2046 return NULL;
2049 if ((flags == (O_WRONLY | O_APPEND)) /* file.c:copy_file_file() -> do_append */
2050 && smbfs_lseek (remote_handle, 0, SEEK_END) == -1)
2052 cli_close (remote_handle->cli, remote_handle->fnum);
2053 return NULL;
2056 return remote_handle;
2059 /* --------------------------------------------------------------------------------------------- */
2061 static void *
2062 smbfs_open (struct vfs_class *me, const char *file, int flags, mode_t mode)
2064 char *remote_file;
2065 void *ret;
2066 smbfs_connection *sc;
2067 smbfs_handle *remote_handle;
2069 (void) me;
2071 DEBUG (3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", file, flags, mode));
2073 if (!(remote_file = smbfs_get_path (&sc, file)))
2074 return 0;
2076 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2078 remote_handle = g_new (smbfs_handle, 2);
2079 remote_handle->cli = sc->cli;
2080 remote_handle->nread = 0;
2082 ret = smbfs_open_readwrite (remote_handle, remote_file, flags, mode);
2084 g_free (remote_file);
2085 if (!ret)
2086 g_free (remote_handle);
2088 return ret;
2091 /* --------------------------------------------------------------------------------------------- */
2093 static int
2094 smbfs_unlink (struct vfs_class *me, const char *path)
2096 smbfs_connection *sc;
2097 char *remote_file;
2099 (void) me;
2101 if ((remote_file = smbfs_get_path (&sc, path)) == 0)
2102 return -1;
2104 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2106 if (!cli_unlink (sc->cli, remote_file))
2108 message (D_ERROR, MSG_ERROR, _("%s removing remote file %s"),
2109 cli_errstr (sc->cli), CNV_LANG (remote_file));
2110 g_free (remote_file);
2111 return -1;
2113 g_free (remote_file);
2114 return 0;
2117 /* --------------------------------------------------------------------------------------------- */
2119 static int
2120 smbfs_rename (struct vfs_class *me, const char *a, const char *b)
2122 smbfs_connection *sc;
2123 char *ra, *rb;
2124 int retval;
2126 (void) me;
2128 if ((ra = smbfs_get_path (&sc, a)) == 0)
2129 return -1;
2131 if ((rb = smbfs_get_path (&sc, b)) == 0)
2133 g_free (ra);
2134 return -1;
2137 ra = free_after (smbfs_convert_path (ra, FALSE), ra);
2138 rb = free_after (smbfs_convert_path (rb, FALSE), rb);
2140 retval = cli_rename (sc->cli, ra, rb);
2142 g_free (ra);
2143 g_free (rb);
2145 if (!retval)
2147 message (D_ERROR, MSG_ERROR, _("%s renaming files\n"), cli_errstr (sc->cli));
2148 return -1;
2150 return 0;
2153 /* --------------------------------------------------------------------------------------------- */
2155 static int
2156 smbfs_fstat (void *data, struct stat *buf)
2158 smbfs_handle *remote_handle = (smbfs_handle *) data;
2160 DEBUG (3, ("smbfs_fstat(fnum:%d)\n", remote_handle->fnum));
2162 /* use left over from previous smbfs_get_remote_stat, if available */
2163 if (single_entry)
2164 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
2165 else
2166 { /* single_entry not set up: bug */
2167 my_errno = EFAULT;
2168 return -EFAULT;
2170 return 0;
2173 /* --------------------------------------------------------------------------------------------- */
2174 /*** public functions ****************************************************************************/
2175 /* --------------------------------------------------------------------------------------------- */
2177 smb_authinfo *
2178 vfs_smb_authinfo_new (const char *host, const char *share, const char *domain,
2179 const char *user, const char *pass)
2181 smb_authinfo *auth;
2183 auth = g_try_new (struct smb_authinfo, 1);
2185 if (auth != NULL)
2187 auth->host = g_strdup (host);
2188 auth->share = g_strdup (share);
2189 auth->domain = g_strdup (domain);
2190 auth->user = g_strdup (user);
2191 auth->password = g_strdup (pass);
2194 return auth;
2197 /* --------------------------------------------------------------------------------------------- */
2199 void
2200 init_smbfs (void)
2202 tcp_init ();
2204 vfs_smbfs_ops.name = "smbfs";
2205 vfs_smbfs_ops.prefix = "smb:";
2206 vfs_smbfs_ops.flags = VFSF_NOLINKS;
2207 vfs_smbfs_ops.init = smbfs_init;
2208 vfs_smbfs_ops.fill_names = smbfs_fill_names;
2209 vfs_smbfs_ops.open = smbfs_open;
2210 vfs_smbfs_ops.close = smbfs_close;
2211 vfs_smbfs_ops.read = smbfs_read;
2212 vfs_smbfs_ops.write = smbfs_write;
2213 vfs_smbfs_ops.opendir = smbfs_opendir;
2214 vfs_smbfs_ops.readdir = smbfs_readdir;
2215 vfs_smbfs_ops.closedir = smbfs_closedir;
2216 vfs_smbfs_ops.stat = smbfs_stat;
2217 vfs_smbfs_ops.lstat = smbfs_lstat;
2218 vfs_smbfs_ops.fstat = smbfs_fstat;
2219 vfs_smbfs_ops.chmod = smbfs_chmod;
2220 vfs_smbfs_ops.chown = smbfs_chown;
2221 vfs_smbfs_ops.utime = smbfs_utime;
2222 vfs_smbfs_ops.readlink = smbfs_readlink;
2223 vfs_smbfs_ops.symlink = smbfs_symlink;
2224 vfs_smbfs_ops.link = smbfs_link;
2225 vfs_smbfs_ops.unlink = smbfs_unlink;
2226 vfs_smbfs_ops.rename = smbfs_rename;
2227 vfs_smbfs_ops.chdir = smbfs_chdir;
2228 vfs_smbfs_ops.ferrno = smbfs_errno;
2229 vfs_smbfs_ops.lseek = smbfs_lseek;
2230 vfs_smbfs_ops.mknod = smbfs_mknod;
2231 vfs_smbfs_ops.free = smbfs_free;
2232 vfs_smbfs_ops.mkdir = smbfs_mkdir;
2233 vfs_smbfs_ops.rmdir = smbfs_rmdir;
2234 vfs_smbfs_ops.setctl = smbfs_setctl;
2235 vfs_register_class (&vfs_smbfs_ops);
2238 /* --------------------------------------------------------------------------------------------- */