1 /* Virtual File System: Midnight Commander file system.
3 Copyright (C) 1995, 1996, 1997 The Free Software Foundation
5 Written by Wayne Roberts <wroberts1@home.com>
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License
9 as published by the Free Software Foundation; either version 2 of
10 the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 /* Namespace: exports vfs_smbfs_ops, smbfs_set_debug(), smbfs_set_debugf() */
24 #include <sys/types.h>
26 #undef USE_NCURSES /* Don't include *curses.h */
29 #undef PACKAGE_BUGREPORT
32 #undef PACKAGE_TARNAME
33 #undef PACKAGE_VERSION
35 #include "samba/include/config.h"
36 /* don't load crap in "samba/include/includes.h" we don't use and which
37 conflicts with definitions in other includes */
38 #undef HAVE_LIBREADLINE
42 #include "samba/include/includes.h"
48 #include "../src/dialog.h"
50 #define SMBFS_MAX_CONNECTIONS 16
51 static const char * const IPC
= "IPC$";
52 static const char * const URL_HEADER
= "/#smb:";
58 /* stuff that is same with each connection */
59 extern int DEBUGLEVEL
;
60 extern pstring myhostname
;
61 extern pstring global_myname
;
62 static int smbfs_open_connections
= 0;
63 static gboolean got_user
= FALSE
;
64 static gboolean got_pass
= FALSE
;
65 static pstring password
;
66 static pstring username
;
68 static struct _smbfs_connection
{
69 struct cli_state
*cli
;
70 struct in_addr dest_ip
;
72 char *host
; /* server name */
73 char *service
; /* share name */
81 } smbfs_connections
[SMBFS_MAX_CONNECTIONS
];
82 /* unique to each connection */
84 static struct cli_state
* smbfs_do_connect (const char *server
, char *share
);
86 typedef struct _smbfs_connection smbfs_connection
;
87 static smbfs_connection
*current_bucket
;
90 struct cli_state
*cli
;
96 static GSList
*auth_list
;
99 authinfo_free (struct smb_authinfo
const *a
)
105 wipe_password (a
->password
);
112 g_slist_foreach (auth_list
, (GFunc
)authinfo_free
, 0);
113 g_slist_free (auth_list
);
119 authinfo_compare_host_and_share (gconstpointer _a
, gconstpointer _b
)
121 struct smb_authinfo
const *a
= (struct smb_authinfo
const *)_a
;
122 struct smb_authinfo
const *b
= (struct smb_authinfo
const *)_b
;
124 if (!a
->host
|| !a
->share
|| !b
->host
|| !b
->share
)
126 if (strcmp (a
->host
, b
->host
) != 0)
128 if (strcmp (a
->share
, b
->share
) != 0)
134 authinfo_compare_host (gconstpointer _a
, gconstpointer _b
)
136 struct smb_authinfo
const *a
= (struct smb_authinfo
const *)_a
;
137 struct smb_authinfo
const *b
= (struct smb_authinfo
const *)_b
;
139 if (!a
->host
|| !b
->host
)
141 if (strcmp (a
->host
, b
->host
) != 0)
143 if (strcmp (a
->share
, IPC
) != 0)
149 authinfo_add (const char *host
, const char *share
, const char *domain
,
150 const char *user
, const char *password
)
152 struct smb_authinfo
*auth
= g_new (struct smb_authinfo
, 1);
157 /* Don't check for NULL, g_strdup already does. */
158 auth
->host
= g_strdup (host
);
159 auth
->share
= g_strdup (share
);
160 auth
->domain
= g_strdup (domain
);
161 auth
->user
= g_strdup (user
);
162 auth
->password
= g_strdup (password
);
163 auth_list
= g_slist_prepend (auth_list
, auth
);
167 authinfo_remove (const char *host
, const char *share
)
169 struct smb_authinfo data
;
170 struct smb_authinfo
*auth
;
173 data
.host
= g_strdup (host
);
174 data
.share
= g_strdup (share
);
175 list
= g_slist_find_custom (auth_list
,
177 authinfo_compare_host_and_share
);
183 auth_list
= g_slist_remove (auth_list
, auth
);
184 authinfo_free (auth
);
187 /* Set authentication information in bucket. Return 1 if successful, else 0 */
188 /* Information in auth_list overrides user if pass is NULL. */
189 /* bucket->host and bucket->service must be valid. */
191 bucket_set_authinfo (smbfs_connection
*bucket
,
192 const char *domain
, const char *user
, const char *pass
,
193 int fallback_to_host
)
195 struct smb_authinfo data
;
196 struct smb_authinfo
*auth
;
199 if (domain
&& user
&& pass
) {
200 g_free (bucket
->domain
);
201 g_free (bucket
->user
);
202 g_free (bucket
->password
);
203 bucket
->domain
= g_strdup (domain
);
204 bucket
->user
= g_strdup (user
);
205 bucket
->password
= g_strdup (pass
);
206 authinfo_remove (bucket
->host
, bucket
->service
);
207 authinfo_add (bucket
->host
, bucket
->service
,
212 data
.host
= bucket
->host
;
213 data
.share
= bucket
->service
;
214 list
= g_slist_find_custom (auth_list
, &data
, authinfo_compare_host_and_share
);
215 if (!list
&& fallback_to_host
)
216 list
= g_slist_find_custom (auth_list
, &data
, authinfo_compare_host
);
219 bucket
->domain
= g_strdup (auth
->domain
);
220 bucket
->user
= g_strdup (auth
->user
);
221 bucket
->password
= g_strdup (auth
->password
);
226 bucket
->domain
= g_strdup (lp_workgroup ());
227 bucket
->user
= g_strdup (got_user
? username
: user
);
228 bucket
->password
= g_strdup (password
);
232 auth
= vfs_smb_get_authinfo (bucket
->host
,
234 (domain
? domain
: lp_workgroup ()),
237 g_free (bucket
->domain
);
238 g_free (bucket
->user
);
239 g_free (bucket
->password
);
240 bucket
->domain
= g_strdup (auth
->domain
);
241 bucket
->user
= g_strdup (auth
->user
);
242 bucket
->password
= g_strdup (auth
->password
);
243 authinfo_remove (bucket
->host
, bucket
->service
);
244 auth_list
= g_slist_prepend (auth_list
, auth
);
251 smbfs_set_debug (int arg
)
257 smbfs_set_debugf (const char *filename
)
259 extern pstring debugf
;
261 if (DEBUGLEVEL
> 0) {
262 FILE *outfile
= fopen (filename
, "w");
264 setup_logging ("", True
); /* No needs for timestamp for each message */
267 pstrcpy (debugf
, filename
);
272 /********************** The callbacks ******************************/
274 smbfs_init (vfs
* me
)
276 char *servicesf
= CONFIGDIR PATH_SEP_STR
"smb.conf";
278 /* DEBUGLEVEL = 4; */
281 charset_initialise ();
283 DEBUG (3, ("smbfs_init(%s)\n", me
->name
));
285 if (!get_myname (myhostname
, NULL
))
286 DEBUG (0, ("Failed to get my hostname.\n"));
288 if (!lp_load (servicesf
, True
, False
, False
))
289 DEBUG (0, ("Cannot load %s - run testparm to debug it\n", servicesf
));
291 codepage_initialise (lp_client_code_page ());
295 if (getenv ("USER")) {
298 pstrcpy (username
, getenv ("USER"));
300 DEBUG (3, ("smbfs_init(): $USER:%s\n", username
));
301 if ((p
= strchr (username
, '%'))) {
303 pstrcpy (password
, p
+ 1);
305 memset (strchr (getenv ("USER"), '%') + 1, 'X', strlen (password
));
306 DEBUG (3, ("smbfs_init(): $USER%%pass: %s%%%s\n",
307 username
, password
));
311 if (getenv ("PASSWD")) {
312 pstrcpy (password
, getenv ("PASSWD"));
319 smbfs_fill_names (vfs
*me
, void (*func
)(char *))
323 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
324 if (smbfs_connections
[i
].cli
) {
325 path
= g_strconcat (URL_HEADER
,
326 smbfs_connections
[i
].user
, "@",
327 smbfs_connections
[i
].host
,
328 "/", smbfs_connections
[i
].service
,
336 #define CNV_LANG(s) dos_to_unix(s,False)
337 #define GNAL_VNC(s) unix_to_dos(s,False)
338 /* does same as do_get() in client.c */
339 /* called from vfs.c:1080, count = buffer size */
341 smbfs_read (void *data
, char *buffer
, int count
)
343 smbfs_handle
*info
= (smbfs_handle
*) data
;
346 DEBUG(3, ("smbfs_read(fnum:%d, nread:%d, count:%d)\n",
347 info
->fnum
, (int)info
->nread
, count
));
348 n
= cli_read(info
->cli
, info
->fnum
, buffer
, info
->nread
, count
);
355 smbfs_write (void *data
, char *buf
, int nbyte
)
357 smbfs_handle
*info
= (smbfs_handle
*) data
;
360 DEBUG(3, ("smbfs_write(fnum:%d, nread:%d, nbyte:%d)\n",
361 info
->fnum
, (int)info
->nread
, nbyte
));
362 n
= cli_write(info
->cli
, info
->fnum
, 0, buf
, info
->nread
, nbyte
);
369 smbfs_close (void *data
)
371 smbfs_handle
*info
= (smbfs_handle
*) data
;
372 DEBUG (3, ("smbfs_close(fnum:%d)\n", info
->fnum
));
374 /* FIXME: Why too different cli have the same outbuf
375 * if file is copied to share
377 if (info
->cli
->outbuf
== NULL
) {
382 /* if imlementing archive_level: add rname to smbfs_handle */
383 if (archive_level
>= 2 && (inf
->attr
& aARCH
)) {
384 cli_setatr (info
->cli
, rname
, info
->attr
& ~(uint16
) aARCH
, 0);
387 return (cli_close (info
->cli
, info
->fnum
) == True
) ? 0 : -1;
391 smbfs_errno (vfs
*me
)
393 DEBUG(3, ("smbfs_errno: %s\n", g_strerror(my_errno
)));
397 typedef struct dir_entry
{
399 struct dir_entry
*next
;
405 gboolean server_list
;
407 char *path
; /* the dir originally passed to smbfs_opendir */
408 smbfs_connection
*conn
;
417 *current_server_info
;
419 static gboolean first_direntry
;
422 new_dir_entry (const char * name
)
424 dir_entry
*new_entry
;
425 new_entry
= g_new0 (dir_entry
, 1);
426 new_entry
->text
= dos_to_unix (g_strdup (name
), 1);
428 if (first_direntry
) {
429 current_info
->entries
= new_entry
;
430 first_direntry
= FALSE
;
432 current_info
->current
->next
= new_entry
;
434 current_info
->current
= new_entry
;
439 /* browse for shares on server */
441 browsing_helper (const char *name
, uint32 type
, const char *comment
, void *state
)
445 dir_entry
*new_entry
= new_dir_entry (name
);
450 /* show this as dir */
451 new_entry
->my_stat
.st_mode
=
452 S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
|
465 DEBUG (3, ("\t%-15.15s%-10.10s%s\n", name
, typestr
, comment
));
469 loaddir_helper (file_info
* finfo
, const char *mask
, void *entry
)
471 dir_entry
*new_entry
= (dir_entry
*) entry
;
472 time_t t
= finfo
->mtime
; /* the time is assumed to be passed as GMT */
473 #if 0 /* I want to see dot files */
474 if (finfo
->mode
& aHIDDEN
)
475 return; /* don't bother with hidden files, "~$" screws up mc */
478 new_entry
= new_dir_entry (finfo
->name
);
480 new_entry
->my_stat
.st_size
= finfo
->size
;
481 new_entry
->my_stat
.st_mtime
= finfo
->mtime
;
482 new_entry
->my_stat
.st_atime
= finfo
->atime
;
483 new_entry
->my_stat
.st_ctime
= finfo
->ctime
;
484 new_entry
->my_stat
.st_uid
= finfo
->uid
;
485 new_entry
->my_stat
.st_gid
= finfo
->gid
;
487 new_entry
->my_stat
.st_mode
= /* rw-rw-rw */
488 S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
;
490 /* if (finfo->mode & aVOLID); nothing similar in real world */
491 if (finfo
->mode
& aDIR
)
492 new_entry
->my_stat
.st_mode
|= /* drwxrwxrwx */
493 S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
495 new_entry
->my_stat
.st_mode
|= S_IFREG
; /* if not dir, regular file? */
496 /* if (finfo->mode & aARCH); DOS archive */
497 /* if (finfo->mode & aHIDDEN); like a dot file? */
498 /* if (finfo->mode & aSYSTEM); like a kernel? */
499 if (finfo
->mode
& aRONLY
)
500 new_entry
->my_stat
.st_mode
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
502 DEBUG (entry
? 3 : 6, (" %-30s%7.7s%8.0f %s",
503 CNV_LANG (finfo
->name
),
504 attrib_string (finfo
->mode
),
505 (double) finfo
->size
,
506 asctime (LocalTime (&t
))));
509 /* takes "/foo/bar/file" and gives malloced "\\foo\\bar\\file" */
511 convert_path(char **remote_file
, gboolean trailing_asterik
)
515 my_remote
= *remote_file
;
516 if (strncmp (my_remote
, URL_HEADER
, HEADER_LEN
) == 0) { /* if passed directly */
518 if (*my_remote
== '/') /* from server browsing */
520 p
= strchr(my_remote
, '/');
522 my_remote
= p
+1; /* advance to end of server name */
525 if (*my_remote
== '/')
526 my_remote
++; /* strip off leading '/' */
527 p
= strchr(my_remote
, '/');
529 my_remote
= p
; /* strip off share/service name */
530 /* create remote filename as understood by smb clientgen */
531 p
= *remote_file
= g_strconcat (my_remote
, trailing_asterik
? "/*" : "", 0);
532 unix_to_dos (*remote_file
, 1);
533 while ((p
= strchr(p
, '/')))
539 server_browsing_helper (const char *name
, uint32 m
, const char *comment
, void *state
)
541 dir_entry
*new_entry
= new_dir_entry (name
);
543 /* show this as dir */
544 new_entry
->my_stat
.st_mode
=
545 S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
547 DEBUG (3, ("\t%-16.16s %s\n", name
, comment
));
551 reconnect(smbfs_connection
*conn
, int *retries
)
554 DEBUG(3, ("RECONNECT\n"));
556 if (*(conn
->host
) == 0)
557 host
= g_strdup(conn
->cli
->desthost
); /* server browsing */
559 host
= g_strdup(conn
->host
);
561 cli_shutdown(conn
->cli
);
563 if (!(conn
->cli
= smbfs_do_connect(host
, conn
->service
))) {
564 message_2s (1, MSG_ERROR
,
565 _(" reconnect to %s failed\n "), conn
->host
);
570 if (++(*retries
) == 2)
576 smb_send(struct cli_state
*cli
)
582 len
= smb_len(cli
->outbuf
) + 4;
584 while (nwritten
< len
) {
585 ret
= write_socket(cli
->fd
, cli
->outbuf
+nwritten
, len
- nwritten
);
586 if (ret
<= 0 && errno
== EPIPE
)
594 /****************************************************************************
595 See if server has cut us off by checking for EPIPE when writing.
596 Taken from cli_chkpath()
597 ****************************************************************************/
599 chkpath(struct cli_state
*cli
, char *path
, BOOL send_only
)
605 unix_to_dos (path2
, 1);
606 trim_string(path2
,NULL
,"\\");
607 if (!*path2
) *path2
= '\\';
609 memset(cli
->outbuf
,'\0',smb_size
);
610 set_message(cli
->outbuf
,0,4 + strlen(path2
),True
);
611 SCVAL(cli
->outbuf
,smb_com
,SMBchkpth
);
612 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
616 SSVAL(cli
->outbuf
,smb_pid
,cli
->pid
);
617 SSVAL(cli
->outbuf
,smb_uid
,cli
->vuid
);
618 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
);
619 if (cli
->protocol
> PROTOCOL_CORE
) {
620 SCVAL(cli
->outbuf
,smb_flg
,0x8);
621 SSVAL(cli
->outbuf
,smb_flg2
,0x1);
624 p
= smb_buf(cli
->outbuf
);
628 if (!smb_send(cli
)) {
629 DEBUG(3, ("chkpath: couldnt send\n"));
633 client_receive_smb(cli
->fd
, cli
->inbuf
, cli
->timeout
);
634 DEBUG(3, ("chkpath: send only OK\n"));
635 return True
; /* just testing for EPIPE */
637 if (!client_receive_smb(cli
->fd
, cli
->inbuf
, cli
->timeout
)) {
638 DEBUG(3, ("chkpath: receive error\n"));
641 if ((my_errno
= cli_error(cli
, NULL
, NULL
, NULL
))) {
642 if (my_errno
== 20 || my_errno
== 13)
643 return True
; /* ignore if 'not a directory' error */
644 DEBUG(3, ("chkpath: cli_error: %s\n", g_strerror(my_errno
)));
653 fs (const char *text
)
655 const char *p
= text
;
658 while ((p
= strchr(p
, '/')) != NULL
) {
669 smbfs_loaddir (opendir_info
*smbfs_info
)
671 uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
672 int servlen
= strlen(smbfs_info
->conn
->service
);
673 char *my_dirname
= smbfs_info
->dirname
;
675 DEBUG(3, ("smbfs_loaddir: dirname:%s\n", my_dirname
));
676 first_direntry
= TRUE
;
679 DEBUG(3, ("smbfs_loaddir: new:'%s', cached:'%s'\n", my_dirname
, current_info
->dirname
));
680 /* if new desired dir is longer than cached in current_info */
681 if (fs(my_dirname
) > fs(current_info
->dirname
)) {
682 DEBUG(3, ("saving to previous_info\n"));
683 previous_info
= current_info
;
687 current_info
= smbfs_info
;
689 if (strcmp(my_dirname
, "/") == 0) {
690 if (!strcmp(smbfs_info
->path
, URL_HEADER
)) {
691 DEBUG(6, ("smbfs_loaddir: browsing %s\n", IPC
));
692 /* browse for servers */
693 if (!cli_NetServerEnum(smbfs_info
->conn
->cli
, smbfs_info
->conn
->domain
,
694 SV_TYPE_ALL
, server_browsing_helper
, NULL
))
697 current_server_info
= smbfs_info
;
698 smbfs_info
->server_list
= TRUE
;
700 /* browse for shares */
701 if (cli_RNetShareEnum(smbfs_info
->conn
->cli
, browsing_helper
, NULL
) < 1)
704 current_share_info
= smbfs_info
;
709 /* do regular directory listing */
710 if(strncmp(smbfs_info
->conn
->service
, my_dirname
+1, servlen
) == 0) {
711 /* strip share name from dir */
712 char *p
= my_dirname
= g_strdup(my_dirname
+ servlen
);
714 convert_path(&my_dirname
, TRUE
);
717 convert_path(&my_dirname
, TRUE
);
719 DEBUG(6, ("smbfs_loaddir: service: %s\n", smbfs_info
->conn
->service
));
720 DEBUG(6, ("smbfs_loaddir: cli->share: %s\n", smbfs_info
->conn
->cli
->share
));
721 DEBUG(6, ("smbfs_loaddir: calling cli_list with mask %s\n", my_dirname
));
722 /* do file listing: cli_list returns number of files */
724 smbfs_info
->conn
->cli
, my_dirname
, attribute
, loaddir_helper
, NULL
) < 0) {
725 /* cli_list returns -1 if directory empty or cannot read socket */
726 my_errno
= cli_error(smbfs_info
->conn
->cli
, NULL
, &err
, NULL
);
730 if (*(my_dirname
) == 0)
731 smbfs_info
->dirname
= smbfs_info
->conn
->service
;
736 /* current_info->parent = smbfs_info->dirname; */
738 smbfs_info
->current
= smbfs_info
->entries
;
739 return 1; /* 1 = ok */
742 #ifdef SMBFS_FREE_DIR
744 smbfs_free_dir (dir_entry
*de
)
748 smbfs_free_dir (de
->next
);
755 /* The readdir routine loads the complete directory */
756 /* It's too slow to ask the server each time */
757 /* It now also sends the complete lstat information for each file */
759 smbfs_readdir(void *info
)
761 static union vfs_dirent smbfs_readdir_data
;
762 static char *const dirent_dest
= smbfs_readdir_data
.dent
.d_name
;
763 opendir_info
*smbfs_info
= (opendir_info
*) info
;
765 DEBUG(4, ("smbfs_readdir(%s)\n", smbfs_info
->dirname
));
767 if (!smbfs_info
->entries
)
768 if (!smbfs_loaddir(smbfs_info
))
771 if (smbfs_info
->current
== 0) { /* reached end of dir entries */
772 DEBUG(3, ("smbfs_readdir: smbfs_info->current = 0\n"));
773 #ifdef SMBFS_FREE_DIR
774 smbfs_free_dir(smbfs_info
->entries
);
775 smbfs_info
->entries
= 0;
779 strncpy(dirent_dest
, smbfs_info
->current
->text
, MC_MAXPATHLEN
);
780 dirent_dest
[MC_MAXPATHLEN
] = 0;
781 smbfs_info
->current
= smbfs_info
->current
->next
;
783 compute_namelen(&smbfs_readdir_data
.dent
);
785 return &smbfs_readdir_data
;
789 smbfs_closedir (void *info
)
791 opendir_info
*smbfs_info
= (opendir_info
*) info
;
792 /* dir_entry *p, *q; */
794 DEBUG(3, ("smbfs_closedir(%s)\n", smbfs_info
->dirname
));
797 /* for (p = smbfs_info->entries; p;){
808 smbfs_chmod (vfs
*me
, char *path
, int mode
)
810 DEBUG(3, ("smbfs_chmod(path:%s, mode:%d)\n", path
, mode
));
811 /* my_errno = EOPNOTSUPP;
812 return -1; */ /* cannot chmod on smb filesystem */
813 return 0; /* make mc happy */
817 smbfs_chown (vfs
*me
, char *path
, int owner
, int group
)
819 DEBUG(3, ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path
, owner
, group
));
820 my_errno
= EOPNOTSUPP
; /* ready for your labotomy? */
825 smbfs_utime (vfs
*me
, char *path
, struct utimbuf
*times
)
827 DEBUG(3, ("smbfs_utime(path:%s)\n", path
));
828 my_errno
= EOPNOTSUPP
;
833 smbfs_readlink (vfs
*me
, char *path
, char *buf
, int size
)
835 DEBUG(3, ("smbfs_readlink(path:%s, buf:%s, size:%d)\n", path
, buf
, size
));
836 my_errno
= EOPNOTSUPP
;
837 return -1; /* no symlinks on smb filesystem? */
841 smbfs_symlink (vfs
*me
, char *n1
, char *n2
)
843 DEBUG(3, ("smbfs_symlink(n1:%s, n2:%s)\n", n1
, n2
));
844 my_errno
= EOPNOTSUPP
;
845 return -1; /* no symlinks on smb filesystem? */
848 /* Extract the hostname and username from the path */
849 /* path is in the form: [user@]hostname/share/remote-dir */
850 #define smbfs_get_host_and_username(path, host, user, port, pass) \
851 vfs_split_url (*path, host, user, port, pass, SMB_PORT, 0)
853 /*****************************************************
854 return a connection to a SMB server
855 current_bucket needs to be set before calling
856 *******************************************************/
857 static struct cli_state
*
858 smbfs_do_connect (const char *server
, char *share
)
861 struct nmb_name called
, calling
;
863 extern struct in_addr ipzero
;
865 DEBUG(3, ("smbfs_do_connect(%s, %s)\n", server
, share
));
866 if (*share
== '\\') {
868 share
= strchr(server
,'\\');
869 if (!share
) return NULL
;
874 make_nmb_name(&calling
, global_myname
, 0x0);
875 make_nmb_name(&called
, server
, current_bucket
->name_type
);
879 ip
= (current_bucket
->have_ip
) ? current_bucket
->dest_ip
: ipzero
;
881 /* have to open a new connection */
882 if (!(c
= cli_initialise(NULL
))) {
887 pwd_init(&(c
->pwd
)); /* should be moved into cli_initialise()? */
888 pwd_set_cleartext(&(c
->pwd
), current_bucket
->password
);
890 if ((cli_set_port(c
, current_bucket
->port
) == 0) ||
891 !cli_connect(c
, server
, &ip
)) {
892 DEBUG(1, ("Connection to %s failed\n", server
));
896 if (!cli_session_request(c
, &calling
, &called
)) {
897 my_errno
= cli_error(c
, NULL
, &err
, NULL
);
898 DEBUG(1, ("session request to %s failed\n", called
.name
));
900 if (strcmp(called
.name
, "*SMBSERVER")) {
901 make_nmb_name(&called
, "*SMBSERVER", 0x20);
907 DEBUG(3, (" session request ok\n"));
909 if (!cli_negprot(c
)) {
910 DEBUG(1, ("protocol negotiation failed\n"));
914 if (!cli_session_setup(c
, current_bucket
->user
,
915 current_bucket
->password
, strlen(current_bucket
->password
),
916 current_bucket
->password
, strlen(current_bucket
->password
),
917 current_bucket
->domain
)) {
918 DEBUG(1,("session setup failed: %s\n", cli_errstr(c
)));
919 authinfo_remove (server
, share
);
923 if (*c
->server_domain
|| *c
->server_os
|| *c
->server_type
)
924 DEBUG(5,("Domain=[%s] OS=[%s] Server=[%s]\n",
925 c
->server_domain
,c
->server_os
,c
->server_type
));
927 DEBUG(3, (" session setup ok\n"));
929 if (!cli_send_tconX(c
, share
, "?????",
930 current_bucket
->password
, strlen(current_bucket
->password
)+1)) {
931 DEBUG(1,("%s: tree connect failed: %s\n", share
, cli_errstr(c
)));
935 DEBUG(3, (" tconx ok\n"));
941 my_errno
= cli_error(c
, NULL
, &err
, NULL
);
948 get_master_browser(char **host
)
951 struct in_addr
*ip_list
, bcast_addr
;
952 extern struct in_addr ipzero
;
954 /* does port = 137 for win95 master browser? */
955 int fd
= open_socket_in( SOCK_DGRAM
, 0, 3,
956 interpret_addr(lp_socket_address()), True
);
959 set_socket_options(fd
, "SO_BROADCAST");
960 ip_list
= iface_bcast(ipzero
);
961 bcast_addr
= *ip_list
;
962 if ((ip_list
= name_query(fd
, "\01\02__MSBROWSE__\02", 1, True
,
963 True
, bcast_addr
, &count
, NULL
))) {
966 /* just return first master browser */
967 *host
= g_strdup(inet_ntoa(ip_list
[0]));
974 free_bucket (smbfs_connection
*bucket
)
976 g_free (bucket
->host
);
977 g_free (bucket
->service
);
978 g_free (bucket
->domain
);
979 g_free (bucket
->user
);
980 wipe_password (bucket
->password
);
981 if (bucket
->home
) g_free (bucket
->home
);
982 memset (bucket
, 0, sizeof (smbfs_connection
));
985 static smbfs_connection
*
986 smbfs_get_free_bucket ()
990 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++)
991 if (!smbfs_connections
[i
].cli
) return &smbfs_connections
[i
];
993 { /* search for most dormant connection */
994 int oldest
= 0; /* index */
995 time_t oldest_time
= smbfs_connections
[0].last_use
;
996 for (i
= 1; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
997 if (smbfs_connections
[i
].last_use
< oldest_time
) {
998 oldest_time
= smbfs_connections
[i
].last_use
;
1002 cli_shutdown(smbfs_connections
[oldest
].cli
);
1003 free_bucket (&smbfs_connections
[oldest
]);
1004 return &smbfs_connections
[oldest
];
1007 /* This can't happend, since we have checked for max connections before */
1008 vfs_die("Internal error: smbfs_get_free_bucket");
1009 return 0; /* shut up, stupid gcc */
1012 /* This routine keeps track of open connections */
1013 /* Returns a connected socket to host */
1014 static smbfs_connection
*
1015 smbfs_open_link (char *host
, char *path
, const char *user
, int *port
,
1019 smbfs_connection
*bucket
;
1021 struct in_addr
*dest_ip
= NULL
;
1023 DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host
, path
));
1025 if (strcmp (host
, path
) == 0) /* if host & path are same: */
1026 pstrcpy (service
, IPC
); /* setup for browse */
1027 else { /* get share name from path, path starts with server name */
1029 if ((p
= strchr (path
, '/'))) /* get share aka */
1030 pstrcpy (service
, ++p
); /* service name from path */
1032 pstrcpy (service
, "");
1033 /* now check for trailing directory/filenames */
1034 p
= strchr (service
, '/');
1036 *p
= 0; /* cut off dir/files: sharename only */
1038 pstrcpy (service
, IPC
); /* setup for browse */
1039 DEBUG (6, ("smbfs_open_link: service from path:%s\n", service
));
1043 user
= username
; /* global from getenv */
1045 /* Is the link actually open? */
1046 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
1047 if (!smbfs_connections
[i
].cli
)
1049 if ((strcmp (host
, smbfs_connections
[i
].host
) == 0) &&
1050 (strcmp (user
, smbfs_connections
[i
].user
) == 0) &&
1051 (strcmp (service
, smbfs_connections
[i
].service
) == 0)) {
1053 BOOL inshare
= (*host
!= 0 && *path
!= 0 && strchr (path
, '/'));
1054 /* check if this connection has died */
1055 while (!chkpath (smbfs_connections
[i
].cli
, "\\", !inshare
)) {
1056 if (!reconnect (&smbfs_connections
[i
], &retries
))
1059 DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i
));
1060 current_bucket
= &smbfs_connections
[i
];
1061 smbfs_connections
[i
].last_use
= time (NULL
);
1062 return &smbfs_connections
[i
];
1064 /* connection not found, find if we have ip for new connection */
1065 if (strcmp (host
, smbfs_connections
[i
].host
) == 0)
1066 dest_ip
= &smbfs_connections
[i
].cli
->dest_ip
;
1069 /* make new connection */
1070 bucket
= smbfs_get_free_bucket ();
1071 bucket
->name_type
= 0x20;
1073 bucket
->port
= *port
;
1074 bucket
->have_ip
= False
;
1076 bucket
->have_ip
= True
;
1077 bucket
->dest_ip
= *dest_ip
;
1079 current_bucket
= bucket
;
1081 bucket
->user
= g_strdup (user
);
1082 bucket
->service
= g_strdup (service
);
1084 if (!(*host
)) { /* if blank host name, browse for servers */
1085 if (!get_master_browser (&host
)) /* set host to ip of master browser */
1086 return 0; /* could not find master browser? */
1088 bucket
->host
= g_strdup (""); /* blank host means master browser */
1090 bucket
->host
= g_strdup (host
);
1092 if (!bucket_set_authinfo (bucket
, 0, /* domain currently not used */
1093 user
, this_pass
, 1))
1096 /* connect to share */
1097 while (!(bucket
->cli
= smbfs_do_connect (host
, service
))) {
1099 if (my_errno
!= EPERM
)
1101 message_1s (1, MSG_ERROR
, _(" Authentication failed "));
1103 /* authentication failed, try again */
1104 authinfo_remove (bucket
->host
, bucket
->service
);
1105 if (!bucket_set_authinfo (bucket
, bucket
->domain
, bucket
->user
, 0, 0))
1110 smbfs_open_connections
++;
1111 DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n",
1112 smbfs_open_connections
));
1117 smbfs_get_path (smbfs_connection
** sc
, const char *path
)
1119 char *user
, *host
, *remote_path
, *pass
;
1120 int port
= SMB_PORT
;
1122 DEBUG (3, ("smbfs_get_path(%s)\n", path
));
1123 if (strncmp (path
, URL_HEADER
, HEADER_LEN
))
1127 if (*path
== '/') /* '/' leading server name */
1128 path
++; /* probably came from server browsing */
1131 smbfs_get_host_and_username (&path
, &host
, &user
, &port
, &pass
)))
1133 smbfs_open_link (host
, remote_path
, user
, &port
, pass
)) == NULL
) {
1134 g_free (remote_path
);
1140 wipe_password (pass
);
1145 /* NOTE: tildes are deprecated. See ftpfs.c */
1147 int f
= !strcmp (remote_path
, "/~");
1148 if (f
|| !strncmp (remote_path
, "/~/", 3)) {
1150 s
= concat_dir_and_file ((*sc
)->home
, remote_path
+ 3 - f
);
1151 g_free (remote_path
);
1160 is_error (int result
, int errno_num
)
1162 if (!(result
== -1))
1163 return my_errno
= 0;
1165 my_errno
= errno_num
;
1171 smbfs_opendir (vfs
*me
, char *dirname
)
1173 opendir_info
*smbfs_info
;
1174 smbfs_connection
*sc
;
1177 DEBUG(3, ("smbfs_opendir(dirname:%s)\n", dirname
));
1179 if (!(remote_dir
= smbfs_get_path (&sc
, dirname
)))
1182 /* FIXME: where freed? */
1183 smbfs_info
= g_new (opendir_info
, 1);
1184 smbfs_info
->server_list
= FALSE
;
1185 smbfs_info
->path
= g_strdup(dirname
); /* keep original */
1186 smbfs_info
->dirname
= remote_dir
;
1187 smbfs_info
->conn
= sc
;
1188 smbfs_info
->entries
= 0;
1189 smbfs_info
->current
= 0;
1195 fake_server_stat(const char *server_url
, const char *path
, struct stat
*buf
)
1200 if ((p
= strrchr(path
, '/')))
1201 path
= p
+ 1; /* advance until last '/' */
1203 if (!current_info
->entries
) {
1204 if (!smbfs_loaddir(current_info
)); /* browse host */
1208 if (current_info
->server_list
== True
) {
1209 dentry
= current_info
->entries
;
1210 DEBUG(4, ("fake stat for SERVER \"%s\"\n", path
));
1212 if (strcmp(dentry
->text
, path
) == 0) {
1213 DEBUG(4, ("fake_server_stat: %s:%4o\n",
1214 dentry
->text
, dentry
->my_stat
.st_mode
));
1215 memcpy(buf
, &dentry
->my_stat
, sizeof(struct stat
));
1218 dentry
= dentry
->next
;
1226 fake_share_stat (const char *server_url
, const char *path
, struct stat
*buf
)
1229 if (strlen (path
) < strlen (server_url
))
1232 if (!current_share_info
) { /* Server was not stat()ed */
1233 /* Make sure there is such share at server */
1234 smbfs_connection
*sc
;
1236 p
= smbfs_get_path (&sc
, path
);
1239 memset (buf
, 0, sizeof (*buf
));
1240 /* show this as dir */
1242 S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
|
1249 path
+= strlen (server_url
); /* we only want share name */
1252 if (*path
== '/') /* '/' leading server name */
1253 path
++; /* probably came from server browsing */
1255 if (!current_share_info
->entries
) {
1256 if (!smbfs_loaddir (current_share_info
)) /* browse host */
1259 dentry
= current_share_info
->entries
;
1260 DEBUG (3, ("fake_share_stat: %s on %s\n", path
, server_url
));
1262 if (strcmp (dentry
->text
, path
) == 0) {
1263 DEBUG (6, ("fake_share_stat: %s:%4o\n",
1264 dentry
->text
, dentry
->my_stat
.st_mode
));
1265 memcpy (buf
, &dentry
->my_stat
, sizeof (struct stat
));
1268 dentry
= dentry
->next
;
1274 /* stat a single file, get_remote_stat callback */
1275 static dir_entry
*single_entry
;
1277 /* stat a single file */
1279 get_remote_stat (smbfs_connection
* sc
, char *path
, struct stat
*buf
)
1281 uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
1282 char *mypath
= path
;
1284 DEBUG (3, ("get_remote_stat(): mypath:%s\n", mypath
));
1286 convert_path (&mypath
, FALSE
);
1288 #if 0 /* single_entry is never free()d now. And only my_stat is used */
1289 single_entry
= g_new (dir_entry
, 1);
1291 single_entry
->text
= dos_to_unix (g_strdup (finfo
->name
), 1);
1293 single_entry
->next
= 0;
1296 single_entry
= g_new0 (dir_entry
, 1);
1299 (sc
->cli
, mypath
, attribute
, loaddir_helper
, single_entry
) < 1) {
1302 return -1; /* cli_list returns number of files */
1305 memcpy (buf
, &single_entry
->my_stat
, sizeof (struct stat
));
1307 /* don't free here, use for smbfs_fstat() */
1308 /* g_free(single_entry->text);
1309 g_free(single_entry); */
1315 search_dir_entry (dir_entry
*dentry
, const char *text
, struct stat
*buf
)
1318 if (strcmp(text
, dentry
->text
) == 0) {
1319 memcpy(buf
, &dentry
->my_stat
, sizeof(struct stat
));
1320 memcpy(&single_entry
->my_stat
, &dentry
->my_stat
,
1321 sizeof(struct stat
));
1324 dentry
= dentry
->next
;
1330 get_stat_info (smbfs_connection
* sc
, char *path
, struct stat
*buf
)
1334 dir_entry
*dentry
= current_info
->entries
;
1336 const char *mypath
= path
;
1338 mypath
++; /* cut off leading '/' */
1339 if ((p
= strrchr (mypath
, '/')))
1340 mypath
= p
+ 1; /* advance until last file/dir name */
1341 DEBUG (3, ("get_stat_info: mypath:%s, current_info->dirname:%s\n",
1342 mypath
, current_info
->dirname
));
1345 DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1346 current_info
->dirname
, path
));
1350 if (!single_entry
) /* when found, this will be written too */
1351 single_entry
= g_new (dir_entry
, 1);
1352 if (search_dir_entry (current_info
->entries
, mypath
, buf
) == 0) {
1355 /* now try to identify mypath as PARENT dir */
1359 mdp
= mydir
= g_strdup (current_info
->dirname
);
1360 if ((p
= strrchr (mydir
, '/')))
1361 *p
= 0; /* advance util last '/' */
1362 if ((p
= strrchr (mydir
, '/')))
1363 mydir
= p
+ 1; /* advance util last '/' */
1364 if (strcmp (mydir
, mypath
) == 0) { /* fake a stat for ".." */
1365 memset (buf
, 0, sizeof (struct stat
));
1366 buf
->st_mode
= S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
;
1367 memcpy (&single_entry
->my_stat
, buf
, sizeof (struct stat
));
1369 DEBUG (1, (" PARENT:found in %s\n", current_info
->dirname
));
1374 /* now try to identify as CURRENT dir? */
1376 char *dnp
= current_info
->dirname
;
1377 DEBUG (6, ("get_stat_info: is %s current dir? this dir is: %s\n",
1378 mypath
, current_info
->dirname
));
1384 if (strcmp (mypath
, dnp
) == 0) {
1385 memset (buf
, 0, sizeof (struct stat
));
1386 buf
->st_mode
= S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
;
1387 memcpy (&single_entry
->my_stat
, buf
, sizeof (struct stat
));
1388 DEBUG (1, (" CURRENT:found in %s\n", current_info
->dirname
));
1392 DEBUG (3, ("'%s' not found in current_info '%s'\n", path
,
1393 current_info
->dirname
));
1394 /* try to find this in the PREVIOUS listing */
1395 if (previous_info
) {
1396 if (search_dir_entry (previous_info
->entries
, mypath
, buf
) == 0)
1398 DEBUG (3, ("'%s' not found in previous_info '%s'\n", path
,
1399 previous_info
->dirname
));
1401 /* try to find this in the SHARE listing */
1402 if (current_share_info
) {
1403 if (search_dir_entry (current_share_info
->entries
, mypath
, buf
) == 0)
1405 DEBUG (3, ("'%s' not found in share_info '%s'\n", path
,
1406 current_share_info
->dirname
));
1408 /* try to find this in the SERVER listing */
1409 if (current_server_info
) {
1410 if (search_dir_entry (current_server_info
->entries
, mypath
, buf
) == 0)
1412 DEBUG (3, ("'%s' not found in server_info '%s'\n", path
,
1413 current_server_info
->dirname
));
1415 /* nothing found. get stat file info from server */
1416 return get_remote_stat (sc
, path
, buf
);
1420 smbfs_chdir (vfs
*me
, char *path
)
1423 smbfs_connection
*sc
;
1425 DEBUG(3, ("smbfs_chdir(path:%s)\n", path
));
1426 if (!(remote_dir
= smbfs_get_path (&sc
, path
)))
1428 g_free (remote_dir
);
1434 loaddir(vfs
*me
, const char *path
)
1439 mypath
= g_strdup(path
);
1440 p
= strrchr(mypath
, '/');
1444 DEBUG(6, ("loaddir(%s)\n", mypath
));
1445 smbfs_chdir(me
, mypath
);
1446 info
= smbfs_opendir (me
, mypath
);
1450 smbfs_readdir(info
);
1451 smbfs_loaddir(info
);
1456 smbfs_stat (vfs
* me
, char *path
, struct stat
*buf
)
1458 smbfs_connection
*sc
;
1460 char *service
, *pp
, *at
;
1463 DEBUG (3, ("smbfs_stat(path:%s)\n", path
));
1465 if (!current_info
) {
1466 DEBUG (1, ("current_info = NULL: "));
1467 if (loaddir (me
, path
) < 0)
1471 /* check if stating server */
1473 if (strncmp (p
, URL_HEADER
, HEADER_LEN
)) {
1474 DEBUG (1, ("'%s' doesnt start with '%s' (length %d)\n",
1475 p
, URL_HEADER
, HEADER_LEN
));
1483 pp
= strchr (p
, '/'); /* advance past next '/' */
1484 at
= strchr (p
, '@');
1485 pstrcpy (server_url
, URL_HEADER
);
1486 if (at
&& at
< pp
) { /* user@server */
1487 char *z
= &(server_url
[sizeof (server_url
) - 1]);
1490 at
= &(server_url
[HEADER_LEN
]) + (at
- p
+ 1);
1493 at
= &(server_url
[HEADER_LEN
]);
1498 pstrcat (server_url
, current_bucket
->host
);
1501 if (!current_info
->server_list
) {
1502 if (loaddir (me
, path
) < 0)
1505 return fake_server_stat (server_url
, path
, buf
);
1508 if (!strchr (++pp
, '/')) {
1509 return fake_share_stat (server_url
, path
, buf
);
1512 /* stating inside share at this point */
1513 if (!(service
= smbfs_get_path (&sc
, path
))) /* connects if necessary */
1516 int hostlen
= strlen (current_bucket
->host
);
1517 char *pp
= service
+ strlen (service
) - hostlen
;
1518 char *sp
= server_url
+ strlen (server_url
) - hostlen
;
1520 if (strcmp (sp
, pp
) == 0) {
1521 /* make server name appear as directory */
1522 DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1523 memset (buf
, 0, sizeof (struct stat
));
1524 buf
->st_mode
= S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
;
1529 /* check if current_info is in share requested */
1531 pp
= strchr (p
, '/');
1533 p
= ++pp
; /* advance past server name */
1534 pp
= strchr (p
, '/');
1537 *pp
= 0; /* cut off everthing after service name */
1539 p
= IPC
; /* browsing for services */
1540 pp
= current_info
->dirname
;
1543 if (strncmp (p
, pp
, strlen (p
)) != 0) {
1544 DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p
, pp
));
1545 if (loaddir (me
, path
) < 0) {
1549 DEBUG (6, ("loaded dir: '%s'\n", current_info
->dirname
));
1552 /* stat dirs & files under shares now */
1553 return get_stat_info (sc
, path
, buf
);
1556 #define smbfs_lstat smbfs_stat /* no symlinks on smb filesystem? */
1559 smbfs_lseek (void *data
, off_t offset
, int whence
)
1561 DEBUG(3, ("smbfs_lseek()\n"));
1562 my_errno
= EOPNOTSUPP
;
1567 smbfs_mknod (vfs
*me
, char *path
, int mode
, int dev
)
1569 DEBUG(3, ("smbfs_mknod(path:%s, mode:%d, dev:%d)\n", path
, mode
, dev
));
1570 my_errno
= EOPNOTSUPP
;
1575 smbfs_mkdir (vfs
*me
, char *path
, mode_t mode
)
1577 smbfs_connection
*sc
;
1580 DEBUG(3, ("smbfs_mkdir(path:%s, mode:%d)\n", path
, mode
));
1581 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1583 g_free (remote_file
);
1584 convert_path(&path
, FALSE
);
1586 if (!cli_mkdir(sc
->cli
, path
)) {
1587 my_errno
= cli_error(sc
->cli
, NULL
, &err
, NULL
);
1588 message_3s (1, MSG_ERROR
, _(" Error %s creating directory %s "),
1589 cli_errstr(sc
->cli
), CNV_LANG(path
));
1598 smbfs_rmdir (vfs
*me
, char *path
)
1600 smbfs_connection
*sc
;
1603 DEBUG(3, ("smbfs_rmdir(path:%s)\n", path
));
1604 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1606 g_free (remote_file
);
1607 convert_path(&path
, FALSE
);
1609 if (!cli_rmdir(sc
->cli
, path
)) {
1610 my_errno
= cli_error(sc
->cli
, NULL
, &err
, NULL
);
1611 message_3s (1, MSG_ERROR
, _(" Error %s removing directory %s "),
1612 cli_errstr(sc
->cli
), CNV_LANG(path
));
1622 smbfs_link (vfs
*me
, char *p1
, char *p2
)
1624 DEBUG(3, ("smbfs_link(p1:%s, p2:%s)\n", p1
, p2
));
1625 my_errno
= EOPNOTSUPP
;
1629 /* We do not free anything right now: we free resources when we run
1633 smbfs_getid (vfs
*me
, char *p
, struct vfs_stamping
**parent
)
1636 DEBUG(3, ("smbfs_getid(p:%s)\n", p
));
1642 smbfs_nothingisopen (vfsid id
)
1644 DEBUG(3, ("smbfs_nothingisopen(%d)\n", (int)id
));
1649 smbfs_free (vfsid id
)
1651 DEBUG(3, ("smbfs_free(%d)\n", (int)id
));
1652 /* FIXME: Should not be empty */
1653 authinfo_free_all ();
1656 /* Gives up on a socket and reopens the connection, the child own the socket
1660 my_forget (char *path
)
1662 char *host
, *user
, *p
;
1665 if (strncmp (path
, URL_HEADER
, HEADER_LEN
))
1668 DEBUG(3, ("my_forget(path:%s)\n", path
));
1671 if (path
[0] == '/' && path
[1] == '/')
1674 if ((p
= smbfs_get_host_and_username (&path
, &host
, &user
, &port
, NULL
))) {
1676 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
1677 if ((strcmp (host
, smbfs_connections
[i
].host
) == 0) &&
1678 (strcmp (user
, smbfs_connections
[i
].user
) == 0) &&
1679 (port
== smbfs_connections
[i
].port
)) {
1681 /* close socket: the child owns it now */
1682 cli_shutdown(smbfs_connections
[i
].cli
);
1684 /* reopen the connection */
1685 smbfs_connections
[i
].cli
=
1686 smbfs_do_connect(host
, smbfs_connections
[i
].service
);
1695 smbfs_setctl (vfs
*me
, char *path
, int ctlop
, char *arg
)
1697 DEBUG(3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path
, ctlop
));
1699 case MCCTL_FORGET_ABOUT
:
1706 static smbfs_handle
*
1707 open_write (smbfs_handle
*remote_handle
, char *rname
, int flags
, int mode
)
1709 if (flags
& O_TRUNC
) /* if it exists truncate to zero */
1710 DEBUG(3, ("open_write: O_TRUNC\n"));
1712 remote_handle
->fnum
= cli_open(remote_handle
->cli
, rname
, flags
, DENY_NONE
);
1714 if (remote_handle
->fnum
== -1) {
1715 message_3s (1, MSG_ERROR
, _(" %s opening remote file %s "),
1716 cli_errstr(remote_handle
->cli
), CNV_LANG(rname
));
1717 DEBUG(1,("smbfs_open(rname:%s) error:%s\n",
1718 rname
, cli_errstr(remote_handle
->cli
)));
1719 my_errno
= cli_error(remote_handle
->cli
, NULL
, &err
, NULL
);
1723 return remote_handle
;
1726 static smbfs_handle
*
1727 open_read (smbfs_handle
*remote_handle
, char *rname
, int flags
, int mode
)
1731 remote_handle
->fnum
=
1732 cli_open(remote_handle
->cli
, rname
, O_RDONLY
, DENY_NONE
);
1734 if (remote_handle
->fnum
== -1) {
1735 message_3s (1, MSG_ERROR
, _(" %s opening remote file %s "),
1736 cli_errstr(remote_handle
->cli
), CNV_LANG(rname
));
1737 DEBUG(1,("smbfs_open(rname:%s) error:%s\n",
1738 rname
, cli_errstr(remote_handle
->cli
)));
1739 my_errno
= cli_error(remote_handle
->cli
, NULL
, &err
, NULL
);
1743 if (!cli_qfileinfo(remote_handle
->cli
, remote_handle
->fnum
,
1744 &remote_handle
->attr
, &size
, NULL
, NULL
, NULL
, NULL
, NULL
) &&
1745 !cli_getattrE(remote_handle
->cli
, remote_handle
->fnum
,
1746 &remote_handle
->attr
, &size
, NULL
, NULL
, NULL
)) {
1747 message_2s (1, MSG_ERROR
, " getattrib: %s ",
1748 cli_errstr(remote_handle
->cli
));
1749 DEBUG(1,("smbfs_open(rname:%s) getattrib:%s\n",
1750 rname
, cli_errstr(remote_handle
->cli
)));
1751 my_errno
= cli_error(remote_handle
->cli
, NULL
, &err
, NULL
);
1755 return remote_handle
;
1759 smbfs_open (vfs
*me
, char *file
, int flags
, int mode
)
1761 char *remote_file
, *p
;
1763 smbfs_connection
*sc
;
1764 smbfs_handle
*remote_handle
;
1766 DEBUG(3, ("smbfs_open(file:%s, flags:%d, mode:%d)\n", file
, flags
, mode
));
1768 if (!(remote_file
= smbfs_get_path (&sc
, file
)))
1772 convert_path(&remote_file
, FALSE
);
1775 remote_handle
= g_new (smbfs_handle
, 2);
1776 remote_handle
->cli
= sc
->cli
;
1777 remote_handle
->nread
= 0;
1779 if (flags
& O_CREAT
)
1780 ret
= open_write(remote_handle
, remote_file
, flags
, mode
);
1782 ret
= open_read(remote_handle
, remote_file
, flags
, mode
);
1784 g_free (remote_file
);
1790 smbfs_unlink (vfs
*me
, char *path
)
1792 smbfs_connection
*sc
;
1793 char *remote_file
, *p
;
1795 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1799 convert_path(&remote_file
, FALSE
);
1802 if (!cli_unlink(sc
->cli
, remote_file
)) {
1803 message_3s (1, MSG_ERROR
, _(" %s removing remote file %s "),
1804 cli_errstr(sc
->cli
), CNV_LANG(remote_file
));
1805 g_free (remote_file
);
1808 g_free (remote_file
);
1813 smbfs_rename (vfs
*me
, char *a
, char *b
)
1815 smbfs_connection
*sc
;
1820 if ((ra
= smbfs_get_path (&sc
, a
)) == 0)
1823 if ((rb
= smbfs_get_path (&sc
, b
)) == 0) {
1829 convert_path(&ra
, FALSE
);
1832 convert_path(&rb
, FALSE
);
1835 retval
= cli_rename(sc
->cli
, ra
, rb
);
1841 message_2s (1, MSG_ERROR
, _(" %s renaming files\n"),
1842 cli_errstr(sc
->cli
));
1849 smbfs_fstat (void *data
, struct stat
*buf
)
1851 smbfs_handle
*remote_handle
= (smbfs_handle
*)data
;
1853 DEBUG(3, ("smbfs_fstat(fnum:%d)\n", remote_handle
->fnum
));
1855 /* use left over from previous get_remote_stat, if available */
1857 memcpy(buf
, &single_entry
->my_stat
, sizeof(struct stat
));
1858 else { /* single_entry not set up: bug */
1865 vfs vfs_smbfs_ops
= {
1866 NULL
, /* This is place of next pointer */
1869 "smb:", /* prefix */
1908 smbfs_nothingisopen
,