1 /* Virtual File System: Midnight Commander file system.
3 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
4 Free Software Foundation, Inc.
6 Written by Wayne Roberts <wroberts1@home.com>, 1997
7 Andrew V. Samoilov <sav@bcs.zp.ua> 2002, 2003
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License
11 as published by the Free Software Foundation; either version 2 of
12 the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 /* Namespace: exports init_smbfs, smbfs_set_debug(), smbfs_set_debugf() */
27 #include <sys/types.h>
29 #include <mhl/types.h>
30 #include <mhl/string.h>
32 #undef USE_NCURSES /* Don't include *curses.h */
33 #include "../src/global.h"
34 #include "../src/tty.h" /* enable/disable interrupt key */
35 #include "../src/wtools.h" /* message() */
36 #include "../src/main.h" /* print_vfs_message */
39 #undef PACKAGE_BUGREPORT
42 #undef PACKAGE_TARNAME
43 #undef PACKAGE_VERSION
45 #include "samba/include/config.h"
46 /* don't load crap in "samba/include/includes.h" we don't use and which
47 conflicts with definitions in other includes */
48 #undef HAVE_LIBREADLINE
52 #include "samba/include/includes.h"
56 #include <mhl/string.h>
62 #define SMBFS_MAX_CONNECTIONS 16
63 static const char * const IPC
= "IPC$";
64 static const char * const URL_HEADER
= "/#smb:";
70 /* stuff that is same with each connection */
71 extern int DEBUGLEVEL
;
72 extern pstring myhostname
;
73 extern struct in_addr ipzero
;
74 static mode_t myumask
= 0755;
75 extern pstring global_myname
;
76 static int smbfs_open_connections
= 0;
77 static bool got_user
= FALSE
;
78 static bool got_pass
= FALSE
;
79 static pstring password
;
80 static pstring username
;
81 static struct vfs_class vfs_smbfs_ops
;
83 static struct _smbfs_connection
{
84 struct cli_state
*cli
;
85 struct in_addr dest_ip
;
87 char *host
; /* server name */
88 char *service
; /* share name */
96 } smbfs_connections
[SMBFS_MAX_CONNECTIONS
];
97 /* unique to each connection */
100 static struct cli_state
* smbfs_do_connect (const char *server
, char *share
);
102 typedef struct _smbfs_connection smbfs_connection
;
103 static smbfs_connection
*current_bucket
;
106 struct cli_state
*cli
;
112 static GSList
*auth_list
;
114 /* this function allows you to write:
115 * char *s = mhl_str_dup("hello, world");
116 * s = free_after(g_strconcat(s, s, (char *)0), s);
119 free_after (char *result
, char *string_to_free
)
121 mhl_mem_free(string_to_free
);
127 smbfs_auth_free (struct smb_authinfo
const *a
)
129 mhl_mem_free (a
->host
);
130 mhl_mem_free (a
->share
);
131 mhl_mem_free (a
->domain
);
132 mhl_mem_free (a
->user
);
133 wipe_password (a
->password
);
137 smbfs_auth_free_all (void)
140 g_slist_foreach (auth_list
, (GFunc
)smbfs_auth_free
, 0);
141 g_slist_free (auth_list
);
147 smbfs_auth_cmp_host_and_share (gconstpointer _a
, gconstpointer _b
)
149 struct smb_authinfo
const *a
= (struct smb_authinfo
const *)_a
;
150 struct smb_authinfo
const *b
= (struct smb_authinfo
const *)_b
;
152 if (!a
->host
|| !a
->share
|| !b
->host
|| !b
->share
)
154 if (strcmp (a
->host
, b
->host
) != 0)
156 if (strcmp (a
->share
, b
->share
) != 0)
162 smbfs_auth_cmp_host (gconstpointer _a
, gconstpointer _b
)
164 struct smb_authinfo
const *a
= (struct smb_authinfo
const *)_a
;
165 struct smb_authinfo
const *b
= (struct smb_authinfo
const *)_b
;
167 if (!a
->host
|| !b
->host
)
169 if (strcmp (a
->host
, b
->host
) != 0)
171 if (strcmp (a
->share
, IPC
) != 0)
177 smbfs_auth_add (const char *host
, const char *share
, const char *domain
,
178 const char *user
, const char *password
)
180 struct smb_authinfo
*auth
= g_new (struct smb_authinfo
, 1);
185 /* Don't check for NULL, mhl_str_dup already does. */
186 auth
->host
= mhl_str_dup (host
);
187 auth
->share
= mhl_str_dup (share
);
188 auth
->domain
= mhl_str_dup (domain
);
189 auth
->user
= mhl_str_dup (user
);
190 auth
->password
= mhl_str_dup (password
);
191 auth_list
= g_slist_prepend (auth_list
, auth
);
195 smbfs_auth_remove (const char *host
, const char *share
)
197 struct smb_authinfo data
;
198 struct smb_authinfo
*auth
;
201 data
.host
= mhl_str_dup (host
);
202 data
.share
= mhl_str_dup (share
);
203 list
= g_slist_find_custom (auth_list
,
205 smbfs_auth_cmp_host_and_share
);
206 mhl_mem_free (data
.host
);
207 mhl_mem_free (data
.share
);
211 auth_list
= g_slist_remove (auth_list
, auth
);
212 smbfs_auth_free (auth
);
215 /* Set authentication information in bucket. Return 1 if successful, else 0 */
216 /* Information in auth_list overrides user if pass is NULL. */
217 /* bucket->host and bucket->service must be valid. */
219 smbfs_bucket_set_authinfo (smbfs_connection
*bucket
,
220 const char *domain
, const char *user
, const char *pass
,
221 int fallback_to_host
)
223 struct smb_authinfo data
;
224 struct smb_authinfo
*auth
;
227 if (domain
&& user
&& pass
) {
228 mhl_mem_free (bucket
->domain
);
229 mhl_mem_free (bucket
->user
);
230 mhl_mem_free (bucket
->password
);
231 bucket
->domain
= mhl_str_dup (domain
);
232 bucket
->user
= mhl_str_dup (user
);
233 bucket
->password
= mhl_str_dup (pass
);
234 smbfs_auth_remove (bucket
->host
, bucket
->service
);
235 smbfs_auth_add (bucket
->host
, bucket
->service
,
240 data
.host
= bucket
->host
;
241 data
.share
= bucket
->service
;
242 list
= g_slist_find_custom (auth_list
, &data
, smbfs_auth_cmp_host_and_share
);
243 if (!list
&& fallback_to_host
)
244 list
= g_slist_find_custom (auth_list
, &data
, smbfs_auth_cmp_host
);
247 bucket
->domain
= mhl_str_dup (auth
->domain
);
248 bucket
->user
= mhl_str_dup (auth
->user
);
249 bucket
->password
= mhl_str_dup (auth
->password
);
254 bucket
->domain
= mhl_str_dup (lp_workgroup ());
255 bucket
->user
= mhl_str_dup (got_user
? username
: user
);
256 bucket
->password
= mhl_str_dup (password
);
260 auth
= vfs_smb_get_authinfo (bucket
->host
,
262 (domain
? domain
: lp_workgroup ()),
265 mhl_mem_free (bucket
->domain
);
266 mhl_mem_free (bucket
->user
);
267 mhl_mem_free (bucket
->password
);
268 bucket
->domain
= mhl_str_dup (auth
->domain
);
269 bucket
->user
= mhl_str_dup (auth
->user
);
270 bucket
->password
= mhl_str_dup (auth
->password
);
271 smbfs_auth_remove (bucket
->host
, bucket
->service
);
272 auth_list
= g_slist_prepend (auth_list
, auth
);
279 smbfs_set_debug (int arg
)
285 smbfs_set_debugf (const char *filename
)
287 extern pstring debugf
;
289 if (DEBUGLEVEL
> 0) {
290 FILE *outfile
= fopen (filename
, "w");
292 setup_logging ("", True
); /* No needs for timestamp for each message */
295 pstrcpy (debugf
, filename
);
300 /********************** The callbacks ******************************/
302 smbfs_init (struct vfs_class
* me
)
304 const char *servicesf
= CONFIGDIR PATH_SEP_STR
"smb.conf";
306 /* DEBUGLEVEL = 4; */
309 charset_initialise ();
311 DEBUG (3, ("smbfs_init(%s)\n", me
->name
));
313 if (!get_myname (myhostname
, NULL
))
314 DEBUG (0, ("Failed to get my hostname.\n"));
316 if (!lp_load (servicesf
, True
, False
, False
))
317 DEBUG (0, ("Cannot load %s - run testparm to debug it\n", servicesf
));
319 codepage_initialise (lp_client_code_page ());
327 if (getenv ("USER")) {
330 pstrcpy (username
, getenv ("USER"));
332 DEBUG (3, ("smbfs_init(): $USER:%s\n", username
));
333 if ((p
= strchr (username
, '%'))) {
335 pstrcpy (password
, p
+ 1);
337 memset (strchr (getenv ("USER"), '%') + 1, 'X', strlen (password
));
338 DEBUG (3, ("smbfs_init(): $USER%%pass: %s%%%s\n",
339 username
, password
));
343 if (getenv ("PASSWD")) {
344 pstrcpy (password
, getenv ("PASSWD"));
351 smbfs_fill_names (struct vfs_class
*me
, fill_names_f func
)
358 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
359 if (smbfs_connections
[i
].cli
) {
360 path
= g_strconcat (URL_HEADER
,
361 smbfs_connections
[i
].user
, "@",
362 smbfs_connections
[i
].host
,
363 "/", smbfs_connections
[i
].service
,
371 #define CNV_LANG(s) dos_to_unix(s,False)
372 #define GNAL_VNC(s) unix_to_dos(s,False)
373 /* does same as do_get() in client.c */
374 /* called from vfs.c:1080, count = buffer size */
376 smbfs_read (void *data
, char *buffer
, int count
)
378 smbfs_handle
*info
= (smbfs_handle
*) data
;
381 DEBUG(3, ("smbfs_read(fnum:%d, nread:%d, count:%d)\n",
382 info
->fnum
, (int)info
->nread
, count
));
383 n
= cli_read(info
->cli
, info
->fnum
, buffer
, info
->nread
, count
);
390 smbfs_write (void *data
, const char *buf
, int nbyte
)
392 smbfs_handle
*info
= (smbfs_handle
*) data
;
395 DEBUG(3, ("smbfs_write(fnum:%d, nread:%d, nbyte:%d)\n",
396 info
->fnum
, (int)info
->nread
, nbyte
));
397 n
= cli_write(info
->cli
, info
->fnum
, 0, buf
, info
->nread
, nbyte
);
404 smbfs_close (void *data
)
406 smbfs_handle
*info
= (smbfs_handle
*) data
;
407 DEBUG (3, ("smbfs_close(fnum:%d)\n", info
->fnum
));
409 /* FIXME: Why too different cli have the same outbuf
410 * if file is copied to share
412 if (info
->cli
->outbuf
== NULL
) {
417 /* if imlementing archive_level: add rname to smbfs_handle */
418 if (archive_level
>= 2 && (inf
->attr
& aARCH
)) {
419 cli_setatr (info
->cli
, rname
, info
->attr
& ~(uint16
) aARCH
, 0);
422 return (cli_close (info
->cli
, info
->fnum
) == True
) ? 0 : -1;
426 smbfs_errno (struct vfs_class
*me
)
430 DEBUG(3, ("smbfs_errno: %s\n", g_strerror(my_errno
)));
434 typedef struct dir_entry
{
436 struct dir_entry
*next
;
444 char *path
; /* the dir originally passed to smbfs_opendir */
445 smbfs_connection
*conn
;
454 *current_server_info
;
456 static bool first_direntry
;
459 smbfs_new_dir_entry (const char *name
)
461 static int inode_counter
;
462 dir_entry
*new_entry
;
463 new_entry
= g_new0 (dir_entry
, 1);
464 new_entry
->text
= dos_to_unix (mhl_str_dup (name
), 1);
466 if (first_direntry
) {
467 current_info
->entries
= new_entry
;
468 first_direntry
= FALSE
;
470 current_info
->current
->next
= new_entry
;
472 current_info
->current
= new_entry
;
473 new_entry
->my_stat
.st_ino
= inode_counter
++;
478 /* browse for shares on server */
480 smbfs_browsing_helper (const char *name
, uint32 type
, const char *comment
, void *state
)
482 const char *typestr
= "";
483 dir_entry
*new_entry
= smbfs_new_dir_entry (name
);
490 /* show this as dir */
491 new_entry
->my_stat
.st_mode
=
492 (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
|
505 DEBUG (3, ("\t%-15.15s%-10.10s%s\n", name
, typestr
, comment
));
509 smbfs_loaddir_helper (file_info
* finfo
, const char *mask
, void *entry
)
511 dir_entry
*new_entry
= (dir_entry
*) entry
;
512 time_t t
= finfo
->mtime
; /* the time is assumed to be passed as GMT */
516 #if 0 /* I want to see dot files */
517 if (finfo
->mode
& aHIDDEN
)
518 return; /* don't bother with hidden files, "~$" screws up mc */
521 new_entry
= smbfs_new_dir_entry (finfo
->name
);
523 new_entry
->my_stat
.st_size
= finfo
->size
;
524 new_entry
->my_stat
.st_mtime
= finfo
->mtime
;
525 new_entry
->my_stat
.st_atime
= finfo
->atime
;
526 new_entry
->my_stat
.st_ctime
= finfo
->ctime
;
527 new_entry
->my_stat
.st_uid
= finfo
->uid
;
528 new_entry
->my_stat
.st_gid
= finfo
->gid
;
530 new_entry
->my_stat
.st_mode
= /* rw-rw-rw */
531 S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
;
533 /* if (finfo->mode & aVOLID); nothing similar in real world */
534 if (finfo
->mode
& aDIR
)
535 new_entry
->my_stat
.st_mode
|= /* drwxrwxrwx */
536 S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
538 new_entry
->my_stat
.st_mode
|= S_IFREG
; /* if not dir, regular file? */
539 /* if (finfo->mode & aARCH); DOS archive */
540 /* if (finfo->mode & aHIDDEN); like a dot file? */
541 /* if (finfo->mode & aSYSTEM); like a kernel? */
542 if (finfo
->mode
& aRONLY
)
543 new_entry
->my_stat
.st_mode
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
544 new_entry
->my_stat
.st_mode
&= myumask
;
546 DEBUG (entry
? 3 : 6, (" %-30s%7.7s%8.0f %s",
547 CNV_LANG (finfo
->name
),
548 attrib_string (finfo
->mode
),
549 (double) finfo
->size
,
550 asctime (LocalTime (&t
))));
553 /* takes "/foo/bar/file" and gives malloced "\\foo\\bar\\file" */
555 smbfs_convert_path (const char *remote_file
, bool trailing_asterik
)
557 const char *p
, *my_remote
;
560 my_remote
= remote_file
;
561 if (strncmp (my_remote
, URL_HEADER
, HEADER_LEN
) == 0) { /* if passed directly */
562 my_remote
+= HEADER_LEN
;
563 if (*my_remote
== '/') /* from server browsing */
565 p
= strchr(my_remote
, '/');
567 my_remote
= p
+1; /* advance to end of server name */
570 if (*my_remote
== '/')
571 my_remote
++; /* strip off leading '/' */
572 p
= strchr(my_remote
, '/');
574 my_remote
= p
; /* strip off share/service name */
575 /* create remote filename as understood by smb clientgen */
576 result
= g_strconcat (my_remote
, trailing_asterik
? "/*" : "", (char *) NULL
);
577 unix_to_dos (result
, /* inplace = */ 1); /* code page conversion */
578 str_replace(result
, '/', '\\');
583 smbfs_srv_browsing_helper (const char *name
, uint32 m
, const char *comment
,
586 dir_entry
*new_entry
= smbfs_new_dir_entry (name
);
591 /* show this as dir */
592 new_entry
->my_stat
.st_mode
=
593 (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
|
596 DEBUG (3, ("\t%-16.16s %s\n", name
, comment
));
600 smbfs_reconnect(smbfs_connection
*conn
, int *retries
)
603 DEBUG(3, ("RECONNECT\n"));
605 if (*(conn
->host
) == 0)
606 host
= mhl_str_dup(conn
->cli
->desthost
); /* server browsing */
608 host
= mhl_str_dup(conn
->host
);
610 cli_shutdown(conn
->cli
);
612 if (!(conn
->cli
= smbfs_do_connect(host
, conn
->service
))) {
613 message (D_ERROR
, MSG_ERROR
,
614 _(" reconnect to %s failed\n "), conn
->host
);
619 if (++(*retries
) == 2)
625 smbfs_send(struct cli_state
*cli
)
631 len
= smb_len(cli
->outbuf
) + 4;
633 while (nwritten
< len
) {
634 ret
= write_socket(cli
->fd
, cli
->outbuf
+nwritten
, len
- nwritten
);
645 /****************************************************************************
646 See if server has cut us off by checking for EPIPE when writing.
647 Taken from cli_chkpath()
648 ****************************************************************************/
650 smbfs_chkpath(struct cli_state
*cli
, const char *path
, BOOL send_only
)
656 unix_to_dos (path2
, 1);
657 trim_string(path2
,NULL
,"\\");
658 if (!*path2
) *path2
= '\\';
660 memset(cli
->outbuf
,'\0',smb_size
);
661 set_message(cli
->outbuf
,0,4 + strlen(path2
),True
);
662 SCVAL(cli
->outbuf
,smb_com
,SMBchkpth
);
663 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
667 SSVAL(cli
->outbuf
,smb_pid
,cli
->pid
);
668 SSVAL(cli
->outbuf
,smb_uid
,cli
->vuid
);
669 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
);
670 if (cli
->protocol
> PROTOCOL_CORE
) {
671 SCVAL(cli
->outbuf
,smb_flg
,0x8);
672 SSVAL(cli
->outbuf
,smb_flg2
,0x1);
675 p
= smb_buf(cli
->outbuf
);
679 if (!smbfs_send(cli
)) {
680 DEBUG(3, ("smbfs_chkpath: couldnt send\n"));
684 client_receive_smb(cli
->fd
, cli
->inbuf
, cli
->timeout
);
685 DEBUG(3, ("smbfs_chkpath: send only OK\n"));
686 return True
; /* just testing for EPIPE */
688 if (!client_receive_smb(cli
->fd
, cli
->inbuf
, cli
->timeout
)) {
689 DEBUG(3, ("smbfs_chkpath: receive error\n"));
692 if ((my_errno
= cli_error(cli
, NULL
, NULL
, NULL
))) {
693 if (my_errno
== 20 || my_errno
== 13)
694 return True
; /* ignore if 'not a directory' error */
695 DEBUG(3, ("smbfs_chkpath: cli_error: %s\n", g_strerror(my_errno
)));
704 smbfs_fs (const char *text
)
706 const char *p
= text
;
709 while ((p
= strchr(p
, '/')) != NULL
) {
720 smbfs_loaddir (opendir_info
*smbfs_info
)
722 uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
723 int servlen
= strlen (smbfs_info
->conn
->service
);
724 const char *info_dirname
= smbfs_info
->dirname
;
727 DEBUG (3, ("smbfs_loaddir: dirname:%s\n", info_dirname
));
728 first_direntry
= TRUE
;
732 ("smbfs_loaddir: new:'%s', cached:'%s'\n", info_dirname
,
733 current_info
->dirname
));
734 /* if new desired dir is longer than cached in current_info */
735 if (smbfs_fs (info_dirname
) > smbfs_fs (current_info
->dirname
)) {
736 DEBUG (3, ("saving to previous_info\n"));
737 previous_info
= current_info
;
741 current_info
= smbfs_info
;
743 if (strcmp (info_dirname
, "/") == 0) {
744 if (!strcmp (smbfs_info
->path
, URL_HEADER
)) {
745 DEBUG (6, ("smbfs_loaddir: browsing %s\n", IPC
));
746 /* browse for servers */
747 if (!cli_NetServerEnum
748 (smbfs_info
->conn
->cli
, smbfs_info
->conn
->domain
,
749 SV_TYPE_ALL
, smbfs_srv_browsing_helper
, NULL
))
752 current_server_info
= smbfs_info
;
753 smbfs_info
->server_list
= TRUE
;
755 /* browse for shares */
756 if (cli_RNetShareEnum
757 (smbfs_info
->conn
->cli
, smbfs_browsing_helper
, NULL
) < 1)
760 current_share_info
= smbfs_info
;
765 /* do regular directory listing */
766 if (strncmp (smbfs_info
->conn
->service
, info_dirname
+ 1, servlen
) == 0) {
767 /* strip share name from dir */
768 my_dirname
= mhl_str_dup (info_dirname
+ servlen
);
770 my_dirname
= free_after(smbfs_convert_path (my_dirname
, TRUE
), my_dirname
);
772 my_dirname
= smbfs_convert_path (info_dirname
, TRUE
);
774 DEBUG (6, ("smbfs_loaddir: service: %s\n", smbfs_info
->conn
->service
));
776 ("smbfs_loaddir: cli->share: %s\n",
777 smbfs_info
->conn
->cli
->share
));
779 ("smbfs_loaddir: calling cli_list with mask %s\n", my_dirname
));
780 /* do file listing: cli_list returns number of files */
782 (smbfs_info
->conn
->cli
, my_dirname
, attribute
,
783 smbfs_loaddir_helper
, NULL
) < 0) {
784 /* cli_list returns -1 if directory empty or cannot read socket */
785 my_errno
= cli_error (smbfs_info
->conn
->cli
, NULL
, &err
, NULL
);
786 mhl_mem_free (my_dirname
);
789 if (*(my_dirname
) == 0)
790 smbfs_info
->dirname
= smbfs_info
->conn
->service
;
791 mhl_mem_free (my_dirname
);
795 /* current_info->parent = smbfs_info->dirname; */
797 smbfs_info
->current
= smbfs_info
->entries
;
798 return 1; /* 1 = ok */
801 #ifdef SMBFS_FREE_DIR
803 smbfs_free_dir (dir_entry
*de
)
807 smbfs_free_dir (de
->next
);
808 mhl_mem_free (de
->text
);
814 /* The readdir routine loads the complete directory */
815 /* It's too slow to ask the server each time */
816 /* It now also sends the complete lstat information for each file */
818 smbfs_readdir(void *info
)
820 static union vfs_dirent smbfs_readdir_data
;
821 static char *const dirent_dest
= smbfs_readdir_data
.dent
.d_name
;
822 opendir_info
*smbfs_info
= (opendir_info
*) info
;
824 DEBUG(4, ("smbfs_readdir(%s)\n", smbfs_info
->dirname
));
826 if (!smbfs_info
->entries
)
827 if (!smbfs_loaddir(smbfs_info
))
830 if (smbfs_info
->current
== 0) { /* reached end of dir entries */
831 DEBUG(3, ("smbfs_readdir: smbfs_info->current = 0\n"));
832 #ifdef SMBFS_FREE_DIR
833 smbfs_free_dir(smbfs_info
->entries
);
834 smbfs_info
->entries
= 0;
838 g_strlcpy(dirent_dest
, smbfs_info
->current
->text
, MC_MAXPATHLEN
);
839 smbfs_info
->current
= smbfs_info
->current
->next
;
841 compute_namelen(&smbfs_readdir_data
.dent
);
843 return &smbfs_readdir_data
;
847 smbfs_closedir (void *info
)
849 opendir_info
*smbfs_info
= (opendir_info
*) info
;
850 /* dir_entry *p, *q; */
852 DEBUG(3, ("smbfs_closedir(%s)\n", smbfs_info
->dirname
));
855 /* for (p = smbfs_info->entries; p;){
858 mhl_mem_free (q->text);
861 mhl_mem_free (info); */
866 smbfs_chmod (struct vfs_class
*me
, const char *path
, int mode
)
870 DEBUG(3, ("smbfs_chmod(path:%s, mode:%d)\n", path
, mode
));
871 /* my_errno = EOPNOTSUPP;
872 return -1; */ /* cannot chmod on smb filesystem */
873 return 0; /* make mc happy */
877 smbfs_chown (struct vfs_class
*me
, const char *path
, int owner
, int group
)
881 DEBUG(3, ("smbfs_chown(path:%s, owner:%d, group:%d)\n", path
, owner
, group
));
882 my_errno
= EOPNOTSUPP
; /* ready for your labotomy? */
887 smbfs_utime (struct vfs_class
*me
, const char *path
, struct utimbuf
*times
)
892 DEBUG(3, ("smbfs_utime(path:%s)\n", path
));
893 my_errno
= EOPNOTSUPP
;
898 smbfs_readlink (struct vfs_class
*me
, const char *path
, char *buf
, size_t size
)
903 ("smbfs_readlink(path:%s, buf:%s, size:%d)\n", path
, buf
,
905 my_errno
= EOPNOTSUPP
;
906 return -1; /* no symlinks on smb filesystem? */
910 smbfs_symlink (struct vfs_class
*me
, const char *n1
, const char *n2
)
914 DEBUG(3, ("smbfs_symlink(n1:%s, n2:%s)\n", n1
, n2
));
915 my_errno
= EOPNOTSUPP
;
916 return -1; /* no symlinks on smb filesystem? */
919 /* Extract the hostname and username from the path */
920 /* path is in the form: [user@]hostname/share/remote-dir */
921 #define smbfs_get_host_and_username(path, host, user, port, pass) \
922 vfs_split_url (*path, host, user, port, pass, SMB_PORT, 0)
924 /*****************************************************
925 return a connection to a SMB server
926 current_bucket needs to be set before calling
927 *******************************************************/
928 static struct cli_state
*
929 smbfs_do_connect (const char *server
, char *share
)
932 struct nmb_name called
, calling
;
935 DEBUG(3, ("smbfs_do_connect(%s, %s)\n", server
, share
));
936 if (*share
== '\\') {
938 share
= strchr(server
,'\\');
939 if (!share
) return NULL
;
944 make_nmb_name(&calling
, global_myname
, 0x0);
945 make_nmb_name(&called
, server
, current_bucket
->name_type
);
949 ip
= (current_bucket
->have_ip
) ? current_bucket
->dest_ip
: ipzero
;
951 /* have to open a new connection */
952 if (!(c
= cli_initialise(NULL
))) {
957 pwd_init(&(c
->pwd
)); /* should be moved into cli_initialise()? */
958 pwd_set_cleartext(&(c
->pwd
), current_bucket
->password
);
960 if ((cli_set_port(c
, current_bucket
->port
) == 0) ||
961 !cli_connect(c
, server
, &ip
)) {
962 DEBUG(1, ("Connection to %s failed\n", server
));
966 if (!cli_session_request(c
, &calling
, &called
)) {
967 my_errno
= cli_error(c
, NULL
, &err
, NULL
);
968 DEBUG(1, ("session request to %s failed\n", called
.name
));
970 if (strcmp(called
.name
, "*SMBSERVER")) {
971 make_nmb_name(&called
, "*SMBSERVER", 0x20);
977 DEBUG(3, (" session request ok\n"));
979 if (!cli_negprot(c
)) {
980 DEBUG(1, ("protocol negotiation failed\n"));
984 if (!cli_session_setup(c
, current_bucket
->user
,
985 current_bucket
->password
, strlen(current_bucket
->password
),
986 current_bucket
->password
, strlen(current_bucket
->password
),
987 current_bucket
->domain
)) {
988 DEBUG(1,("session setup failed: %s\n", cli_errstr(c
)));
989 smbfs_auth_remove (server
, share
);
993 if (*c
->server_domain
|| *c
->server_os
|| *c
->server_type
)
994 DEBUG(5,("Domain=[%s] OS=[%s] Server=[%s]\n",
995 c
->server_domain
,c
->server_os
,c
->server_type
));
997 DEBUG(3, (" session setup ok\n"));
999 if (!cli_send_tconX(c
, share
, "?????",
1000 current_bucket
->password
, strlen(current_bucket
->password
)+1)) {
1001 DEBUG(1,("%s: tree connect failed: %s\n", share
, cli_errstr(c
)));
1005 DEBUG(3, (" tconx ok\n"));
1011 my_errno
= cli_error(c
, NULL
, &err
, NULL
);
1018 smbfs_get_master_browser(char **host
)
1020 static char so_broadcast
[] = "SO_BROADCAST";
1022 struct in_addr
*ip_list
, bcast_addr
;
1024 /* does port = 137 for win95 master browser? */
1025 int fd
= open_socket_in( SOCK_DGRAM
, 0, 3,
1026 interpret_addr(lp_socket_address()), True
);
1029 set_socket_options(fd
, so_broadcast
);
1030 ip_list
= iface_bcast(ipzero
);
1031 bcast_addr
= *ip_list
;
1032 if ((ip_list
= name_query(fd
, "\01\02__MSBROWSE__\02", 1, True
,
1033 True
, bcast_addr
, &count
, NULL
))) {
1036 /* just return first master browser */
1037 *host
= mhl_str_dup(inet_ntoa(ip_list
[0]));
1044 smbfs_free_bucket (smbfs_connection
*bucket
)
1046 mhl_mem_free (bucket
->host
);
1047 mhl_mem_free (bucket
->service
);
1048 mhl_mem_free (bucket
->domain
);
1049 mhl_mem_free (bucket
->user
);
1050 wipe_password (bucket
->password
);
1051 mhl_mem_free (bucket
->home
);
1052 memset (bucket
, 0, sizeof (smbfs_connection
));
1055 static smbfs_connection
*
1056 smbfs_get_free_bucket (void)
1060 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++)
1061 if (!smbfs_connections
[i
].cli
) return &smbfs_connections
[i
];
1063 { /* search for most dormant connection */
1064 int oldest
= 0; /* index */
1065 time_t oldest_time
= smbfs_connections
[0].last_use
;
1066 for (i
= 1; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
1067 if (smbfs_connections
[i
].last_use
< oldest_time
) {
1068 oldest_time
= smbfs_connections
[i
].last_use
;
1072 cli_shutdown(smbfs_connections
[oldest
].cli
);
1073 smbfs_free_bucket (&smbfs_connections
[oldest
]);
1074 return &smbfs_connections
[oldest
];
1077 /* This can't happend, since we have checked for max connections before */
1078 vfs_die("Internal error: smbfs_get_free_bucket");
1079 return 0; /* shut up, stupid gcc */
1082 /* This routine keeps track of open connections */
1083 /* Returns a connected socket to host */
1084 static smbfs_connection
*
1085 smbfs_open_link (char *host
, char *path
, const char *user
, int *port
,
1089 smbfs_connection
*bucket
;
1091 struct in_addr
*dest_ip
= NULL
;
1093 DEBUG (3, ("smbfs_open_link(host:%s, path:%s)\n", host
, path
));
1095 if (strcmp (host
, path
) == 0) /* if host & path are same: */
1096 pstrcpy (service
, IPC
); /* setup for browse */
1097 else { /* get share name from path, path starts with server name */
1099 if ((p
= strchr (path
, '/'))) /* get share aka */
1100 pstrcpy (service
, ++p
); /* service name from path */
1102 pstrcpy (service
, "");
1103 /* now check for trailing directory/filenames */
1104 p
= strchr (service
, '/');
1106 *p
= 0; /* cut off dir/files: sharename only */
1108 pstrcpy (service
, IPC
); /* setup for browse */
1109 DEBUG (6, ("smbfs_open_link: service from path:%s\n", service
));
1113 user
= username
; /* global from getenv */
1115 /* Is the link actually open? */
1116 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
1117 if (!smbfs_connections
[i
].cli
)
1119 if ((strcmp (host
, smbfs_connections
[i
].host
) == 0) &&
1120 (strcmp (user
, smbfs_connections
[i
].user
) == 0) &&
1121 (strcmp (service
, smbfs_connections
[i
].service
) == 0)) {
1123 BOOL inshare
= (*host
!= 0 && *path
!= 0 && strchr (path
, '/'));
1124 /* check if this connection has died */
1125 while (!smbfs_chkpath (smbfs_connections
[i
].cli
, "\\", !inshare
)) {
1126 if (!smbfs_reconnect (&smbfs_connections
[i
], &retries
))
1129 DEBUG (6, ("smbfs_open_link: returning smbfs_connection[%d]\n", i
));
1130 current_bucket
= &smbfs_connections
[i
];
1131 smbfs_connections
[i
].last_use
= time (NULL
);
1132 return &smbfs_connections
[i
];
1134 /* connection not found, find if we have ip for new connection */
1135 if (strcmp (host
, smbfs_connections
[i
].host
) == 0)
1136 dest_ip
= &smbfs_connections
[i
].cli
->dest_ip
;
1139 /* make new connection */
1140 bucket
= smbfs_get_free_bucket ();
1141 bucket
->name_type
= 0x20;
1143 bucket
->port
= *port
;
1144 bucket
->have_ip
= False
;
1146 bucket
->have_ip
= True
;
1147 bucket
->dest_ip
= *dest_ip
;
1149 current_bucket
= bucket
;
1151 bucket
->user
= mhl_str_dup (user
);
1152 bucket
->service
= mhl_str_dup (service
);
1154 if (!(*host
)) { /* if blank host name, browse for servers */
1155 if (!smbfs_get_master_browser (&host
)) /* set host to ip of master browser */
1156 return 0; /* could not find master browser? */
1157 mhl_mem_free (host
);
1158 bucket
->host
= mhl_str_dup (""); /* blank host means master browser */
1160 bucket
->host
= mhl_str_dup (host
);
1162 if (!smbfs_bucket_set_authinfo (bucket
, 0, /* domain currently not used */
1163 user
, this_pass
, 1))
1166 /* connect to share */
1167 while (!(bucket
->cli
= smbfs_do_connect (host
, service
))) {
1169 if (my_errno
!= EPERM
)
1171 message (D_ERROR
, MSG_ERROR
, _(" Authentication failed "));
1173 /* authentication failed, try again */
1174 smbfs_auth_remove (bucket
->host
, bucket
->service
);
1175 if (!smbfs_bucket_set_authinfo (bucket
, bucket
->domain
, bucket
->user
, 0, 0))
1180 smbfs_open_connections
++;
1181 DEBUG (3, ("smbfs_open_link:smbfs_open_connections: %d\n",
1182 smbfs_open_connections
));
1187 smbfs_get_path (smbfs_connection
** sc
, const char *path
)
1189 char *user
, *host
, *remote_path
, *pass
;
1190 int port
= SMB_PORT
;
1192 DEBUG (3, ("smbfs_get_path(%s)\n", path
));
1193 if (strncmp (path
, URL_HEADER
, HEADER_LEN
))
1197 if (*path
== '/') /* '/' leading server name */
1198 path
++; /* probably came from server browsing */
1201 smbfs_get_host_and_username (&path
, &host
, &user
, &port
, &pass
)))
1203 smbfs_open_link (host
, remote_path
, user
, &port
, pass
)) == NULL
) {
1204 mhl_mem_free (remote_path
);
1207 mhl_mem_free (host
);
1208 mhl_mem_free (user
);
1210 wipe_password (pass
);
1215 /* NOTE: tildes are deprecated. See ftpfs.c */
1217 int f
= !strcmp (remote_path
, "/~");
1218 if (f
|| !strncmp (remote_path
, "/~/", 3)) {
1220 s
= mhl_str_dir_plus_file ((*sc
)->home
, remote_path
+ 3 - f
);
1221 mhl_mem_free (remote_path
);
1230 is_error (int result
, int errno_num
)
1232 if (!(result
== -1))
1233 return my_errno
= 0;
1235 my_errno
= errno_num
;
1241 smbfs_opendir (struct vfs_class
*me
, const char *dirname
)
1243 opendir_info
*smbfs_info
;
1244 smbfs_connection
*sc
;
1249 DEBUG(3, ("smbfs_opendir(dirname:%s)\n", dirname
));
1251 if (!(remote_dir
= smbfs_get_path (&sc
, dirname
)))
1254 /* FIXME: where freed? */
1255 smbfs_info
= g_new (opendir_info
, 1);
1256 smbfs_info
->server_list
= FALSE
;
1257 smbfs_info
->path
= mhl_str_dup(dirname
); /* keep original */
1258 smbfs_info
->dirname
= remote_dir
;
1259 smbfs_info
->conn
= sc
;
1260 smbfs_info
->entries
= 0;
1261 smbfs_info
->current
= 0;
1267 smbfs_fake_server_stat (const char *server_url
, const char *path
, struct stat
*buf
)
1274 if ((p
= strrchr (path
, '/')))
1275 path
= p
+ 1; /* advance until last '/' */
1277 if (!current_info
->entries
) {
1278 if (!smbfs_loaddir (current_info
)) /* browse host */
1282 if (current_info
->server_list
== True
) {
1283 dentry
= current_info
->entries
;
1284 DEBUG (4, ("fake stat for SERVER \"%s\"\n", path
));
1286 if (strcmp (dentry
->text
, path
) == 0) {
1287 DEBUG (4, ("smbfs_fake_server_stat: %s:%4o\n",
1288 dentry
->text
, (int)dentry
->my_stat
.st_mode
));
1289 memcpy (buf
, &dentry
->my_stat
, sizeof (struct stat
));
1292 dentry
= dentry
->next
;
1300 smbfs_fake_share_stat (const char *server_url
, const char *path
, struct stat
*buf
)
1303 if (strlen (path
) < strlen (server_url
))
1306 if (!current_share_info
) { /* Server was not stat()ed */
1307 /* Make sure there is such share at server */
1308 smbfs_connection
*sc
;
1310 p
= smbfs_get_path (&sc
, path
);
1313 memset (buf
, 0, sizeof (*buf
));
1314 /* show this as dir */
1316 (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
| S_IXUSR
| S_IXGRP
|
1323 path
+= strlen (server_url
); /* we only want share name */
1326 if (*path
== '/') /* '/' leading server name */
1327 path
++; /* probably came from server browsing */
1329 if (!current_share_info
->entries
) {
1330 if (!smbfs_loaddir (current_share_info
)) /* browse host */
1333 dentry
= current_share_info
->entries
;
1334 DEBUG (3, ("smbfs_fake_share_stat: %s on %s\n", path
, server_url
));
1336 if (strcmp (dentry
->text
, path
) == 0) {
1337 DEBUG (6, ("smbfs_fake_share_stat: %s:%4o\n",
1338 dentry
->text
, (int) dentry
->my_stat
.st_mode
));
1339 memcpy (buf
, &dentry
->my_stat
, sizeof (struct stat
));
1342 dentry
= dentry
->next
;
1348 /* stat a single file, smbfs_get_remote_stat callback */
1349 static dir_entry
*single_entry
;
1351 /* stat a single file */
1353 smbfs_get_remote_stat (smbfs_connection
* sc
, const char *path
, struct stat
*buf
)
1355 uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
1358 DEBUG (3, ("smbfs_get_remote_stat(): mypath:%s\n", path
));
1360 mypath
= smbfs_convert_path (path
, FALSE
);
1362 #if 0 /* single_entry is never free()d now. And only my_stat is used */
1363 single_entry
= g_new (dir_entry
, 1);
1365 single_entry
->text
= dos_to_unix (mhl_str_dup (finfo
->name
), 1);
1367 single_entry
->next
= 0;
1370 single_entry
= g_new0 (dir_entry
, 1);
1373 (sc
->cli
, mypath
, attribute
, smbfs_loaddir_helper
, single_entry
) < 1) {
1375 mhl_mem_free (mypath
);
1376 return -1; /* cli_list returns number of files */
1379 memcpy (buf
, &single_entry
->my_stat
, sizeof (struct stat
));
1381 /* don't free here, use for smbfs_fstat() */
1382 /* mhl_mem_free(single_entry->text);
1383 mhl_mem_free(single_entry); */
1384 mhl_mem_free (mypath
);
1389 smbfs_search_dir_entry (dir_entry
*dentry
, const char *text
, struct stat
*buf
)
1392 if (strcmp(text
, dentry
->text
) == 0) {
1393 memcpy(buf
, &dentry
->my_stat
, sizeof(struct stat
));
1394 memcpy(&single_entry
->my_stat
, &dentry
->my_stat
,
1395 sizeof(struct stat
));
1398 dentry
= dentry
->next
;
1404 smbfs_get_stat_info (smbfs_connection
* sc
, const char *path
, struct stat
*buf
)
1408 dir_entry
*dentry
= current_info
->entries
;
1410 const char *mypath
= path
;
1412 mypath
++; /* cut off leading '/' */
1413 if ((p
= strrchr (mypath
, '/')))
1414 mypath
= p
+ 1; /* advance until last file/dir name */
1415 DEBUG (3, ("smbfs_get_stat_info: mypath:%s, current_info->dirname:%s\n",
1416 mypath
, current_info
->dirname
));
1419 DEBUG (1, ("No dir entries (empty dir) cached:'%s', wanted:'%s'\n",
1420 current_info
->dirname
, path
));
1424 if (!single_entry
) /* when found, this will be written too */
1425 single_entry
= g_new (dir_entry
, 1);
1426 if (smbfs_search_dir_entry (current_info
->entries
, mypath
, buf
) == 0) {
1429 /* now try to identify mypath as PARENT dir */
1433 mdp
= mydir
= mhl_str_dup (current_info
->dirname
);
1434 if ((p
= strrchr (mydir
, '/')))
1435 *p
= 0; /* advance util last '/' */
1436 if ((p
= strrchr (mydir
, '/')))
1437 mydir
= p
+ 1; /* advance util last '/' */
1438 if (strcmp (mydir
, mypath
) == 0) { /* fake a stat for ".." */
1439 memset (buf
, 0, sizeof (struct stat
));
1440 buf
->st_mode
= (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
) & myumask
;
1441 memcpy (&single_entry
->my_stat
, buf
, sizeof (struct stat
));
1443 DEBUG (1, (" PARENT:found in %s\n", current_info
->dirname
));
1448 /* now try to identify as CURRENT dir? */
1450 char *dnp
= current_info
->dirname
;
1451 DEBUG (6, ("smbfs_get_stat_info: is %s current dir? this dir is: %s\n",
1452 mypath
, current_info
->dirname
));
1458 if (strcmp (mypath
, dnp
) == 0) {
1459 memset (buf
, 0, sizeof (struct stat
));
1460 buf
->st_mode
= (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
) & myumask
;
1461 memcpy (&single_entry
->my_stat
, buf
, sizeof (struct stat
));
1462 DEBUG (1, (" CURRENT:found in %s\n", current_info
->dirname
));
1466 DEBUG (3, ("'%s' not found in current_info '%s'\n", path
,
1467 current_info
->dirname
));
1468 /* try to find this in the PREVIOUS listing */
1469 if (previous_info
) {
1470 if (smbfs_search_dir_entry (previous_info
->entries
, mypath
, buf
) == 0)
1472 DEBUG (3, ("'%s' not found in previous_info '%s'\n", path
,
1473 previous_info
->dirname
));
1475 /* try to find this in the SHARE listing */
1476 if (current_share_info
) {
1477 if (smbfs_search_dir_entry (current_share_info
->entries
, mypath
, buf
) == 0)
1479 DEBUG (3, ("'%s' not found in share_info '%s'\n", path
,
1480 current_share_info
->dirname
));
1482 /* try to find this in the SERVER listing */
1483 if (current_server_info
) {
1484 if (smbfs_search_dir_entry (current_server_info
->entries
, mypath
, buf
) == 0)
1486 DEBUG (3, ("'%s' not found in server_info '%s'\n", path
,
1487 current_server_info
->dirname
));
1489 /* nothing found. get stat file info from server */
1490 return smbfs_get_remote_stat (sc
, path
, buf
);
1494 smbfs_chdir (struct vfs_class
*me
, const char *path
)
1497 smbfs_connection
*sc
;
1501 DEBUG (3, ("smbfs_chdir(path:%s)\n", path
));
1502 if (!(remote_dir
= smbfs_get_path (&sc
, path
)))
1504 mhl_mem_free (remote_dir
);
1510 smbfs_loaddir_by_name (struct vfs_class
*me
, const char *path
)
1515 mypath
= mhl_str_dup(path
);
1516 p
= strrchr(mypath
, '/');
1520 DEBUG(6, ("smbfs_loaddir_by_name(%s)\n", mypath
));
1521 smbfs_chdir(me
, mypath
);
1522 info
= smbfs_opendir (me
, mypath
);
1523 mhl_mem_free(mypath
);
1526 smbfs_readdir(info
);
1527 smbfs_loaddir(info
);
1532 smbfs_stat (struct vfs_class
* me
, const char *path
, struct stat
*buf
)
1534 smbfs_connection
*sc
;
1536 char *service
, *pp
, *at
;
1539 DEBUG (3, ("smbfs_stat(path:%s)\n", path
));
1541 if (!current_info
) {
1542 DEBUG (1, ("current_info = NULL: "));
1543 if (smbfs_loaddir_by_name (me
, path
) < 0)
1547 /* check if stating server */
1549 if (strncmp (p
, URL_HEADER
, HEADER_LEN
)) {
1550 DEBUG (1, ("'%s' doesnt start with '%s' (length %d)\n",
1551 p
, URL_HEADER
, HEADER_LEN
));
1559 pp
= strchr (p
, '/'); /* advance past next '/' */
1560 at
= strchr (p
, '@');
1561 pstrcpy (server_url
, URL_HEADER
);
1562 if (at
&& at
< pp
) { /* user@server */
1563 char *z
= &(server_url
[sizeof (server_url
) - 1]);
1566 at
= &(server_url
[HEADER_LEN
]) + (at
- p
+ 1);
1569 at
= &(server_url
[HEADER_LEN
]);
1574 pstrcat (server_url
, current_bucket
->host
);
1577 if (!current_info
->server_list
) {
1578 if (smbfs_loaddir_by_name (me
, path
) < 0)
1581 return smbfs_fake_server_stat (server_url
, path
, buf
);
1584 if (!strchr (++pp
, '/')) {
1585 return smbfs_fake_share_stat (server_url
, path
, buf
);
1588 /* stating inside share at this point */
1589 if (!(service
= smbfs_get_path (&sc
, path
))) /* connects if necessary */
1592 int hostlen
= strlen (current_bucket
->host
);
1593 char *ppp
= service
+ strlen (service
) - hostlen
;
1594 char *sp
= server_url
+ strlen (server_url
) - hostlen
;
1596 if (strcmp (sp
, ppp
) == 0) {
1597 /* make server name appear as directory */
1598 DEBUG (1, ("smbfs_stat: showing server as directory\n"));
1599 memset (buf
, 0, sizeof (struct stat
));
1600 buf
->st_mode
= (S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
) & myumask
;
1601 mhl_mem_free (service
);
1605 /* check if current_info is in share requested */
1607 pp
= strchr (p
, '/');
1609 p
= ++pp
; /* advance past server name */
1610 pp
= strchr (p
, '/');
1613 *pp
= 0; /* cut off everthing after service name */
1615 p
= IPC
; /* browsing for services */
1616 pp
= current_info
->dirname
;
1619 if (strncmp (p
, pp
, strlen (p
)) != 0) {
1620 DEBUG (6, ("desired '%s' is not loaded, we have '%s'\n", p
, pp
));
1621 if (smbfs_loaddir_by_name (me
, path
) < 0) {
1622 mhl_mem_free (service
);
1625 DEBUG (6, ("loaded dir: '%s'\n", current_info
->dirname
));
1627 mhl_mem_free (service
);
1628 /* stat dirs & files under shares now */
1629 return smbfs_get_stat_info (sc
, path
, buf
);
1632 #define smbfs_lstat smbfs_stat /* no symlinks on smb filesystem? */
1635 smbfs_lseek (void *data
, off_t offset
, int whence
)
1637 smbfs_handle
*info
= (smbfs_handle
*) data
;
1641 ("smbfs_lseek(info->nread => %d, offset => %d, whence => %d) \n",
1642 (int) info
->nread
, (int) offset
, whence
));
1646 info
->nread
= offset
;
1649 info
->nread
+= offset
;
1652 if (!cli_qfileinfo (info
->cli
, info
->fnum
,
1653 NULL
, &size
, NULL
, NULL
, NULL
,
1655 !cli_getattrE (info
->cli
, info
->fnum
,
1656 NULL
, &size
, NULL
, NULL
, NULL
)) {
1660 info
->nread
= size
+ offset
;
1668 smbfs_mknod (struct vfs_class
*me
, const char *path
, int mode
, int dev
)
1672 DEBUG(3, ("smbfs_mknod(path:%s, mode:%d, dev:%d)\n", path
, mode
, dev
));
1673 my_errno
= EOPNOTSUPP
;
1678 smbfs_mkdir (struct vfs_class
* me
, const char *path
, mode_t mode
)
1680 smbfs_connection
*sc
;
1686 DEBUG (3, ("smbfs_mkdir(path:%s, mode:%d)\n", path
, (int) mode
));
1687 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1689 mhl_mem_free (remote_file
);
1690 cpath
= smbfs_convert_path (path
, FALSE
);
1692 if (!cli_mkdir (sc
->cli
, cpath
)) {
1693 my_errno
= cli_error (sc
->cli
, NULL
, &err
, NULL
);
1694 message (D_ERROR
, MSG_ERROR
, _(" Error %s creating directory %s "),
1695 cli_errstr (sc
->cli
), CNV_LANG (cpath
));
1696 mhl_mem_free (cpath
);
1699 mhl_mem_free (cpath
);
1704 smbfs_rmdir (struct vfs_class
*me
, const char *path
)
1706 smbfs_connection
*sc
;
1712 DEBUG(3, ("smbfs_rmdir(path:%s)\n", path
));
1713 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1715 mhl_mem_free (remote_file
);
1716 cpath
= smbfs_convert_path (path
, FALSE
);
1718 if (!cli_rmdir(sc
->cli
, cpath
)) {
1719 my_errno
= cli_error(sc
->cli
, NULL
, &err
, NULL
);
1720 message (D_ERROR
, MSG_ERROR
, _(" Error %s removing directory %s "),
1721 cli_errstr(sc
->cli
), CNV_LANG(cpath
));
1722 mhl_mem_free (cpath
);
1726 mhl_mem_free (cpath
);
1731 smbfs_link (struct vfs_class
*me
, const char *p1
, const char *p2
)
1735 DEBUG (3, ("smbfs_link(p1:%s, p2:%s)\n", p1
, p2
));
1736 my_errno
= EOPNOTSUPP
;
1741 smbfs_free (vfsid id
)
1743 DEBUG (3, ("smbfs_free(%p)\n", id
));
1744 smbfs_auth_free_all ();
1747 /* Gives up on a socket and reopens the connection, the child own the socket
1751 smbfs_forget (const char *path
)
1753 char *host
, *user
, *p
;
1756 if (strncmp (path
, URL_HEADER
, HEADER_LEN
))
1759 DEBUG (3, ("smbfs_forget(path:%s)\n", path
));
1762 if (path
[0] == '/' && path
[1] == '/')
1765 if ((p
= smbfs_get_host_and_username (&path
, &host
, &user
, &port
, NULL
))) {
1767 for (i
= 0; i
< SMBFS_MAX_CONNECTIONS
; i
++) {
1768 if (smbfs_connections
[i
].cli
1769 && (strcmp (host
, smbfs_connections
[i
].host
) == 0)
1770 && (strcmp (user
, smbfs_connections
[i
].user
) == 0)
1771 && (port
== smbfs_connections
[i
].port
)) {
1773 /* close socket: the child owns it now */
1774 cli_shutdown (smbfs_connections
[i
].cli
);
1776 /* reopen the connection */
1777 smbfs_connections
[i
].cli
=
1778 smbfs_do_connect (host
, smbfs_connections
[i
].service
);
1782 mhl_mem_free (host
);
1783 mhl_mem_free (user
);
1787 smbfs_setctl (struct vfs_class
*me
, const char *path
, int ctlop
, void *arg
)
1792 DEBUG (3, ("smbfs_setctl(path:%s, ctlop:%d)\n", path
, ctlop
));
1794 case VFS_SETCTL_FORGET
:
1795 smbfs_forget (path
);
1802 static smbfs_handle
*
1803 smbfs_open_readwrite (smbfs_handle
*remote_handle
, char *rname
, int flags
, int mode
)
1809 if (flags
& O_TRUNC
) /* if it exists truncate to zero */
1810 DEBUG (3, ("smbfs_open: O_TRUNC\n"));
1812 remote_handle
->fnum
=
1813 #if 1 /* Don't play with flags, it is cli_open() headache */
1814 cli_open (remote_handle
->cli
, rname
, flags
, DENY_NONE
);
1815 #else /* What's a reasons to has this code ? */
1816 cli_open (remote_handle
->cli
, rname
, ((flags
& O_CREAT
)
1818 (O_WRONLY
| O_APPEND
))) ?
1819 flags
: O_RDONLY
, DENY_NONE
);
1821 if (remote_handle
->fnum
== -1) {
1822 message (D_ERROR
, MSG_ERROR
, _(" %s opening remote file %s "),
1823 cli_errstr (remote_handle
->cli
), CNV_LANG (rname
));
1824 DEBUG (1, ("smbfs_open(rname:%s) error:%s\n",
1825 rname
, cli_errstr (remote_handle
->cli
)));
1826 my_errno
= cli_error (remote_handle
->cli
, NULL
, &err
, NULL
);
1830 if (flags
& O_CREAT
)
1831 return remote_handle
;
1833 if (!cli_qfileinfo (remote_handle
->cli
, remote_handle
->fnum
,
1834 &remote_handle
->attr
, &size
, NULL
, NULL
, NULL
, NULL
,
1836 && !cli_getattrE (remote_handle
->cli
, remote_handle
->fnum
,
1837 &remote_handle
->attr
, &size
, NULL
, NULL
, NULL
)) {
1838 message (D_ERROR
, MSG_ERROR
, " getattrib: %s ",
1839 cli_errstr (remote_handle
->cli
));
1841 ("smbfs_open(rname:%s) getattrib:%s\n", rname
,
1842 cli_errstr (remote_handle
->cli
)));
1843 my_errno
= cli_error (remote_handle
->cli
, NULL
, &err
, NULL
);
1844 cli_close (remote_handle
->cli
, remote_handle
->fnum
);
1848 if ((flags
== (O_WRONLY
| O_APPEND
)) /* file.c:copy_file_file() -> do_append */
1849 && smbfs_lseek (remote_handle
, 0, SEEK_END
) == -1) {
1850 cli_close (remote_handle
->cli
, remote_handle
->fnum
);
1854 return remote_handle
;
1858 smbfs_open (struct vfs_class
*me
, const char *file
, int flags
, int mode
)
1862 smbfs_connection
*sc
;
1863 smbfs_handle
*remote_handle
;
1867 DEBUG(3, ("smbfs_open(file:%s, flags:%d, mode:%o)\n", file
, flags
, mode
));
1869 if (!(remote_file
= smbfs_get_path (&sc
, file
)))
1872 remote_file
= free_after(smbfs_convert_path (remote_file
, FALSE
), remote_file
);
1874 remote_handle
= g_new (smbfs_handle
, 2);
1875 remote_handle
->cli
= sc
->cli
;
1876 remote_handle
->nread
= 0;
1878 ret
= smbfs_open_readwrite (remote_handle
, remote_file
, flags
, mode
);
1880 mhl_mem_free (remote_file
);
1882 mhl_mem_free (remote_handle
);
1888 smbfs_unlink (struct vfs_class
*me
, const char *path
)
1890 smbfs_connection
*sc
;
1895 if ((remote_file
= smbfs_get_path (&sc
, path
)) == 0)
1898 remote_file
= free_after(smbfs_convert_path (remote_file
, FALSE
), remote_file
);
1900 if (!cli_unlink(sc
->cli
, remote_file
)) {
1901 message (D_ERROR
, MSG_ERROR
, _(" %s removing remote file %s "),
1902 cli_errstr(sc
->cli
), CNV_LANG(remote_file
));
1903 mhl_mem_free (remote_file
);
1906 mhl_mem_free (remote_file
);
1911 smbfs_rename (struct vfs_class
*me
, const char *a
, const char *b
)
1913 smbfs_connection
*sc
;
1919 if ((ra
= smbfs_get_path (&sc
, a
)) == 0)
1922 if ((rb
= smbfs_get_path (&sc
, b
)) == 0) {
1927 ra
= free_after (smbfs_convert_path (ra
, FALSE
), ra
);
1928 rb
= free_after (smbfs_convert_path (rb
, FALSE
), rb
);
1930 retval
= cli_rename(sc
->cli
, ra
, rb
);
1936 message (D_ERROR
, MSG_ERROR
, _(" %s renaming files\n"),
1937 cli_errstr(sc
->cli
));
1944 smbfs_fstat (void *data
, struct stat
*buf
)
1946 smbfs_handle
*remote_handle
= (smbfs_handle
*)data
;
1948 DEBUG(3, ("smbfs_fstat(fnum:%d)\n", remote_handle
->fnum
));
1950 /* use left over from previous smbfs_get_remote_stat, if available */
1952 memcpy(buf
, &single_entry
->my_stat
, sizeof(struct stat
));
1953 else { /* single_entry not set up: bug */
1963 vfs_smbfs_ops
.name
= "smbfs";
1964 vfs_smbfs_ops
.prefix
= "smb:";
1965 vfs_smbfs_ops
.flags
= VFSF_NOLINKS
;
1966 vfs_smbfs_ops
.init
= smbfs_init
;
1967 vfs_smbfs_ops
.fill_names
= smbfs_fill_names
;
1968 vfs_smbfs_ops
.open
= smbfs_open
;
1969 vfs_smbfs_ops
.close
= smbfs_close
;
1970 vfs_smbfs_ops
.read
= smbfs_read
;
1971 vfs_smbfs_ops
.write
= smbfs_write
;
1972 vfs_smbfs_ops
.opendir
= smbfs_opendir
;
1973 vfs_smbfs_ops
.readdir
= smbfs_readdir
;
1974 vfs_smbfs_ops
.closedir
= smbfs_closedir
;
1975 vfs_smbfs_ops
.stat
= smbfs_stat
;
1976 vfs_smbfs_ops
.lstat
= smbfs_lstat
;
1977 vfs_smbfs_ops
.fstat
= smbfs_fstat
;
1978 vfs_smbfs_ops
.chmod
= smbfs_chmod
;
1979 vfs_smbfs_ops
.chown
= smbfs_chown
;
1980 vfs_smbfs_ops
.utime
= smbfs_utime
;
1981 vfs_smbfs_ops
.readlink
= smbfs_readlink
;
1982 vfs_smbfs_ops
.symlink
= smbfs_symlink
;
1983 vfs_smbfs_ops
.link
= smbfs_link
;
1984 vfs_smbfs_ops
.unlink
= smbfs_unlink
;
1985 vfs_smbfs_ops
.rename
= smbfs_rename
;
1986 vfs_smbfs_ops
.chdir
= smbfs_chdir
;
1987 vfs_smbfs_ops
.ferrno
= smbfs_errno
;
1988 vfs_smbfs_ops
.lseek
= smbfs_lseek
;
1989 vfs_smbfs_ops
.mknod
= smbfs_mknod
;
1990 vfs_smbfs_ops
.free
= smbfs_free
;
1991 vfs_smbfs_ops
.mkdir
= smbfs_mkdir
;
1992 vfs_smbfs_ops
.rmdir
= smbfs_rmdir
;
1993 vfs_smbfs_ops
.setctl
= smbfs_setctl
;
1994 vfs_register_class (&vfs_smbfs_ops
);