Following prototypes of functions was changed in VFS-module API:
[midnight-commander.git] / src / vfs / smbfs / smbfs.c
blob15c07264bb8d9a0d242239cecdbd610e8db939c2
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(), smbfs_set_debugf()
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 "helpers/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 "helpers/include/includes.h"
63 #include "lib/vfs/vfs.h"
64 #include "lib/vfs/netutil.h"
65 #include "lib/vfs/utilvfs.h"
67 #include "smbfs.h"
69 /*** global variables ****************************************************************************/
71 extern int DEBUGLEVEL;
72 extern pstring myhostname;
73 extern struct in_addr ipzero;
74 extern pstring global_myname;
75 extern pstring debugf;
76 extern FILE *dbf;
78 /*** file scope macro definitions ****************************************************************/
80 #define SMBFS_MAX_CONNECTIONS 16
82 #define HEADER_LEN 6
84 #define CNV_LANG(s) dos_to_unix(s,False)
85 #define GNAL_VNC(s) unix_to_dos(s,False)
87 #define smbfs_lstat smbfs_stat /* no symlinks on smb filesystem? */
89 /*** file scope type declarations ****************************************************************/
91 typedef struct _smbfs_connection smbfs_connection;
93 typedef struct
95 struct cli_state *cli;
96 int fnum;
97 off_t nread;
98 uint16 attr;
99 } smbfs_handle;
101 typedef struct dir_entry
103 char *text;
104 struct dir_entry *next;
105 struct stat my_stat;
106 int merrno;
107 } dir_entry;
109 typedef struct
111 gboolean server_list;
112 char *dirname;
113 char *path; /* the dir originally passed to smbfs_opendir */
114 smbfs_connection *conn;
115 dir_entry *entries;
116 dir_entry *current;
117 } opendir_info;
119 /*** file scope variables ************************************************************************/
121 static const char *const IPC = "IPC$";
122 static const char *const URL_HEADER = "/#smb:";
124 static int my_errno;
125 static uint32 err;
127 /* stuff that is same with each connection */
129 static mode_t myumask = 0755;
130 static int smbfs_open_connections = 0;
131 static gboolean got_user = FALSE;
132 static gboolean got_pass = FALSE;
133 static pstring password;
134 static pstring username;
135 static struct vfs_class vfs_smbfs_ops;
137 static struct _smbfs_connection
139 struct cli_state *cli;
140 struct in_addr dest_ip;
141 BOOL have_ip;
142 char *host; /* server name */
143 char *service; /* share name */
144 char *domain;
145 char *user;
146 char *home;
147 char *password;
148 int port;
149 int name_type;
150 time_t last_use;
151 } smbfs_connections[SMBFS_MAX_CONNECTIONS];
152 /* unique to each connection */
154 static smbfs_connection *current_bucket;
156 static GSList *auth_list;
158 static opendir_info *previous_info, *current_info, *current_share_info, *current_server_info;
160 static gboolean first_direntry;
162 /* stat a single file, smbfs_get_remote_stat callback */
163 static dir_entry *single_entry;
165 /*** file scope functions ************************************************************************/
166 /* --------------------------------------------------------------------------------------------- */
168 /* modifies *share */
169 static struct cli_state *smbfs_do_connect (const char *server, char *share);
171 /* --------------------------------------------------------------------------------------------- */
172 /* this function allows you to write:
173 * char *s = g_strdup("hello, world");
174 * s = free_after(g_strconcat(s, s, (char *)0), s);
177 static inline char *
178 free_after (char *result, char *string_to_free)
180 g_free (string_to_free);
181 return result;
184 /* --------------------------------------------------------------------------------------------- */
186 static void
187 smbfs_auth_free (struct smb_authinfo const *a)
189 g_free (a->host);
190 g_free (a->share);
191 g_free (a->domain);
192 g_free (a->user);
193 wipe_password (a->password);
196 /* --------------------------------------------------------------------------------------------- */
198 static void
199 smbfs_auth_free_all (void)
201 if (auth_list)
203 g_slist_foreach (auth_list, (GFunc) smbfs_auth_free, 0);
204 g_slist_free (auth_list);
205 auth_list = 0;
209 /* --------------------------------------------------------------------------------------------- */
211 static gint
212 smbfs_auth_cmp_host_and_share (gconstpointer _a, gconstpointer _b)
214 struct smb_authinfo const *a = (struct smb_authinfo const *) _a;
215 struct smb_authinfo const *b = (struct smb_authinfo const *) _b;
217 if (!a->host || !a->share || !b->host || !b->share)
218 return 1;
219 if (strcmp (a->host, b->host) != 0)
220 return 1;
221 if (strcmp (a->share, b->share) != 0)
222 return 1;
223 return 0;
226 /* --------------------------------------------------------------------------------------------- */
228 static gint
229 smbfs_auth_cmp_host (gconstpointer _a, gconstpointer _b)
231 struct smb_authinfo const *a = (struct smb_authinfo const *) _a;
232 struct smb_authinfo const *b = (struct smb_authinfo const *) _b;
234 if (!a->host || !b->host)
235 return 1;
236 if (strcmp (a->host, b->host) != 0)
237 return 1;
238 if (strcmp (a->share, IPC) != 0)
239 return 1;
240 return 0;
243 /* --------------------------------------------------------------------------------------------- */
245 static void
246 smbfs_auth_add (const char *host, const char *share, const char *domain,
247 const char *user, const char *pass)
249 struct smb_authinfo *auth;
251 auth = vfs_smb_authinfo_new (host, share, domain, user, pass);
253 if (auth != NULL)
254 auth_list = g_slist_prepend (auth_list, auth);
257 /* --------------------------------------------------------------------------------------------- */
259 static void
260 smbfs_auth_remove (const char *host, const char *share)
262 struct smb_authinfo data;
263 struct smb_authinfo *auth;
264 GSList *list;
266 data.host = g_strdup (host);
267 data.share = g_strdup (share);
268 list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host_and_share);
269 g_free (data.host);
270 g_free (data.share);
271 if (!list)
272 return;
273 auth = list->data;
274 auth_list = g_slist_remove (auth_list, auth);
275 smbfs_auth_free (auth);
278 /* --------------------------------------------------------------------------------------------- */
279 /* Set authentication information in bucket. Return 1 if successful, else 0 */
280 /* Information in auth_list overrides user if pass is NULL. */
281 /* bucket->host and bucket->service must be valid. */
283 static int
284 smbfs_bucket_set_authinfo (smbfs_connection * bucket,
285 const char *domain, const char *user, const char *pass,
286 int fallback_to_host)
288 struct smb_authinfo data;
289 struct smb_authinfo *auth;
290 GSList *list;
292 if (domain && user && pass)
294 g_free (bucket->domain);
295 g_free (bucket->user);
296 g_free (bucket->password);
297 bucket->domain = g_strdup (domain);
298 bucket->user = g_strdup (user);
299 bucket->password = g_strdup (pass);
300 smbfs_auth_remove (bucket->host, bucket->service);
301 smbfs_auth_add (bucket->host, bucket->service, domain, user, pass);
302 return 1;
305 data.host = bucket->host;
306 data.share = bucket->service;
307 list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host_and_share);
308 if (!list && fallback_to_host)
309 list = g_slist_find_custom (auth_list, &data, smbfs_auth_cmp_host);
310 if (list)
312 auth = list->data;
313 bucket->domain = g_strdup (auth->domain);
314 bucket->user = g_strdup (auth->user);
315 bucket->password = g_strdup (auth->password);
316 return 1;
319 if (got_pass)
321 bucket->domain = g_strdup (lp_workgroup ());
322 bucket->user = g_strdup (got_user ? username : user);
323 bucket->password = g_strdup (password);
324 return 1;
327 auth = vfs_smb_get_authinfo (bucket->host,
328 bucket->service, (domain ? domain : lp_workgroup ()), user);
329 if (auth)
331 g_free (bucket->domain);
332 g_free (bucket->user);
333 g_free (bucket->password);
334 bucket->domain = g_strdup (auth->domain);
335 bucket->user = g_strdup (auth->user);
336 bucket->password = g_strdup (auth->password);
337 smbfs_auth_remove (bucket->host, bucket->service);
338 auth_list = g_slist_prepend (auth_list, auth);
339 return 1;
341 return 0;
344 /* --------------------------------------------------------------------------------------------- */
346 void
347 smbfs_set_debug (int arg)
349 DEBUGLEVEL = arg;
352 /* --------------------------------------------------------------------------------------------- */
354 void
355 smbfs_set_debugf (const char *filename)
357 if (DEBUGLEVEL > 0)
359 FILE *outfile = fopen (filename, "w");
360 if (outfile)
362 setup_logging ("", True); /* No needs for timestamp for each message */
363 dbf = outfile;
364 setbuf (dbf, NULL);
365 pstrcpy (debugf, filename);
370 /* --------------------------------------------------------------------------------------------- */
371 /********************** The callbacks ******************************/
373 static int
374 smbfs_init (struct vfs_class *me)
376 const char *servicesf = CONFIGDIR PATH_SEP_STR "smb.conf";
378 /* DEBUGLEVEL = 4; */
380 TimeInit ();
381 charset_initialise ();
383 DEBUG (3, ("smbfs_init(%s)\n", me->name));
385 if (!get_myname (myhostname, NULL))
386 DEBUG (0, ("Failed to get my hostname.\n"));
388 if (!lp_load (servicesf, True, False, False))
389 DEBUG (0, ("Cannot load %s - run testparm to debug it\n", servicesf));
391 codepage_initialise (lp_client_code_page ());
393 load_interfaces ();
395 myumask = umask (0);
396 umask (myumask);
397 myumask = ~myumask;
399 if (getenv ("USER"))
401 char *p;
403 pstrcpy (username, getenv ("USER"));
404 got_user = TRUE;
405 DEBUG (3, ("smbfs_init(): $USER:%s\n", username));
406 if ((p = strchr (username, '%')))
408 *p = 0;
409 pstrcpy (password, p + 1);
410 got_pass = TRUE;
411 memset (strchr (getenv ("USER"), '%') + 1, 'X', strlen (password));
412 DEBUG (3, ("smbfs_init(): $USER%%pass: %s%%%s\n", username, password));
414 strupper (username);
416 if (getenv ("PASSWD"))
418 pstrcpy (password, getenv ("PASSWD"));
419 got_pass = TRUE;
421 return 1;
424 /* --------------------------------------------------------------------------------------------- */
426 static void
427 smbfs_fill_names (struct vfs_class *me, fill_names_f func)
429 size_t i;
430 char *path;
432 (void) me;
434 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
436 if (smbfs_connections[i].cli)
438 path = g_strconcat (URL_HEADER,
439 smbfs_connections[i].user, "@",
440 smbfs_connections[i].host,
441 "/", smbfs_connections[i].service, (char *) NULL);
442 (*func) (path);
443 g_free (path);
448 /* --------------------------------------------------------------------------------------------- */
449 /* does same as do_get() in client.c */
450 /* called from vfs.c:1080, count = buffer size */
452 static ssize_t
453 smbfs_read (void *data, char *buffer, size_t count)
455 smbfs_handle *info = (smbfs_handle *) data;
456 ssize_t n;
458 DEBUG (3, ("smbfs_read(fnum:%d, nread:%d, count:%zu)\n", info->fnum, (int) info->nread, count));
459 n = cli_read (info->cli, info->fnum, buffer, info->nread, count);
460 if (n > 0)
461 info->nread += n;
462 return n;
465 /* --------------------------------------------------------------------------------------------- */
467 static ssize_t
468 smbfs_write (void *data, const char *buf, size_t nbyte)
470 smbfs_handle *info = (smbfs_handle *) data;
471 ssize_t n;
473 DEBUG (3, ("smbfs_write(fnum:%d, nread:%d, nbyte:%zu)\n",
474 info->fnum, (int) info->nread, nbyte));
475 n = cli_write (info->cli, info->fnum, 0, buf, info->nread, nbyte);
476 if (n > 0)
477 info->nread += n;
478 return n;
481 /* --------------------------------------------------------------------------------------------- */
483 static int
484 smbfs_close (void *data)
486 smbfs_handle *info = (smbfs_handle *) data;
487 DEBUG (3, ("smbfs_close(fnum:%d)\n", info->fnum));
489 /* FIXME: Why too different cli have the same outbuf
490 * if file is copied to share
492 if (info->cli->outbuf == NULL)
494 my_errno = EINVAL;
495 return -1;
497 #if 0
498 /* if imlementing archive_level: add rname to smbfs_handle */
499 if (archive_level >= 2 && (inf->attr & aARCH))
501 cli_setatr (info->cli, rname, info->attr & ~(uint16) aARCH, 0);
503 #endif
504 return (cli_close (info->cli, info->fnum) == True) ? 0 : -1;
507 /* --------------------------------------------------------------------------------------------- */
509 static int
510 smbfs_errno (struct vfs_class *me)
512 (void) me;
514 DEBUG (3, ("smbfs_errno: %s\n", unix_error_string (my_errno)));
515 return my_errno;
518 /* --------------------------------------------------------------------------------------------- */
520 static dir_entry *
521 smbfs_new_dir_entry (const char *name)
523 static int inode_counter;
524 dir_entry *new_entry;
525 new_entry = g_new0 (dir_entry, 1);
526 new_entry->text = dos_to_unix (g_strdup (name), 1);
528 if (first_direntry)
530 current_info->entries = new_entry;
531 first_direntry = FALSE;
533 else
535 current_info->current->next = new_entry;
537 current_info->current = new_entry;
538 new_entry->my_stat.st_ino = inode_counter++;
540 return new_entry;
543 /* --------------------------------------------------------------------------------------------- */
544 /* browse for shares on server */
546 static void
547 smbfs_browsing_helper (const char *name, uint32 type, const char *comment, void *state)
549 const char *typestr = "";
550 dir_entry *new_entry = smbfs_new_dir_entry (name);
552 (void) state;
554 switch (type)
556 case STYPE_DISKTREE:
557 typestr = "Disk";
558 /* show this as dir */
559 new_entry->my_stat.st_mode =
560 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
561 break;
562 case STYPE_PRINTQ:
563 typestr = "Printer";
564 break;
565 case STYPE_DEVICE:
566 typestr = "Device";
567 break;
568 case STYPE_IPC:
569 typestr = "IPC";
570 break;
572 DEBUG (3, ("\t%-15.15s%-10.10s%s\n", name, typestr, comment));
575 /* --------------------------------------------------------------------------------------------- */
577 static void
578 smbfs_loaddir_helper (file_info * finfo, const char *mask, void *entry)
580 dir_entry *new_entry = (dir_entry *) entry;
581 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
583 (void) mask;
585 #if 0 /* I want to see dot files */
586 if (finfo->mode & aHIDDEN)
587 return; /* don't bother with hidden files, "~$" screws up mc */
588 #endif
589 if (!entry)
590 new_entry = smbfs_new_dir_entry (finfo->name);
592 new_entry->my_stat.st_size = finfo->size;
593 new_entry->my_stat.st_mtime = finfo->mtime;
594 new_entry->my_stat.st_atime = finfo->atime;
595 new_entry->my_stat.st_ctime = finfo->ctime;
596 new_entry->my_stat.st_uid = finfo->uid;
597 new_entry->my_stat.st_gid = finfo->gid;
599 new_entry->my_stat.st_mode = /* rw-rw-rw */
600 S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
602 /* if (finfo->mode & aVOLID); nothing similar in real world */
603 if (finfo->mode & aDIR)
604 new_entry->my_stat.st_mode |= /* drwxrwxrwx */
605 S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
606 else
607 new_entry->my_stat.st_mode |= S_IFREG; /* if not dir, regular file? */
608 /* if (finfo->mode & aARCH); DOS archive */
609 /* if (finfo->mode & aHIDDEN); like a dot file? */
610 /* if (finfo->mode & aSYSTEM); like a kernel? */
611 if (finfo->mode & aRONLY)
612 new_entry->my_stat.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
613 new_entry->my_stat.st_mode &= myumask;
615 DEBUG (entry ? 3 : 6, (" %-30s%7.7s%8.0f %s",
616 CNV_LANG (finfo->name),
617 attrib_string (finfo->mode),
618 (double) finfo->size, asctime (LocalTime (&t))));
621 /* --------------------------------------------------------------------------------------------- */
622 /* takes "/foo/bar/file" and gives malloced "\\foo\\bar\\file" */
624 static char *
625 smbfs_convert_path (const char *remote_file, gboolean trailing_asterik)
627 const char *p, *my_remote;
628 char *result;
630 my_remote = remote_file;
631 if (strncmp (my_remote, URL_HEADER, HEADER_LEN) == 0)
632 { /* if passed directly */
633 my_remote += HEADER_LEN;
634 if (*my_remote == '/') /* from server browsing */
635 my_remote++;
636 p = strchr (my_remote, '/');
637 if (p)
638 my_remote = p + 1; /* advance to end of server name */
641 if (*my_remote == '/')
642 my_remote++; /* strip off leading '/' */
643 p = strchr (my_remote, '/');
644 if (p)
645 my_remote = p; /* strip off share/service name */
646 /* create remote filename as understood by smb clientgen */
647 result = g_strconcat (my_remote, trailing_asterik ? "/*" : "", (char *) NULL);
648 unix_to_dos (result, /* inplace = */ 1); /* code page conversion */
649 str_replace (result, '/', '\\');
650 return result;
653 /* --------------------------------------------------------------------------------------------- */
655 static void
656 smbfs_srv_browsing_helper (const char *name, uint32 m, const char *comment, void *state)
658 dir_entry *new_entry = smbfs_new_dir_entry (name);
660 (void) m;
661 (void) state;
663 /* show this as dir */
664 new_entry->my_stat.st_mode =
665 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
667 DEBUG (3, ("\t%-16.16s %s\n", name, comment));
670 /* --------------------------------------------------------------------------------------------- */
672 static BOOL
673 smbfs_reconnect (smbfs_connection * conn, int *retries)
675 char *host;
676 DEBUG (3, ("RECONNECT\n"));
678 if (*(conn->host) == 0)
679 host = g_strdup (conn->cli->desthost); /* server browsing */
680 else
681 host = g_strdup (conn->host);
683 cli_shutdown (conn->cli);
685 if (!(conn->cli = smbfs_do_connect (host, conn->service)))
687 message (D_ERROR, MSG_ERROR, _("reconnect to %s failed"), conn->host);
688 g_free (host);
689 return False;
691 g_free (host);
692 if (++(*retries) == 2)
693 return False;
694 return True;
697 /* --------------------------------------------------------------------------------------------- */
699 static BOOL
700 smbfs_send (struct cli_state *cli)
702 size_t len;
703 size_t nwritten = 0;
704 ssize_t ret;
706 len = smb_len (cli->outbuf) + 4;
708 while (nwritten < len)
710 ret = write_socket (cli->fd, cli->outbuf + nwritten, len - nwritten);
711 if (ret <= 0)
713 if (errno == EPIPE)
714 return False;
716 else
717 nwritten += ret;
720 return True;
723 /* --------------------------------------------------------------------------------------------- */
724 /****************************************************************************
725 See if server has cut us off by checking for EPIPE when writing.
726 Taken from cli_chkpath()
727 ****************************************************************************/
729 static BOOL
730 smbfs_chkpath (struct cli_state *cli, const char *path, BOOL send_only)
732 fstring path2;
733 char *p;
735 fstrcpy (path2, path);
736 unix_to_dos (path2, 1);
737 trim_string (path2, NULL, "\\");
738 if (!*path2)
739 *path2 = '\\';
741 memset (cli->outbuf, '\0', smb_size);
742 set_message (cli->outbuf, 0, 4 + strlen (path2), True);
743 SCVAL (cli->outbuf, smb_com, SMBchkpth);
744 SSVAL (cli->outbuf, smb_tid, cli->cnum);
746 cli->rap_error = 0;
747 cli->nt_error = 0;
748 SSVAL (cli->outbuf, smb_pid, cli->pid);
749 SSVAL (cli->outbuf, smb_uid, cli->vuid);
750 SSVAL (cli->outbuf, smb_mid, cli->mid);
751 if (cli->protocol > PROTOCOL_CORE)
753 SCVAL (cli->outbuf, smb_flg, 0x8);
754 SSVAL (cli->outbuf, smb_flg2, 0x1);
757 p = smb_buf (cli->outbuf);
758 *p++ = 4;
759 fstrcpy (p, path2);
761 if (!smbfs_send (cli))
763 DEBUG (3, ("smbfs_chkpath: couldnt send\n"));
764 return False;
766 if (send_only)
768 client_receive_smb (cli->fd, cli->inbuf, cli->timeout);
769 DEBUG (3, ("smbfs_chkpath: send only OK\n"));
770 return True; /* just testing for EPIPE */
772 if (!client_receive_smb (cli->fd, cli->inbuf, cli->timeout))
774 DEBUG (3, ("smbfs_chkpath: receive error\n"));
775 return False;
777 if ((my_errno = cli_error (cli, NULL, NULL, NULL)))
779 if (my_errno == 20 || my_errno == 13)
780 return True; /* ignore if 'not a directory' error */
781 DEBUG (3, ("smbfs_chkpath: cli_error: %s\n", unix_error_string (my_errno)));
782 return False;
785 return True;
788 /* --------------------------------------------------------------------------------------------- */
790 #if 1
791 static int
792 smbfs_fs (const char *text)
794 const char *p = text;
795 int count = 0;
797 while ((p = strchr (p, '/')) != NULL)
799 count++;
800 p++;
802 if (count == 1)
803 return strlen (text);
804 return count;
806 #endif
808 /* --------------------------------------------------------------------------------------------- */
810 static int
811 smbfs_loaddir (opendir_info * smbfs_info)
813 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
814 int servlen = strlen (smbfs_info->conn->service);
815 const char *info_dirname = smbfs_info->dirname;
816 char *my_dirname;
818 DEBUG (3, ("smbfs_loaddir: dirname:%s\n", info_dirname));
819 first_direntry = TRUE;
821 if (current_info)
823 DEBUG (3, ("smbfs_loaddir: new:'%s', cached:'%s'\n", info_dirname, current_info->dirname));
824 /* if new desired dir is longer than cached in current_info */
825 if (smbfs_fs (info_dirname) > smbfs_fs (current_info->dirname))
827 DEBUG (3, ("saving to previous_info\n"));
828 previous_info = current_info;
832 current_info = smbfs_info;
834 if (strcmp (info_dirname, "/") == 0)
836 if (!strcmp (smbfs_info->path, URL_HEADER))
838 DEBUG (6, ("smbfs_loaddir: browsing %s\n", IPC));
839 /* browse for servers */
840 if (!cli_NetServerEnum
841 (smbfs_info->conn->cli, smbfs_info->conn->domain,
842 SV_TYPE_ALL, smbfs_srv_browsing_helper, NULL))
843 return 0;
844 else
845 current_server_info = smbfs_info;
846 smbfs_info->server_list = TRUE;
848 else
850 /* browse for shares */
851 if (cli_RNetShareEnum (smbfs_info->conn->cli, smbfs_browsing_helper, NULL) < 1)
852 return 0;
853 else
854 current_share_info = smbfs_info;
856 goto done;
859 /* do regular directory listing */
860 if (strncmp (smbfs_info->conn->service, info_dirname + 1, servlen) == 0)
862 /* strip share name from dir */
863 my_dirname = g_strdup (info_dirname + servlen);
864 *my_dirname = '/';
865 my_dirname = free_after (smbfs_convert_path (my_dirname, TRUE), my_dirname);
867 else
868 my_dirname = smbfs_convert_path (info_dirname, TRUE);
870 DEBUG (6, ("smbfs_loaddir: service: %s\n", smbfs_info->conn->service));
871 DEBUG (6, ("smbfs_loaddir: cli->share: %s\n", smbfs_info->conn->cli->share));
872 DEBUG (6, ("smbfs_loaddir: calling cli_list with mask %s\n", my_dirname));
873 /* do file listing: cli_list returns number of files */
874 if (cli_list (smbfs_info->conn->cli, my_dirname, attribute, smbfs_loaddir_helper, NULL) < 0)
876 /* cli_list returns -1 if directory empty or cannot read socket */
877 my_errno = cli_error (smbfs_info->conn->cli, NULL, &err, NULL);
878 g_free (my_dirname);
879 return 0;
881 if (*(my_dirname) == 0)
882 smbfs_info->dirname = smbfs_info->conn->service;
883 g_free (my_dirname);
884 /* do_dskattr(); */
886 done:
887 /* current_info->parent = smbfs_info->dirname; */
889 smbfs_info->current = smbfs_info->entries;
890 return 1; /* 1 = ok */
893 /* --------------------------------------------------------------------------------------------- */
895 #ifdef SMBFS_FREE_DIR
896 static void
897 smbfs_free_dir (dir_entry * de)
899 if (!de)
900 return;
902 smbfs_free_dir (de->next);
903 g_free (de->text);
904 g_free (de);
906 #endif
908 /* --------------------------------------------------------------------------------------------- */
909 /* The readdir routine loads the complete directory */
910 /* It's too slow to ask the server each time */
911 /* It now also sends the complete lstat information for each file */
913 static void *
914 smbfs_readdir (void *info)
916 static union vfs_dirent smbfs_readdir_data;
917 static char *const dirent_dest = smbfs_readdir_data.dent.d_name;
918 opendir_info *smbfs_info = (opendir_info *) info;
920 DEBUG (4, ("smbfs_readdir(%s)\n", smbfs_info->dirname));
922 if (!smbfs_info->entries)
923 if (!smbfs_loaddir (smbfs_info))
924 return NULL;
926 if (smbfs_info->current == 0)
927 { /* reached end of dir entries */
928 DEBUG (3, ("smbfs_readdir: smbfs_info->current = 0\n"));
929 #ifdef SMBFS_FREE_DIR
930 smbfs_free_dir (smbfs_info->entries);
931 smbfs_info->entries = 0;
932 #endif
933 return NULL;
935 g_strlcpy (dirent_dest, smbfs_info->current->text, MC_MAXPATHLEN);
936 smbfs_info->current = smbfs_info->current->next;
938 compute_namelen (&smbfs_readdir_data.dent);
940 return &smbfs_readdir_data;
943 /* --------------------------------------------------------------------------------------------- */
945 static int
946 smbfs_closedir (void *info)
948 opendir_info *smbfs_info = (opendir_info *) info;
949 /* dir_entry *p, *q; */
951 DEBUG (3, ("smbfs_closedir(%s)\n", smbfs_info->dirname));
952 /* CLOSE HERE */
954 /* for (p = smbfs_info->entries; p;){
955 q = p;
956 p = p->next;
957 g_free (q->text);
958 g_free (q);
960 g_free (info); */
961 return 0;
964 /* --------------------------------------------------------------------------------------------- */
966 static int
967 smbfs_chmod (const vfs_path_t * vpath, int mode)
969 DEBUG (3, ("smbfs_chmod(path:%s, mode:%d)\n", vpath->unparsed, mode));
970 /* my_errno = EOPNOTSUPP;
971 return -1; *//* cannot chmod on smb filesystem */
972 return 0; /* make mc happy */
975 /* --------------------------------------------------------------------------------------------- */
977 static int
978 smbfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
980 DEBUG (3, ("smbfs_chown(path:%s, owner:%d, group:%d)\n", vpath->unparsed, owner, group));
981 my_errno = EOPNOTSUPP; /* ready for your labotomy? */
982 return -1;
985 /* --------------------------------------------------------------------------------------------- */
987 static int
988 smbfs_utime (const vfs_path_t * vpath, struct utimbuf *times)
990 (void) times;
992 DEBUG (3, ("smbfs_utime(path:%s)\n", vpath->unparsed));
993 my_errno = EOPNOTSUPP;
994 return -1;
997 /* --------------------------------------------------------------------------------------------- */
999 static int
1000 smbfs_readlink (const vfs_path_t * vpath, char *buf, size_t size)
1002 DEBUG (3, ("smbfs_readlink(path:%s, buf:%s, size:%zu)\n", vpath->unparsed, buf, size));
1003 my_errno = EOPNOTSUPP;
1004 return -1; /* no symlinks on smb filesystem? */
1007 /* --------------------------------------------------------------------------------------------- */
1009 static int
1010 smbfs_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
1012 DEBUG (3, ("smbfs_symlink(n1:%s, n2:%s)\n", vpath1->unparsed, vpath2->unparsed));
1013 my_errno = EOPNOTSUPP;
1014 return -1; /* no symlinks on smb filesystem? */
1017 /* --------------------------------------------------------------------------------------------- */
1018 /*****************************************************
1019 return a connection to a SMB server
1020 current_bucket needs to be set before calling
1021 *******************************************************/
1023 static struct cli_state *
1024 smbfs_do_connect (const char *server, char *share)
1026 struct cli_state *c;
1027 struct nmb_name called, calling;
1028 struct in_addr ip;
1030 DEBUG (3, ("smbfs_do_connect(%s, %s)\n", server, share));
1031 if (*share == '\\')
1033 server = share + 2;
1034 share = strchr (server, '\\');
1035 if (!share)
1036 return NULL;
1037 *share = 0;
1038 share++;
1041 make_nmb_name (&calling, global_myname, 0x0);
1042 make_nmb_name (&called, server, current_bucket->name_type);
1044 for (;;)
1047 ip = (current_bucket->have_ip) ? current_bucket->dest_ip : ipzero;
1049 /* have to open a new connection */
1050 if (!(c = cli_initialise (NULL)))
1052 my_errno = ENOMEM;
1053 return NULL;
1056 pwd_init (&(c->pwd)); /* should be moved into cli_initialise()? */
1057 pwd_set_cleartext (&(c->pwd), current_bucket->password);
1059 if ((cli_set_port (c, current_bucket->port) == 0) || !cli_connect (c, server, &ip))
1061 DEBUG (1, ("Connection to %s failed\n", server));
1062 break;
1065 if (!cli_session_request (c, &calling, &called))
1067 my_errno = cli_error (c, NULL, &err, NULL);
1068 DEBUG (1, ("session request to %s failed\n", called.name));
1069 cli_shutdown (c);
1070 if (strcmp (called.name, "*SMBSERVER"))
1072 make_nmb_name (&called, "*SMBSERVER", 0x20);
1073 continue;
1075 return NULL;
1078 DEBUG (3, (" session request ok\n"));
1080 if (!cli_negprot (c))
1082 DEBUG (1, ("protocol negotiation failed\n"));
1083 break;
1086 if (!cli_session_setup (c, current_bucket->user,
1087 current_bucket->password, strlen (current_bucket->password),
1088 current_bucket->password, strlen (current_bucket->password),
1089 current_bucket->domain))
1091 DEBUG (1, ("session setup failed: %s\n", cli_errstr (c)));
1092 smbfs_auth_remove (server, share);
1093 break;
1096 if (*c->server_domain || *c->server_os || *c->server_type)
1097 DEBUG (5, ("Domain=[%s] OS=[%s] Server=[%s]\n",
1098 c->server_domain, c->server_os, c->server_type));
1100 DEBUG (3, (" session setup ok\n"));
1102 if (!cli_send_tconX (c, share, "?????",
1103 current_bucket->password, strlen (current_bucket->password) + 1))
1105 DEBUG (1, ("%s: tree connect failed: %s\n", share, cli_errstr (c)));
1106 break;
1109 DEBUG (3, (" tconx ok\n"));
1111 my_errno = 0;
1112 return c;
1115 my_errno = cli_error (c, NULL, &err, NULL);
1116 cli_shutdown (c);
1117 return NULL;
1121 /* --------------------------------------------------------------------------------------------- */
1123 static int
1124 smbfs_get_master_browser (char **host)
1126 static char so_broadcast[] = "SO_BROADCAST";
1127 int count;
1128 struct in_addr *ip_list, bcast_addr;
1130 /* does port = 137 for win95 master browser? */
1131 int fd = open_socket_in (SOCK_DGRAM, 0, 3,
1132 interpret_addr (lp_socket_address ()), True);
1133 if (fd == -1)
1134 return 0;
1135 set_socket_options (fd, so_broadcast);
1136 ip_list = iface_bcast (ipzero);
1137 bcast_addr = *ip_list;
1138 if ((ip_list = name_query (fd, "\01\02__MSBROWSE__\02", 1, True,
1139 True, bcast_addr, &count, NULL)))
1141 if (!count)
1142 return 0;
1143 /* just return first master browser */
1144 *host = g_strdup (inet_ntoa (ip_list[0]));
1145 return 1;
1147 return 0;
1150 /* --------------------------------------------------------------------------------------------- */
1152 static void
1153 smbfs_free_bucket (smbfs_connection * bucket)
1155 g_free (bucket->host);
1156 g_free (bucket->service);
1157 g_free (bucket->domain);
1158 g_free (bucket->user);
1159 wipe_password (bucket->password);
1160 g_free (bucket->home);
1161 memset (bucket, 0, sizeof (smbfs_connection));
1164 /* --------------------------------------------------------------------------------------------- */
1166 static smbfs_connection *
1167 smbfs_get_free_bucket (void)
1169 int i;
1171 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1172 if (!smbfs_connections[i].cli)
1173 return &smbfs_connections[i];
1175 { /* search for most dormant connection */
1176 int oldest = 0; /* index */
1177 time_t oldest_time = smbfs_connections[0].last_use;
1178 for (i = 1; i < SMBFS_MAX_CONNECTIONS; i++)
1180 if (smbfs_connections[i].last_use < oldest_time)
1182 oldest_time = smbfs_connections[i].last_use;
1183 oldest = i;
1186 cli_shutdown (smbfs_connections[oldest].cli);
1187 smbfs_free_bucket (&smbfs_connections[oldest]);
1188 return &smbfs_connections[oldest];
1191 /* This can't happend, since we have checked for max connections before */
1192 vfs_die ("Internal error: smbfs_get_free_bucket");
1193 return 0; /* shut up, stupid gcc */
1196 /* --------------------------------------------------------------------------------------------- */
1197 /* This routine keeps track of open connections */
1198 /* Returns a connected socket to host */
1200 static smbfs_connection *
1201 smbfs_open_link (char *host, char *path, const char *user, int *port, char *this_pass)
1203 int i;
1204 smbfs_connection *bucket;
1205 pstring service;
1206 struct in_addr *dest_ip = NULL;
1208 DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host, path));
1210 if (strcmp (host, path) == 0) /* if host & path are same: */
1211 pstrcpy (service, IPC); /* setup for browse */
1212 else
1213 { /* get share name from path, path starts with server name */
1214 char *p;
1215 if ((p = strchr (path, '/'))) /* get share aka */
1216 pstrcpy (service, ++p); /* service name from path */
1217 else
1218 pstrcpy (service, "");
1219 /* now check for trailing directory/filenames */
1220 p = strchr (service, '/');
1221 if (p)
1222 *p = 0; /* cut off dir/files: sharename only */
1223 if (!*service)
1224 pstrcpy (service, IPC); /* setup for browse */
1225 DEBUG (6, ("smbfs_open_link: service from path:%s\n", service));
1228 if (got_user)
1229 user = username; /* global from getenv */
1231 /* Is the link actually open? */
1232 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1234 if (!smbfs_connections[i].cli)
1235 continue;
1236 if ((strcmp (host, smbfs_connections[i].host) == 0) &&
1237 (strcmp (user, smbfs_connections[i].user) == 0) &&
1238 (strcmp (service, smbfs_connections[i].service) == 0))
1240 int retries = 0;
1241 BOOL inshare = (*host != 0 && *path != 0 && strchr (path, '/'));
1242 /* check if this connection has died */
1243 while (!smbfs_chkpath (smbfs_connections[i].cli, "\\", !inshare))
1245 if (!smbfs_reconnect (&smbfs_connections[i], &retries))
1246 return 0;
1248 DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i));
1249 current_bucket = &smbfs_connections[i];
1250 smbfs_connections[i].last_use = time (NULL);
1251 return &smbfs_connections[i];
1253 /* connection not found, find if we have ip for new connection */
1254 if (strcmp (host, smbfs_connections[i].host) == 0)
1255 dest_ip = &smbfs_connections[i].cli->dest_ip;
1258 /* make new connection */
1259 bucket = smbfs_get_free_bucket ();
1260 bucket->name_type = 0x20;
1261 bucket->home = 0;
1262 bucket->port = *port;
1263 bucket->have_ip = False;
1264 if (dest_ip)
1266 bucket->have_ip = True;
1267 bucket->dest_ip = *dest_ip;
1269 current_bucket = bucket;
1271 bucket->user = g_strdup (user);
1272 bucket->service = g_strdup (service);
1274 if (!(*host))
1275 { /* if blank host name, browse for servers */
1276 if (!smbfs_get_master_browser (&host)) /* set host to ip of master browser */
1277 return 0; /* could not find master browser? */
1278 g_free (host);
1279 bucket->host = g_strdup (""); /* blank host means master browser */
1281 else
1282 bucket->host = g_strdup (host);
1284 if (!smbfs_bucket_set_authinfo (bucket, 0, /* domain currently not used */
1285 user, this_pass, 1))
1286 return 0;
1288 /* connect to share */
1289 while (!(bucket->cli = smbfs_do_connect (host, service)))
1292 if (my_errno != EPERM)
1293 return 0;
1294 message (D_ERROR, MSG_ERROR, _("Authentication failed"));
1296 /* authentication failed, try again */
1297 smbfs_auth_remove (bucket->host, bucket->service);
1298 if (!smbfs_bucket_set_authinfo (bucket, bucket->domain, bucket->user, 0, 0))
1299 return 0;
1303 smbfs_open_connections++;
1304 DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n", smbfs_open_connections));
1305 return bucket;
1308 /* --------------------------------------------------------------------------------------------- */
1310 static char *
1311 smbfs_get_path (smbfs_connection ** sc, const char *path)
1313 char *remote_path = NULL;
1314 vfs_url_t *url;
1316 DEBUG (3, ("smbfs_get_path(%s)\n", path));
1317 if (strncmp (path, URL_HEADER, HEADER_LEN) != 0)
1318 return NULL;
1319 path += HEADER_LEN;
1321 if (*path == '/') /* '/' leading server name */
1322 path++; /* probably came from server browsing */
1324 url = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1326 if (url != NULL)
1328 *sc = smbfs_open_link (url->host, url->path, url->user, &url->port, url->password);
1329 wipe_password (url->password);
1331 if (*sc != NULL)
1332 remote_path = g_strdup (url->path);
1334 vfs_url_free (url);
1337 if (remote_path == NULL)
1338 return NULL;
1340 /* NOTE: tildes are deprecated. See ftpfs.c */
1342 int f = strcmp (remote_path, "/~") ? 0 : 1;
1344 if (f != 0 || strncmp (remote_path, "/~/", 3) == 0)
1346 char *s;
1347 s = concat_dir_and_file ((*sc)->home, remote_path + 3 - f);
1348 g_free (remote_path);
1349 remote_path = s;
1353 return remote_path;
1356 /* --------------------------------------------------------------------------------------------- */
1358 #if 0
1359 static int
1360 is_error (int result, int errno_num)
1362 if (!(result == -1))
1363 return my_errno = 0;
1364 else
1365 my_errno = errno_num;
1366 return 1;
1368 #endif
1370 /* --------------------------------------------------------------------------------------------- */
1372 static void *
1373 smbfs_opendir (const vfs_path_t * vpath)
1375 opendir_info *smbfs_info;
1376 smbfs_connection *sc;
1377 char *remote_dir;
1379 DEBUG (3, ("smbfs_opendir(dirname:%s)\n", vpath->unparsed));
1381 if (!(remote_dir = smbfs_get_path (&sc, vpath->unparsed)))
1382 return NULL;
1384 /* FIXME: where freed? */
1385 smbfs_info = g_new (opendir_info, 1);
1386 smbfs_info->server_list = FALSE;
1387 smbfs_info->path = g_strdup (vpath->unparsed); /* keep original */
1388 smbfs_info->dirname = remote_dir;
1389 smbfs_info->conn = sc;
1390 smbfs_info->entries = 0;
1391 smbfs_info->current = 0;
1393 return smbfs_info;
1396 /* --------------------------------------------------------------------------------------------- */
1398 static int
1399 smbfs_fake_server_stat (const char *server_url, const char *path, struct stat *buf)
1401 dir_entry *dentry;
1402 const char *p;
1404 (void) server_url;
1406 if ((p = strrchr (path, '/')))
1407 path = p + 1; /* advance until last '/' */
1409 if (!current_info->entries)
1411 if (!smbfs_loaddir (current_info)) /* browse host */
1412 return -1;
1415 if (current_info->server_list == True)
1417 dentry = current_info->entries;
1418 DEBUG (4, ("fake stat for SERVER \"%s\"\n", path));
1419 while (dentry)
1421 if (strcmp (dentry->text, path) == 0)
1423 DEBUG (4, ("smbfs_fake_server_stat: %s:%4o\n",
1424 dentry->text, (int) dentry->my_stat.st_mode));
1425 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1426 return 0;
1428 dentry = dentry->next;
1431 my_errno = ENOENT;
1432 return -1;
1435 /* --------------------------------------------------------------------------------------------- */
1437 static int
1438 smbfs_fake_share_stat (const char *server_url, const char *path, struct stat *buf)
1440 dir_entry *dentry;
1441 if (strlen (path) < strlen (server_url))
1442 return -1;
1444 if (!current_share_info)
1445 { /* Server was not stat()ed */
1446 /* Make sure there is such share at server */
1447 smbfs_connection *sc;
1448 char *p;
1449 p = smbfs_get_path (&sc, path);
1450 g_free (p);
1451 if (p)
1453 memset (buf, 0, sizeof (*buf));
1454 /* show this as dir */
1455 buf->st_mode =
1456 (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) & myumask;
1457 return 0;
1459 return -1;
1462 path += strlen (server_url); /* we only want share name */
1463 path++;
1465 if (*path == '/') /* '/' leading server name */
1466 path++; /* probably came from server browsing */
1468 if (!current_share_info->entries)
1470 if (!smbfs_loaddir (current_share_info)) /* browse host */
1471 return -1;
1473 dentry = current_share_info->entries;
1474 DEBUG (3, ("smbfs_fake_share_stat: %s on %s\n", path, server_url));
1475 while (dentry)
1477 if (strcmp (dentry->text, path) == 0)
1479 DEBUG (6, ("smbfs_fake_share_stat: %s:%4o\n",
1480 dentry->text, (int) dentry->my_stat.st_mode));
1481 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1482 return 0;
1484 dentry = dentry->next;
1486 my_errno = ENOENT;
1487 return -1;
1490 /* --------------------------------------------------------------------------------------------- */
1491 /* stat a single file */
1493 static int
1494 smbfs_get_remote_stat (smbfs_connection * sc, const char *path, struct stat *buf)
1496 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
1497 char *mypath;
1499 DEBUG (3, ("smbfs_get_remote_stat(): mypath:%s\n", path));
1501 mypath = smbfs_convert_path (path, FALSE);
1503 #if 0 /* single_entry is never free()d now. And only my_stat is used */
1504 single_entry = g_new (dir_entry, 1);
1506 single_entry->text = dos_to_unix (g_strdup (finfo->name), 1);
1508 single_entry->next = 0;
1509 #endif
1510 if (!single_entry)
1511 single_entry = g_new0 (dir_entry, 1);
1513 if (cli_list (sc->cli, mypath, attribute, smbfs_loaddir_helper, single_entry) < 1)
1515 my_errno = ENOENT;
1516 g_free (mypath);
1517 return -1; /* cli_list returns number of files */
1520 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
1522 /* don't free here, use for smbfs_fstat() */
1523 /* g_free(single_entry->text);
1524 g_free(single_entry); */
1525 g_free (mypath);
1526 return 0;
1529 /* --------------------------------------------------------------------------------------------- */
1531 static int
1532 smbfs_search_dir_entry (dir_entry * dentry, const char *text, struct stat *buf)
1534 while (dentry)
1536 if (strcmp (text, dentry->text) == 0)
1538 memcpy (buf, &dentry->my_stat, sizeof (struct stat));
1539 memcpy (&single_entry->my_stat, &dentry->my_stat, sizeof (struct stat));
1540 return 0;
1542 dentry = dentry->next;
1544 return -1;
1547 /* --------------------------------------------------------------------------------------------- */
1549 static int
1550 smbfs_get_stat_info (smbfs_connection * sc, const char *path, struct stat *buf)
1552 char *p;
1553 #if 0
1554 dir_entry *dentry = current_info->entries;
1555 #endif
1556 const char *mypath = path;
1558 mypath++; /* cut off leading '/' */
1559 if ((p = strrchr (mypath, '/')))
1560 mypath = p + 1; /* advance until last file/dir name */
1561 DEBUG (3, ("smbfs_get_stat_info: mypath:%s, current_info->dirname:%s\n",
1562 mypath, current_info->dirname));
1563 #if 0
1564 if (!dentry)
1566 DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1567 current_info->dirname, path));
1568 return -1;
1570 #endif
1571 if (!single_entry) /* when found, this will be written too */
1572 single_entry = g_new (dir_entry, 1);
1573 if (smbfs_search_dir_entry (current_info->entries, mypath, buf) == 0)
1575 return 0;
1577 /* now try to identify mypath as PARENT dir */
1579 char *mdp;
1580 char *mydir;
1581 mdp = mydir = g_strdup (current_info->dirname);
1582 if ((p = strrchr (mydir, '/')))
1583 *p = 0; /* advance util last '/' */
1584 if ((p = strrchr (mydir, '/')))
1585 mydir = p + 1; /* advance util last '/' */
1586 if (strcmp (mydir, mypath) == 0)
1587 { /* fake a stat for ".." */
1588 memset (buf, 0, sizeof (struct stat));
1589 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1590 memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1591 g_free (mdp);
1592 DEBUG (1, (" PARENT:found in %s\n", current_info->dirname));
1593 return 0;
1595 g_free (mdp);
1597 /* now try to identify as CURRENT dir? */
1599 char *dnp = current_info->dirname;
1600 DEBUG (6, ("smbfs_get_stat_info: is %s current dir? this dir is: %s\n",
1601 mypath, current_info->dirname));
1602 if (*dnp == '/')
1603 dnp++;
1604 else
1606 return -1;
1608 if (strcmp (mypath, dnp) == 0)
1610 memset (buf, 0, sizeof (struct stat));
1611 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1612 memcpy (&single_entry->my_stat, buf, sizeof (struct stat));
1613 DEBUG (1, (" CURRENT:found in %s\n", current_info->dirname));
1614 return 0;
1617 DEBUG (3, ("'%s' not found in current_info '%s'\n", path, current_info->dirname));
1618 /* try to find this in the PREVIOUS listing */
1619 if (previous_info)
1621 if (smbfs_search_dir_entry (previous_info->entries, mypath, buf) == 0)
1622 return 0;
1623 DEBUG (3, ("'%s' not found in previous_info '%s'\n", path, previous_info->dirname));
1625 /* try to find this in the SHARE listing */
1626 if (current_share_info)
1628 if (smbfs_search_dir_entry (current_share_info->entries, mypath, buf) == 0)
1629 return 0;
1630 DEBUG (3, ("'%s' not found in share_info '%s'\n", path, current_share_info->dirname));
1632 /* try to find this in the SERVER listing */
1633 if (current_server_info)
1635 if (smbfs_search_dir_entry (current_server_info->entries, mypath, buf) == 0)
1636 return 0;
1637 DEBUG (3, ("'%s' not found in server_info '%s'\n", path, current_server_info->dirname));
1639 /* nothing found. get stat file info from server */
1640 return smbfs_get_remote_stat (sc, path, buf);
1643 /* --------------------------------------------------------------------------------------------- */
1645 static int
1646 smbfs_chdir (const vfs_path_t * vpath)
1648 char *remote_dir;
1649 smbfs_connection *sc;
1651 DEBUG (3, ("smbfs_chdir(path:%s)\n", vpath->unparsed));
1652 if (!(remote_dir = smbfs_get_path (&sc, vpath->unparsed)))
1653 return -1;
1654 g_free (remote_dir);
1656 return 0;
1659 /* --------------------------------------------------------------------------------------------- */
1661 static int
1662 smbfs_loaddir_by_name (const vfs_path_t * vpath)
1664 void *info;
1665 char *mypath, *p;
1667 mypath = g_strdup (vpath->unparsed);
1668 p = strrchr (mypath, '/');
1670 if (p > mypath)
1671 *p = 0;
1672 DEBUG (6, ("smbfs_loaddir_by_name(%s)\n", mypath));
1673 smbfs_chdir (vpath);
1674 info = smbfs_opendir (vpath);
1675 g_free (mypath);
1676 if (!info)
1677 return -1;
1678 smbfs_readdir (info);
1679 smbfs_loaddir (info);
1680 return 0;
1683 /* --------------------------------------------------------------------------------------------- */
1685 static int
1686 smbfs_stat (const vfs_path_t * vpath, struct stat *buf)
1688 smbfs_connection *sc;
1689 pstring server_url;
1690 char *service, *pp, *at;
1691 const char *p;
1693 DEBUG (3, ("smbfs_stat(path:%s)\n", vpath->unparsed));
1695 if (!current_info)
1697 DEBUG (1, ("current_info = NULL: "));
1698 if (smbfs_loaddir_by_name (vpath) < 0)
1699 return -1;
1702 /* check if stating server */
1703 p = vpath->unparsed;
1704 if (strncmp (p, URL_HEADER, HEADER_LEN))
1706 DEBUG (1, ("'%s' doesnt start with '%s' (length %d)\n", p, URL_HEADER, HEADER_LEN));
1707 return -1;
1710 p += HEADER_LEN;
1711 if (*p == '/')
1712 p++;
1714 pp = strchr (p, '/'); /* advance past next '/' */
1715 at = strchr (p, '@');
1716 pstrcpy (server_url, URL_HEADER);
1717 if (at && at < pp)
1718 { /* user@server */
1719 char *z = &(server_url[sizeof (server_url) - 1]);
1720 const char *s = p;
1722 at = &(server_url[HEADER_LEN]) + (at - p + 1);
1723 if (z > at)
1724 z = at;
1725 at = &(server_url[HEADER_LEN]);
1726 while (at < z)
1727 *at++ = *s++;
1728 *z = 0;
1730 pstrcat (server_url, current_bucket->host);
1732 if (!pp)
1734 if (!current_info->server_list)
1736 if (smbfs_loaddir_by_name (vpath) < 0)
1737 return -1;
1739 return smbfs_fake_server_stat (server_url, vpath->unparsed, buf);
1742 if (!strchr (++pp, '/'))
1744 return smbfs_fake_share_stat (server_url, vpath->unparsed, buf);
1747 /* stating inside share at this point */
1748 if (!(service = smbfs_get_path (&sc, vpath->unparsed))) /* connects if necessary */
1749 return -1;
1751 int hostlen = strlen (current_bucket->host);
1752 char *ppp = service + strlen (service) - hostlen;
1753 char *sp = server_url + strlen (server_url) - hostlen;
1755 if (strcmp (sp, ppp) == 0)
1757 /* make server name appear as directory */
1758 DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1759 memset (buf, 0, sizeof (struct stat));
1760 buf->st_mode = (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) & myumask;
1761 g_free (service);
1762 return 0;
1765 /* check if current_info is in share requested */
1766 p = service;
1767 pp = strchr (p, '/');
1768 if (pp)
1770 p = ++pp; /* advance past server name */
1771 pp = strchr (p, '/');
1773 if (pp)
1774 *pp = 0; /* cut off everthing after service name */
1775 else
1776 p = IPC; /* browsing for services */
1777 pp = current_info->dirname;
1778 if (*pp == '/')
1779 pp++;
1780 if (strncmp (p, pp, strlen (p)) != 0)
1782 DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p, pp));
1783 if (smbfs_loaddir_by_name (vpath) < 0)
1785 g_free (service);
1786 return -1;
1788 DEBUG (6, ("loaded dir: '%s'\n", current_info->dirname));
1790 g_free (service);
1791 /* stat dirs & files under shares now */
1792 return smbfs_get_stat_info (sc, vpath->unparsed, buf);
1795 /* --------------------------------------------------------------------------------------------- */
1797 static off_t
1798 smbfs_lseek (void *data, off_t offset, int whence)
1800 smbfs_handle *info = (smbfs_handle *) data;
1801 size_t size;
1803 DEBUG (3,
1804 ("smbfs_lseek(info->nread => %d, offset => %d, whence => %d) \n",
1805 (int) info->nread, (int) offset, whence));
1807 switch (whence)
1809 case SEEK_SET:
1810 info->nread = offset;
1811 break;
1812 case SEEK_CUR:
1813 info->nread += offset;
1814 break;
1815 case SEEK_END:
1816 if (!cli_qfileinfo (info->cli, info->fnum,
1817 NULL, &size, NULL, NULL, NULL,
1818 NULL, NULL) &&
1819 !cli_getattrE (info->cli, info->fnum, NULL, &size, NULL, NULL, NULL))
1821 errno = EINVAL;
1822 return -1;
1824 info->nread = size + offset;
1825 break;
1828 return info->nread;
1831 /* --------------------------------------------------------------------------------------------- */
1833 static int
1834 smbfs_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev)
1836 DEBUG (3,
1837 ("smbfs_mknod(path:%s, mode:%d, dev:%u)\n", vpath->unparsed, mode, (unsigned int) dev));
1838 my_errno = EOPNOTSUPP;
1839 return -1;
1842 /* --------------------------------------------------------------------------------------------- */
1844 static int
1845 smbfs_mkdir (const vfs_path_t * vpath, mode_t mode)
1847 smbfs_connection *sc;
1848 char *remote_file;
1849 char *cpath;
1851 DEBUG (3, ("smbfs_mkdir(path:%s, mode:%d)\n", vpath->unparsed, (int) mode));
1852 if ((remote_file = smbfs_get_path (&sc, vpath->unparsed)) == 0)
1853 return -1;
1854 g_free (remote_file);
1855 cpath = smbfs_convert_path (vpath->unparsed, FALSE);
1857 if (!cli_mkdir (sc->cli, cpath))
1859 my_errno = cli_error (sc->cli, NULL, &err, NULL);
1860 message (D_ERROR, MSG_ERROR, _("Error %s creating directory %s"),
1861 cli_errstr (sc->cli), CNV_LANG (cpath));
1862 g_free (cpath);
1863 return -1;
1865 g_free (cpath);
1866 return 0;
1869 /* --------------------------------------------------------------------------------------------- */
1871 static int
1872 smbfs_rmdir (const vfs_path_t * vpath)
1874 smbfs_connection *sc;
1875 char *remote_file;
1876 char *cpath;
1878 DEBUG (3, ("smbfs_rmdir(path:%s)\n", vpath->unparsed));
1879 if ((remote_file = smbfs_get_path (&sc, vpath->unparsed)) == 0)
1880 return -1;
1881 g_free (remote_file);
1882 cpath = smbfs_convert_path (vpath->unparsed, FALSE);
1884 if (!cli_rmdir (sc->cli, cpath))
1886 my_errno = cli_error (sc->cli, NULL, &err, NULL);
1887 message (D_ERROR, MSG_ERROR, _("Error %s removing directory %s"),
1888 cli_errstr (sc->cli), CNV_LANG (cpath));
1889 g_free (cpath);
1890 return -1;
1893 g_free (cpath);
1894 return 0;
1897 /* --------------------------------------------------------------------------------------------- */
1899 static int
1900 smbfs_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
1902 DEBUG (3, ("smbfs_link(p1:%s, p2:%s)\n", vpath1->unparsed, vpath2->unparsed));
1903 my_errno = EOPNOTSUPP;
1904 return -1;
1907 /* --------------------------------------------------------------------------------------------- */
1909 static void
1910 smbfs_free (vfsid id)
1912 DEBUG (3, ("smbfs_free(%p)\n", id));
1913 smbfs_auth_free_all ();
1916 /* --------------------------------------------------------------------------------------------- */
1917 /* Gives up on a socket and reopens the connection, the child own the socket
1918 * now
1921 static void
1922 smbfs_forget (const char *path)
1924 vfs_url_t *p;
1926 if (strncmp (path, URL_HEADER, HEADER_LEN) != 0)
1927 return;
1929 DEBUG (3, ("smbfs_forget(path:%s)\n", path));
1931 path += 6;
1932 if (path[0] == '/' && path[1] == '/')
1933 path += 2;
1935 p = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1936 if (p != NULL)
1938 size_t i;
1940 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1942 if (smbfs_connections[i].cli
1943 && (strcmp (p->host, smbfs_connections[i].host) == 0)
1944 && (strcmp (p->user, smbfs_connections[i].user) == 0)
1945 && (p->port == smbfs_connections[i].port))
1948 /* close socket: the child owns it now */
1949 cli_shutdown (smbfs_connections[i].cli);
1951 /* reopen the connection */
1952 smbfs_connections[i].cli = smbfs_do_connect (p->host, smbfs_connections[i].service);
1956 vfs_url_free (p);
1960 /* --------------------------------------------------------------------------------------------- */
1962 static int
1963 smbfs_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
1965 (void) arg;
1967 DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", vpath->unparsed, ctlop));
1968 switch (ctlop)
1970 case VFS_SETCTL_FORGET:
1971 smbfs_forget (vpath->unparsed);
1972 return 0;
1974 return 0;
1977 /* --------------------------------------------------------------------------------------------- */
1979 static smbfs_handle *
1980 smbfs_open_readwrite (smbfs_handle * remote_handle, char *rname, int flags, mode_t mode)
1982 size_t size;
1984 (void) mode;
1986 if (flags & O_TRUNC) /* if it exists truncate to zero */
1987 DEBUG (3, ("smbfs_open: O_TRUNC\n"));
1989 remote_handle->fnum =
1990 #if 1 /* Don't play with flags, it is cli_open() headache */
1991 cli_open (remote_handle->cli, rname, flags, DENY_NONE);
1992 #else /* What's a reasons to has this code ? */
1993 cli_open (remote_handle->cli, rname, ((flags & O_CREAT)
1994 || (flags ==
1995 (O_WRONLY | O_APPEND))) ?
1996 flags : O_RDONLY, DENY_NONE);
1997 #endif
1998 if (remote_handle->fnum == -1)
2000 message (D_ERROR, MSG_ERROR, _("%s opening remote file %s"),
2001 cli_errstr (remote_handle->cli), CNV_LANG (rname));
2002 DEBUG (1, ("smbfs_open(rname:%s) error:%s\n", rname, cli_errstr (remote_handle->cli)));
2003 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2004 return NULL;
2007 if (flags & O_CREAT)
2008 return remote_handle;
2010 if (!cli_qfileinfo (remote_handle->cli, remote_handle->fnum,
2011 &remote_handle->attr, &size, NULL, NULL, NULL, NULL,
2012 NULL)
2013 && !cli_getattrE (remote_handle->cli, remote_handle->fnum,
2014 &remote_handle->attr, &size, NULL, NULL, NULL))
2016 message (D_ERROR, MSG_ERROR, "getattrib: %s", cli_errstr (remote_handle->cli));
2017 DEBUG (1, ("smbfs_open(rname:%s) getattrib:%s\n", rname, cli_errstr (remote_handle->cli)));
2018 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2019 cli_close (remote_handle->cli, remote_handle->fnum);
2020 return NULL;
2023 if ((flags == (O_WRONLY | O_APPEND)) /* file.c:copy_file_file() -> do_append */
2024 && smbfs_lseek (remote_handle, 0, SEEK_END) == -1)
2026 cli_close (remote_handle->cli, remote_handle->fnum);
2027 return NULL;
2030 return remote_handle;
2033 /* --------------------------------------------------------------------------------------------- */
2035 static void *
2036 smbfs_open (const vfs_path_t * vpath, int flags, mode_t mode)
2038 char *remote_file;
2039 void *ret;
2040 smbfs_connection *sc;
2041 smbfs_handle *remote_handle;
2043 DEBUG (3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", vpath->unparsed, flags, mode));
2045 if (!(remote_file = smbfs_get_path (&sc, vpath->unparsed)))
2046 return 0;
2048 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2050 remote_handle = g_new (smbfs_handle, 2);
2051 remote_handle->cli = sc->cli;
2052 remote_handle->nread = 0;
2054 ret = smbfs_open_readwrite (remote_handle, remote_file, flags, mode);
2056 g_free (remote_file);
2057 if (!ret)
2058 g_free (remote_handle);
2060 return ret;
2063 /* --------------------------------------------------------------------------------------------- */
2065 static int
2066 smbfs_unlink (const vfs_path_t * vpath)
2068 smbfs_connection *sc;
2069 char *remote_file;
2071 if ((remote_file = smbfs_get_path (&sc, vpath->unparsed)) == 0)
2072 return -1;
2074 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2076 if (!cli_unlink (sc->cli, remote_file))
2078 message (D_ERROR, MSG_ERROR, _("%s removing remote file %s"),
2079 cli_errstr (sc->cli), CNV_LANG (remote_file));
2080 g_free (remote_file);
2081 return -1;
2083 g_free (remote_file);
2084 return 0;
2087 /* --------------------------------------------------------------------------------------------- */
2089 static int
2090 smbfs_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
2092 smbfs_connection *sc;
2093 char *ra, *rb;
2094 int retval;
2096 if ((ra = smbfs_get_path (&sc, vpath1->unparsed)) == 0)
2097 return -1;
2099 if ((rb = smbfs_get_path (&sc, vpath2->unparsed)) == 0)
2101 g_free (ra);
2102 return -1;
2105 ra = free_after (smbfs_convert_path (ra, FALSE), ra);
2106 rb = free_after (smbfs_convert_path (rb, FALSE), rb);
2108 retval = cli_rename (sc->cli, ra, rb);
2110 g_free (ra);
2111 g_free (rb);
2113 if (!retval)
2115 message (D_ERROR, MSG_ERROR, _("%s renaming files\n"), cli_errstr (sc->cli));
2116 return -1;
2118 return 0;
2121 /* --------------------------------------------------------------------------------------------- */
2123 static int
2124 smbfs_fstat (void *data, struct stat *buf)
2126 smbfs_handle *remote_handle = (smbfs_handle *) data;
2128 DEBUG (3, ("smbfs_fstat(fnum:%d)\n", remote_handle->fnum));
2130 /* use left over from previous smbfs_get_remote_stat, if available */
2131 if (single_entry)
2132 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
2133 else
2134 { /* single_entry not set up: bug */
2135 my_errno = EFAULT;
2136 return -EFAULT;
2138 return 0;
2141 /* --------------------------------------------------------------------------------------------- */
2142 /*** public functions ****************************************************************************/
2143 /* --------------------------------------------------------------------------------------------- */
2145 smb_authinfo *
2146 vfs_smb_authinfo_new (const char *host, const char *share, const char *domain,
2147 const char *user, const char *pass)
2149 smb_authinfo *auth;
2151 auth = g_try_new (struct smb_authinfo, 1);
2153 if (auth != NULL)
2155 auth->host = g_strdup (host);
2156 auth->share = g_strdup (share);
2157 auth->domain = g_strdup (domain);
2158 auth->user = g_strdup (user);
2159 auth->password = g_strdup (pass);
2162 return auth;
2165 /* --------------------------------------------------------------------------------------------- */
2167 void
2168 init_smbfs (void)
2170 tcp_init ();
2172 vfs_smbfs_ops.name = "smbfs";
2173 vfs_smbfs_ops.prefix = "smb:";
2174 vfs_smbfs_ops.flags = VFSF_NOLINKS;
2175 vfs_smbfs_ops.init = smbfs_init;
2176 vfs_smbfs_ops.fill_names = smbfs_fill_names;
2177 vfs_smbfs_ops.open = smbfs_open;
2178 vfs_smbfs_ops.close = smbfs_close;
2179 vfs_smbfs_ops.read = smbfs_read;
2180 vfs_smbfs_ops.write = smbfs_write;
2181 vfs_smbfs_ops.opendir = smbfs_opendir;
2182 vfs_smbfs_ops.readdir = smbfs_readdir;
2183 vfs_smbfs_ops.closedir = smbfs_closedir;
2184 vfs_smbfs_ops.stat = smbfs_stat;
2185 vfs_smbfs_ops.lstat = smbfs_lstat;
2186 vfs_smbfs_ops.fstat = smbfs_fstat;
2187 vfs_smbfs_ops.chmod = smbfs_chmod;
2188 vfs_smbfs_ops.chown = smbfs_chown;
2189 vfs_smbfs_ops.utime = smbfs_utime;
2190 vfs_smbfs_ops.readlink = smbfs_readlink;
2191 vfs_smbfs_ops.symlink = smbfs_symlink;
2192 vfs_smbfs_ops.link = smbfs_link;
2193 vfs_smbfs_ops.unlink = smbfs_unlink;
2194 vfs_smbfs_ops.rename = smbfs_rename;
2195 vfs_smbfs_ops.chdir = smbfs_chdir;
2196 vfs_smbfs_ops.ferrno = smbfs_errno;
2197 vfs_smbfs_ops.lseek = smbfs_lseek;
2198 vfs_smbfs_ops.mknod = smbfs_mknod;
2199 vfs_smbfs_ops.free = smbfs_free;
2200 vfs_smbfs_ops.mkdir = smbfs_mkdir;
2201 vfs_smbfs_ops.rmdir = smbfs_rmdir;
2202 vfs_smbfs_ops.setctl = smbfs_setctl;
2203 vfs_register_class (&vfs_smbfs_ops);
2206 /* --------------------------------------------------------------------------------------------- */