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>
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License
11 as published by the Free Software Foundation; either version 2 of
12 the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 /* Namespace: exports smbfs_vfs_ops, smbfs_set_debug */
26 #include <sys/types.h>
29 #include "samba/include/config.h"
30 /* don't load crap in "samba/include/includes.h" we don't use and which
31 conflicts with definitions in other includes */
32 #undef HAVE_LIBREADLINE
36 #include "samba/include/includes.h"
42 #include "../src/dialog.h"
44 #define SMBFS_MAX_CONNECTIONS 16
45 static const char * const IPC
= "IPC$";
46 static const char * const URL_HEADER
= "/#smb:";
52 /* stuff that is same with each connection */
53 extern int DEBUGLEVEL
;
54 extern pstring myhostname
;
55 static mode_t myumask
= 0755;
56 extern pstring global_myname
;
57 static int smbfs_open_connections
= 0;
58 static gboolean got_user
= FALSE
;
59 static gboolean got_pass
= FALSE
;
60 static pstring password
;
61 static pstring username
;
63 static struct _smbfs_connection
{
64 struct cli_state
*cli
;
65 struct in_addr dest_ip
;
67 char *host
; /* server name */
68 char *service
; /* share name */
76 } smbfs_connections
[SMBFS_MAX_CONNECTIONS
];
77 /* unique to each connection */
79 typedef struct _smbfs_connection smbfs_connection
;
80 static smbfs_connection
*current_bucket
;
83 struct cli_state
*cli
;
89 static GSList
*auth_list
;
92 authinfo_free (struct smb_authinfo
const *a
)
98 wipe_password (a
->password
);
105 g_slist_foreach (auth_list
, (GFunc
)authinfo_free
, 0);
106 g_slist_free (auth_list
);
112 authinfo_compare_host_and_share (gconstpointer _a
, gconstpointer _b
)
114 struct smb_authinfo
const *a
= (struct smb_authinfo
const *)_a
;
115 struct smb_authinfo
const *b
= (struct smb_authinfo
const *)_b
;
117 if (!a
->host
|| !a
->share
|| !b
->host
|| !b
->share
)
119 if (strcmp (a
->host
, b
->host
) != 0)
121 if (strcmp (a
->share
, b
->share
) != 0)
127 authinfo_compare_host (gconstpointer _a
, gconstpointer _b
)
129 struct smb_authinfo
const *a
= (struct smb_authinfo
const *)_a
;
130 struct smb_authinfo
const *b
= (struct smb_authinfo
const *)_b
;
132 if (!a
->host
|| !b
->host
)
134 if (strcmp (a
->host
, b
->host
) != 0)
136 if (strcmp (a
->share
, IPC
) != 0)
142 authinfo_add (const char *host
, const char *share
, const char *domain
,
143 const char *user
, const char *password
)
145 struct smb_authinfo
*auth
= g_new (struct smb_authinfo
, 1);
150 /* Don't check for NULL, g_strdup already does. */
151 auth
->host
= g_strdup (host
);
152 auth
->share
= g_strdup (share
);
153 auth
->domain
= g_strdup (domain
);
154 auth
->user
= g_strdup (user
);
155 auth
->password
= g_strdup (password
);
156 auth_list
= g_slist_prepend (auth_list
, auth
);
160 authinfo_remove (const char *host
, const char *share
)
162 struct smb_authinfo data
;
163 struct smb_authinfo
*auth
;
166 data
.host
= g_strdup (host
);
167 data
.share
= g_strdup (share
);
168 list
= g_slist_find_custom (auth_list
,
170 authinfo_compare_host_and_share
);
176 auth_list
= g_slist_remove (auth_list
, auth
);
177 authinfo_free (auth
);
180 /* Set authentication information in bucket. Return 1 if successful, else 0 */
181 /* Information in auth_list overrides user if pass is NULL. */
182 /* bucket->host and bucket->service must be valid. */
184 bucket_set_authinfo (smbfs_connection
*bucket
,
185 const char *domain
, const char *user
, const char *pass
,
186 int fallback_to_host
)
188 struct smb_authinfo data
;
189 struct smb_authinfo
*auth
;
192 if (domain
&& user
&& pass
) {
193 g_free (bucket
->domain
);
194 g_free (bucket
->user
);
195 g_free (bucket
->password
);
196 bucket
->domain
= g_strdup (domain
);
197 bucket
->user
= g_strdup (user
);
198 bucket
->password
= g_strdup (pass
);
199 authinfo_remove (bucket
->host
, bucket
->service
);
200 authinfo_add (bucket
->host
, bucket
->service
,
205 data
.host
= bucket
->host
;
206 data
.share
= bucket
->service
;
207 list
= g_slist_find_custom (auth_list
, &data
, authinfo_compare_host_and_share
);
208 if (!list
&& fallback_to_host
)
209 list
= g_slist_find_custom (auth_list
, &data
, authinfo_compare_host
);
212 bucket
->domain
= g_strdup (auth
->domain
);
213 bucket
->user
= g_strdup (auth
->user
);
214 bucket
->password
= g_strdup (auth
->password
);
219 bucket
->domain
= g_strdup (lp_workgroup ());
220 bucket
->user
= g_strdup (got_user
? username
: user
);
221 bucket
->password
= g_strdup (password
);
225 auth
= vfs_smb_get_authinfo (bucket
->host
,
227 (domain
? domain
: lp_workgroup ()),
230 g_free (bucket
->domain
);
231 g_free (bucket
->user
);
232 g_free (bucket
->password
);
233 bucket
->domain
= g_strdup (auth
->domain
);
234 bucket
->user
= g_strdup (auth
->user
);
235 bucket
->password
= g_strdup (auth
->password
);
236 authinfo_remove (bucket
->host
, bucket
->service
);
237 auth_list
= g_slist_prepend (auth_list
, auth
);
244 smbfs_set_debug(int arg
)
249 /********************** The callbacks ******************************/
253 char *servicesf
= CONFIGDIR
"/smb.conf";
255 /* DEBUGLEVEL = 4; */
257 setup_logging("mc", True
);
259 charset_initialise();
261 DEBUG(3, ("smbfs_init(%s)\n", me
->name
));
263 if(!get_myname(myhostname
,NULL
))
264 DEBUG(0,("Failed to get my hostname.\n"));
266 if (!lp_load(servicesf
,True
,False
,False
))
267 DEBUG(0, ("Cannot load %s - run testparm to debug it\n", servicesf
));
269 codepage_initialise(lp_client_code_page());
275 if (getenv("USER")) {
277 pstrcpy(username
, getenv("USER"));
279 DEBUG(3, ("smbfs_init(): $USER:%s\n", username
));
280 if ((p
= strchr(username
, '%'))) {
282 pstrcpy(password
, p
+1);
284 memset(strchr(getenv("USER"), '%')+1, 'X', strlen(password
));
285 DEBUG(3, ("smbfs_init(): $USER%%pass: %s%%%s\n",
286 username
, password
));
290 if (getenv("PASSWD")) {
291 pstrcpy(password
, getenv("PASSWD"));
298 smbfs_fill_names (vfs
*me
, void (*func
)(char *))
302 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
303 if (smbfs_connections
[i
].cli
) {
304 path
= g_strconcat (URL_HEADER
,
305 smbfs_connections
[i
].host
,
306 "/", smbfs_connections
[i
].service
,
314 #define CNV_LANG(s) dos_to_unix(s,False)
315 #define GNAL_VNC(s) unix_to_dos(s,False)
316 /* does same as do_get() in client.c */
317 /* called from vfs.c:1080, count = buffer size */
319 smbfs_read (void *data
, char *buffer
, int count
)
321 smbfs_handle
*info
= (smbfs_handle
*) data
;
324 DEBUG(3, ("smbfs_read(fnum:%d, nread:%d, count:%d)\n",
325 info
->fnum
, (int)info
->nread
, count
));
326 n
= cli_read(info
->cli
, info
->fnum
, buffer
, info
->nread
, count
);
333 smbfs_write (void *data
, char *buf
, int nbyte
)
335 smbfs_handle
*info
= (smbfs_handle
*) data
;
338 DEBUG(3, ("smbfs_write(fnum:%d, nread:%d, nbyte:%d)\n",
339 info
->fnum
, (int)info
->nread
, nbyte
));
340 n
= cli_write(info
->cli
, info
->fnum
, 0, buf
, info
->nread
, nbyte
);
347 smbfs_close (void *data
)
349 smbfs_handle
*info
= (smbfs_handle
*) data
;
350 DEBUG(3, ("smbfs_close(fnum:%d)\n", info
->fnum
));
351 /* if imlementing archive_level: add rname to smbfs_handle
352 if (archive_level >= 2 && (inf->attr & aARCH)) {
353 cli_setatr(info->cli, rname, info->attr & ~(uint16)aARCH, 0);
355 return (cli_close(info
->cli
, info
->fnum
) == True
) ? 0 : -1;
359 smbfs_errno (vfs
*me
)
361 DEBUG(3, ("smbfs_errno: %s\n", g_strerror(my_errno
)));
365 typedef struct dir_entry
{
367 struct dir_entry
*next
;
373 gboolean server_list
;
375 char *path
; /* the dir originally passed to smbfs_opendir */
376 smbfs_connection
*conn
;
385 *current_server_info
;
387 static gboolean first_direntry
;
390 new_dir_entry (const char * name
)
392 dir_entry
*new_entry
;
393 new_entry
= g_new0 (dir_entry
, 1);
394 new_entry
->text
= dos_to_unix (g_strdup (name
), 1);
396 if (first_direntry
) {
397 current_info
->entries
= new_entry
;
398 first_direntry
= FALSE
;
400 current_info
->current
->next
= new_entry
;
402 current_info
->current
= new_entry
;
408 smbfs_add_dots (opendir_info
*current_info
)
412 entry
= g_new0 (dir_entry
, 1);
413 entry
->text
= g_strdup (".");
414 entry
->my_stat
.st_mode
= S_IFDIR
|S_IRUSR
|S_IRGRP
|S_IROTH
;
416 entry
->next
= g_new0 (dir_entry
, 1);
417 entry
->next
->text
= g_strdup ("..");
418 entry
->next
->my_stat
.st_mode
= S_IFDIR
|S_IRUSR
|S_IRGRP
|S_IROTH
;
420 entry
->next
->next
= current_info
->entries
;
421 current_info
->entries
= entry
;
425 /* browse for shares on server */
427 browsing_helper(const char *name
, uint32 type
, const char *comment
)
431 dir_entry
*new_entry
= new_dir_entry (name
);
436 /* show this as dir */
437 new_entry
->my_stat
.st_mode
= S_IFDIR
|S_IRUSR
|S_IRGRP
|S_IROTH
;
440 typestr
= "Printer"; break;
442 typestr
= "Device"; break;
444 typestr
= "IPC"; break;
446 DEBUG(3, ("\t%-15.15s%-10.10s%s\n", name
, typestr
, comment
));
450 loaddir_helper(file_info
*finfo
, const char *mask
)
452 dir_entry
*new_entry
;
453 time_t t
= finfo
->mtime
; /* the time is assumed to be passed as GMT */
454 #if 0 /* I want to see dot files */
455 if (finfo
->mode
& aHIDDEN
)
456 return; /* don't bother with hidden files, "~$" screws up mc */
458 new_entry
= new_dir_entry (finfo
->name
);
460 new_entry
->my_stat
.st_size
= finfo
->size
;
461 new_entry
->my_stat
.st_mtime
= finfo
->mtime
;
462 new_entry
->my_stat
.st_atime
= finfo
->atime
;
463 new_entry
->my_stat
.st_ctime
= finfo
->ctime
;
464 new_entry
->my_stat
.st_uid
= finfo
->uid
;
465 new_entry
->my_stat
.st_gid
= finfo
->gid
;
468 new_entry
->my_stat
.st_mode
=
469 S_IRUSR
|S_IRGRP
|S_IROTH
|S_IWUSR
|S_IWGRP
|S_IWOTH
;
471 /* if (finfo->mode & aVOLID); nothing similar in real world */
472 if (finfo
->mode
& aDIR
)
473 new_entry
->my_stat
.st_mode
|= S_IFDIR
;
475 new_entry
->my_stat
.st_mode
|= S_IFREG
; /* if not dir, regular file? */
476 /* if (finfo->mode & aARCH); DOS archive */
477 /* if (finfo->mode & aHIDDEN); like a dot file? */
478 /* if (finfo->mode & aSYSTEM); like a kernel? */
479 if (finfo
->mode
& aRONLY
)
480 new_entry
->my_stat
.st_mode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
482 DEBUG(3, (" %-30s%7.7s%8.0f %s",
483 CNV_LANG(finfo
->name
),
484 attrib_string(finfo
->mode
),
486 asctime(LocalTime(&t
))));
489 /* takes "/foo/bar/file" and gives malloced "\\foo\\bar\\file" */
491 convert_path(char **remote_file
, gboolean trailing_asterik
)
495 my_remote
= *remote_file
;
496 if (strncmp (my_remote
, URL_HEADER
, HEADER_LEN
) == 0) { /* if passed directly */
498 if (*my_remote
== '/') /* from server browsing */
500 p
= strchr(my_remote
, '/');
502 my_remote
= p
+1; /* advance to end of server name */
505 if (*my_remote
== '/')
506 my_remote
++; /* strip off leading '/' */
507 p
= strchr(my_remote
, '/');
509 my_remote
= p
; /* strip off share/service name */
510 /* create remote filename as understood by smb clientgen */
511 p
= *remote_file
= g_strconcat (my_remote
, trailing_asterik
? "/*" : "", 0);
512 unix_to_dos (*remote_file
, 1);
513 while ((p
= strchr(p
, '/')))
519 server_browsing_helper(const char *name
, uint32 m
, const char *comment
)
521 dir_entry
*new_entry
= new_dir_entry (name
);
523 /* show this as dir */
524 new_entry
->my_stat
.st_mode
= S_IFDIR
|S_IRUSR
|S_IRGRP
|S_IROTH
;
526 DEBUG(3, ("\t%-16.16s %s\n", name
, comment
));
530 reconnect(smbfs_connection
*conn
, int *retries
)
533 DEBUG(3, ("RECONNECT\n"));
535 if (*(conn
->host
) == 0)
536 host
= g_strdup(conn
->cli
->desthost
); /* server browsing */
538 host
= g_strdup(conn
->host
);
540 cli_shutdown(conn
->cli
);
542 if (!(conn
->cli
= do_connect(host
, conn
->service
))) {
543 message_2s (1, MSG_ERROR
,
544 _(" reconnect to %s failed\n "), conn
->host
);
549 if (++(*retries
) == 2)
555 smb_send(struct cli_state
*cli
)
561 len
= smb_len(cli
->outbuf
) + 4;
563 while (nwritten
< len
) {
564 ret
= write_socket(cli
->fd
, cli
->outbuf
+nwritten
, len
- nwritten
);
565 if (ret
<= 0 && errno
== EPIPE
)
573 /****************************************************************************
574 See if server has cut us off by checking for EPIPE when writing.
575 Taken from cli_chkpath()
576 ****************************************************************************/
578 chkpath(struct cli_state
*cli
, char *path
, BOOL send_only
)
584 unix_to_dos (path2
, 1);
585 trim_string(path2
,NULL
,"\\");
586 if (!*path2
) *path2
= '\\';
588 memset(cli
->outbuf
,'\0',smb_size
);
589 set_message(cli
->outbuf
,0,4 + strlen(path2
),True
);
590 SCVAL(cli
->outbuf
,smb_com
,SMBchkpth
);
591 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
595 SSVAL(cli
->outbuf
,smb_pid
,cli
->pid
);
596 SSVAL(cli
->outbuf
,smb_uid
,cli
->vuid
);
597 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
);
598 if (cli
->protocol
> PROTOCOL_CORE
) {
599 SCVAL(cli
->outbuf
,smb_flg
,0x8);
600 SSVAL(cli
->outbuf
,smb_flg2
,0x1);
603 p
= smb_buf(cli
->outbuf
);
607 if (!smb_send(cli
)) {
608 DEBUG(3, ("chkpath: couldnt send\n"));
612 client_receive_smb(cli
->fd
, cli
->inbuf
, cli
->timeout
);
613 DEBUG(3, ("chkpath: send only OK\n"));
614 return True
; /* just testing for EPIPE */
616 if (!client_receive_smb(cli
->fd
, cli
->inbuf
, cli
->timeout
)) {
617 DEBUG(3, ("chkpath: receive error\n"));
620 if ((my_errno
= cli_error(cli
, NULL
, NULL
, NULL
))) {
621 if (my_errno
== 20 || my_errno
== 13)
622 return True
; /* ignore if 'not a directory' error */
623 DEBUG(3, ("chkpath: cli_error: %s\n", g_strerror(my_errno
)));
632 fs (const char *text
)
634 const char *p
= text
;
637 while ((p
= strchr(p
, '/')) != NULL
) {
648 smbfs_loaddir (opendir_info
*smbfs_info
)
650 uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
651 int servlen
= strlen(smbfs_info
->conn
->service
);
652 char *my_dirname
= smbfs_info
->dirname
;
654 DEBUG(3, ("smbfs_loaddir: dirname:%s\n", my_dirname
));
655 first_direntry
= TRUE
;
658 DEBUG(3, ("smbfs_loaddir: new:'%s', cached:'%s'\n", my_dirname
, current_info
->dirname
));
659 /* if new desired dir is longer than cached in current_info */
660 if (fs(my_dirname
) > fs(current_info
->dirname
)) {
661 DEBUG(3, ("saving to previous_info\n"));
662 previous_info
= current_info
;
666 current_info
= smbfs_info
;
668 if (strcmp(my_dirname
, "/") == 0) {
669 if (!strcmp(smbfs_info
->path
, URL_HEADER
)) {
670 DEBUG(6, ("smbfs_loaddir: browsing %s\n", IPC
));
671 /* browse for servers */
672 if (!cli_NetServerEnum(smbfs_info
->conn
->cli
, smbfs_info
->conn
->domain
,
673 SV_TYPE_ALL
, server_browsing_helper
))
676 current_server_info
= smbfs_info
;
677 smbfs_info
->server_list
= TRUE
;
679 /* browse for shares */
680 if (cli_RNetShareEnum(smbfs_info
->conn
->cli
, browsing_helper
) < 1)
683 current_share_info
= smbfs_info
;
685 smbfs_add_dots (smbfs_info
);
689 /* do regular directory listing */
690 if(strncmp(smbfs_info
->conn
->service
, my_dirname
+1, servlen
) == 0) {
691 /* strip share name from dir */
692 char *p
= my_dirname
= g_strdup(my_dirname
+ servlen
);
694 convert_path(&my_dirname
, TRUE
);
697 convert_path(&my_dirname
, TRUE
);
699 DEBUG(6, ("smbfs_loaddir: service: %s\n", smbfs_info
->conn
->service
));
700 DEBUG(6, ("smbfs_loaddir: cli->share: %s\n", smbfs_info
->conn
->cli
->share
));
701 DEBUG(6, ("smbfs_loaddir: calling cli_list with mask %s\n", my_dirname
));
702 /* do file listing: cli_list returns number of files */
704 smbfs_info
->conn
->cli
, my_dirname
, attribute
, loaddir_helper
) < 0) {
705 /* cli_list returns -1 if directory empty or cannot read socket */
706 my_errno
= cli_error(smbfs_info
->conn
->cli
, NULL
, &err
, NULL
);
710 if (*(my_dirname
) == 0)
711 smbfs_info
->dirname
= smbfs_info
->conn
->service
;
716 /* current_info->parent = smbfs_info->dirname; */
718 smbfs_info
->current
= smbfs_info
->entries
;
719 return 1; /* 1 = ok */
722 #ifdef SMBFS_FREE_DIR
724 smbfs_free_dir (dir_entry
*de
)
728 smbfs_free_dir (de
->next
);
735 * On some operating systems (Slowaris 2 for example)
736 * the d_name member is just a char long (Nice trick that break everything,
737 * so we need to set up some space for the filename.
741 #ifdef NEED_EXTRA_DIRENT_BUFFER
742 char extra_buffer
[MC_MAXPATHLEN
];
744 } smbfs_readdir_data
;
747 /* The readdir routine loads the complete directory */
748 /* It's too slow to ask the server each time */
749 /* It now also sends the complete lstat information for each file */
751 smbfs_readdir (void *info
)
753 static char * const dirent_dest
= &(smbfs_readdir_data
.dent
.d_name
[0]);
754 opendir_info
*smbfs_info
= (opendir_info
*) info
;
756 DEBUG(4, ("smbfs_readdir(%s)\n", smbfs_info
->dirname
));
758 if (!smbfs_info
->entries
)
759 if (!smbfs_loaddir (smbfs_info
))
762 if (smbfs_info
->current
== 0) { /* reached end of dir entries */
763 DEBUG(3, ("smbfs_readdir: smbfs_info->current = 0\n"));
764 #ifdef SMBFS_FREE_DIR
765 smbfs_free_dir (smbfs_info
->entries
);
766 smbfs_info
->entries
= 0;
770 pstrcpy (dirent_dest
, smbfs_info
->current
->text
);
771 smbfs_info
->current
= smbfs_info
->current
->next
;
773 #ifndef DIRENT_LENGTH_COMPUTED
774 smbfs_readdir_data
.dent
.d_namlen
= strlen (smbfs_readdir_data
.dent
.d_name
);
777 return &smbfs_readdir_data
;
781 smbfs_closedir (void *info
)
783 opendir_info
*smbfs_info
= (opendir_info
*) info
;
784 /* dir_entry *p, *q; */
786 DEBUG(3, ("smbfs_closedir(%s)\n", smbfs_info
->dirname
));
789 /* for (p = smbfs_info->entries; p;){
800 smbfs_chmod (vfs
*me
, char *path
, int mode
)
802 DEBUG(3, ("smbfs_chmod(path:%s, mode:%d)\n", path
, mode
));
803 /* my_errno = EOPNOTSUPP;
804 return -1; */ /* cant chmod on smb filesystem */
805 return 0; /* make mc happy */
809 smbfs_chown (vfs
*me
, char *path
, int owner
, int group
)
811 DEBUG(3, ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path
, owner
, group
));
812 my_errno
= EOPNOTSUPP
; /* ready for your labotomy? */
817 smbfs_utime (vfs
*me
, char *path
, struct utimbuf
*times
)
819 DEBUG(3, ("smbfs_utime(path:%s)\n", path
));
820 my_errno
= EOPNOTSUPP
;
825 smbfs_readlink (vfs
*me
, char *path
, char *buf
, int size
)
827 DEBUG(3, ("smbfs_readlink(path:%s, buf:%s, size:%d)\n", path
, buf
, size
));
828 my_errno
= EOPNOTSUPP
;
829 return -1; /* no symlinks on smb filesystem? */
833 smbfs_symlink (vfs
*me
, char *n1
, char *n2
)
835 DEBUG(3, ("smbfs_symlink(n1:%s, n2:%s)\n", n1
, n2
));
836 my_errno
= EOPNOTSUPP
;
837 return -1; /* no symlinks on smb filesystem? */
840 /* Extract the hostname and username from the path */
841 /* path is in the form: hostname:user/remote-dir */
844 smbfs_get_host_and_username
845 (char **path
, char **host
, char **user
, int *port
, char **pass
)
850 ret
= vfs_split_url (*path
, host
, user
, port
, pass
, SMB_PORT
, 0);
853 if ((p
= strchr(*path
, '@'))) /* user:pass@server */
854 *path
= ++p
; /* don't want user:pass@ in path */
855 if ((p
= strchr(ret
, '@'))) /* user:pass@server */
856 ret
= ++p
; /* don't want user:pass@ in path */
862 #define smbfs_get_host_and_username(path, host, user, port, pass) \
863 vfs_split_url (*path, host, user, port, pass, SMB_PORT, 0)
865 /*****************************************************
866 return a connection to a SMB server
867 current_bucket needs to be set before calling
868 *******************************************************/
870 do_connect (char *server
, char *share
)
873 struct nmb_name called
, calling
;
875 extern struct in_addr ipzero
;
877 DEBUG(3, ("do_connect(%s, %s)\n", server
, share
));
878 if (*share
== '\\') {
880 share
= strchr(server
,'\\');
881 if (!share
) return NULL
;
888 make_nmb_name(&calling
, global_myname
, 0x0, "");
889 make_nmb_name(&called
, server
, current_bucket
->name_type
, "");
894 if (current_bucket
->have_ip
) ip
= current_bucket
->dest_ip
;
896 /* have to open a new connection */
897 if (!(c
= cli_initialise(NULL
))) {
902 pwd_init(&(c
->pwd
)); /* should be moved into cli_initialise()? */
903 pwd_set_cleartext(&(c
->pwd
), current_bucket
->password
);
905 if ((cli_set_port(c
, current_bucket
->port
) == 0) ||
906 !cli_connect(c
, server
, &ip
)) {
907 DEBUG(1, ("Connection to %s failed\n", server
));
911 if (!cli_session_request(c
, &calling
, &called
)) {
912 my_errno
= cli_error(c
, NULL
, &err
, NULL
);
913 DEBUG(1, ("session request to %s failed\n", called
.name
));
915 if (strcmp(called
.name
, "*SMBSERVER")) {
916 make_nmb_name(&called
, "*SMBSERVER", 0x20, "");
922 DEBUG(3, (" session request ok\n"));
924 if (!cli_negprot(c
)) {
925 DEBUG(1, ("protocol negotiation failed\n"));
929 if (!cli_session_setup(c
, current_bucket
->user
,
930 current_bucket
->password
, strlen(current_bucket
->password
),
931 current_bucket
->password
, strlen(current_bucket
->password
),
932 current_bucket
->domain
)) {
933 DEBUG(1,("session setup failed: %s\n", cli_errstr(c
)));
934 authinfo_remove (server
, share
);
938 if (*c
->server_domain
|| *c
->server_os
|| *c
->server_type
)
939 DEBUG(5,("Domain=[%s] OS=[%s] Server=[%s]\n",
940 c
->server_domain
,c
->server_os
,c
->server_type
));
942 DEBUG(3, (" session setup ok\n"));
944 if (!cli_send_tconX(c
, share
, "?????",
945 current_bucket
->password
, strlen(current_bucket
->password
)+1)) {
946 DEBUG(1,("%s: tree connect failed: %s\n", share
, cli_errstr(c
)));
950 DEBUG(3, (" tconx ok\n"));
956 my_errno
= cli_error(c
, NULL
, &err
, NULL
);
963 get_master_browser(char **host
)
966 struct in_addr
*ip_list
, bcast_addr
;
967 extern struct in_addr ipzero
;
969 /* does port = 137 for win95 master browser? */
970 int fd
= open_socket_in( SOCK_DGRAM
, 0, 3,
971 interpret_addr(lp_socket_address()), True
);
974 set_socket_options(fd
, "SO_BROADCAST");
975 ip_list
= iface_bcast(ipzero
);
976 bcast_addr
= *ip_list
;
977 if ((ip_list
= name_query(fd
, "\01\02__MSBROWSE__\02", 1, True
,
978 True
, bcast_addr
, &count
, NULL
))) {
981 /* just return first master browser */
982 *host
= g_strdup(inet_ntoa(ip_list
[0]));
989 free_bucket (smbfs_connection
*bucket
)
991 g_free (bucket
->host
);
992 g_free (bucket
->service
);
993 g_free (bucket
->domain
);
994 g_free (bucket
->user
);
995 wipe_password (bucket
->password
);
996 g_free (bucket
->home
);
997 bzero (bucket
, sizeof (smbfs_connection
));
1000 static smbfs_connection
*
1001 smbfs_get_free_bucket ()
1005 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++)
1006 if (!smbfs_connections
[i
].cli
) return &smbfs_connections
[i
];
1008 { /* search for most dormant connection */
1009 int oldest
= 0; /* index */
1010 time_t oldest_time
= smbfs_connections
[0].last_use
;
1011 for (i
= 1; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
1012 if (smbfs_connections
[i
].last_use
< oldest_time
) {
1013 oldest_time
= smbfs_connections
[i
].last_use
;
1017 cli_shutdown(smbfs_connections
[oldest
].cli
);
1018 free_bucket (&smbfs_connections
[oldest
]);
1019 return &smbfs_connections
[oldest
];
1022 /* This can't happend, since we have checked for max connections before */
1023 vfs_die("Internal error: smbfs_get_free_bucket");
1024 return 0; /* shut up, stupid gcc */
1027 /* This routine keeps track of open connections */
1028 /* Returns a connected socket to host */
1029 static smbfs_connection
*
1030 smbfs_open_link(char *host
, char *path
, const char *user
, int *port
, char *this_pass
)
1033 smbfs_connection
*bucket
;
1035 struct in_addr
*dest_ip
= NULL
;
1037 DEBUG(3, ("smbfs_open_link(host:%s, path:%s)\n", host
, path
));
1039 if (strcmp(host
, path
) == 0) /* if host & path are same: */
1040 pstrcpy(service
, IPC
); /* setup for browse */
1041 else { /* get share name from path, path starts with server name */
1043 if ((p
= strchr(path
, '/'))) /* get share aka */
1044 pstrcpy(service
, ++p
); /* service name from path */
1046 pstrcpy(service
, "");
1047 /* now check for trailing directory/filenames */
1048 p
= strchr(service
, '/');
1050 *p
= 0; /* cut off dir/files: sharename only */
1052 DEBUG(6, ("smbfs_open_link: service from path:%s\n", service
));
1056 user
= username
; /* global from getenv */
1058 /* Is the link actually open? */
1059 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
1060 if (!smbfs_connections
[i
].cli
)
1062 if ((strcmp (host
, smbfs_connections
[i
].host
) == 0) &&
1063 (strcmp (user
, smbfs_connections
[i
].user
) == 0) &&
1064 (strcmp (service
, smbfs_connections
[i
].service
) == 0)) {
1066 BOOL inshare
= (*host
!= 0 && *path
!= 0 && strchr(path
, '/'));
1067 /* check if this connection has died */
1068 while (!chkpath(smbfs_connections
[i
].cli
, "\\", !inshare
)) {
1069 if (!reconnect(&smbfs_connections
[i
], &retries
))
1072 DEBUG(6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i
));
1073 current_bucket
= &smbfs_connections
[i
];
1074 smbfs_connections
[i
].last_use
= time(NULL
);
1075 return &smbfs_connections
[i
];
1077 /* connection not found, find if we have ip for new connection */
1078 if (strcmp (host
, smbfs_connections
[i
].host
) == 0)
1079 dest_ip
= &smbfs_connections
[i
].cli
->dest_ip
;
1082 /* make new connection */
1083 bucket
= smbfs_get_free_bucket ();
1084 bucket
->name_type
= 0x20;
1086 bucket
->port
= *port
;
1087 bucket
->have_ip
= False
;
1089 bucket
->have_ip
= True
;
1090 bucket
->dest_ip
= *dest_ip
;
1092 current_bucket
= bucket
;
1094 bucket
->user
= g_strdup(user
);
1095 bucket
->service
= g_strdup (service
);
1097 if (!(*host
)) { /* if blank host name, browse for servers */
1098 if (!get_master_browser(&host
)) /* set host to ip of master browser */
1099 return 0; /* couldnt find master browser? */
1101 bucket
->host
= g_strdup(""); /* blank host means master browser */
1103 bucket
->host
= g_strdup(host
);
1105 if (!bucket_set_authinfo (bucket
,
1106 0, /* domain currently not used */
1112 /* connect to share */
1113 while (!(bucket
->cli
= do_connect(host
, service
))) {
1115 if (my_errno
!= EPERM
)
1117 message_1s (1, MSG_ERROR
,
1118 _(" Authentication failed "));
1120 /* authentication failed, try again */
1121 authinfo_remove (bucket
->host
, bucket
->service
);
1122 if (!bucket_set_authinfo (bucket
,
1131 smbfs_open_connections
++;
1132 DEBUG(3, ("smbfs_open_link:smbfs_open_connections: %d\n",
1133 smbfs_open_connections
));
1138 smbfs_get_path(smbfs_connection
**sc
, char *path
)
1140 char *user
, *host
, *remote_path
, *pass
;
1141 int port
= SMB_PORT
;
1143 DEBUG(3, ("smbfs_get_path(%s)\n", path
));
1144 if (strncmp (path
, URL_HEADER
, HEADER_LEN
))
1148 if (*path
== '/') /* '/' leading server name */
1149 path
++; /* probably came from server browsing */
1151 if ((remote_path
= smbfs_get_host_and_username(
1152 &path
, &host
, &user
, &port
, &pass
)))
1153 if ((*sc
= smbfs_open_link (host
, path
, user
, &port
, pass
)) == NULL
){
1154 g_free (remote_path
);
1159 if (pass
) wipe_password (pass
);
1161 if (!remote_path
) return NULL
;
1163 /* NOTE: tildes are deprecated. See ftpfs.c */
1165 int f
= !strcmp( remote_path
, "/~" );
1166 if (f
|| !strncmp( remote_path
, "/~/", 3 )) {
1168 s
= concat_dir_and_file( (*sc
)->home
, remote_path
+3-f
);
1169 g_free (remote_path
);
1178 is_error (int result
, int errno_num
)
1180 if (!(result
== -1))
1181 return my_errno
= 0;
1183 my_errno
= errno_num
;
1189 smbfs_opendir (vfs
*me
, char *dirname
)
1191 opendir_info
*smbfs_info
;
1192 smbfs_connection
*sc
;
1195 DEBUG(3, ("smbfs_opendir(dirname:%s)\n", dirname
));
1197 if (!(remote_dir
= smbfs_get_path (&sc
, dirname
)))
1200 /* FIXME: where freed? */
1201 smbfs_info
= g_new (opendir_info
, 1);
1202 smbfs_info
->server_list
= FALSE
;
1203 smbfs_info
->path
= g_strdup(dirname
); /* keep original */
1204 smbfs_info
->dirname
= remote_dir
;
1205 smbfs_info
->conn
= sc
;
1206 smbfs_info
->entries
= 0;
1207 smbfs_info
->current
= 0;
1213 fake_server_stat(const char *server_url
, const char *path
, struct stat
*buf
)
1218 if ((p
= strrchr(path
, '/')))
1219 path
= p
+ 1; /* advance until last '/' */
1221 if (!current_info
->entries
) {
1222 if (!smbfs_loaddir(current_info
)); /* browse host */
1226 if (current_info
->server_list
== True
) {
1227 dentry
= current_info
->entries
;
1228 DEBUG(4, ("fake stat for SERVER \"%s\"\n", path
));
1230 if (strcmp(dentry
->text
, path
) == 0) {
1231 DEBUG(4, ("fake_server_stat: %s:%4o\n",
1232 dentry
->text
, dentry
->my_stat
.st_mode
));
1233 memcpy(buf
, &dentry
->my_stat
, sizeof(struct stat
));
1236 dentry
= dentry
->next
;
1244 fake_share_stat(const char *server_url
, const char *path
, struct stat
*buf
)
1247 if (strlen(path
) < strlen(server_url
))
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 statfile_helper(file_info
*finfo
, const char *mask
)
1279 time_t t
= finfo
->mtime
; /* the time is assumed to be passed as GMT */
1281 #if 0 /* single_entry is never freed now. And only my_stat is used */
1282 single_entry
= g_new (dir_entry
, 1);
1284 single_entry
->text
= dos_to_unix (g_strdup (finfo
->name
), 1);
1286 single_entry
->next
= 0;
1289 single_entry
= g_new0 (dir_entry
, 1);
1291 single_entry
->my_stat
.st_size
= finfo
->size
;
1292 single_entry
->my_stat
.st_mtime
= finfo
->mtime
;
1293 single_entry
->my_stat
.st_atime
= finfo
->atime
;
1294 single_entry
->my_stat
.st_ctime
= finfo
->ctime
;
1295 single_entry
->my_stat
.st_uid
= finfo
->uid
;
1296 single_entry
->my_stat
.st_gid
= finfo
->gid
;
1298 single_entry
->my_stat
.st_mode
=
1299 S_IRUSR
|S_IRGRP
|S_IROTH
|S_IWUSR
|S_IWGRP
|S_IWOTH
;
1301 /* if (finfo->mode & aVOLID); nothing similar in real world */
1302 if (finfo
->mode
& aDIR
)
1303 single_entry
->my_stat
.st_mode
|= S_IFDIR
;
1305 single_entry
->my_stat
.st_mode
|= S_IFREG
;/* if not dir, regular file? */
1306 /* if (finfo->mode & aARCH); DOS archive */
1307 /* if (finfo->mode & aHIDDEN); like a dot file? */
1308 /* if (finfo->mode & aSYSTEM); like a kernel? */
1309 if (finfo
->mode
& aRONLY
)
1310 single_entry
->my_stat
.st_mode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
1312 DEBUG(6, (" %-30s%7.7s%8.0f %s",
1313 CNV_LANG(finfo
->name
),
1314 attrib_string(finfo
->mode
),
1315 (double)finfo
->size
,
1316 asctime(LocalTime(&t
))));
1319 /* stat a single file */
1321 get_remote_stat(smbfs_connection
*sc
, char *path
, struct stat
*buf
)
1323 uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
1324 char *mypath
= path
;
1326 DEBUG(3, ("get_remote_stat(): mypath:%s\n", mypath
));
1328 convert_path(&mypath
, FALSE
);
1330 if (cli_list(sc
->cli
, mypath
, attribute
, statfile_helper
) < 1) {
1333 return -1; /* cli_list returns number of files */
1336 memcpy(buf
, &single_entry
->my_stat
, sizeof(struct stat
));
1338 /* dont free here, use for smbfs_fstat() */
1339 /* g_free(single_entry->text);
1340 g_free(single_entry); */
1346 search_dir_entry (dir_entry
*dentry
, const char *text
, struct stat
*buf
)
1349 if (strcmp(text
, dentry
->text
) == 0) {
1350 memcpy(buf
, &dentry
->my_stat
, sizeof(struct stat
));
1351 memcpy(&single_entry
->my_stat
, &dentry
->my_stat
,
1352 sizeof(struct stat
));
1355 dentry
= dentry
->next
;
1361 get_stat_info (smbfs_connection
*sc
, char *path
, struct stat
*buf
)
1365 dir_entry
*dentry
= current_info
->entries
;
1367 const char *mypath
= path
;
1369 mypath
++; /* cut off leading '/' */
1370 if ((p
= strrchr(mypath
, '/')))
1371 mypath
= p
+ 1; /* advance until last file/dir name */
1372 DEBUG(3, ("get_stat_info: mypath:%s, current_info->dirname:%s\n",
1373 mypath
, current_info
->dirname
));
1376 DEBUG(1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n", current_info
->dirname
, path
));
1380 if (!single_entry
) /* when found, this will be written too */
1381 single_entry
= g_new (dir_entry
, 1);
1382 if (search_dir_entry(current_info
->entries
, mypath
, buf
) == 0) {
1385 /* now try to identify mypath as PARENT dir */
1389 mdp
= mydir
= g_strdup(current_info
->dirname
);
1390 if ((p
= strrchr(mydir
, '/')))
1391 *p
= 0; /* advance util last '/' */
1392 if ((p
= strrchr(mydir
, '/')))
1393 mydir
= p
+ 1; /* advance util last '/' */
1394 if (strcmp(mydir
, mypath
) == 0) { /* fake a stat for ".." */
1395 bzero(buf
, sizeof(struct stat
));
1396 buf
->st_mode
= S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
;
1397 memcpy(&single_entry
->my_stat
, buf
, sizeof(struct stat
));
1399 DEBUG(1, (" PARENT:found in %s\n", current_info
->dirname
));
1404 /* now try to identify as CURRENT dir? */
1406 char *dnp
= current_info
->dirname
;
1407 DEBUG(6, ("get_stat_info: is %s current dir? this dir is: %s\n",
1408 mypath
, current_info
->dirname
));
1414 if (strcmp(mypath
, dnp
) == 0) {
1415 bzero(buf
, sizeof(struct stat
));
1416 buf
->st_mode
= S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
;
1417 memcpy(&single_entry
->my_stat
, buf
, sizeof(struct stat
));
1418 DEBUG(1, (" CURRENT:found in %s\n", current_info
->dirname
));
1422 DEBUG(3, ("'%s' not found in current_info '%s'\n", path
, current_info
->dirname
));
1423 /* try to find this in the PREVIOUS listing */
1424 if (previous_info
) {
1425 if (search_dir_entry(previous_info
->entries
, mypath
, buf
) == 0)
1427 DEBUG(3, ("'%s' not found in previous_info '%s'\n", path
, previous_info
->dirname
));
1429 /* try to find this in the SHARE listing */
1430 if (current_share_info
&& search_dir_entry(current_share_info
->entries
, mypath
, buf
) == 0)
1432 DEBUG(3, ("'%s' not found in share_info '%s'\n", path
, current_share_info
->dirname
));
1433 /* try to find this in the SERVER listing */
1434 if (current_server_info
&& search_dir_entry(current_server_info
->entries
, mypath
, buf
) == 0)
1436 DEBUG(3, ("'%s' not found in server_info '%s'\n", path
, current_server_info
->dirname
));
1437 /* nothing found. get stat file info from server */
1438 return get_remote_stat(sc
, path
, buf
);
1442 smbfs_chdir (vfs
*me
, char *path
)
1445 smbfs_connection
*sc
;
1447 DEBUG(3, ("smbfs_chdir(path:%s)\n", path
));
1448 if (!(remote_dir
= smbfs_get_path (&sc
, path
)))
1450 g_free (remote_dir
);
1456 loaddir(vfs
*me
, const char *path
)
1461 mypath
= g_strdup(path
);
1462 p
= strrchr(mypath
, '/');
1466 DEBUG(6, ("loaddir(%s)\n", mypath
));
1467 smbfs_chdir(me
, mypath
);
1468 info
= smbfs_opendir (me
, mypath
);
1472 smbfs_readdir(info
);
1473 smbfs_loaddir(info
);
1478 smbfs_stat (vfs
*me
, char *path
, struct stat
*buf
)
1481 smbfs_connection
*sc
;
1486 DEBUG(3, ("smbfs_stat(path:%s)\n", path
));
1489 if (p
= strchr(path
, '@')) /* user:pass@server */
1490 path
= ++p
; /* don't want user:pass@ in path */
1493 if (!current_info
) {
1494 DEBUG(1, ("current_info = NULL: "));
1495 if (loaddir(me
, path
) < 0)
1499 pstrcpy(server_url
, URL_HEADER
);
1500 pstrcat(server_url
, current_bucket
->host
);
1502 /* check if stating server */
1504 if (strncmp(p
, URL_HEADER
, HEADER_LEN
)) {
1505 DEBUG(1, ("'%s' doesnt start with '%s' (length %d)\n",
1506 p
, URL_HEADER
, HEADER_LEN
));
1513 p
= strchr(p
, '/'); /* advance past next '/' */
1515 if (!current_info
->server_list
) {
1516 if (loaddir(me
, path
) < 0)
1519 return fake_server_stat(server_url
, path
, buf
);
1521 if (!strchr(++p
, '/')) {
1522 return fake_share_stat(server_url
, path
, buf
);
1525 /* stating inside share at this point */
1526 if (!(remote_dir
= smbfs_get_path (&sc
, path
))) /* connects if necessary */
1528 g_free (remote_dir
);
1530 char *sp
, *pp
= path
;
1531 int hostlen
= strlen(current_bucket
->host
);
1532 pp
+= strlen(path
)-hostlen
;
1534 sp
+= strlen(server_url
)-hostlen
;
1535 if (strcmp(sp
, pp
) == 0) {
1536 /* make server name appear as directory */
1537 DEBUG(1, ("smbfs_stat: showing server as directory\n"));
1538 bzero(buf
, sizeof(struct stat
));
1539 buf
->st_mode
= S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
;
1543 /* check if current_info is in share requested */
1545 if (strncmp(p
, URL_HEADER
, HEADER_LEN
) == 0)
1549 p
= service
= g_strdup(p
);
1550 pp
= strchr(p
, '/');
1552 p
= ++pp
; /* advance past server name */
1553 pp
= strchr(p
, '/');
1555 *pp
= 0; /* cut off everthing after service name */
1557 p
= IPC
; /* browsing for services */
1558 pp
= current_info
->dirname
;
1561 if (strncmp(p
, pp
, strlen(p
)) != 0) {
1562 DEBUG(6, ("desired '%s' is not loaded, we have '%s'\n", p
, pp
));
1563 if (loaddir(me
, path
) < 0) {
1567 DEBUG(6, ("loaded dir: '%s'\n", current_info
->dirname
));
1570 /* stat dirs & files under shares now */
1571 return get_stat_info(sc
, path
, buf
);
1575 smbfs_lstat (vfs
*me
, char *path
, struct stat
*buf
)
1577 DEBUG(4, ("smbfs_lstat(path:%s)\n", path
));
1578 return smbfs_stat(me
, path
, buf
); /* no symlinks on smb filesystem? */
1582 smbfs_lseek (void *data
, off_t offset
, int whence
)
1584 DEBUG(3, ("smbfs_lseek()\n"));
1585 my_errno
= EOPNOTSUPP
;
1590 smbfs_mknod (vfs
*me
, char *path
, int mode
, int dev
)
1592 DEBUG(3, ("smbfs_mknod(path:%s, mode:%d, dev:%d)\n", path
, mode
, dev
));
1593 my_errno
= EOPNOTSUPP
;
1598 smbfs_mkdir (vfs
*me
, char *path
, mode_t mode
)
1600 smbfs_connection
*sc
;
1603 DEBUG(3, ("smbfs_mkdir(path:%s, mode:%d)\n", path
, mode
));
1604 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1606 g_free (remote_file
);
1607 convert_path(&path
, FALSE
);
1609 if (!cli_mkdir(sc
->cli
, path
)) {
1610 my_errno
= cli_error(sc
->cli
, NULL
, &err
, NULL
);
1611 message_3s (1, MSG_ERROR
, _(" %s mkdir'ing %s "),
1612 cli_errstr(sc
->cli
), CNV_LANG(path
));
1621 smbfs_rmdir (vfs
*me
, char *path
)
1623 smbfs_connection
*sc
;
1626 DEBUG(3, ("smbfs_rmdir(path:%s)\n", path
));
1627 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1629 g_free (remote_file
);
1630 convert_path(&path
, FALSE
);
1632 if (!cli_rmdir(sc
->cli
, path
)) {
1633 my_errno
= cli_error(sc
->cli
, NULL
, &err
, NULL
);
1634 message_3s (1, MSG_ERROR
, _(" %s rmdir'ing %s "),
1635 cli_errstr(sc
->cli
), CNV_LANG(path
));
1645 smbfs_link (vfs
*me
, char *p1
, char *p2
)
1647 DEBUG(3, ("smbfs_link(p1:%s, p2:%s)\n", p1
, p2
));
1648 my_errno
= EOPNOTSUPP
;
1652 /* We do not free anything right now: we free resources when we run
1656 smbfs_getid (vfs
*me
, char *p
, struct vfs_stamping
**parent
)
1659 DEBUG(3, ("smbfs_getid(p:%s)\n", p
));
1665 smbfs_nothingisopen (vfsid id
)
1667 DEBUG(3, ("smbfs_nothingisopen(%d)\n", (int)id
));
1672 smbfs_free (vfsid id
)
1674 DEBUG(3, ("smbfs_free(%d)\n", (int)id
));
1675 /* FIXME: Should not be empty */
1676 authinfo_free_all ();
1679 /* Gives up on a socket and reopens the connection, the child own the socket
1683 my_forget (char *path
)
1685 char *host
, *user
, *p
;
1688 if (strncmp (path
, URL_HEADER
, HEADER_LEN
))
1691 DEBUG(3, ("my_forget(path:%s)\n", path
));
1694 if (path
[0] == '/' && path
[1] == '/')
1697 if ((p
= smbfs_get_host_and_username (&path
, &host
, &user
, &port
, NULL
))) {
1699 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
1700 if ((strcmp (host
, smbfs_connections
[i
].host
) == 0) &&
1701 (strcmp (user
, smbfs_connections
[i
].user
) == 0) &&
1702 (port
== smbfs_connections
[i
].port
)) {
1704 /* close socket: the child owns it now */
1705 cli_shutdown(smbfs_connections
[i
].cli
);
1707 /* reopen the connection */
1708 smbfs_connections
[i
].cli
=
1709 do_connect(host
, smbfs_connections
[i
].service
);
1718 smbfs_setctl (vfs
*me
, char *path
, int ctlop
, char *arg
)
1720 DEBUG(3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path
, ctlop
));
1722 case MCCTL_FORGET_ABOUT
:
1729 static smbfs_handle
*
1730 open_write (smbfs_handle
*remote_handle
, char *rname
, int flags
, int mode
)
1732 if (flags
& O_TRUNC
) /* if it exists truncate to zero */
1733 DEBUG(3, ("open_write: O_TRUNC\n"));
1735 remote_handle
->fnum
= cli_open(remote_handle
->cli
, rname
, flags
, DENY_NONE
);
1737 if (remote_handle
->fnum
== -1) {
1738 message_3s (1, MSG_ERROR
, _(" %s opening remote file %s "),
1739 cli_errstr(remote_handle
->cli
), CNV_LANG(rname
));
1740 DEBUG(1,("smbfs_open(rname:%s) error:%s\n",
1741 rname
, cli_errstr(remote_handle
->cli
)));
1742 my_errno
= cli_error(remote_handle
->cli
, NULL
, &err
, NULL
);
1746 return remote_handle
;
1749 static smbfs_handle
*
1750 open_read (smbfs_handle
*remote_handle
, char *rname
, int flags
, int mode
)
1754 remote_handle
->fnum
=
1755 cli_open(remote_handle
->cli
, rname
, O_RDONLY
, DENY_NONE
);
1757 if (remote_handle
->fnum
== -1) {
1758 message_3s (1, MSG_ERROR
, _(" %s opening remote file %s "),
1759 cli_errstr(remote_handle
->cli
), CNV_LANG(rname
));
1760 DEBUG(1,("smbfs_open(rname:%s) error:%s\n",
1761 rname
, cli_errstr(remote_handle
->cli
)));
1762 my_errno
= cli_error(remote_handle
->cli
, NULL
, &err
, NULL
);
1766 if (!cli_qfileinfo(remote_handle
->cli
, remote_handle
->fnum
,
1767 &remote_handle
->attr
, &size
, NULL
, NULL
, NULL
, NULL
, NULL
) &&
1768 !cli_getattrE(remote_handle
->cli
, remote_handle
->fnum
,
1769 &remote_handle
->attr
, &size
, NULL
, NULL
, NULL
)) {
1770 message_2s (1, MSG_ERROR
, " getattrib: %s ",
1771 cli_errstr(remote_handle
->cli
));
1772 DEBUG(1,("smbfs_open(rname:%s) getattrib:%s\n",
1773 rname
, cli_errstr(remote_handle
->cli
)));
1774 my_errno
= cli_error(remote_handle
->cli
, NULL
, &err
, NULL
);
1778 return remote_handle
;
1782 smbfs_open (vfs
*me
, char *file
, int flags
, int mode
)
1784 char *remote_file
, *p
;
1786 smbfs_connection
*sc
;
1787 smbfs_handle
*remote_handle
;
1789 DEBUG(3, ("smbfs_open(file:%s, flags:%d, mode:%d)\n", file
, flags
, mode
));
1791 if (!(remote_file
= smbfs_get_path (&sc
, file
)))
1795 convert_path(&remote_file
, FALSE
);
1798 remote_handle
= g_new (smbfs_handle
, 2);
1799 remote_handle
->cli
= sc
->cli
;
1800 remote_handle
->nread
= 0;
1802 if (flags
& O_CREAT
)
1803 ret
= open_write(remote_handle
, remote_file
, flags
, mode
);
1805 ret
= open_read(remote_handle
, remote_file
, flags
, mode
);
1807 g_free (remote_file
);
1813 smbfs_unlink (vfs
*me
, char *path
)
1815 smbfs_connection
*sc
;
1816 char *remote_file
, *p
;
1818 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1822 convert_path(&remote_file
, FALSE
);
1825 if (!cli_unlink(sc
->cli
, remote_file
)) {
1826 message_3s (1, MSG_ERROR
, _(" %s removing remote file %s "),
1827 cli_errstr(sc
->cli
), CNV_LANG(remote_file
));
1828 g_free (remote_file
);
1831 g_free (remote_file
);
1836 smbfs_rename (vfs
*me
, char *a
, char *b
)
1838 smbfs_connection
*sc
;
1843 if ((ra
= smbfs_get_path (&sc
, a
)) == 0)
1846 if ((rb
= smbfs_get_path (&sc
, b
)) == 0) {
1852 convert_path(&ra
, FALSE
);
1855 convert_path(&rb
, FALSE
);
1858 retval
= cli_rename(sc
->cli
, ra
, rb
);
1864 message_2s (1, MSG_ERROR
, _(" %s renaming files\n"),
1865 cli_errstr(sc
->cli
));
1872 smbfs_fstat (void *data
, struct stat
*buf
)
1874 smbfs_handle
*remote_handle
= (smbfs_handle
*)data
;
1876 DEBUG(3, ("smbfs_fstat(fnum:%d)\n", remote_handle
->fnum
));
1878 /* use left over from previous get_remote_stat, if available */
1880 memcpy(buf
, &single_entry
->my_stat
, sizeof(struct stat
));
1881 else { /* single_entry not set up: bug */
1888 vfs vfs_smbfs_ops
= {
1889 NULL
, /* This is place of next pointer */
1892 "smb:", /* prefix */
1931 smbfs_nothingisopen
,