Following prototypes of functions was changed in VFS-module API:
[midnight-commander.git] / src / vfs / smbfs / smbfs.c
blobcacbe630a8c9c2dd3a9ff68ddd26dbd46ec0266d
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 (struct vfs_class *me, const char *path, int mode)
969 (void) me;
971 DEBUG (3, ("smbfs_chmod(path:%s, mode:%d)\n", path, mode));
972 /* my_errno = EOPNOTSUPP;
973 return -1; *//* cannot chmod on smb filesystem */
974 return 0; /* make mc happy */
977 /* --------------------------------------------------------------------------------------------- */
979 static int
980 smbfs_chown (struct vfs_class *me, const char *path, uid_t owner, gid_t group)
982 (void) me;
984 DEBUG (3, ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path, owner, group));
985 my_errno = EOPNOTSUPP; /* ready for your labotomy? */
986 return -1;
989 /* --------------------------------------------------------------------------------------------- */
991 static int
992 smbfs_utime (struct vfs_class *me, const char *path, struct utimbuf *times)
994 (void) me;
995 (void) times;
997 DEBUG (3, ("smbfs_utime(path:%s)\n", path));
998 my_errno = EOPNOTSUPP;
999 return -1;
1002 /* --------------------------------------------------------------------------------------------- */
1004 static int
1005 smbfs_readlink (struct vfs_class *me, const char *path, char *buf, size_t size)
1007 (void) me;
1009 DEBUG (3, ("smbfs_readlink(path:%s, buf:%s, size:%zu)\n", path, buf, size));
1010 my_errno = EOPNOTSUPP;
1011 return -1; /* no symlinks on smb filesystem? */
1014 /* --------------------------------------------------------------------------------------------- */
1016 static int
1017 smbfs_symlink (struct vfs_class *me, const char *n1, const char *n2)
1019 (void) me;
1021 DEBUG (3, ("smbfs_symlink(n1:%s, n2:%s)\n", n1, n2));
1022 my_errno = EOPNOTSUPP;
1023 return -1; /* no symlinks on smb filesystem? */
1026 /* --------------------------------------------------------------------------------------------- */
1027 /*****************************************************
1028 return a connection to a SMB server
1029 current_bucket needs to be set before calling
1030 *******************************************************/
1032 static struct cli_state *
1033 smbfs_do_connect (const char *server, char *share)
1035 struct cli_state *c;
1036 struct nmb_name called, calling;
1037 struct in_addr ip;
1039 DEBUG (3, ("smbfs_do_connect(%s, %s)\n", server, share));
1040 if (*share == '\\')
1042 server = share + 2;
1043 share = strchr (server, '\\');
1044 if (!share)
1045 return NULL;
1046 *share = 0;
1047 share++;
1050 make_nmb_name (&calling, global_myname, 0x0);
1051 make_nmb_name (&called, server, current_bucket->name_type);
1053 for (;;)
1056 ip = (current_bucket->have_ip) ? current_bucket->dest_ip : ipzero;
1058 /* have to open a new connection */
1059 if (!(c = cli_initialise (NULL)))
1061 my_errno = ENOMEM;
1062 return NULL;
1065 pwd_init (&(c->pwd)); /* should be moved into cli_initialise()? */
1066 pwd_set_cleartext (&(c->pwd), current_bucket->password);
1068 if ((cli_set_port (c, current_bucket->port) == 0) || !cli_connect (c, server, &ip))
1070 DEBUG (1, ("Connection to %s failed\n", server));
1071 break;
1074 if (!cli_session_request (c, &calling, &called))
1076 my_errno = cli_error (c, NULL, &err, NULL);
1077 DEBUG (1, ("session request to %s failed\n", called.name));
1078 cli_shutdown (c);
1079 if (strcmp (called.name, "*SMBSERVER"))
1081 make_nmb_name (&called, "*SMBSERVER", 0x20);
1082 continue;
1084 return NULL;
1087 DEBUG (3, (" session request ok\n"));
1089 if (!cli_negprot (c))
1091 DEBUG (1, ("protocol negotiation failed\n"));
1092 break;
1095 if (!cli_session_setup (c, current_bucket->user,
1096 current_bucket->password, strlen (current_bucket->password),
1097 current_bucket->password, strlen (current_bucket->password),
1098 current_bucket->domain))
1100 DEBUG (1, ("session setup failed: %s\n", cli_errstr (c)));
1101 smbfs_auth_remove (server, share);
1102 break;
1105 if (*c->server_domain || *c->server_os || *c->server_type)
1106 DEBUG (5, ("Domain=[%s] OS=[%s] Server=[%s]\n",
1107 c->server_domain, c->server_os, c->server_type));
1109 DEBUG (3, (" session setup ok\n"));
1111 if (!cli_send_tconX (c, share, "?????",
1112 current_bucket->password, strlen (current_bucket->password) + 1))
1114 DEBUG (1, ("%s: tree connect failed: %s\n", share, cli_errstr (c)));
1115 break;
1118 DEBUG (3, (" tconx ok\n"));
1120 my_errno = 0;
1121 return c;
1124 my_errno = cli_error (c, NULL, &err, NULL);
1125 cli_shutdown (c);
1126 return NULL;
1130 /* --------------------------------------------------------------------------------------------- */
1132 static int
1133 smbfs_get_master_browser (char **host)
1135 static char so_broadcast[] = "SO_BROADCAST";
1136 int count;
1137 struct in_addr *ip_list, bcast_addr;
1139 /* does port = 137 for win95 master browser? */
1140 int fd = open_socket_in (SOCK_DGRAM, 0, 3,
1141 interpret_addr (lp_socket_address ()), True);
1142 if (fd == -1)
1143 return 0;
1144 set_socket_options (fd, so_broadcast);
1145 ip_list = iface_bcast (ipzero);
1146 bcast_addr = *ip_list;
1147 if ((ip_list = name_query (fd, "\01\02__MSBROWSE__\02", 1, True,
1148 True, bcast_addr, &count, NULL)))
1150 if (!count)
1151 return 0;
1152 /* just return first master browser */
1153 *host = g_strdup (inet_ntoa (ip_list[0]));
1154 return 1;
1156 return 0;
1159 /* --------------------------------------------------------------------------------------------- */
1161 static void
1162 smbfs_free_bucket (smbfs_connection * bucket)
1164 g_free (bucket->host);
1165 g_free (bucket->service);
1166 g_free (bucket->domain);
1167 g_free (bucket->user);
1168 wipe_password (bucket->password);
1169 g_free (bucket->home);
1170 memset (bucket, 0, sizeof (smbfs_connection));
1173 /* --------------------------------------------------------------------------------------------- */
1175 static smbfs_connection *
1176 smbfs_get_free_bucket (void)
1178 int i;
1180 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1181 if (!smbfs_connections[i].cli)
1182 return &smbfs_connections[i];
1184 { /* search for most dormant connection */
1185 int oldest = 0; /* index */
1186 time_t oldest_time = smbfs_connections[0].last_use;
1187 for (i = 1; i < SMBFS_MAX_CONNECTIONS; i++)
1189 if (smbfs_connections[i].last_use < oldest_time)
1191 oldest_time = smbfs_connections[i].last_use;
1192 oldest = i;
1195 cli_shutdown (smbfs_connections[oldest].cli);
1196 smbfs_free_bucket (&smbfs_connections[oldest]);
1197 return &smbfs_connections[oldest];
1200 /* This can't happend, since we have checked for max connections before */
1201 vfs_die ("Internal error: smbfs_get_free_bucket");
1202 return 0; /* shut up, stupid gcc */
1205 /* --------------------------------------------------------------------------------------------- */
1206 /* This routine keeps track of open connections */
1207 /* Returns a connected socket to host */
1209 static smbfs_connection *
1210 smbfs_open_link (char *host, char *path, const char *user, int *port, char *this_pass)
1212 int i;
1213 smbfs_connection *bucket;
1214 pstring service;
1215 struct in_addr *dest_ip = NULL;
1217 DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host, path));
1219 if (strcmp (host, path) == 0) /* if host & path are same: */
1220 pstrcpy (service, IPC); /* setup for browse */
1221 else
1222 { /* get share name from path, path starts with server name */
1223 char *p;
1224 if ((p = strchr (path, '/'))) /* get share aka */
1225 pstrcpy (service, ++p); /* service name from path */
1226 else
1227 pstrcpy (service, "");
1228 /* now check for trailing directory/filenames */
1229 p = strchr (service, '/');
1230 if (p)
1231 *p = 0; /* cut off dir/files: sharename only */
1232 if (!*service)
1233 pstrcpy (service, IPC); /* setup for browse */
1234 DEBUG (6, ("smbfs_open_link: service from path:%s\n", service));
1237 if (got_user)
1238 user = username; /* global from getenv */
1240 /* Is the link actually open? */
1241 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1243 if (!smbfs_connections[i].cli)
1244 continue;
1245 if ((strcmp (host, smbfs_connections[i].host) == 0) &&
1246 (strcmp (user, smbfs_connections[i].user) == 0) &&
1247 (strcmp (service, smbfs_connections[i].service) == 0))
1249 int retries = 0;
1250 BOOL inshare = (*host != 0 && *path != 0 && strchr (path, '/'));
1251 /* check if this connection has died */
1252 while (!smbfs_chkpath (smbfs_connections[i].cli, "\\", !inshare))
1254 if (!smbfs_reconnect (&smbfs_connections[i], &retries))
1255 return 0;
1257 DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i));
1258 current_bucket = &smbfs_connections[i];
1259 smbfs_connections[i].last_use = time (NULL);
1260 return &smbfs_connections[i];
1262 /* connection not found, find if we have ip for new connection */
1263 if (strcmp (host, smbfs_connections[i].host) == 0)
1264 dest_ip = &smbfs_connections[i].cli->dest_ip;
1267 /* make new connection */
1268 bucket = smbfs_get_free_bucket ();
1269 bucket->name_type = 0x20;
1270 bucket->home = 0;
1271 bucket->port = *port;
1272 bucket->have_ip = False;
1273 if (dest_ip)
1275 bucket->have_ip = True;
1276 bucket->dest_ip = *dest_ip;
1278 current_bucket = bucket;
1280 bucket->user = g_strdup (user);
1281 bucket->service = g_strdup (service);
1283 if (!(*host))
1284 { /* if blank host name, browse for servers */
1285 if (!smbfs_get_master_browser (&host)) /* set host to ip of master browser */
1286 return 0; /* could not find master browser? */
1287 g_free (host);
1288 bucket->host = g_strdup (""); /* blank host means master browser */
1290 else
1291 bucket->host = g_strdup (host);
1293 if (!smbfs_bucket_set_authinfo (bucket, 0, /* domain currently not used */
1294 user, this_pass, 1))
1295 return 0;
1297 /* connect to share */
1298 while (!(bucket->cli = smbfs_do_connect (host, service)))
1301 if (my_errno != EPERM)
1302 return 0;
1303 message (D_ERROR, MSG_ERROR, _("Authentication failed"));
1305 /* authentication failed, try again */
1306 smbfs_auth_remove (bucket->host, bucket->service);
1307 if (!smbfs_bucket_set_authinfo (bucket, bucket->domain, bucket->user, 0, 0))
1308 return 0;
1312 smbfs_open_connections++;
1313 DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n", smbfs_open_connections));
1314 return bucket;
1317 /* --------------------------------------------------------------------------------------------- */
1319 static char *
1320 smbfs_get_path (smbfs_connection ** sc, const char *path)
1322 char *remote_path = NULL;
1323 vfs_url_t *url;
1325 DEBUG (3, ("smbfs_get_path(%s)\n", path));
1326 if (strncmp (path, URL_HEADER, HEADER_LEN) != 0)
1327 return NULL;
1328 path += HEADER_LEN;
1330 if (*path == '/') /* '/' leading server name */
1331 path++; /* probably came from server browsing */
1333 url = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1335 if (url != NULL)
1337 *sc = smbfs_open_link (url->host, url->path, url->user, &url->port, url->password);
1338 wipe_password (url->password);
1340 if (*sc != NULL)
1341 remote_path = g_strdup (url->path);
1343 vfs_url_free (url);
1346 if (remote_path == NULL)
1347 return NULL;
1349 /* NOTE: tildes are deprecated. See ftpfs.c */
1351 int f = strcmp (remote_path, "/~") ? 0 : 1;
1353 if (f != 0 || strncmp (remote_path, "/~/", 3) == 0)
1355 char *s;
1356 s = concat_dir_and_file ((*sc)->home, remote_path + 3 - f);
1357 g_free (remote_path);
1358 remote_path = 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 vfs_url_t *p;
1946 if (strncmp (path, URL_HEADER, HEADER_LEN) != 0)
1947 return;
1949 DEBUG (3, ("smbfs_forget(path:%s)\n", path));
1951 path += 6;
1952 if (path[0] == '/' && path[1] == '/')
1953 path += 2;
1955 p = vfs_url_split (path, SMB_PORT, URL_FLAGS_NONE);
1956 if (p != NULL)
1958 size_t i;
1960 for (i = 0; i < SMBFS_MAX_CONNECTIONS; i++)
1962 if (smbfs_connections[i].cli
1963 && (strcmp (p->host, smbfs_connections[i].host) == 0)
1964 && (strcmp (p->user, smbfs_connections[i].user) == 0)
1965 && (p->port == smbfs_connections[i].port))
1968 /* close socket: the child owns it now */
1969 cli_shutdown (smbfs_connections[i].cli);
1971 /* reopen the connection */
1972 smbfs_connections[i].cli = smbfs_do_connect (p->host, smbfs_connections[i].service);
1976 vfs_url_free (p);
1980 /* --------------------------------------------------------------------------------------------- */
1982 static int
1983 smbfs_setctl (struct vfs_class *me, const char *path, int ctlop, void *arg)
1985 (void) me;
1986 (void) arg;
1988 DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path, ctlop));
1989 switch (ctlop)
1991 case VFS_SETCTL_FORGET:
1992 smbfs_forget (path);
1993 return 0;
1995 return 0;
1998 /* --------------------------------------------------------------------------------------------- */
2000 static smbfs_handle *
2001 smbfs_open_readwrite (smbfs_handle * remote_handle, char *rname, int flags, mode_t mode)
2003 size_t size;
2005 (void) mode;
2007 if (flags & O_TRUNC) /* if it exists truncate to zero */
2008 DEBUG (3, ("smbfs_open: O_TRUNC\n"));
2010 remote_handle->fnum =
2011 #if 1 /* Don't play with flags, it is cli_open() headache */
2012 cli_open (remote_handle->cli, rname, flags, DENY_NONE);
2013 #else /* What's a reasons to has this code ? */
2014 cli_open (remote_handle->cli, rname, ((flags & O_CREAT)
2015 || (flags ==
2016 (O_WRONLY | O_APPEND))) ?
2017 flags : O_RDONLY, DENY_NONE);
2018 #endif
2019 if (remote_handle->fnum == -1)
2021 message (D_ERROR, MSG_ERROR, _("%s opening remote file %s"),
2022 cli_errstr (remote_handle->cli), CNV_LANG (rname));
2023 DEBUG (1, ("smbfs_open(rname:%s) error:%s\n", rname, cli_errstr (remote_handle->cli)));
2024 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2025 return NULL;
2028 if (flags & O_CREAT)
2029 return remote_handle;
2031 if (!cli_qfileinfo (remote_handle->cli, remote_handle->fnum,
2032 &remote_handle->attr, &size, NULL, NULL, NULL, NULL,
2033 NULL)
2034 && !cli_getattrE (remote_handle->cli, remote_handle->fnum,
2035 &remote_handle->attr, &size, NULL, NULL, NULL))
2037 message (D_ERROR, MSG_ERROR, "getattrib: %s", cli_errstr (remote_handle->cli));
2038 DEBUG (1, ("smbfs_open(rname:%s) getattrib:%s\n", rname, cli_errstr (remote_handle->cli)));
2039 my_errno = cli_error (remote_handle->cli, NULL, &err, NULL);
2040 cli_close (remote_handle->cli, remote_handle->fnum);
2041 return NULL;
2044 if ((flags == (O_WRONLY | O_APPEND)) /* file.c:copy_file_file() -> do_append */
2045 && smbfs_lseek (remote_handle, 0, SEEK_END) == -1)
2047 cli_close (remote_handle->cli, remote_handle->fnum);
2048 return NULL;
2051 return remote_handle;
2054 /* --------------------------------------------------------------------------------------------- */
2056 static void *
2057 smbfs_open (const vfs_path_t * vpath, int flags, mode_t mode)
2059 char *remote_file;
2060 void *ret;
2061 smbfs_connection *sc;
2062 smbfs_handle *remote_handle;
2064 DEBUG (3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", vpath->unparsed, flags, mode));
2066 if (!(remote_file = smbfs_get_path (&sc, vpath->unparsed)))
2067 return 0;
2069 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2071 remote_handle = g_new (smbfs_handle, 2);
2072 remote_handle->cli = sc->cli;
2073 remote_handle->nread = 0;
2075 ret = smbfs_open_readwrite (remote_handle, remote_file, flags, mode);
2077 g_free (remote_file);
2078 if (!ret)
2079 g_free (remote_handle);
2081 return ret;
2084 /* --------------------------------------------------------------------------------------------- */
2086 static int
2087 smbfs_unlink (struct vfs_class *me, const char *path)
2089 smbfs_connection *sc;
2090 char *remote_file;
2092 (void) me;
2094 if ((remote_file = smbfs_get_path (&sc, path)) == 0)
2095 return -1;
2097 remote_file = free_after (smbfs_convert_path (remote_file, FALSE), remote_file);
2099 if (!cli_unlink (sc->cli, remote_file))
2101 message (D_ERROR, MSG_ERROR, _("%s removing remote file %s"),
2102 cli_errstr (sc->cli), CNV_LANG (remote_file));
2103 g_free (remote_file);
2104 return -1;
2106 g_free (remote_file);
2107 return 0;
2110 /* --------------------------------------------------------------------------------------------- */
2112 static int
2113 smbfs_rename (struct vfs_class *me, const char *a, const char *b)
2115 smbfs_connection *sc;
2116 char *ra, *rb;
2117 int retval;
2119 (void) me;
2121 if ((ra = smbfs_get_path (&sc, a)) == 0)
2122 return -1;
2124 if ((rb = smbfs_get_path (&sc, b)) == 0)
2126 g_free (ra);
2127 return -1;
2130 ra = free_after (smbfs_convert_path (ra, FALSE), ra);
2131 rb = free_after (smbfs_convert_path (rb, FALSE), rb);
2133 retval = cli_rename (sc->cli, ra, rb);
2135 g_free (ra);
2136 g_free (rb);
2138 if (!retval)
2140 message (D_ERROR, MSG_ERROR, _("%s renaming files\n"), cli_errstr (sc->cli));
2141 return -1;
2143 return 0;
2146 /* --------------------------------------------------------------------------------------------- */
2148 static int
2149 smbfs_fstat (void *data, struct stat *buf)
2151 smbfs_handle *remote_handle = (smbfs_handle *) data;
2153 DEBUG (3, ("smbfs_fstat(fnum:%d)\n", remote_handle->fnum));
2155 /* use left over from previous smbfs_get_remote_stat, if available */
2156 if (single_entry)
2157 memcpy (buf, &single_entry->my_stat, sizeof (struct stat));
2158 else
2159 { /* single_entry not set up: bug */
2160 my_errno = EFAULT;
2161 return -EFAULT;
2163 return 0;
2166 /* --------------------------------------------------------------------------------------------- */
2167 /*** public functions ****************************************************************************/
2168 /* --------------------------------------------------------------------------------------------- */
2170 smb_authinfo *
2171 vfs_smb_authinfo_new (const char *host, const char *share, const char *domain,
2172 const char *user, const char *pass)
2174 smb_authinfo *auth;
2176 auth = g_try_new (struct smb_authinfo, 1);
2178 if (auth != NULL)
2180 auth->host = g_strdup (host);
2181 auth->share = g_strdup (share);
2182 auth->domain = g_strdup (domain);
2183 auth->user = g_strdup (user);
2184 auth->password = g_strdup (pass);
2187 return auth;
2190 /* --------------------------------------------------------------------------------------------- */
2192 void
2193 init_smbfs (void)
2195 tcp_init ();
2197 vfs_smbfs_ops.name = "smbfs";
2198 vfs_smbfs_ops.prefix = "smb:";
2199 vfs_smbfs_ops.flags = VFSF_NOLINKS;
2200 vfs_smbfs_ops.init = smbfs_init;
2201 vfs_smbfs_ops.fill_names = smbfs_fill_names;
2202 vfs_smbfs_ops.open = smbfs_open;
2203 vfs_smbfs_ops.close = smbfs_close;
2204 vfs_smbfs_ops.read = smbfs_read;
2205 vfs_smbfs_ops.write = smbfs_write;
2206 vfs_smbfs_ops.opendir = smbfs_opendir;
2207 vfs_smbfs_ops.readdir = smbfs_readdir;
2208 vfs_smbfs_ops.closedir = smbfs_closedir;
2209 vfs_smbfs_ops.stat = smbfs_stat;
2210 vfs_smbfs_ops.lstat = smbfs_lstat;
2211 vfs_smbfs_ops.fstat = smbfs_fstat;
2212 vfs_smbfs_ops.chmod = smbfs_chmod;
2213 vfs_smbfs_ops.chown = smbfs_chown;
2214 vfs_smbfs_ops.utime = smbfs_utime;
2215 vfs_smbfs_ops.readlink = smbfs_readlink;
2216 vfs_smbfs_ops.symlink = smbfs_symlink;
2217 vfs_smbfs_ops.link = smbfs_link;
2218 vfs_smbfs_ops.unlink = smbfs_unlink;
2219 vfs_smbfs_ops.rename = smbfs_rename;
2220 vfs_smbfs_ops.chdir = smbfs_chdir;
2221 vfs_smbfs_ops.ferrno = smbfs_errno;
2222 vfs_smbfs_ops.lseek = smbfs_lseek;
2223 vfs_smbfs_ops.mknod = smbfs_mknod;
2224 vfs_smbfs_ops.free = smbfs_free;
2225 vfs_smbfs_ops.mkdir = smbfs_mkdir;
2226 vfs_smbfs_ops.rmdir = smbfs_rmdir;
2227 vfs_smbfs_ops.setctl = smbfs_setctl;
2228 vfs_register_class (&vfs_smbfs_ops);
2231 /* --------------------------------------------------------------------------------------------- */