summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--client/Makefile.am30
-rw-r--r--configure.ac71
-rw-r--r--daemon/.gitignore3
-rw-r--r--daemon/Makefile.am7
-rw-r--r--daemon/gvfsbackend.c2
-rw-r--r--daemon/gvfsbackendsmb.c570
-rw-r--r--daemon/gvfsbackendsmb.h46
-rw-r--r--daemon/smb.c54
9 files changed, 786 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 2180db67..f64cd33c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,10 @@ Makefile
Makefile.in
*~
*.o
+*.la
+*.lo
+.deps
+.libs
test
aclocal.m4
autom4te.cache
diff --git a/client/Makefile.am b/client/Makefile.am
new file mode 100644
index 00000000..4bd74aa6
--- /dev/null
+++ b/client/Makefile.am
@@ -0,0 +1,30 @@
+NULL =
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/gvfs \
+ -I$(top_srcdir)/daemon \
+ $(GLIB_CFLAGS) $(DBUS_CFLAGS) \
+ -DG_LOG_DOMAIN=\"GVFS\" -DG_DISABLE_DEPRECATED \
+ -DDBUS_API_SUBJECT_TO_CHANGE
+
+module_flags = -export_dynamic -avoid-version -module -no-undefined
+modulesdir = $(libdir)/gio/gvfs-modules
+
+modules_LTLIBRARIES = libgvfsdbus.la
+
+libgvfsdbus_la_LDFLAGS = $(module_flags)
+libgvfsdbus_la_SOURCES = \
+ gsysutils.c gsysutils.h \
+ gdbusutils.c gdbusutils.h \
+ gvfsimpldaemon.c gvfsimpldaemon.h \
+ gfiledaemon.c gfiledaemon.h \
+ gfiledaemonlocal.c gfiledaemonlocal.h \
+ gvfsuriutils.c gvfsuriutils.h \
+ gfileinputstreamdaemon.c gfileinputstreamdaemon.h \
+ gfileenumeratordaemon.c gfileenumeratordaemon.h \
+ gvfsdaemondbus.c \
+ $(NULL)
+
+libgvfsdbus_la_LIBADD = \
+ $(top_builddir)/gio/libgio.la \
+ $(DBUS_LIBS) \
+ $(GLIB_LIBS)
diff --git a/configure.ac b/configure.ac
index a1d0a615..ae966945 100644
--- a/configure.ac
+++ b/configure.ac
@@ -101,11 +101,82 @@ fi
AC_SUBST(XATTR_LIBS)
dnl ==========================================================================
+dnl Samba 3.0
+
+AC_ARG_ENABLE(samba, [ --disable-samba build without samba support])
+msg_samba="no"
+if test "x$enable_samba" != "xno"; then
+ AC_ARG_WITH(samba-includes, [ --with-samba-includes=PREFIX Location of samba includes.],
+ with_samba_includes="$withval", with_samba_includes="/usr/include")
+ have_samba_includes="no"
+ if test "x${with_samba_includes}" != "xno"; then
+ CPPFLAGS_save="$CPPFLAGS"
+
+ echo "before test, samba_includes: ${samba_includes}"
+
+ CPPFLAGS="$CPPFLAGS -I$with_samba_includes"
+ AC_CHECK_HEADER(libsmbclient.h, [ samba_includes="yes" ])
+ CPPFLAGS="$CPPFLAGS_save"
+
+ if test "x{samba_includes}" != "xno" -a "x${samba_includes}" != "x"; then
+ have_samba_includes="yes"
+ if test "${with_samba_includes}" != "/usr/include" ; then
+ SAMBA_CFLAGS="-I$with_samba_includes"
+ else
+ SAMBA_CFLAGS=""
+ fi
+
+ CPPFLAGS="$CPPFLAGS -I$with_samba_includes"
+ AC_CHECK_MEMBER(SMBCCTX.flags,
+ [AC_DEFINE(HAVE_SAMBA_FLAGS,, [Defined if flags availible in SMBCCTXT])],,
+ [#include <libsmbclient.h>])
+ AC_CHECK_MEMBER(SMBCCTX.close,
+ [AC_DEFINE(HAVE_SAMBA_OLD_CLOSE, , [Defined if old close is available in SMBCCTXT])],,
+ [#include <libsmbclient.h>])
+ CPPFLAGS="$CPPFLAGS_save"
+ else
+ SAMBA_CFLAGS=""
+ fi
+ fi
+ echo "have_samba_includes: ${have_samba_includes}"
+ AC_ARG_WITH(samba-libs, [ --with-samba-libs=PREFIX Location of Samba libs.],
+ with_samba_libs="$withval", with_samba_libs="/usr/lib")
+ if test "x${with_samba_libs}" != "xno" -a "x${have_samba_includes}" != "xno"; then
+ LDFLAGS_save="$LDFLAGS"
+
+ LDFLAGS="$LDFLAGS -L$with_samba_libs"
+ AC_CHECK_LIB(smbclient, smbc_new_context,samba_libs="yes", samba_libs="no")
+ LDFLAGS="$LDFLAGS_save"
+ if test "x${samba_libs}" != "xno"; then
+ AC_DEFINE(HAVE_SAMBA,, [Define to 1 if you have the samba 3.0 libraries])
+ msg_samba="yes"
+ if test x$with_samba_libs != x/usr/lib; then
+ SAMBA_LIBS="-L$with_samba_libs -lsmbclient"
+ else
+ SAMBA_LIBS="-lsmbclient"
+ fi
+ else
+ SAMBA_CFLAGS=""
+ SAMBA_LIBS=""
+ fi
+ fi
+ AC_MSG_CHECKING(for Samba 3.0 libraries)
+ AC_MSG_RESULT($msg_samba)
+fi
+AM_CONDITIONAL(HAVE_SAMBA, test $msg_samba = yes)
+AC_SUBST(SAMBA_CFLAGS)
+AC_SUBST(SAMBA_LIBS)
+
+dnl ==========================================================================
dnl Globally define_GNU_SOURCE and therefore enable the GNU extensions
AC_DEFINE(_GNU_SOURCE, 1, [Enable GNU Extensions])
dnl ==========================================================================
+
+AC_DEFINE(_FILE_OFFSET_BITS, 64, [Enable LFS])
+
+dnl ==========================================================================
AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
diff --git a/daemon/.gitignore b/daemon/.gitignore
index bcc5ada5..3df41a58 100644
--- a/daemon/.gitignore
+++ b/daemon/.gitignore
@@ -7,3 +7,6 @@
Makefile
Makefile.in
gvfs-daemon
+gvfs-daemon-smb
+gvfs-daemon-test
+
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 059ea34c..7241e757 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -18,6 +18,7 @@ libraries = \
noinst_PROGRAMS = \
gvfs-daemon \
gvfs-daemon-test \
+ gvfs-daemon-smb \
$(NULL)
libdaemon_la_SOURCES = \
@@ -48,3 +49,9 @@ gvfs_daemon_test_SOURCES = \
test.c
gvfs_daemon_test_LDADD = $(libraries)
+
+gvfs_daemon_smb_SOURCES = \
+ gvfsbackendsmb.c gvfsbackendsmb.h \
+ smb.c
+
+gvfs_daemon_smb_LDADD = $(libraries) $(SAMBA_LIBS)
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
index bf96bcc2..f2263368 100644
--- a/daemon/gvfsbackend.c
+++ b/daemon/gvfsbackend.c
@@ -307,7 +307,7 @@ void
g_vfs_backend_register_with_daemon (GVfsBackend *backend,
GVfsDaemon *daemon)
{
- g_print ("registering %s\n", backend->object_path);
+ g_print ("registering %s with %p\n", backend->object_path, daemon);
g_vfs_daemon_add_job_source (daemon, G_VFS_JOB_SOURCE (backend));
g_vfs_daemon_register_path (daemon, backend->object_path,
backend_dbus_handler, backend);
diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c
new file mode 100644
index 00000000..d284b8b7
--- /dev/null
+++ b/daemon/gvfsbackendsmb.c
@@ -0,0 +1,570 @@
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+#include <glib/gi18n.h>
+#include <gio/gvfserror.h>
+#include <gio/gfile.h>
+#include <gio/gfilelocal.h>
+
+#include "gvfsbackendsmb.h"
+#include "gvfsjobopenforread.h"
+#include "gvfsjobread.h"
+#include "gvfsjobseekread.h"
+#include "gvfsjobgetinfo.h"
+#include "gvfsjobenumerate.h"
+#include "gvfsdaemonprotocol.h"
+
+G_DEFINE_TYPE (GVfsBackendSmb, g_vfs_backend_smb, G_TYPE_VFS_BACKEND);
+
+static GVfsBackendSmb *smb_backend = NULL;
+
+static void
+g_vfs_backend_smb_finalize (GObject *object)
+{
+ GVfsBackendSmb *backend;
+
+ backend = G_VFS_BACKEND_SMB (object);
+
+ if (G_OBJECT_CLASS (g_vfs_backend_smb_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_vfs_backend_smb_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_backend_smb_init (GVfsBackendSmb *backend)
+{
+}
+
+/* Authentication callback function type (traditional method)
+ *
+ * Type for the the authentication function called by the library to
+ * obtain authentication credentals
+ *
+ * @param srv Server being authenticated to
+ * @param shr Share being authenticated to
+ * @param wg Pointer to buffer containing a "hint" for the
+ * workgroup to be authenticated. Should be filled in
+ * with the correct workgroup if the hint is wrong.
+ * @param wglen The size of the workgroup buffer in bytes
+ * @param un Pointer to buffer containing a "hint" for the
+ * user name to be use for authentication. Should be
+ * filled in with the correct workgroup if the hint is
+ * wrong.
+ * @param unlen The size of the username buffer in bytes
+ * @param pw Pointer to buffer containing to which password
+ * copied
+ * @param pwlen The size of the password buffer in bytes
+ *
+ */
+static void
+auth_callback (const char *server_name, const char *share_name,
+ char *domain_out, int domainmaxlen,
+ char *username_out, int unmaxlen,
+ char *password_out, int pwmaxlen)
+{
+ g_print ("auth_callback: %s %s\n", server_name, share_name);
+}
+
+/* Add a server to the cache system
+ *
+ * @param c pointer to smb context
+ * @param srv pointer to server to add
+ * @param server server name
+ * @param share share name
+ * @param workgroup workgroup used to connect
+ * @param username username used to connect
+ * @return 0 on success. 1 on failure.
+ *
+ */
+static int
+add_cached_server (SMBCCTX *context, SMBCSRV *new,
+ const char *server_name, const char *share_name,
+ const char *domain, const char *username)
+{
+ g_print ("add_cached_server\n");
+ if (smb_backend->server != NULL)
+ return 1;
+
+ smb_backend->server_name = g_strdup (server_name);
+ smb_backend->share_name = g_strdup (share_name);
+ smb_backend->domain = g_strdup (domain);
+ smb_backend->username = g_strdup (username);
+ smb_backend->server = new;
+
+ return 0;
+}
+
+/* Remove cached server
+ *
+ * @param c pointer to smb context
+ * @param srv pointer to server to remove
+ * @return 0 when found and removed. 1 on failure.
+ *
+ */
+static int
+remove_cached_server(SMBCCTX * context, SMBCSRV * server)
+{
+ g_print ("remove_cached_server\n");
+ if (smb_backend->server == server)
+ {
+ g_free (smb_backend->server_name);
+ smb_backend->server_name = NULL;
+ g_free (smb_backend->share_name);
+ smb_backend->share_name = NULL;
+ g_free (smb_backend->domain);
+ smb_backend->domain = NULL;
+ g_free (smb_backend->username);
+ smb_backend->username = NULL;
+ smb_backend->server = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+
+/* Look up a server in the cache system
+ *
+ * @param c pointer to smb context
+ * @param server server name to match
+ * @param share share name to match
+ * @param workgroup workgroup to match
+ * @param username username to match
+ * @return pointer to SMBCSRV on success. NULL on failure.
+ *
+ */
+static SMBCSRV *
+get_cached_server (SMBCCTX * context,
+ const char *server_name, const char *share_name,
+ const char *domain, const char *username)
+{
+ if (smb_backend->server != NULL &&
+ strcmp (smb_backend->server_name, server_name) == 0 &&
+ strcmp (smb_backend->share_name, server_name) == 0 &&
+ strcmp (smb_backend->domain, domain) == 0 &&
+ strcmp (smb_backend->username, username) == 0)
+ return smb_backend->server;
+
+ return NULL;
+}
+
+/* Try to remove all servers from the cache system and disconnect
+ *
+ * @param c pointer to smb context
+ *
+ * @return 0 when found and removed. 1 on failure.
+ *
+ */
+static int
+purge_cached (SMBCCTX * context)
+{
+ if (smb_backend->server)
+ remove_cached_server(context, smb_backend->server);
+
+ return 0;
+}
+
+#define SUB_DELIM_CHARS "!$&'()*+,;="
+
+static gboolean
+is_valid (char c, const char *reserved_chars_allowed)
+{
+ if (g_ascii_isalnum (c) ||
+ c == '-' ||
+ c == '.' ||
+ c == '_' ||
+ c == '~')
+ return TRUE;
+
+ if (reserved_chars_allowed &&
+ strchr (reserved_chars_allowed, c) != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+g_string_append_encoded (GString *string,
+ const char *encoded,
+ const char *reserved_chars_allowed)
+{
+ char c;
+ static const gchar hex[16] = "0123456789ABCDEF";
+
+ while ((c = *encoded++) != 0)
+ {
+ if (is_valid (c, reserved_chars_allowed))
+ g_string_append_c (string, c);
+ else
+ {
+ g_string_append_c (string, '%');
+ g_string_append_c (string, hex[((guchar)c) >> 4]);
+ g_string_append_c (string, hex[((guchar)c) & 0xf]);
+ }
+ }
+}
+
+static char *
+create_smb_uri (const char *server,
+ const char *share,
+ const char *path)
+{
+ GString *uri;
+
+ uri = g_string_new ("smb://");
+ g_string_append_encoded (uri, server, NULL);
+ g_string_append_c (uri, '/');
+ g_string_append_encoded (uri, share, NULL);
+ if (path != NULL)
+ {
+ if (*path != '/')
+ g_string_append_c (uri, '/');
+ g_string_append_encoded (uri, path, SUB_DELIM_CHARS ":@/");
+ }
+ return g_string_free (uri, FALSE);
+}
+
+
+GVfsBackendSmb *
+g_vfs_backend_smb_new (const char *server,
+ const char *share)
+{
+ GVfsBackendSmb *backend;
+ char *obj_path, *bus_name;
+ SMBCCTX *smb_context;
+ int res;
+ char *uri;
+ struct stat st;
+
+ g_assert (smb_backend == NULL);
+
+ smb_context = smbc_new_context ();
+ if (smb_context == NULL)
+ return NULL;
+
+ smb_context->debug = 0;
+ smb_context->callbacks.auth_fn = auth_callback;
+
+ smb_context->callbacks.add_cached_srv_fn = add_cached_server;
+ smb_context->callbacks.get_cached_srv_fn = get_cached_server;
+ smb_context->callbacks.remove_cached_srv_fn = remove_cached_server;
+ smb_context->callbacks.purge_cached_fn = purge_cached;
+
+#if defined(HAVE_SAMBA_FLAGS)
+#if defined(SMB_CTX_FLAG_USE_KERBEROS) && defined(SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS)
+ smb_context->flags |= SMB_CTX_FLAG_USE_KERBEROS | SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS;
+#endif
+#if defined(SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON)
+ //smb_context->flags |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON;
+#endif
+#endif
+
+ if (0)
+ smbc_option_set(smb_context, "debug_stderr", (void *) 1);
+
+
+ if (!smbc_init_context (smb_context))
+ {
+ g_print ("init context failed\n");
+ smbc_free_context (smb_context, FALSE);
+ return NULL;
+ }
+
+ obj_path = g_strdup_printf (G_VFS_DBUS_MOUNTPOINT_PATH"smbshare/h_%s/f_%s", server, share);
+ bus_name = g_strdup_printf (G_VFS_DBUS_MOUNTPOINT_NAME"smbshare.h_%s.f_%s", server, share);
+
+ backend = g_object_new (G_TYPE_VFS_BACKEND_SMB,
+ "object-path", obj_path,
+ "bus-name", bus_name,
+ NULL);
+ smb_backend = backend;
+ backend->smb_context = smb_context;
+
+ uri = create_smb_uri (server, share, NULL);
+ res = smb_context->stat (smb_context, uri, &st);
+ g_free (uri);
+ if (res != 0)
+ {
+ g_object_unref (backend);
+ return NULL;
+ }
+
+ return backend;
+}
+
+static gboolean
+open_idle_cb (gpointer data)
+{
+ GVfsJobOpenForRead *job = data;
+ int fd;
+
+ if (g_vfs_job_is_cancelled (G_VFS_JOB (job)))
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_VFS_ERROR,
+ G_VFS_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ return FALSE;
+ }
+
+ fd = g_open (job->filename, O_RDONLY);
+ if (fd == -1)
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "Error opening file %s: %s",
+ job->filename, g_strerror (errno));
+ }
+ else
+ {
+ g_vfs_job_open_for_read_set_can_seek (job, TRUE);
+ g_vfs_job_open_for_read_set_handle (job, GINT_TO_POINTER (fd));
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+ return FALSE;
+}
+
+static void
+open_read_cancelled_cb (GVfsJob *job, gpointer data)
+{
+ guint tag = GPOINTER_TO_INT (data);
+
+ g_print ("open_read_cancelled_cb\n");
+
+ if (g_source_remove (tag))
+ g_vfs_job_failed (job, G_VFS_ERROR,
+ G_VFS_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+}
+
+static gboolean
+do_open_for_read (GVfsBackend *backend,
+ GVfsJobOpenForRead *job,
+ char *filename)
+{
+ GError *error;
+
+ g_print ("open_for_read (%s)\n", filename);
+
+ if (strcmp (filename, "/fail") == 0)
+ {
+ error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_IO, "Smb error");
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ return TRUE;
+ }
+ else
+ {
+ guint tag = g_timeout_add (0, open_idle_cb, job);
+ g_signal_connect (job, "cancelled", (GCallback)open_read_cancelled_cb, GINT_TO_POINTER (tag));
+ return TRUE;
+ }
+}
+
+static gboolean
+read_idle_cb (gpointer data)
+{
+ GVfsJobRead *job = data;
+ int fd;
+ ssize_t res;
+
+ fd = GPOINTER_TO_INT (job->handle);
+
+ res = read (fd, job->buffer, job->bytes_requested);
+
+ if (res == -1)
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "Error reading from file: %s",
+ g_strerror (errno));
+ }
+ else
+ {
+ g_vfs_job_read_set_size (job, res);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+
+ return FALSE;
+}
+
+static void
+read_cancelled_cb (GVfsJob *job, gpointer data)
+{
+ guint tag = GPOINTER_TO_INT (job->backend_data);
+
+ g_source_remove (tag);
+ g_vfs_job_failed (job, G_VFS_ERROR,
+ G_VFS_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+}
+
+static gboolean
+do_read (GVfsBackend *backend,
+ GVfsJobRead *job,
+ GVfsBackendHandle handle,
+ char *buffer,
+ gsize bytes_requested)
+{
+ guint tag;
+
+ g_print ("read (%d)\n", bytes_requested);
+
+ tag = g_timeout_add (0, read_idle_cb, job);
+ G_VFS_JOB (job)->backend_data = GINT_TO_POINTER (tag);
+ g_signal_connect (job, "cancelled", (GCallback)read_cancelled_cb, NULL);
+
+ return TRUE;
+}
+
+static gboolean
+do_seek_on_read (GVfsBackend *backend,
+ GVfsJobSeekRead *job,
+ GVfsBackendHandle handle,
+ goffset offset,
+ GSeekType type)
+{
+ int whence;
+ int fd;
+ off_t final_offset;
+
+ g_print ("seek_on_read (%d, %d)\n", (int)offset, type);
+
+ switch (type)
+ {
+ default:
+ case G_SEEK_SET:
+ whence = SEEK_SET;
+ break;
+ case G_SEEK_CUR:
+ whence = SEEK_CUR;
+ break;
+ case G_SEEK_END:
+ whence = SEEK_END;
+ break;
+ }
+
+
+ fd = GPOINTER_TO_INT (handle);
+
+ final_offset = lseek (fd, offset, whence);
+
+ if (final_offset == (off_t)-1)
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "Error seeking in file: %s",
+ g_strerror (errno));
+ }
+ else
+ {
+ g_vfs_job_seek_read_set_offset (job, offset);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+
+ return TRUE;
+}
+
+static gboolean
+do_close_read (GVfsBackend *backend,
+ GVfsJobCloseRead *job,
+ GVfsBackendHandle handle)
+{
+ int fd;
+
+ g_print ("close ()\n");
+
+ fd = GPOINTER_TO_INT (handle);
+ close(fd);
+
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ return TRUE;
+}
+
+static gboolean
+do_get_info (GVfsBackend *backend,
+ GVfsJobGetInfo *job,
+ char *filename,
+ GFileInfoRequestFlags requested,
+ const char *attributes,
+ gboolean follow_symlinks)
+{
+ GFile *file;
+ GFileInfo *info;
+ GError *error;
+
+ file = g_file_local_new (filename);
+
+ error = NULL;
+ info = g_file_get_info (file, requested, attributes, follow_symlinks,
+ NULL, &error);
+
+ if (info)
+ {
+ g_vfs_job_get_info_set_info (job, requested, info);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+ else
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+
+ g_object_unref (info);
+ g_object_unref (file);
+
+ return TRUE;
+}
+
+static gboolean
+do_enumerate (GVfsBackend *backend,
+ GVfsJobEnumerate *job,
+ char *filename,
+ GFileInfoRequestFlags requested,
+ const char *attributes,
+ gboolean follow_symlinks)
+{
+ GFileInfo *info1, *info2;;
+ GList *l;
+
+ g_vfs_job_enumerate_set_result (job, requested);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ info1 = g_file_info_new ();
+ info2 = g_file_info_new ();
+ g_file_info_set_name (info1, "file1");
+ g_file_info_set_file_type (info1, G_FILE_TYPE_REGULAR);
+ g_file_info_set_name (info2, "file2");
+ g_file_info_set_file_type (info2, G_FILE_TYPE_REGULAR);
+
+ l = NULL;
+ l = g_list_append (l, info1);
+ l = g_list_append (l, info2);
+
+ g_vfs_job_enumerate_add_info (job, l);
+
+ g_list_free (l);
+ g_object_unref (info1);
+ g_object_unref (info2);
+
+ g_vfs_job_enumerate_done (job);
+
+ return TRUE;
+}
+
+static void
+g_vfs_backend_smb_class_init (GVfsBackendSmbClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
+
+ gobject_class->finalize = g_vfs_backend_smb_finalize;
+
+ backend_class->open_for_read = do_open_for_read;
+ backend_class->read = do_read;
+ backend_class->seek_on_read = do_seek_on_read;
+ backend_class->close_read = do_close_read;
+ backend_class->get_info = do_get_info;
+ backend_class->enumerate = do_enumerate;
+}
diff --git a/daemon/gvfsbackendsmb.h b/daemon/gvfsbackendsmb.h
new file mode 100644
index 00000000..99a967e3
--- /dev/null
+++ b/daemon/gvfsbackendsmb.h
@@ -0,0 +1,46 @@
+#ifndef __G_VFS_BACKEND_SMB_H__
+#define __G_VFS_BACKEND_SMB_H__
+
+#include <gvfsbackend.h>
+
+#include <libsmbclient.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_VFS_BACKEND_SMB (g_vfs_backend_smb_get_type ())
+#define G_VFS_BACKEND_SMB(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_BACKEND_SMB, GVfsBackendSmb))
+#define G_VFS_BACKEND_SMB_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_BACKEND_SMB, GVfsBackendSmbClass))
+#define G_IS_VFS_BACKEND_SMB(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_BACKEND_SMB))
+#define G_IS_VFS_BACKEND_SMB_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_BACKEND_SMB))
+#define G_VFS_BACKEND_SMB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_BACKEND_SMB, GVfsBackendSmbClass))
+
+typedef struct _GVfsBackendSmb GVfsBackendSmb;
+typedef struct _GVfsBackendSmbClass GVfsBackendSmbClass;
+
+struct _GVfsBackendSmb
+{
+ GVfsBackend parent_instance;
+
+ SMBCCTX *smb_context;
+
+ /* Cache */
+ char *server_name;
+ char *share_name;
+ char *domain;
+ char *username;
+ SMBCSRV *server;
+};
+
+struct _GVfsBackendSmbClass
+{
+ GVfsBackendClass parent_class;
+};
+
+GType g_vfs_backend_smb_get_type (void) G_GNUC_CONST;
+
+GVfsBackendSmb *g_vfs_backend_smb_new (const char *server,
+ const char *share);
+
+G_END_DECLS
+
+#endif /* __G_VFS_BACKEND_SMB_H__ */
diff --git a/daemon/smb.c b/daemon/smb.c
new file mode 100644
index 00000000..5f3c6416
--- /dev/null
+++ b/daemon/smb.c
@@ -0,0 +1,54 @@
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus-gmain.h>
+#include "gvfsdaemon.h"
+#include "gvfsbackendsmb.h"
+#include <gvfsdaemonprotocol.h>
+
+int
+main (int argc, char *argv[])
+{
+ GMainLoop *loop;
+ GVfsDaemon *daemon;
+ GVfsBackendSmb *backend;
+ const char *server, *share;
+
+ if (argc < 3)
+ {
+ g_print ("Args: server share\n");
+ return 0;
+ }
+
+ server = argv[1];
+ share = argv[2];
+
+ g_thread_init (NULL);
+
+ g_type_init ();
+
+ daemon = g_vfs_daemon_new (FALSE, FALSE);
+ if (daemon == NULL)
+ return 1;
+
+ backend = g_vfs_backend_smb_new (server, share);
+
+ if (backend == NULL)
+ {
+ g_print ("Failed instantiating backend\n");
+ return 1;
+ }
+
+ g_vfs_backend_register_with_daemon (G_VFS_BACKEND (backend), daemon);
+ g_object_unref (backend);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ g_print ("Entering mainloop\n");
+ g_main_loop_run (loop);
+
+ return 0;
+}