2 Virtual File System: Midnight Commander file system.
4 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2011
5 The Free Software Foundation, Inc.
8 Wayne Roberts <wroberts1@home.com>, 1997
9 Andrew V. Samoilov <sav@bcs.zp.ua> 2002, 2003
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 * \brief Source: Virtual File System: smb file system
30 * \author Wayne Roberts <wroberts1@home.com>
31 * \author Andrew V. Samoilov <sav@bcs.zp.ua>
32 * \date 1997, 2002, 2003
34 * Namespace: exports init_smbfs, smbfs_set_debug()
40 #include <sys/types.h>
42 #undef USE_NCURSES /* Don't include *curses.h */
47 #include "lib/global.h"
48 #include "lib/strutil.h"
50 #include "lib/widget.h" /* message() */
52 #undef PACKAGE_BUGREPORT
55 #undef PACKAGE_TARNAME
56 #undef PACKAGE_VERSION
58 #include "helpers/include/config.h"
59 /* don't load crap in "samba/include/includes.h" we don't use and which
60 conflicts with definitions in other includes */
61 #undef HAVE_LIBREADLINE
65 #include "helpers/include/includes.h"
67 #include "lib/vfs/vfs.h"
68 #include "lib/vfs/netutil.h"
69 #include "lib/vfs/utilvfs.h"
73 /*** global variables ****************************************************************************/
75 extern int DEBUGLEVEL
;
76 extern pstring myhostname
;
77 extern struct in_addr ipzero
;
78 extern pstring global_myname
;
79 extern pstring debugf
;
82 /*** file scope macro definitions ****************************************************************/
84 #define SMBFS_MAX_CONNECTIONS 16
88 #define CNV_LANG(s) dos_to_unix(s,False)
89 #define GNAL_VNC(s) unix_to_dos(s,False)
91 #define smbfs_lstat smbfs_stat /* no symlinks on smb filesystem? */
93 /*** file scope type declarations ****************************************************************/
95 typedef struct _smbfs_connection smbfs_connection
;
99 struct cli_state
*cli
;
105 typedef struct dir_entry
108 struct dir_entry
*next
;
115 gboolean server_list
;
117 char *path
; /* the dir originally passed to smbfs_opendir */
118 smbfs_connection
*conn
;
123 /*** file scope variables ************************************************************************/
125 static const char *const IPC
= "IPC$";
126 static const char *const URL_HEADER
= "smb" VFS_PATH_URL_DELIMITER
;
131 /* stuff that is same with each connection */
133 static mode_t myumask
= 0755;
134 static int smbfs_open_connections
= 0;
135 static gboolean got_user
= FALSE
;
136 static gboolean got_pass
= FALSE
;
137 static pstring password
;
138 static pstring username
;
139 static struct vfs_class vfs_smbfs_ops
;
141 static struct _smbfs_connection
143 struct cli_state
*cli
;
144 struct in_addr dest_ip
;
146 char *host
; /* server name */
147 char *service
; /* share name */
155 } smbfs_connections
[SMBFS_MAX_CONNECTIONS
];
156 /* unique to each connection */
158 static smbfs_connection
*current_bucket
;
160 static GSList
*auth_list
;
162 static opendir_info
*previous_info
, *current_info
, *current_share_info
, *current_server_info
;
164 static gboolean first_direntry
;
166 /* stat a single file, smbfs_get_remote_stat callback */
167 static dir_entry
*single_entry
;
169 /*** file scope functions ************************************************************************/
170 /* --------------------------------------------------------------------------------------------- */
172 /* modifies *share */
173 static struct cli_state
*smbfs_do_connect (const char *server
, char *share
);
175 /* --------------------------------------------------------------------------------------------- */
178 smbfs_set_debugf (const char *filename
)
182 FILE *outfile
= fopen (filename
, "w");
185 setup_logging ("", True
); /* No needs for timestamp for each message */
188 pstrcpy (debugf
, filename
);
193 /* --------------------------------------------------------------------------------------------- */
194 /* this function allows you to write:
195 * char *s = g_strdup("hello, world");
196 * s = free_after(g_strconcat(s, s, (char *)0), s);
200 free_after (char *result
, char *string_to_free
)
202 g_free (string_to_free
);
206 /* --------------------------------------------------------------------------------------------- */
209 smbfs_auth_free (struct smb_authinfo
const *a
)
215 wipe_password (a
->password
);
218 /* --------------------------------------------------------------------------------------------- */
221 smbfs_auth_free_all (void)
225 g_slist_foreach (auth_list
, (GFunc
) smbfs_auth_free
, 0);
226 g_slist_free (auth_list
);
231 /* --------------------------------------------------------------------------------------------- */
234 smbfs_auth_cmp_host_and_share (gconstpointer _a
, gconstpointer _b
)
236 struct smb_authinfo
const *a
= (struct smb_authinfo
const *) _a
;
237 struct smb_authinfo
const *b
= (struct smb_authinfo
const *) _b
;
239 if (!a
->host
|| !a
->share
|| !b
->host
|| !b
->share
)
241 if (strcmp (a
->host
, b
->host
) != 0)
243 if (strcmp (a
->share
, b
->share
) != 0)
248 /* --------------------------------------------------------------------------------------------- */
251 smbfs_auth_cmp_host (gconstpointer _a
, gconstpointer _b
)
253 struct smb_authinfo
const *a
= (struct smb_authinfo
const *) _a
;
254 struct smb_authinfo
const *b
= (struct smb_authinfo
const *) _b
;
256 if (!a
->host
|| !b
->host
)
258 if (strcmp (a
->host
, b
->host
) != 0)
260 if (strcmp (a
->share
, IPC
) != 0)
265 /* --------------------------------------------------------------------------------------------- */
268 smbfs_auth_add (const char *host
, const char *share
, const char *domain
,
269 const char *user
, const char *pass
)
271 struct smb_authinfo
*auth
;
273 auth
= vfs_smb_authinfo_new (host
, share
, domain
, user
, pass
);
276 auth_list
= g_slist_prepend (auth_list
, auth
);
279 /* --------------------------------------------------------------------------------------------- */
282 smbfs_auth_remove (const char *host
, const char *share
)
284 struct smb_authinfo data
;
285 struct smb_authinfo
*auth
;
288 data
.host
= g_strdup (host
);
289 data
.share
= g_strdup (share
);
290 list
= g_slist_find_custom (auth_list
, &data
, smbfs_auth_cmp_host_and_share
);
296 auth_list
= g_slist_remove (auth_list
, auth
);
297 smbfs_auth_free (auth
);
300 /* --------------------------------------------------------------------------------------------- */
301 /* Set authentication information in bucket. Return 1 if successful, else 0 */
302 /* Information in auth_list overrides user if pass is NULL. */
303 /* bucket->host and bucket->service must be valid. */
306 smbfs_bucket_set_authinfo (smbfs_connection
* bucket
,
307 const char *domain
, const char *user
, const char *pass
,
308 int fallback_to_host
)
310 struct smb_authinfo data
;
311 struct smb_authinfo
*auth
;
314 if (domain
&& user
&& pass
)
316 g_free (bucket
->domain
);
317 g_free (bucket
->user
);
318 g_free (bucket
->password
);
319 bucket
->domain
= g_strdup (domain
);
320 bucket
->user
= g_strdup (user
);
321 bucket
->password
= g_strdup (pass
);
322 smbfs_auth_remove (bucket
->host
, bucket
->service
);
323 smbfs_auth_add (bucket
->host
, bucket
->service
, domain
, user
, pass
);
327 data
.host
= bucket
->host
;
328 data
.share
= bucket
->service
;
329 list
= g_slist_find_custom (auth_list
, &data
, smbfs_auth_cmp_host_and_share
);
330 if (!list
&& fallback_to_host
)
331 list
= g_slist_find_custom (auth_list
, &data
, smbfs_auth_cmp_host
);
335 bucket
->domain
= g_strdup (auth
->domain
);
336 bucket
->user
= g_strdup (auth
->user
);
337 bucket
->password
= g_strdup (auth
->password
);
343 bucket
->domain
= g_strdup (lp_workgroup ());
344 bucket
->user
= g_strdup (got_user
? username
: user
);
345 bucket
->password
= g_strdup (password
);
349 auth
= vfs_smb_get_authinfo (bucket
->host
,
350 bucket
->service
, (domain
? domain
: lp_workgroup ()), user
);
353 g_free (bucket
->domain
);
354 g_free (bucket
->user
);
355 g_free (bucket
->password
);
356 bucket
->domain
= g_strdup (auth
->domain
);
357 bucket
->user
= g_strdup (auth
->user
);
358 bucket
->password
= g_strdup (auth
->password
);
359 smbfs_auth_remove (bucket
->host
, bucket
->service
);
360 auth_list
= g_slist_prepend (auth_list
, auth
);
366 /* --------------------------------------------------------------------------------------------- */
369 smbfs_set_debug (int arg
)
374 /* --------------------------------------------------------------------------------------------- */
375 /********************** The callbacks ******************************/
378 smbfs_init (struct vfs_class
*me
)
380 const char *servicesf
= CONFIGDIR PATH_SEP_STR
"smb.conf";
382 /* DEBUGLEVEL = 4; */
385 charset_initialise ();
387 DEBUG (3, ("smbfs_init(%s)\n", me
->name
));
389 if (!get_myname (myhostname
, NULL
))
390 DEBUG (0, ("Failed to get my hostname.\n"));
392 if (!lp_load (servicesf
, True
, False
, False
))
393 DEBUG (0, ("Cannot load %s - run testparm to debug it\n", servicesf
));
395 codepage_initialise (lp_client_code_page ());
407 pstrcpy (username
, getenv ("USER"));
409 DEBUG (3, ("smbfs_init(): $USER:%s\n", username
));
410 if ((p
= strchr (username
, '%')))
413 pstrcpy (password
, p
+ 1);
415 memset (strchr (getenv ("USER"), '%') + 1, 'X', strlen (password
));
416 DEBUG (3, ("smbfs_init(): $USER%%pass: %s%%%s\n", username
, password
));
420 if (getenv ("PASSWD"))
422 pstrcpy (password
, getenv ("PASSWD"));
428 /* --------------------------------------------------------------------------------------------- */
431 smbfs_fill_names (struct vfs_class
*me
, fill_names_f func
)
438 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++)
440 if (smbfs_connections
[i
].cli
)
442 path
= g_strconcat (URL_HEADER
,
443 smbfs_connections
[i
].user
, "@",
444 smbfs_connections
[i
].host
,
445 "/", smbfs_connections
[i
].service
, (char *) NULL
);
452 /* --------------------------------------------------------------------------------------------- */
453 /* does same as do_get() in client.c */
454 /* called from vfs.c:1080, count = buffer size */
457 smbfs_read (void *data
, char *buffer
, size_t count
)
459 smbfs_handle
*info
= (smbfs_handle
*) data
;
462 DEBUG (3, ("smbfs_read(fnum:%d, nread:%d, count:%zu)\n", info
->fnum
, (int) info
->nread
, count
));
463 n
= cli_read (info
->cli
, info
->fnum
, buffer
, info
->nread
, count
);
469 /* --------------------------------------------------------------------------------------------- */
472 smbfs_write (void *data
, const char *buf
, size_t nbyte
)
474 smbfs_handle
*info
= (smbfs_handle
*) data
;
477 DEBUG (3, ("smbfs_write(fnum:%d, nread:%d, nbyte:%zu)\n",
478 info
->fnum
, (int) info
->nread
, nbyte
));
479 n
= cli_write (info
->cli
, info
->fnum
, 0, buf
, info
->nread
, nbyte
);
485 /* --------------------------------------------------------------------------------------------- */
488 smbfs_close (void *data
)
490 smbfs_handle
*info
= (smbfs_handle
*) data
;
491 DEBUG (3, ("smbfs_close(fnum:%d)\n", info
->fnum
));
493 /* FIXME: Why too different cli have the same outbuf
494 * if file is copied to share
496 if (info
->cli
->outbuf
== NULL
)
502 /* if imlementing archive_level: add rname to smbfs_handle */
503 if (archive_level
>= 2 && (inf
->attr
& aARCH
))
505 cli_setatr (info
->cli
, rname
, info
->attr
& ~(uint16
) aARCH
, 0);
508 return (cli_close (info
->cli
, info
->fnum
) == True
) ? 0 : -1;
511 /* --------------------------------------------------------------------------------------------- */
514 smbfs_errno (struct vfs_class
*me
)
518 DEBUG (3, ("smbfs_errno: %s\n", unix_error_string (my_errno
)));
522 /* --------------------------------------------------------------------------------------------- */
525 smbfs_new_dir_entry (const char *name
)
527 static int inode_counter
;
528 dir_entry
*new_entry
;
529 new_entry
= g_new0 (dir_entry
, 1);
530 new_entry
->text
= dos_to_unix (g_strdup (name
), 1);
534 current_info
->entries
= new_entry
;
535 first_direntry
= FALSE
;
539 current_info
->current
->next
= new_entry
;
541 current_info
->current
= new_entry
;
542 new_entry
->my_stat
.st_ino
= inode_counter
++;
547 /* --------------------------------------------------------------------------------------------- */
548 /* browse for shares on server */
551 smbfs_browsing_helper (const char *name
, uint32 type
, const char *comment
, void *state
)
553 const char *typestr
= "";
554 dir_entry
*new_entry
= smbfs_new_dir_entry (name
);
562 /* show this as dir */
563 new_entry
->my_stat
.st_mode
=
564 (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
| S_IXOTH
) & myumask
;
576 DEBUG (3, ("\t%-15.15s%-10.10s%s\n", name
, typestr
, comment
));
579 /* --------------------------------------------------------------------------------------------- */
582 smbfs_loaddir_helper (file_info
* finfo
, const char *mask
, void *entry
)
584 dir_entry
*new_entry
= (dir_entry
*) entry
;
585 time_t t
= finfo
->mtime
; /* the time is assumed to be passed as GMT */
589 #if 0 /* I want to see dot files */
590 if (finfo
->mode
& aHIDDEN
)
591 return; /* don't bother with hidden files, "~$" screws up mc */
594 new_entry
= smbfs_new_dir_entry (finfo
->name
);
596 new_entry
->my_stat
.st_size
= finfo
->size
;
597 new_entry
->my_stat
.st_mtime
= finfo
->mtime
;
598 new_entry
->my_stat
.st_atime
= finfo
->atime
;
599 new_entry
->my_stat
.st_ctime
= finfo
->ctime
;
600 new_entry
->my_stat
.st_uid
= finfo
->uid
;
601 new_entry
->my_stat
.st_gid
= finfo
->gid
;
603 new_entry
->my_stat
.st_mode
= /* rw-rw-rw */
604 S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
;
606 /* if (finfo->mode & aVOLID); nothing similar in real world */
607 if (finfo
->mode
& aDIR
)
608 new_entry
->my_stat
.st_mode
|= /* drwxrwxrwx */
609 S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
611 new_entry
->my_stat
.st_mode
|= S_IFREG
; /* if not dir, regular file? */
612 /* if (finfo->mode & aARCH); DOS archive */
613 /* if (finfo->mode & aHIDDEN); like a dot file? */
614 /* if (finfo->mode & aSYSTEM); like a kernel? */
615 if (finfo
->mode
& aRONLY
)
616 new_entry
->my_stat
.st_mode
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
617 new_entry
->my_stat
.st_mode
&= myumask
;
619 DEBUG (entry
? 3 : 6, (" %-30s%7.7s%8.0f %s",
620 CNV_LANG (finfo
->name
),
621 attrib_string (finfo
->mode
),
622 (double) finfo
->size
, asctime (LocalTime (&t
))));
625 /* --------------------------------------------------------------------------------------------- */
626 /* takes "/foo/bar/file" and gives malloced "\\foo\\bar\\file" */
629 smbfs_convert_path (const char *remote_file
, gboolean trailing_asterik
)
631 const char *p
, *my_remote
;
634 my_remote
= remote_file
;
635 if (strncmp (my_remote
, URL_HEADER
, HEADER_LEN
) == 0)
636 { /* if passed directly */
637 my_remote
+= HEADER_LEN
;
638 if (*my_remote
== '/') /* from server browsing */
640 p
= strchr (my_remote
, '/');
642 my_remote
= p
+ 1; /* advance to end of server name */
645 if (*my_remote
== '/')
646 my_remote
++; /* strip off leading '/' */
647 p
= strchr (my_remote
, '/');
649 my_remote
= p
; /* strip off share/service name */
650 /* create remote filename as understood by smb clientgen */
651 result
= g_strconcat (my_remote
, trailing_asterik
? "/*" : "", (char *) NULL
);
652 unix_to_dos (result
, /* inplace = */ 1); /* code page conversion */
653 str_replace (result
, '/', '\\');
657 /* --------------------------------------------------------------------------------------------- */
660 smbfs_srv_browsing_helper (const char *name
, uint32 m
, const char *comment
, void *state
)
662 dir_entry
*new_entry
= smbfs_new_dir_entry (name
);
667 /* show this as dir */
668 new_entry
->my_stat
.st_mode
=
669 (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
| S_IXOTH
) & myumask
;
671 DEBUG (3, ("\t%-16.16s %s\n", name
, comment
));
674 /* --------------------------------------------------------------------------------------------- */
677 smbfs_reconnect (smbfs_connection
* conn
, int *retries
)
680 DEBUG (3, ("RECONNECT\n"));
682 if (*(conn
->host
) == 0)
683 host
= g_strdup (conn
->cli
->desthost
); /* server browsing */
685 host
= g_strdup (conn
->host
);
687 cli_shutdown (conn
->cli
);
689 if (!(conn
->cli
= smbfs_do_connect (host
, conn
->service
)))
691 message (D_ERROR
, MSG_ERROR
, _("reconnect to %s failed"), conn
->host
);
696 if (++(*retries
) == 2)
701 /* --------------------------------------------------------------------------------------------- */
704 smbfs_send (struct cli_state
*cli
)
710 len
= smb_len (cli
->outbuf
) + 4;
712 while (nwritten
< len
)
714 ret
= write_socket (cli
->fd
, cli
->outbuf
+ nwritten
, len
- nwritten
);
727 /* --------------------------------------------------------------------------------------------- */
728 /****************************************************************************
729 See if server has cut us off by checking for EPIPE when writing.
730 Taken from cli_chkpath()
731 ****************************************************************************/
734 smbfs_chkpath (struct cli_state
*cli
, const char *path
, BOOL send_only
)
739 fstrcpy (path2
, path
);
740 unix_to_dos (path2
, 1);
741 trim_string (path2
, NULL
, "\\");
745 memset (cli
->outbuf
, '\0', smb_size
);
746 set_message (cli
->outbuf
, 0, 4 + strlen (path2
), True
);
747 SCVAL (cli
->outbuf
, smb_com
, SMBchkpth
);
748 SSVAL (cli
->outbuf
, smb_tid
, cli
->cnum
);
752 SSVAL (cli
->outbuf
, smb_pid
, cli
->pid
);
753 SSVAL (cli
->outbuf
, smb_uid
, cli
->vuid
);
754 SSVAL (cli
->outbuf
, smb_mid
, cli
->mid
);
755 if (cli
->protocol
> PROTOCOL_CORE
)
757 SCVAL (cli
->outbuf
, smb_flg
, 0x8);
758 SSVAL (cli
->outbuf
, smb_flg2
, 0x1);
761 p
= smb_buf (cli
->outbuf
);
765 if (!smbfs_send (cli
))
767 DEBUG (3, ("smbfs_chkpath: couldnt send\n"));
772 client_receive_smb (cli
->fd
, cli
->inbuf
, cli
->timeout
);
773 DEBUG (3, ("smbfs_chkpath: send only OK\n"));
774 return True
; /* just testing for EPIPE */
776 if (!client_receive_smb (cli
->fd
, cli
->inbuf
, cli
->timeout
))
778 DEBUG (3, ("smbfs_chkpath: receive error\n"));
781 if ((my_errno
= cli_error (cli
, NULL
, NULL
, NULL
)))
783 if (my_errno
== 20 || my_errno
== 13)
784 return True
; /* ignore if 'not a directory' error */
785 DEBUG (3, ("smbfs_chkpath: cli_error: %s\n", unix_error_string (my_errno
)));
792 /* --------------------------------------------------------------------------------------------- */
796 smbfs_fs (const char *text
)
798 const char *p
= text
;
801 while ((p
= strchr (p
, '/')) != NULL
)
807 return strlen (text
);
812 /* --------------------------------------------------------------------------------------------- */
815 smbfs_loaddir (opendir_info
* smbfs_info
)
817 uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
818 int servlen
= strlen (smbfs_info
->conn
->service
);
819 const char *info_dirname
= smbfs_info
->dirname
;
822 DEBUG (3, ("smbfs_loaddir: dirname:%s\n", info_dirname
));
823 first_direntry
= TRUE
;
827 DEBUG (3, ("smbfs_loaddir: new:'%s', cached:'%s'\n", info_dirname
, current_info
->dirname
));
828 /* if new desired dir is longer than cached in current_info */
829 if (smbfs_fs (info_dirname
) > smbfs_fs (current_info
->dirname
))
831 DEBUG (3, ("saving to previous_info\n"));
832 previous_info
= current_info
;
836 current_info
= smbfs_info
;
838 if (strcmp (info_dirname
, "/") == 0)
840 if (!strcmp (smbfs_info
->path
, URL_HEADER
))
842 DEBUG (6, ("smbfs_loaddir: browsing %s\n", IPC
));
843 /* browse for servers */
844 if (!cli_NetServerEnum
845 (smbfs_info
->conn
->cli
, smbfs_info
->conn
->domain
,
846 SV_TYPE_ALL
, smbfs_srv_browsing_helper
, NULL
))
849 current_server_info
= smbfs_info
;
850 smbfs_info
->server_list
= TRUE
;
854 /* browse for shares */
855 if (cli_RNetShareEnum (smbfs_info
->conn
->cli
, smbfs_browsing_helper
, NULL
) < 1)
858 current_share_info
= smbfs_info
;
863 /* do regular directory listing */
864 if (strncmp (smbfs_info
->conn
->service
, info_dirname
+ 1, servlen
) == 0)
866 /* strip share name from dir */
867 my_dirname
= g_strdup (info_dirname
+ servlen
);
869 my_dirname
= free_after (smbfs_convert_path (my_dirname
, TRUE
), my_dirname
);
872 my_dirname
= smbfs_convert_path (info_dirname
, TRUE
);
874 DEBUG (6, ("smbfs_loaddir: service: %s\n", smbfs_info
->conn
->service
));
875 DEBUG (6, ("smbfs_loaddir: cli->share: %s\n", smbfs_info
->conn
->cli
->share
));
876 DEBUG (6, ("smbfs_loaddir: calling cli_list with mask %s\n", my_dirname
));
877 /* do file listing: cli_list returns number of files */
878 if (cli_list (smbfs_info
->conn
->cli
, my_dirname
, attribute
, smbfs_loaddir_helper
, NULL
) < 0)
880 /* cli_list returns -1 if directory empty or cannot read socket */
881 my_errno
= cli_error (smbfs_info
->conn
->cli
, NULL
, &err
, NULL
);
885 if (*(my_dirname
) == 0)
886 smbfs_info
->dirname
= smbfs_info
->conn
->service
;
891 /* current_info->parent = smbfs_info->dirname; */
893 smbfs_info
->current
= smbfs_info
->entries
;
894 return 1; /* 1 = ok */
897 /* --------------------------------------------------------------------------------------------- */
899 #ifdef SMBFS_FREE_DIR
901 smbfs_free_dir (dir_entry
* de
)
906 smbfs_free_dir (de
->next
);
912 /* --------------------------------------------------------------------------------------------- */
913 /* The readdir routine loads the complete directory */
914 /* It's too slow to ask the server each time */
915 /* It now also sends the complete lstat information for each file */
918 smbfs_readdir (void *info
)
920 static union vfs_dirent smbfs_readdir_data
;
921 static char *const dirent_dest
= smbfs_readdir_data
.dent
.d_name
;
922 opendir_info
*smbfs_info
= (opendir_info
*) info
;
924 DEBUG (4, ("smbfs_readdir(%s)\n", smbfs_info
->dirname
));
926 if (!smbfs_info
->entries
)
927 if (!smbfs_loaddir (smbfs_info
))
930 if (smbfs_info
->current
== 0)
931 { /* reached end of dir entries */
932 DEBUG (3, ("smbfs_readdir: smbfs_info->current = 0\n"));
933 #ifdef SMBFS_FREE_DIR
934 smbfs_free_dir (smbfs_info
->entries
);
935 smbfs_info
->entries
= 0;
939 g_strlcpy (dirent_dest
, smbfs_info
->current
->text
, MC_MAXPATHLEN
);
940 smbfs_info
->current
= smbfs_info
->current
->next
;
942 compute_namelen (&smbfs_readdir_data
.dent
);
944 return &smbfs_readdir_data
;
947 /* --------------------------------------------------------------------------------------------- */
950 smbfs_closedir (void *info
)
952 opendir_info
*smbfs_info
= (opendir_info
*) info
;
953 /* dir_entry *p, *q; */
955 DEBUG (3, ("smbfs_closedir(%s)\n", smbfs_info
->dirname
));
958 /* for (p = smbfs_info->entries; p;){
968 /* --------------------------------------------------------------------------------------------- */
971 smbfs_chmod (const vfs_path_t
* vpath
, mode_t mode
)
973 const vfs_path_element_t
*path_element
;
975 path_element
= vfs_path_get_by_index (vpath
, -1);
976 DEBUG (3, ("smbfs_chmod(path:%s, mode:%d)\n", path_element
->path
, (int) mode
));
977 /* my_errno = EOPNOTSUPP;
978 return -1; *//* cannot chmod on smb filesystem */
979 return 0; /* make mc happy */
982 /* --------------------------------------------------------------------------------------------- */
985 smbfs_chown (const vfs_path_t
* vpath
, uid_t owner
, gid_t group
)
987 const vfs_path_element_t
*path_element
;
989 path_element
= vfs_path_get_by_index (vpath
, -1);
990 DEBUG (3, ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path_element
->path
, owner
, group
));
991 my_errno
= EOPNOTSUPP
; /* ready for your labotomy? */
995 /* --------------------------------------------------------------------------------------------- */
998 smbfs_utime (const vfs_path_t
* vpath
, struct utimbuf
*times
)
1000 const vfs_path_element_t
*path_element
;
1004 path_element
= vfs_path_get_by_index (vpath
, -1);
1005 DEBUG (3, ("smbfs_utime(path:%s)\n", path_element
->path
));
1006 my_errno
= EOPNOTSUPP
;
1010 /* --------------------------------------------------------------------------------------------- */
1013 smbfs_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
)
1015 const vfs_path_element_t
*path_element
;
1017 path_element
= vfs_path_get_by_index (vpath
, -1);
1018 DEBUG (3, ("smbfs_readlink(path:%s, buf:%s, size:%zu)\n", path_element
->path
, buf
, size
));
1019 my_errno
= EOPNOTSUPP
;
1020 return -1; /* no symlinks on smb filesystem? */
1023 /* --------------------------------------------------------------------------------------------- */
1026 smbfs_symlink (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
)
1028 const vfs_path_element_t
*path_element1
;
1029 const vfs_path_element_t
*path_element2
;
1031 path_element1
= vfs_path_get_by_index (vpath1
, -1);
1032 path_element2
= vfs_path_get_by_index (vpath2
, -1);
1033 DEBUG (3, ("smbfs_symlink(n1:%s, n2:%s)\n", path_element1
->path
, path_element2
->path
));
1034 my_errno
= EOPNOTSUPP
;
1035 return -1; /* no symlinks on smb filesystem? */
1038 /* --------------------------------------------------------------------------------------------- */
1039 /*****************************************************
1040 return a connection to a SMB server
1041 current_bucket needs to be set before calling
1042 *******************************************************/
1044 static struct cli_state
*
1045 smbfs_do_connect (const char *server
, char *share
)
1047 struct cli_state
*c
;
1048 struct nmb_name called
, calling
;
1051 DEBUG (3, ("smbfs_do_connect(%s, %s)\n", server
, share
));
1055 share
= strchr (server
, '\\');
1062 make_nmb_name (&calling
, global_myname
, 0x0);
1063 make_nmb_name (&called
, server
, current_bucket
->name_type
);
1068 ip
= (current_bucket
->have_ip
) ? current_bucket
->dest_ip
: ipzero
;
1070 /* have to open a new connection */
1071 if (!(c
= cli_initialise (NULL
)))
1077 pwd_init (&(c
->pwd
)); /* should be moved into cli_initialise()? */
1078 pwd_set_cleartext (&(c
->pwd
), current_bucket
->password
);
1080 if ((cli_set_port (c
, current_bucket
->port
) == 0) || !cli_connect (c
, server
, &ip
))
1082 DEBUG (1, ("Connection to %s failed\n", server
));
1086 if (!cli_session_request (c
, &calling
, &called
))
1088 my_errno
= cli_error (c
, NULL
, &err
, NULL
);
1089 DEBUG (1, ("session request to %s failed\n", called
.name
));
1091 if (strcmp (called
.name
, "*SMBSERVER"))
1093 make_nmb_name (&called
, "*SMBSERVER", 0x20);
1099 DEBUG (3, (" session request ok\n"));
1101 if (!cli_negprot (c
))
1103 DEBUG (1, ("protocol negotiation failed\n"));
1107 if (!cli_session_setup (c
, current_bucket
->user
,
1108 current_bucket
->password
, strlen (current_bucket
->password
),
1109 current_bucket
->password
, strlen (current_bucket
->password
),
1110 current_bucket
->domain
))
1112 DEBUG (1, ("session setup failed: %s\n", cli_errstr (c
)));
1113 smbfs_auth_remove (server
, share
);
1117 if (*c
->server_domain
|| *c
->server_os
|| *c
->server_type
)
1118 DEBUG (5, ("Domain=[%s] OS=[%s] Server=[%s]\n",
1119 c
->server_domain
, c
->server_os
, c
->server_type
));
1121 DEBUG (3, (" session setup ok\n"));
1123 if (!cli_send_tconX (c
, share
, "?????",
1124 current_bucket
->password
, strlen (current_bucket
->password
) + 1))
1126 DEBUG (1, ("%s: tree connect failed: %s\n", share
, cli_errstr (c
)));
1130 DEBUG (3, (" tconx ok\n"));
1136 my_errno
= cli_error (c
, NULL
, &err
, NULL
);
1142 /* --------------------------------------------------------------------------------------------- */
1145 smbfs_get_master_browser (char **host
)
1147 static char so_broadcast
[] = "SO_BROADCAST";
1149 struct in_addr
*ip_list
, bcast_addr
;
1151 /* does port = 137 for win95 master browser? */
1152 int fd
= open_socket_in (SOCK_DGRAM
, 0, 3,
1153 interpret_addr (lp_socket_address ()), True
);
1156 set_socket_options (fd
, so_broadcast
);
1157 ip_list
= iface_bcast (ipzero
);
1158 bcast_addr
= *ip_list
;
1159 if ((ip_list
= name_query (fd
, "\01\02__MSBROWSE__\02", 1, True
,
1160 True
, bcast_addr
, &count
, NULL
)))
1164 /* just return first master browser */
1165 *host
= g_strdup (inet_ntoa (ip_list
[0]));
1171 /* --------------------------------------------------------------------------------------------- */
1174 smbfs_free_bucket (smbfs_connection
* bucket
)
1176 g_free (bucket
->host
);
1177 g_free (bucket
->service
);
1178 g_free (bucket
->domain
);
1179 g_free (bucket
->user
);
1180 wipe_password (bucket
->password
);
1181 g_free (bucket
->home
);
1182 memset (bucket
, 0, sizeof (smbfs_connection
));
1185 /* --------------------------------------------------------------------------------------------- */
1187 static smbfs_connection
*
1188 smbfs_get_free_bucket (void)
1192 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++)
1193 if (!smbfs_connections
[i
].cli
)
1194 return &smbfs_connections
[i
];
1196 { /* search for most dormant connection */
1197 int oldest
= 0; /* index */
1198 time_t oldest_time
= smbfs_connections
[0].last_use
;
1199 for (i
= 1; i
< SMBFS_MAX_CONNECTIONS
; i
++)
1201 if (smbfs_connections
[i
].last_use
< oldest_time
)
1203 oldest_time
= smbfs_connections
[i
].last_use
;
1207 cli_shutdown (smbfs_connections
[oldest
].cli
);
1208 smbfs_free_bucket (&smbfs_connections
[oldest
]);
1209 return &smbfs_connections
[oldest
];
1212 /* This can't happend, since we have checked for max connections before */
1213 vfs_die ("Internal error: smbfs_get_free_bucket");
1214 return 0; /* shut up, stupid gcc */
1217 /* --------------------------------------------------------------------------------------------- */
1218 /* This routine keeps track of open connections */
1219 /* Returns a connected socket to host */
1221 static smbfs_connection
*
1222 smbfs_open_link (char *host
, char *path
, const char *user
, int *port
, char *this_pass
)
1225 smbfs_connection
*bucket
;
1227 struct in_addr
*dest_ip
= NULL
;
1229 DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host
, path
));
1231 if (strcmp (host
, path
) == 0) /* if host & path are same: */
1232 pstrcpy (service
, IPC
); /* setup for browse */
1234 { /* get share name from path, path starts with server name */
1236 if ((p
= strchr (path
, '/'))) /* get share aka */
1237 pstrcpy (service
, ++p
); /* service name from path */
1239 pstrcpy (service
, "");
1240 /* now check for trailing directory/filenames */
1241 p
= strchr (service
, '/');
1243 *p
= 0; /* cut off dir/files: sharename only */
1245 pstrcpy (service
, IPC
); /* setup for browse */
1246 DEBUG (6, ("smbfs_open_link: service from path:%s\n", service
));
1250 user
= username
; /* global from getenv */
1252 /* Is the link actually open? */
1253 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++)
1255 if (!smbfs_connections
[i
].cli
)
1257 if ((strcmp (host
, smbfs_connections
[i
].host
) == 0) &&
1258 (strcmp (user
, smbfs_connections
[i
].user
) == 0) &&
1259 (strcmp (service
, smbfs_connections
[i
].service
) == 0))
1262 BOOL inshare
= (*host
!= 0 && *path
!= 0 && strchr (path
, '/'));
1263 /* check if this connection has died */
1264 while (!smbfs_chkpath (smbfs_connections
[i
].cli
, "\\", !inshare
))
1266 if (!smbfs_reconnect (&smbfs_connections
[i
], &retries
))
1269 DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i
));
1270 current_bucket
= &smbfs_connections
[i
];
1271 smbfs_connections
[i
].last_use
= time (NULL
);
1272 return &smbfs_connections
[i
];
1274 /* connection not found, find if we have ip for new connection */
1275 if (strcmp (host
, smbfs_connections
[i
].host
) == 0)
1276 dest_ip
= &smbfs_connections
[i
].cli
->dest_ip
;
1279 /* make new connection */
1280 bucket
= smbfs_get_free_bucket ();
1281 bucket
->name_type
= 0x20;
1283 bucket
->port
= *port
;
1284 bucket
->have_ip
= False
;
1287 bucket
->have_ip
= True
;
1288 bucket
->dest_ip
= *dest_ip
;
1290 current_bucket
= bucket
;
1292 bucket
->user
= g_strdup (user
);
1293 bucket
->service
= g_strdup (service
);
1296 { /* if blank host name, browse for servers */
1297 if (!smbfs_get_master_browser (&host
)) /* set host to ip of master browser */
1298 return 0; /* could not find master browser? */
1300 bucket
->host
= g_strdup (""); /* blank host means master browser */
1303 bucket
->host
= g_strdup (host
);
1305 if (!smbfs_bucket_set_authinfo (bucket
, 0, /* domain currently not used */
1306 user
, this_pass
, 1))
1309 /* connect to share */
1310 while (!(bucket
->cli
= smbfs_do_connect (host
, service
)))
1313 if (my_errno
!= EPERM
)
1315 message (D_ERROR
, MSG_ERROR
, _("Authentication failed"));
1317 /* authentication failed, try again */
1318 smbfs_auth_remove (bucket
->host
, bucket
->service
);
1319 if (!smbfs_bucket_set_authinfo (bucket
, bucket
->domain
, bucket
->user
, 0, 0))
1324 smbfs_open_connections
++;
1325 DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n", smbfs_open_connections
));
1329 /* --------------------------------------------------------------------------------------------- */
1332 smbfs_get_path (smbfs_connection
** sc
, const vfs_path_t
* vpath
)
1334 char *remote_path
= NULL
;
1335 vfs_path_element_t
*url
;
1336 const vfs_path_element_t
*path_element
;
1339 path_element
= vfs_path_get_by_index (vpath
, -1);
1340 path
= path_element
->path
;
1342 DEBUG (3, ("smbfs_get_path(%s)\n", path
));
1344 if (path_element
->class != &vfs_smbfs_ops
)
1347 while (*path
== '/') /* '/' leading server name */
1348 path
++; /* probably came from server browsing */
1350 url
= vfs_url_split (path
, SMB_PORT
, URL_FLAGS_NONE
);
1354 *sc
= smbfs_open_link (url
->host
, url
->path
, url
->user
, &url
->port
, url
->password
);
1355 wipe_password (url
->password
);
1358 remote_path
= g_strdup (url
->path
);
1360 vfs_path_element_free (url
);
1363 if (remote_path
== NULL
)
1366 /* NOTE: tildes are deprecated. See ftpfs.c */
1368 int f
= strcmp (remote_path
, "/~") ? 0 : 1;
1370 if (f
!= 0 || strncmp (remote_path
, "/~/", 3) == 0)
1374 s
= mc_build_filename ((*sc
)->home
, remote_path
+ 3 - f
, NULL
);
1375 g_free (remote_path
);
1383 /* --------------------------------------------------------------------------------------------- */
1387 is_error (int result
, int errno_num
)
1389 if (!(result
== -1))
1390 return my_errno
= 0;
1392 my_errno
= errno_num
;
1397 /* --------------------------------------------------------------------------------------------- */
1400 smbfs_opendir (const vfs_path_t
* vpath
)
1402 opendir_info
*smbfs_info
;
1403 smbfs_connection
*sc
;
1405 const vfs_path_element_t
*path_element
;
1407 path_element
= vfs_path_get_by_index (vpath
, -1);
1408 DEBUG (3, ("smbfs_opendir(dirname:%s)\n", path_element
->path
));
1410 if (!(remote_dir
= smbfs_get_path (&sc
, vpath
)))
1413 /* FIXME: where freed? */
1414 smbfs_info
= g_new (opendir_info
, 1);
1415 smbfs_info
->server_list
= FALSE
;
1416 smbfs_info
->path
= g_strdup (path_element
->path
); /* keep original */
1417 smbfs_info
->dirname
= remote_dir
;
1418 smbfs_info
->conn
= sc
;
1419 smbfs_info
->entries
= 0;
1420 smbfs_info
->current
= 0;
1425 /* --------------------------------------------------------------------------------------------- */
1428 smbfs_fake_server_stat (const char *server_url
, const char *path
, struct stat
*buf
)
1435 if ((p
= strrchr (path
, '/')))
1436 path
= p
+ 1; /* advance until last '/' */
1438 if (!current_info
->entries
)
1440 if (!smbfs_loaddir (current_info
)) /* browse host */
1444 if (current_info
->server_list
== True
)
1446 dentry
= current_info
->entries
;
1447 DEBUG (4, ("fake stat for SERVER \"%s\"\n", path
));
1450 if (strcmp (dentry
->text
, path
) == 0)
1452 DEBUG (4, ("smbfs_fake_server_stat: %s:%4o\n",
1453 dentry
->text
, (int) dentry
->my_stat
.st_mode
));
1454 memcpy (buf
, &dentry
->my_stat
, sizeof (struct stat
));
1457 dentry
= dentry
->next
;
1464 /* --------------------------------------------------------------------------------------------- */
1467 smbfs_fake_share_stat (const char *server_url
, const char *path
, struct stat
*buf
)
1470 if (strlen (path
) < strlen (server_url
))
1473 if (!current_share_info
)
1474 { /* Server was not stat()ed */
1475 /* Make sure there is such share at server */
1476 smbfs_connection
*sc
;
1478 vfs_path_t
*vpath
= vfs_path_from_str (path
);
1480 p
= smbfs_get_path (&sc
, vpath
);
1481 vfs_path_free (vpath
);
1486 memset (buf
, 0, sizeof (*buf
));
1487 /* show this as dir */
1489 (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
| S_IXOTH
) & myumask
;
1495 path
+= strlen (server_url
); /* we only want share name */
1498 if (*path
== '/') /* '/' leading server name */
1499 path
++; /* probably came from server browsing */
1501 if (!current_share_info
->entries
)
1503 if (!smbfs_loaddir (current_share_info
)) /* browse host */
1506 dentry
= current_share_info
->entries
;
1507 DEBUG (3, ("smbfs_fake_share_stat: %s on %s\n", path
, server_url
));
1510 if (strcmp (dentry
->text
, path
) == 0)
1512 DEBUG (6, ("smbfs_fake_share_stat: %s:%4o\n",
1513 dentry
->text
, (int) dentry
->my_stat
.st_mode
));
1514 memcpy (buf
, &dentry
->my_stat
, sizeof (struct stat
));
1517 dentry
= dentry
->next
;
1523 /* --------------------------------------------------------------------------------------------- */
1524 /* stat a single file */
1527 smbfs_get_remote_stat (smbfs_connection
* sc
, const char *path
, struct stat
*buf
)
1529 uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
1532 DEBUG (3, ("smbfs_get_remote_stat(): mypath:%s\n", path
));
1534 mypath
= smbfs_convert_path (path
, FALSE
);
1536 #if 0 /* single_entry is never free()d now. And only my_stat is used */
1537 single_entry
= g_new (dir_entry
, 1);
1539 single_entry
->text
= dos_to_unix (g_strdup (finfo
->name
), 1);
1541 single_entry
->next
= 0;
1544 single_entry
= g_new0 (dir_entry
, 1);
1546 if (cli_list (sc
->cli
, mypath
, attribute
, smbfs_loaddir_helper
, single_entry
) < 1)
1550 return -1; /* cli_list returns number of files */
1553 memcpy (buf
, &single_entry
->my_stat
, sizeof (struct stat
));
1555 /* don't free here, use for smbfs_fstat() */
1556 /* g_free(single_entry->text);
1557 g_free(single_entry); */
1562 /* --------------------------------------------------------------------------------------------- */
1565 smbfs_search_dir_entry (dir_entry
* dentry
, const char *text
, struct stat
*buf
)
1569 if (strcmp (text
, dentry
->text
) == 0)
1571 memcpy (buf
, &dentry
->my_stat
, sizeof (struct stat
));
1572 memcpy (&single_entry
->my_stat
, &dentry
->my_stat
, sizeof (struct stat
));
1575 dentry
= dentry
->next
;
1580 /* --------------------------------------------------------------------------------------------- */
1583 smbfs_get_stat_info (smbfs_connection
* sc
, const char *path
, struct stat
*buf
)
1587 dir_entry
*dentry
= current_info
->entries
;
1589 const char *mypath
= path
;
1591 mypath
++; /* cut off leading '/' */
1592 if ((p
= strrchr (mypath
, '/')))
1593 mypath
= p
+ 1; /* advance until last file/dir name */
1594 DEBUG (3, ("smbfs_get_stat_info: mypath:%s, current_info->dirname:%s\n",
1595 mypath
, current_info
->dirname
));
1599 DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1600 current_info
->dirname
, path
));
1604 if (!single_entry
) /* when found, this will be written too */
1605 single_entry
= g_new (dir_entry
, 1);
1606 if (smbfs_search_dir_entry (current_info
->entries
, mypath
, buf
) == 0)
1610 /* now try to identify mypath as PARENT dir */
1614 mdp
= mydir
= g_strdup (current_info
->dirname
);
1615 if ((p
= strrchr (mydir
, '/')))
1616 *p
= 0; /* advance util last '/' */
1617 if ((p
= strrchr (mydir
, '/')))
1618 mydir
= p
+ 1; /* advance util last '/' */
1619 if (strcmp (mydir
, mypath
) == 0)
1620 { /* fake a stat for ".." */
1621 memset (buf
, 0, sizeof (struct stat
));
1622 buf
->st_mode
= (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
) & myumask
;
1623 memcpy (&single_entry
->my_stat
, buf
, sizeof (struct stat
));
1625 DEBUG (1, (" PARENT:found in %s\n", current_info
->dirname
));
1630 /* now try to identify as CURRENT dir? */
1632 char *dnp
= current_info
->dirname
;
1633 DEBUG (6, ("smbfs_get_stat_info: is %s current dir? this dir is: %s\n",
1634 mypath
, current_info
->dirname
));
1641 if (strcmp (mypath
, dnp
) == 0)
1643 memset (buf
, 0, sizeof (struct stat
));
1644 buf
->st_mode
= (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
) & myumask
;
1645 memcpy (&single_entry
->my_stat
, buf
, sizeof (struct stat
));
1646 DEBUG (1, (" CURRENT:found in %s\n", current_info
->dirname
));
1650 DEBUG (3, ("'%s' not found in current_info '%s'\n", path
, current_info
->dirname
));
1651 /* try to find this in the PREVIOUS listing */
1654 if (smbfs_search_dir_entry (previous_info
->entries
, mypath
, buf
) == 0)
1656 DEBUG (3, ("'%s' not found in previous_info '%s'\n", path
, previous_info
->dirname
));
1658 /* try to find this in the SHARE listing */
1659 if (current_share_info
)
1661 if (smbfs_search_dir_entry (current_share_info
->entries
, mypath
, buf
) == 0)
1663 DEBUG (3, ("'%s' not found in share_info '%s'\n", path
, current_share_info
->dirname
));
1665 /* try to find this in the SERVER listing */
1666 if (current_server_info
)
1668 if (smbfs_search_dir_entry (current_server_info
->entries
, mypath
, buf
) == 0)
1670 DEBUG (3, ("'%s' not found in server_info '%s'\n", path
, current_server_info
->dirname
));
1672 /* nothing found. get stat file info from server */
1673 return smbfs_get_remote_stat (sc
, path
, buf
);
1676 /* --------------------------------------------------------------------------------------------- */
1679 smbfs_chdir (const vfs_path_t
* vpath
)
1682 smbfs_connection
*sc
;
1683 const vfs_path_element_t
*path_element
;
1685 path_element
= vfs_path_get_by_index (vpath
, -1);
1686 DEBUG (3, ("smbfs_chdir(path:%s)\n", path_element
->path
));
1687 if (!(remote_dir
= smbfs_get_path (&sc
, vpath
)))
1689 g_free (remote_dir
);
1694 /* --------------------------------------------------------------------------------------------- */
1697 smbfs_loaddir_by_name (const vfs_path_t
* vpath
)
1701 const vfs_path_element_t
*path_element
;
1703 path_element
= vfs_path_get_by_index (vpath
, -1);
1704 mypath
= g_strdup (path_element
->path
);
1705 p
= strrchr (mypath
, '/');
1709 DEBUG (6, ("smbfs_loaddir_by_name(%s)\n", mypath
));
1710 smbfs_chdir (vpath
);
1711 info
= smbfs_opendir (vpath
);
1715 smbfs_readdir (info
);
1716 smbfs_loaddir (info
);
1720 /* --------------------------------------------------------------------------------------------- */
1723 smbfs_stat (const vfs_path_t
* vpath
, struct stat
*buf
)
1725 smbfs_connection
*sc
;
1727 char *service
, *pp
, *at
;
1729 const vfs_path_element_t
*path_element
;
1731 path_element
= vfs_path_get_by_index (vpath
, -1);
1732 DEBUG (3, ("smbfs_stat(path:%s)\n", path_element
->path
));
1736 DEBUG (1, ("current_info = NULL: "));
1737 if (smbfs_loaddir_by_name (vpath
) < 0)
1741 /* check if stating server */
1742 p
= path_element
->path
;
1743 if (path_element
->class != &vfs_smbfs_ops
)
1746 while (*p
== '/') /* '/' leading server name */
1747 p
++; /* probably came from server browsing */
1749 pp
= strchr (p
, '/'); /* advance past next '/' */
1750 at
= strchr (p
, '@');
1751 pstrcpy (server_url
, URL_HEADER
);
1754 char *z
= &(server_url
[sizeof (server_url
) - 1]);
1757 at
= &(server_url
[HEADER_LEN
]) + (at
- p
+ 1);
1760 at
= &(server_url
[HEADER_LEN
]);
1765 pstrcat (server_url
, current_bucket
->host
);
1769 if (!current_info
->server_list
)
1771 if (smbfs_loaddir_by_name (vpath
) < 0)
1774 return smbfs_fake_server_stat (server_url
, path_element
->path
, buf
);
1777 if (!strchr (++pp
, '/'))
1779 return smbfs_fake_share_stat (server_url
, path_element
->path
, buf
);
1782 /* stating inside share at this point */
1783 if (!(service
= smbfs_get_path (&sc
, vpath
))) /* connects if necessary */
1786 int hostlen
= strlen (current_bucket
->host
);
1787 char *ppp
= service
+ strlen (service
) - hostlen
;
1788 char *sp
= server_url
+ strlen (server_url
) - hostlen
;
1790 if (strcmp (sp
, ppp
) == 0)
1792 /* make server name appear as directory */
1793 DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1794 memset (buf
, 0, sizeof (struct stat
));
1795 buf
->st_mode
= (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
) & myumask
;
1800 /* check if current_info is in share requested */
1802 pp
= strchr (p
, '/');
1805 p
= ++pp
; /* advance past server name */
1806 pp
= strchr (p
, '/');
1809 *pp
= 0; /* cut off everthing after service name */
1811 p
= IPC
; /* browsing for services */
1812 pp
= current_info
->dirname
;
1815 if (strncmp (p
, pp
, strlen (p
)) != 0)
1817 DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p
, pp
));
1818 if (smbfs_loaddir_by_name (vpath
) < 0)
1823 DEBUG (6, ("loaded dir: '%s'\n", current_info
->dirname
));
1826 /* stat dirs & files under shares now */
1827 return smbfs_get_stat_info (sc
, path_element
->path
, buf
);
1830 /* --------------------------------------------------------------------------------------------- */
1833 smbfs_lseek (void *data
, off_t offset
, int whence
)
1835 smbfs_handle
*info
= (smbfs_handle
*) data
;
1839 ("smbfs_lseek(info->nread => %d, offset => %d, whence => %d) \n",
1840 (int) info
->nread
, (int) offset
, whence
));
1845 info
->nread
= offset
;
1848 info
->nread
+= offset
;
1851 if (!cli_qfileinfo (info
->cli
, info
->fnum
,
1852 NULL
, &size
, NULL
, NULL
, NULL
,
1854 !cli_getattrE (info
->cli
, info
->fnum
, NULL
, &size
, NULL
, NULL
, NULL
))
1859 info
->nread
= size
+ offset
;
1866 /* --------------------------------------------------------------------------------------------- */
1869 smbfs_mknod (const vfs_path_t
* vpath
, mode_t mode
, dev_t dev
)
1871 const vfs_path_element_t
*path_element
;
1873 path_element
= vfs_path_get_by_index (vpath
, -1);
1875 ("smbfs_mknod(path:%s, mode:%d, dev:%u)\n", path_element
->path
, mode
,
1876 (unsigned int) dev
));
1877 my_errno
= EOPNOTSUPP
;
1881 /* --------------------------------------------------------------------------------------------- */
1884 smbfs_mkdir (const vfs_path_t
* vpath
, mode_t mode
)
1886 smbfs_connection
*sc
;
1889 const vfs_path_element_t
*path_element
;
1891 path_element
= vfs_path_get_by_index (vpath
, -1);
1892 DEBUG (3, ("smbfs_mkdir(path:%s, mode:%d)\n", path_element
->path
, (int) mode
));
1893 if ((remote_file
= smbfs_get_path (&sc
, vpath
)) == 0)
1895 g_free (remote_file
);
1896 cpath
= smbfs_convert_path (path_element
->path
, FALSE
);
1898 if (!cli_mkdir (sc
->cli
, cpath
))
1900 my_errno
= cli_error (sc
->cli
, NULL
, &err
, NULL
);
1901 message (D_ERROR
, MSG_ERROR
, _("Error %s creating directory %s"),
1902 cli_errstr (sc
->cli
), CNV_LANG (cpath
));
1910 /* --------------------------------------------------------------------------------------------- */
1913 smbfs_rmdir (const vfs_path_t
* vpath
)
1915 smbfs_connection
*sc
;
1918 const vfs_path_element_t
*path_element
;
1920 path_element
= vfs_path_get_by_index (vpath
, -1);
1921 DEBUG (3, ("smbfs_rmdir(path:%s)\n", path_element
->path
));
1922 if ((remote_file
= smbfs_get_path (&sc
, vpath
)) == 0)
1924 g_free (remote_file
);
1925 cpath
= smbfs_convert_path (path_element
->path
, FALSE
);
1927 if (!cli_rmdir (sc
->cli
, cpath
))
1929 my_errno
= cli_error (sc
->cli
, NULL
, &err
, NULL
);
1930 message (D_ERROR
, MSG_ERROR
, _("Error %s removing directory %s"),
1931 cli_errstr (sc
->cli
), CNV_LANG (cpath
));
1940 /* --------------------------------------------------------------------------------------------- */
1943 smbfs_link (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
)
1945 const vfs_path_element_t
*path_element1
;
1946 const vfs_path_element_t
*path_element2
;
1948 path_element1
= vfs_path_get_by_index (vpath1
, -1);
1949 path_element2
= vfs_path_get_by_index (vpath2
, -1);
1950 DEBUG (3, ("smbfs_link(p1:%s, p2:%s)\n", path_element1
->path
, path_element2
->path
));
1951 my_errno
= EOPNOTSUPP
;
1955 /* --------------------------------------------------------------------------------------------- */
1958 smbfs_free (vfsid id
)
1960 DEBUG (3, ("smbfs_free(%p)\n", id
));
1961 smbfs_auth_free_all ();
1964 /* --------------------------------------------------------------------------------------------- */
1965 /* Gives up on a socket and reopens the connection, the child own the socket
1970 smbfs_forget (const vfs_path_t
* vpath
)
1972 const vfs_path_element_t
*path_element
;
1973 vfs_path_element_t
*p
;
1976 path_element
= vfs_path_get_by_index (vpath
, -1);
1977 if (path_element
->class != &vfs_smbfs_ops
)
1980 path
= path_element
->path
;
1982 DEBUG (3, ("smbfs_forget(path:%s)\n", path
));
1984 while (*path
== '/') /* '/' leading server name */
1985 path
++; /* probably came from server browsing */
1987 p
= vfs_url_split (path
, SMB_PORT
, URL_FLAGS_NONE
);
1992 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++)
1994 if (smbfs_connections
[i
].cli
1995 && (strcmp (p
->host
, smbfs_connections
[i
].host
) == 0)
1996 && (strcmp (p
->user
, smbfs_connections
[i
].user
) == 0)
1997 && (p
->port
== smbfs_connections
[i
].port
))
2000 /* close socket: the child owns it now */
2001 cli_shutdown (smbfs_connections
[i
].cli
);
2003 /* reopen the connection */
2004 smbfs_connections
[i
].cli
= smbfs_do_connect (p
->host
, smbfs_connections
[i
].service
);
2008 vfs_path_element_free (p
);
2012 /* --------------------------------------------------------------------------------------------- */
2015 smbfs_setctl (const vfs_path_t
* vpath
, int ctlop
, void *arg
)
2017 const vfs_path_element_t
*path_element
;
2021 path_element
= vfs_path_get_by_index (vpath
, -1);
2022 DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path_element
->path
, ctlop
));
2025 case VFS_SETCTL_FORGET
:
2026 smbfs_forget (vpath
);
2028 case VFS_SETCTL_LOGFILE
:
2029 smbfs_set_debugf ((const char *) arg
);
2035 /* --------------------------------------------------------------------------------------------- */
2037 static smbfs_handle
*
2038 smbfs_open_readwrite (smbfs_handle
* remote_handle
, char *rname
, int flags
, mode_t mode
)
2044 if (flags
& O_TRUNC
) /* if it exists truncate to zero */
2045 DEBUG (3, ("smbfs_open: O_TRUNC\n"));
2047 remote_handle
->fnum
=
2048 #if 1 /* Don't play with flags, it is cli_open() headache */
2049 cli_open (remote_handle
->cli
, rname
, flags
, DENY_NONE
);
2050 #else /* What's a reasons to has this code ? */
2051 cli_open (remote_handle
->cli
, rname
, ((flags
& O_CREAT
)
2053 (O_WRONLY
| O_APPEND
))) ?
2054 flags
: O_RDONLY
, DENY_NONE
);
2056 if (remote_handle
->fnum
== -1)
2058 message (D_ERROR
, MSG_ERROR
, _("%s opening remote file %s"),
2059 cli_errstr (remote_handle
->cli
), CNV_LANG (rname
));
2060 DEBUG (1, ("smbfs_open(rname:%s) error:%s\n", rname
, cli_errstr (remote_handle
->cli
)));
2061 my_errno
= cli_error (remote_handle
->cli
, NULL
, &err
, NULL
);
2065 if (flags
& O_CREAT
)
2066 return remote_handle
;
2068 if (!cli_qfileinfo (remote_handle
->cli
, remote_handle
->fnum
,
2069 &remote_handle
->attr
, &size
, NULL
, NULL
, NULL
, NULL
,
2071 && !cli_getattrE (remote_handle
->cli
, remote_handle
->fnum
,
2072 &remote_handle
->attr
, &size
, NULL
, NULL
, NULL
))
2074 message (D_ERROR
, MSG_ERROR
, "getattrib: %s", cli_errstr (remote_handle
->cli
));
2075 DEBUG (1, ("smbfs_open(rname:%s) getattrib:%s\n", rname
, cli_errstr (remote_handle
->cli
)));
2076 my_errno
= cli_error (remote_handle
->cli
, NULL
, &err
, NULL
);
2077 cli_close (remote_handle
->cli
, remote_handle
->fnum
);
2081 if ((flags
== (O_WRONLY
| O_APPEND
)) /* file.c:copy_file_file() -> do_append */
2082 && smbfs_lseek (remote_handle
, 0, SEEK_END
) == -1)
2084 cli_close (remote_handle
->cli
, remote_handle
->fnum
);
2088 return remote_handle
;
2091 /* --------------------------------------------------------------------------------------------- */
2094 smbfs_open (const vfs_path_t
* vpath
, int flags
, mode_t mode
)
2098 smbfs_connection
*sc
;
2099 smbfs_handle
*remote_handle
;
2100 const vfs_path_element_t
*path_element
;
2102 path_element
= vfs_path_get_by_index (vpath
, -1);
2103 DEBUG (3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", path_element
->path
, flags
, mode
));
2105 if (!(remote_file
= smbfs_get_path (&sc
, vpath
)))
2108 remote_file
= free_after (smbfs_convert_path (remote_file
, FALSE
), remote_file
);
2110 remote_handle
= g_new (smbfs_handle
, 2);
2111 remote_handle
->cli
= sc
->cli
;
2112 remote_handle
->nread
= 0;
2114 ret
= smbfs_open_readwrite (remote_handle
, remote_file
, flags
, mode
);
2116 g_free (remote_file
);
2118 g_free (remote_handle
);
2123 /* --------------------------------------------------------------------------------------------- */
2126 smbfs_unlink (const vfs_path_t
* vpath
)
2128 smbfs_connection
*sc
;
2131 if ((remote_file
= smbfs_get_path (&sc
, vpath
)) == 0)
2134 remote_file
= free_after (smbfs_convert_path (remote_file
, FALSE
), remote_file
);
2136 if (!cli_unlink (sc
->cli
, remote_file
))
2138 message (D_ERROR
, MSG_ERROR
, _("%s removing remote file %s"),
2139 cli_errstr (sc
->cli
), CNV_LANG (remote_file
));
2140 g_free (remote_file
);
2143 g_free (remote_file
);
2147 /* --------------------------------------------------------------------------------------------- */
2150 smbfs_rename (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
)
2152 smbfs_connection
*sc
;
2156 if ((ra
= smbfs_get_path (&sc
, vpath1
)) == 0)
2159 if ((rb
= smbfs_get_path (&sc
, vpath2
)) == 0)
2165 ra
= free_after (smbfs_convert_path (ra
, FALSE
), ra
);
2166 rb
= free_after (smbfs_convert_path (rb
, FALSE
), rb
);
2168 retval
= cli_rename (sc
->cli
, ra
, rb
);
2175 message (D_ERROR
, MSG_ERROR
, _("%s renaming files\n"), cli_errstr (sc
->cli
));
2181 /* --------------------------------------------------------------------------------------------- */
2184 smbfs_fstat (void *data
, struct stat
*buf
)
2186 smbfs_handle
*remote_handle
= (smbfs_handle
*) data
;
2188 DEBUG (3, ("smbfs_fstat(fnum:%d)\n", remote_handle
->fnum
));
2190 /* use left over from previous smbfs_get_remote_stat, if available */
2192 memcpy (buf
, &single_entry
->my_stat
, sizeof (struct stat
));
2194 { /* single_entry not set up: bug */
2201 /* --------------------------------------------------------------------------------------------- */
2202 /*** public functions ****************************************************************************/
2203 /* --------------------------------------------------------------------------------------------- */
2206 vfs_smb_authinfo_new (const char *host
, const char *share
, const char *domain
,
2207 const char *user
, const char *pass
)
2211 auth
= g_try_new (struct smb_authinfo
, 1);
2215 auth
->host
= g_strdup (host
);
2216 auth
->share
= g_strdup (share
);
2217 auth
->domain
= g_strdup (domain
);
2218 auth
->user
= g_strdup (user
);
2219 auth
->password
= g_strdup (pass
);
2225 /* --------------------------------------------------------------------------------------------- */
2232 vfs_smbfs_ops
.name
= "smbfs";
2233 vfs_smbfs_ops
.prefix
= "smb";
2234 vfs_smbfs_ops
.flags
= VFSF_NOLINKS
;
2235 vfs_smbfs_ops
.init
= smbfs_init
;
2236 vfs_smbfs_ops
.fill_names
= smbfs_fill_names
;
2237 vfs_smbfs_ops
.open
= smbfs_open
;
2238 vfs_smbfs_ops
.close
= smbfs_close
;
2239 vfs_smbfs_ops
.read
= smbfs_read
;
2240 vfs_smbfs_ops
.write
= smbfs_write
;
2241 vfs_smbfs_ops
.opendir
= smbfs_opendir
;
2242 vfs_smbfs_ops
.readdir
= smbfs_readdir
;
2243 vfs_smbfs_ops
.closedir
= smbfs_closedir
;
2244 vfs_smbfs_ops
.stat
= smbfs_stat
;
2245 vfs_smbfs_ops
.lstat
= smbfs_lstat
;
2246 vfs_smbfs_ops
.fstat
= smbfs_fstat
;
2247 vfs_smbfs_ops
.chmod
= smbfs_chmod
;
2248 vfs_smbfs_ops
.chown
= smbfs_chown
;
2249 vfs_smbfs_ops
.utime
= smbfs_utime
;
2250 vfs_smbfs_ops
.readlink
= smbfs_readlink
;
2251 vfs_smbfs_ops
.symlink
= smbfs_symlink
;
2252 vfs_smbfs_ops
.link
= smbfs_link
;
2253 vfs_smbfs_ops
.unlink
= smbfs_unlink
;
2254 vfs_smbfs_ops
.rename
= smbfs_rename
;
2255 vfs_smbfs_ops
.chdir
= smbfs_chdir
;
2256 vfs_smbfs_ops
.ferrno
= smbfs_errno
;
2257 vfs_smbfs_ops
.lseek
= smbfs_lseek
;
2258 vfs_smbfs_ops
.mknod
= smbfs_mknod
;
2259 vfs_smbfs_ops
.free
= smbfs_free
;
2260 vfs_smbfs_ops
.mkdir
= smbfs_mkdir
;
2261 vfs_smbfs_ops
.rmdir
= smbfs_rmdir
;
2262 vfs_smbfs_ops
.setctl
= smbfs_setctl
;
2263 vfs_register_class (&vfs_smbfs_ops
);
2266 /* --------------------------------------------------------------------------------------------- */