summaryrefslogtreecommitdiff
path: root/daemon/gvfsbackendsmbbrowse.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/gvfsbackendsmbbrowse.c')
-rw-r--r--daemon/gvfsbackendsmbbrowse.c1225
1 files changed, 0 insertions, 1225 deletions
diff --git a/daemon/gvfsbackendsmbbrowse.c b/daemon/gvfsbackendsmbbrowse.c
deleted file mode 100644
index 3ae0c87e..00000000
--- a/daemon/gvfsbackendsmbbrowse.c
+++ /dev/null
@@ -1,1225 +0,0 @@
-/* GIO - GLib Input, Output and Streaming Library
- *
- * Copyright (C) 2006-2007 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Alexander Larsson <alexl@redhat.com>
- */
-
-#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/gio.h>
-
-#include "gvfsbackendsmbbrowse.h"
-#include "gvfsjobmountmountable.h"
-#include "gvfsjobopenforread.h"
-#include "gvfsjobread.h"
-#include "gvfsjobseekread.h"
-#include "gvfsjobqueryinfo.h"
-#include "gvfsjobenumerate.h"
-#include "gvfsdaemonprotocol.h"
-#include "gmounttracker.h"
-
-#include <libsmbclient.h>
-#include "libsmb-compat.h"
-
-#ifdef HAVE_GCONF
-#include <gconf/gconf-client.h>
-#endif
-
-/* We load a default workgroup from gconf */
-#define PATH_GCONF_GNOME_VFS_SMB_WORKGROUP "/system/smb/workgroup"
-
-/* The magic "default workgroup" hostname */
-#define DEFAULT_WORKGROUP_NAME "X-GNOME-DEFAULT-WORKGROUP"
-
-typedef struct {
- unsigned int smbc_type;
- char *name;
- char *name_normalized;
- char *name_utf8;
- char *comment;
-} BrowseEntry;
-
-struct _GVfsBackendSmbBrowse
-{
- GVfsBackend parent_instance;
-
- char *user;
- char *domain;
- char *server;
- char *mounted_server; /* server or DEFAULT_WORKGROUP_NAME */
- SMBCCTX *smb_context;
-
- GMutex *entries_lock;
- time_t last_entry_update;
- GList *entries;
- int entry_errno;
-};
-
-static char *default_workgroup = NULL;
-
-static GHashTable *server_cache = NULL;
-static GMountTracker *mount_tracker = NULL;
-
-typedef struct {
- char *server_name;
- char *share_name;
- char *domain;
- char *username;
-} CachedServer;
-
-G_DEFINE_TYPE (GVfsBackendSmbBrowse, g_vfs_backend_smb_browse, G_VFS_TYPE_BACKEND)
-
-static char *
-normalize_smb_name_helper (const char *name, gssize len, gboolean valid_utf8)
-{
- if (valid_utf8)
- return g_utf8_casefold (name, len);
- else
- return g_ascii_strdown (name, len);
-}
-
-static char *
-normalize_smb_name (const char *name, gssize len)
-{
- gboolean valid_utf8;
-
- valid_utf8 = g_utf8_validate (name, len, NULL);
- return normalize_smb_name_helper (name, len, valid_utf8);
-}
-
-static char *
-smb_name_to_utf8 (const char *name, gboolean *valid_utf8_out)
-{
- GString *string;
- const gchar *remainder, *invalid;
- gint remaining_bytes, valid_bytes;
- gboolean valid_utf8;
-
- remainder = name;
- remaining_bytes = strlen (name);
- valid_utf8 = TRUE;
-
- string = g_string_sized_new (remaining_bytes);
- while (remaining_bytes != 0)
- {
- if (g_utf8_validate (remainder, remaining_bytes, &invalid))
- break;
- valid_utf8 = FALSE;
-
- valid_bytes = invalid - remainder;
-
- g_string_append_len (string, remainder, valid_bytes);
- /* append U+FFFD REPLACEMENT CHARACTER */
- g_string_append (string, "\357\277\275");
-
- remaining_bytes -= valid_bytes + 1;
- remainder = invalid + 1;
- }
-
- g_string_append (string, remainder);
-
- if (valid_utf8_out)
- *valid_utf8_out = valid_utf8;
-
- return g_string_free (string, FALSE);
-}
-
-static void
-browse_entry_free (BrowseEntry *entry)
-{
- g_free (entry->name);
- g_free (entry->comment);
- g_free (entry);
-}
-
-static gboolean
-cached_server_equal (gconstpointer _a,
- gconstpointer _b)
-{
- const CachedServer *a = _a;
- const CachedServer *b = _b;
-
- return
- strcmp (a->server_name, b->server_name) == 0 &&
- strcmp (a->share_name, b->share_name) == 0 &&
- strcmp (a->domain, b->domain) == 0 &&
- strcmp (a->username, b->username) == 0;
-}
-
-static guint
-cached_server_hash (gconstpointer key)
-{
- const CachedServer *server = key;
-
- return
- g_str_hash (server->server_name) ^
- g_str_hash (server->share_name) ^
- g_str_hash (server->domain) ^
- g_str_hash (server->username);
-}
-
-static void
-cached_server_free (CachedServer *server)
-{
- g_free (server->server_name);
- g_free (server->share_name);
- g_free (server->domain);
- g_free (server->username);
- g_free (server);
-}
-
-static void
-g_vfs_backend_smb_browse_finalize (GObject *object)
-{
- GVfsBackendSmbBrowse *backend;
-
- backend = G_VFS_BACKEND_SMB_BROWSE (object);
-
- g_free (backend->user);
- g_free (backend->domain);
- g_free (backend->mounted_server);
- g_free (backend->server);
-
- g_mutex_free (backend->entries_lock);
-
- smbc_free_context (backend->smb_context, TRUE);
-
- g_list_foreach (backend->entries, (GFunc)browse_entry_free, NULL);
- g_list_free (backend->entries);
-
- if (G_OBJECT_CLASS (g_vfs_backend_smb_browse_parent_class)->finalize)
- (*G_OBJECT_CLASS (g_vfs_backend_smb_browse_parent_class)->finalize) (object);
-}
-
-static void
-g_vfs_backend_smb_browse_init (GVfsBackendSmbBrowse *backend)
-{
- backend->entries_lock = g_mutex_new ();
-
- if (mount_tracker == NULL)
- mount_tracker = g_mount_tracker_new (NULL);
-}
-
-/**
- * Authentication callback function type (method that includes context)
- *
- * Type for the the authentication function called by the library to
- * obtain authentication credentals
- *
- * @param context Pointer to the smb context
- * @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 (SMBCCTX *context,
- const char *server_name, const char *share_name,
- char *domain_out, int domainmaxlen,
- char *username_out, int unmaxlen,
- char *password_out, int pwmaxlen)
-{
- GVfsBackendSmbBrowse *backend;
-
- backend = smbc_getOptionUserData (context);
-
- if (backend->domain)
- strncpy (domain_out, backend->domain, domainmaxlen);
- if (backend->user)
- strncpy (username_out, backend->user, unmaxlen);
- strncpy (password_out, "", pwmaxlen);
-}
-
-/* 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)
-{
- CachedServer *cached_server;
-
- cached_server = g_new (CachedServer, 1);
- cached_server->server_name = g_strdup (server_name);
- cached_server->share_name = g_strdup (share_name);
- cached_server->domain = g_strdup (domain);
- cached_server->username = g_strdup (username);
-
- if (server_cache == NULL)
- server_cache = g_hash_table_new_full (cached_server_hash, cached_server_equal,
- (GDestroyNotify)cached_server_free, NULL);
-
- g_hash_table_insert (server_cache, cached_server, new);
-
- return 0;
-}
-
-static gboolean
-remove_cb (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- return value == user_data;
-}
-
-/* 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)
-{
- guint num;
-
- if (server_cache)
- {
- num = g_hash_table_foreach_remove (server_cache, remove_cb, server);
- if (num != 0)
- 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)
-{
- const CachedServer key = {
- (char *)server_name,
- (char *)share_name,
- (char *)domain,
- (char *)username
- };
-
- if (server_cache)
- return g_hash_table_lookup (server_cache, &key);
- else
- 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 (server_cache)
- g_hash_table_remove_all (server_cache);
-
- 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 *encoded_end,
- const char *reserved_chars_allowed)
-{
- char c;
- static const gchar hex[16] = "0123456789ABCDEF";
-
- if (encoded_end == NULL)
- encoded_end = encoded + strlen (encoded);
-
- while (encoded < encoded_end)
- {
- c = *encoded++;
-
- 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 void
-update_cache (GVfsBackendSmbBrowse *backend)
-{
- GString *uri;
- char dirents[1024*4];
- struct smbc_dirent *dirp;
- GList *entries;
- int entry_errno;
- SMBCFILE *dir;
- int res;
- smbc_opendir_fn smbc_opendir;
- smbc_getdents_fn smbc_getdents;
- smbc_closedir_fn smbc_closedir;
-
-
- entries = NULL;
- entry_errno = 0;
-
- /* Update Cache */
- uri = g_string_new ("smb://");
-
- if (backend->server)
- {
- g_string_append_encoded (uri, backend->server, NULL, NULL);
- g_string_append_c (uri, '/');
- }
-
- smbc_opendir = smbc_getFunctionOpendir (backend->smb_context);
- smbc_getdents = smbc_getFunctionGetdents (backend->smb_context);
- smbc_closedir = smbc_getFunctionClosedir (backend->smb_context);
-
- dir = smbc_opendir (backend->smb_context, uri->str);
- g_string_free (uri, TRUE);
- if (dir == NULL)
- {
- entry_errno = errno;
- goto out;
- }
-
- while (TRUE)
- {
- res = smbc_getdents (backend->smb_context, dir, (struct smbc_dirent *)dirents, sizeof (dirents));
- if (res <= 0)
- break;
-
- dirp = (struct smbc_dirent *)dirents;
- while (res > 0)
- {
- unsigned int dirlen;
-
- if (dirp->smbc_type != SMBC_IPC_SHARE &&
- dirp->smbc_type != SMBC_COMMS_SHARE &&
- dirp->smbc_type != SMBC_PRINTER_SHARE &&
- strcmp (dirp->name, ".") != 0 &&
- strcmp (dirp->name, "..") != 0)
- {
- BrowseEntry *entry = g_new (BrowseEntry, 1);
- gboolean valid_utf8;
-
- entry->smbc_type = dirp->smbc_type;
- entry->name = g_strdup (dirp->name);
- entry->name_utf8 = smb_name_to_utf8 (dirp->name, &valid_utf8);
- entry->name_normalized = normalize_smb_name_helper (dirp->name, -1, valid_utf8);
- entry->comment = smb_name_to_utf8 (dirp->comment, NULL);
-
- entries = g_list_prepend (entries, entry);
- }
-
- dirlen = dirp->dirlen;
- dirp = (struct smbc_dirent *) (((char *)dirp) + dirlen);
- res -= dirlen;
- }
-
- entries = g_list_reverse (entries);
- }
-
- smbc_closedir (backend->smb_context, dir);
-
-
- out:
-
- g_mutex_lock (backend->entries_lock);
-
- /* Clear old cache */
- g_list_foreach (backend->entries, (GFunc)browse_entry_free, NULL);
- g_list_free (backend->entries);
- backend->entries = entries;
- backend->entry_errno = entry_errno;
- backend->last_entry_update = time (NULL);
-
- g_mutex_unlock (backend->entries_lock);
-
-}
-
-static BrowseEntry *
-find_entry_unlocked (GVfsBackendSmbBrowse *backend,
- const char *filename)
-{
- BrowseEntry *entry, *found;
- GList *l;
- char *end;
- int len;
- char *normalized;
-
- while (*filename == '/')
- filename++;
-
- end = strchr (filename, '/');
- if (end)
- {
- len = end - filename;
-
- while (*end == '/')
- end++;
-
- if (*end != 0)
- return NULL;
- }
- else
- len = strlen (filename);
-
- /* First look for an exact filename match */
- found = NULL;
- for (l = backend->entries; l != NULL; l = l->next)
- {
- entry = l->data;
-
- if (strncmp (filename, entry->name, len) == 0 &&
- strlen (entry->name) == len)
- {
- found = entry;
- break;
- }
- }
-
- if (found == NULL)
- {
- /* That failed, try normalizing the filename */
- normalized = normalize_smb_name (filename, len);
-
- for (l = backend->entries; l != NULL; l = l->next)
- {
- entry = l->data;
-
- if (strcmp (normalized, entry->name_normalized) == 0)
- {
- found = entry;
- break;
- }
- }
- g_free (normalized);
- }
-
- return found;
-}
-
-static GMountSpec *
-get_mount_spec_for_share (const char *server,
- const char *share)
-{
- GMountSpec *mount_spec;
- char *normalized;
-
- mount_spec = g_mount_spec_new ("smb-share");
- normalized = normalize_smb_name (server, -1);
- g_mount_spec_set (mount_spec, "server", normalized);
- g_free (normalized);
- normalized = normalize_smb_name (share, -1);
- g_mount_spec_set (mount_spec, "share", normalized);
- g_free (normalized);
-
- return mount_spec;
-}
-
-static gboolean
-is_root (const char *filename)
-{
- const char *p;
-
- p = filename;
- while (*p == '/')
- p++;
-
- return *p == 0;
-}
-
-static gboolean
-has_name (GVfsBackendSmbBrowse *backend,
- const char *filename)
-{
- gboolean res;
-
- g_mutex_lock (backend->entries_lock);
- res = (find_entry_unlocked (backend, filename) != NULL);
- g_mutex_unlock (backend->entries_lock);
- return res;
-}
-
-static gboolean
-cache_needs_updating (GVfsBackendSmbBrowse *backend)
-{
- time_t now = time (NULL);
-
- return now < backend->last_entry_update ||
- (now - backend->last_entry_update) > 10;
-}
-
-static void
-do_mount (GVfsBackend *backend,
- GVfsJobMount *job,
- GMountSpec *mount_spec,
- GMountSource *mount_source,
- gboolean is_automount)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
- SMBCCTX *smb_context;
- char *display_name;
- char *icon;
- GMountSpec *browse_mount_spec;
-
- smb_context = smbc_new_context ();
- if (smb_context == NULL)
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_FAILED,
- "Failed to allocate smb context");
- return;
- }
-
- smbc_setOptionUserData (smb_context, backend);
-
- smbc_setDebug (smb_context, 0);
- smbc_setFunctionAuthDataWithContext (smb_context, auth_callback);
-
- smbc_setFunctionAddCachedServer (smb_context, add_cached_server);
- smbc_setFunctionGetCachedServer (smb_context, get_cached_server);
- smbc_setFunctionRemoveCachedServer (smb_context, remove_cached_server);
- smbc_setFunctionPurgeCachedServers (smb_context, purge_cached);
-
- /* FIXME: is strdup() still needed here? -- removed */
- if (default_workgroup != NULL)
- smbc_setWorkgroup (smb_context, default_workgroup);
-
-#ifndef DEPRECATED_SMBC_INTERFACE
- smb_context->flags = 0;
-#endif
-
- smbc_setOptionUseKerberos (smb_context, 1);
- smbc_setOptionFallbackAfterKerberos (smb_context, 1);
- //smbc_setOptionNoAutoAnonymousLogin (smb_context, 1);
-
-
-#if 0
- smbc_setOptionDebugToStderr (smb_context, 1);
-#endif
-
- if (!smbc_init_context (smb_context))
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_FAILED,
- "Failed to initialize smb context");
- smbc_free_context (smb_context, FALSE);
- return;
- }
-
- op_backend->smb_context = smb_context;
-
- /* Convert DEFAULT_WORKGROUP_NAME to real domain */
- if (op_backend->mounted_server != NULL &&
- g_ascii_strcasecmp (op_backend->mounted_server, DEFAULT_WORKGROUP_NAME) == 0)
- op_backend->server = g_strdup (smbc_getWorkgroup (smb_context));
- else
- op_backend->server = g_strdup (op_backend->mounted_server);
-
- icon = NULL;
- if (op_backend->server == NULL)
- {
- display_name = g_strdup (_("Windows Network"));
- browse_mount_spec = g_mount_spec_new ("smb-network");
- icon = "network-workgroup";
- }
- else
- {
- /* translators: Name for the location that lists the smb shares
- availible on a server (%s is the name of the server) */
- display_name = g_strdup_printf (_("Windows shares on %s"), op_backend->server);
- browse_mount_spec = g_mount_spec_new ("smb-server");
- g_mount_spec_set (browse_mount_spec, "server", op_backend->mounted_server);
- icon = "network-server";
- }
-
- if (op_backend->user)
- g_mount_spec_set (browse_mount_spec, "user", op_backend->user);
- if (op_backend->domain)
- g_mount_spec_set (browse_mount_spec, "domain", op_backend->domain);
-
- g_vfs_backend_set_display_name (backend, display_name);
- g_free (display_name);
- if (icon)
- g_vfs_backend_set_icon_name (backend, icon);
- g_vfs_backend_set_user_visible (backend, FALSE);
- g_vfs_backend_set_mount_spec (backend, browse_mount_spec);
- g_mount_spec_unref (browse_mount_spec);
-
- g_vfs_job_succeeded (G_VFS_JOB (job));
-}
-
-static gboolean
-try_mount (GVfsBackend *backend,
- GVfsJobMount *job,
- GMountSpec *mount_spec,
- GMountSource *mount_source,
- gboolean is_automount)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
- const char *server;
- const char *user, *domain;
-
- if (strcmp (g_mount_spec_get_type (mount_spec), "smb-network") == 0)
- server = NULL;
- else
- {
- server = g_mount_spec_get (mount_spec, "server");
- if (server == NULL)
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
- "No server specified for smb-server share");
- return TRUE;
- }
- }
-
- user = g_mount_spec_get (mount_spec, "user");
- domain = g_mount_spec_get (mount_spec, "domain");
-
- if (is_automount &&
- ((user != NULL) || (domain != NULL)))
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
- "Can't automount smb browsing with specified user or domain");
- return TRUE;
- }
-
- op_backend->user = g_strdup (user);
- op_backend->domain = g_strdup (domain);
- op_backend->mounted_server = g_strdup (server);
-
- return FALSE;
-}
-
-static void
-run_mount_mountable (GVfsBackendSmbBrowse *backend,
- GVfsJobMountMountable *job,
- const char *filename,
- GMountSource *mount_source)
-{
- BrowseEntry *entry;
- GError *error = NULL;
- GMountSpec *mount_spec;
-
- g_mutex_lock (backend->entries_lock);
-
- entry = find_entry_unlocked (backend, filename);
-
- if (entry)
- {
- if (backend->server != NULL &&
- entry->smbc_type == SMBC_FILE_SHARE)
- {
- mount_spec = get_mount_spec_for_share (backend->server, entry->name);
- g_vfs_job_mount_mountable_set_target (job, mount_spec, "/", TRUE);
- g_mount_spec_unref (mount_spec);
- }
- else
- g_set_error_literal (&error,
- G_IO_ERROR, G_IO_ERROR_NOT_MOUNTABLE_FILE,
- _("The file is not a mountable"));
- }
- else
- g_set_error_literal (&error,
- G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("File doesn't exist"));
-
- g_mutex_unlock (backend->entries_lock);
-
- if (error)
- {
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
- }
- else
- g_vfs_job_succeeded (G_VFS_JOB (job));
-}
-
-static void
-do_mount_mountable (GVfsBackend *backend,
- GVfsJobMountMountable *job,
- const char *filename,
- GMountSource *mount_source)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
-
- update_cache (op_backend);
-
- run_mount_mountable (op_backend,
- job,
- filename,
- mount_source);
-}
-
-static gboolean
-try_mount_mountable (GVfsBackend *backend,
- GVfsJobMountMountable *job,
- const char *filename,
- GMountSource *mount_source)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
-
- if (is_root (filename))
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_NOT_MOUNTABLE_FILE,
- _("The file is not a mountable"));
- return TRUE;
- }
-
- if (cache_needs_updating (op_backend))
- return FALSE;
-
- run_mount_mountable (op_backend,
- job,
- filename,
- mount_source);
- return TRUE;
-}
-
-static void
-run_open_for_read (GVfsBackendSmbBrowse *backend,
- GVfsJobOpenForRead *job,
- const char *filename)
-{
- if (has_name (backend, filename))
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
- _("Not a regular file"));
- else
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("File doesn't exist"));
-}
-
-static void
-do_open_for_read (GVfsBackend *backend,
- GVfsJobOpenForRead *job,
- const char *filename)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
-
- update_cache (op_backend);
-
- run_open_for_read (op_backend, job, filename);
-}
-
-static gboolean
-try_open_for_read (GVfsBackend *backend,
- GVfsJobOpenForRead *job,
- const char *filename)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
-
- if (cache_needs_updating (op_backend))
- return FALSE;
-
- run_open_for_read (op_backend, job, filename);
-
- return TRUE;
-}
-
-static gboolean
-try_read (GVfsBackend *backend,
- GVfsJobRead *job,
- GVfsBackendHandle handle,
- char *buffer,
- gsize bytes_requested)
-{
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
- "Invalid argument");
-
- return TRUE;
-}
-
-static gboolean
-try_seek_on_read (GVfsBackend *backend,
- GVfsJobSeekRead *job,
- GVfsBackendHandle handle,
- goffset offset,
- GSeekType type)
-{
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
- "Invalid argument");
- return TRUE;
-}
-
-static gboolean
-try_close_read (GVfsBackend *backend,
- GVfsJobCloseRead *job,
- GVfsBackendHandle handle)
-{
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
- "Invalid argument");
- return TRUE;
-}
-
-static void
-get_file_info_from_entry (GVfsBackendSmbBrowse *backend, BrowseEntry *entry, GFileInfo *info)
-{
- GMountSpec *mount_spec;
- GString *uri;
- GIcon *icon;
-
- g_file_info_set_name (info, entry->name);
- g_file_info_set_display_name (info, entry->name_utf8);
- g_file_info_set_edit_name (info, entry->name_utf8);
- g_file_info_set_attribute_string (info, "smb::comment", entry->comment);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VIRTUAL, TRUE);
-
- icon = NULL;
- if (entry->smbc_type == SMBC_WORKGROUP)
- icon = g_themed_icon_new ("network-workgroup");
- else if (entry->smbc_type == SMBC_SERVER)
- icon = g_themed_icon_new ("network-server");
- else
- icon = g_themed_icon_new ("folder-remote");
-
- if (icon)
- {
- g_file_info_set_icon (info, icon);
- g_object_unref (icon);
- }
-
- mount_spec = NULL;
- if (backend->server)
- {
- /* browsing server/workgroup */
- if (entry->smbc_type == SMBC_WORKGROUP ||
- entry->smbc_type == SMBC_SERVER)
- {
- uri = g_string_new ("smb://");
- g_string_append_encoded (uri, entry->name, NULL, NULL);
- g_string_append_c (uri, '/');
- }
- else
- {
- mount_spec = get_mount_spec_for_share (backend->server, entry->name);
-
- uri = g_string_new ("smb://");
- g_string_append_encoded (uri, backend->server, NULL, NULL);
- g_string_append_c (uri, '/');
- g_string_append_encoded (uri, entry->name, NULL, NULL);
- }
- }
- else
- {
- /* browsing network */
- uri = g_string_new ("smb://");
- g_string_append_encoded (uri, entry->name, NULL, NULL);
- g_string_append_c (uri, '/');
-
- /* these are auto-mounted, so no CAN_MOUNT/UNMOUNT */
- }
-
- if (mount_spec)
- {
- g_file_info_set_file_type (info, G_FILE_TYPE_MOUNTABLE);
- if (g_mount_tracker_has_mount_spec (mount_tracker, mount_spec))
- {
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT, FALSE);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT, TRUE);
- }
- else
- {
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT, TRUE);
- g_file_info_set_attribute_boolean(info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT, FALSE);
- }
- g_mount_spec_unref (mount_spec);
- }
- else
- g_file_info_set_file_type (info, G_FILE_TYPE_SHORTCUT);
-
- g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, uri->str);
- g_string_free (uri, TRUE);
-}
-
-static void
-run_query_info (GVfsBackendSmbBrowse *backend,
- GVfsJobQueryInfo *job,
- const char *filename,
- GFileInfo *info,
- GFileAttributeMatcher *matcher)
-{
- BrowseEntry *entry;
-
- g_mutex_lock (backend->entries_lock);
-
- entry = find_entry_unlocked (backend, filename);
-
- if (entry)
- get_file_info_from_entry (backend, entry, info);
-
- g_mutex_unlock (backend->entries_lock);
-
- if (entry)
- g_vfs_job_succeeded (G_VFS_JOB (job));
- else
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("File doesn't exist"));
-}
-
-static void
-do_query_info (GVfsBackend *backend,
- GVfsJobQueryInfo *job,
- const char *filename,
- GFileQueryInfoFlags flags,
- GFileInfo *info,
- GFileAttributeMatcher *matcher)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
-
- update_cache (op_backend);
-
- run_query_info (op_backend, job, filename, info, matcher);
-}
-
-
-static gboolean
-try_query_info (GVfsBackend *backend,
- GVfsJobQueryInfo *job,
- const char *filename,
- GFileQueryInfoFlags flags,
- GFileInfo *info,
- GFileAttributeMatcher *matcher)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
- const char *icon_name;
- GIcon *icon;
-
- if (is_root (filename))
- {
- g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
- g_file_info_set_name (info, "/");
- g_file_info_set_display_name (info, g_vfs_backend_get_display_name (backend));
- icon_name = g_vfs_backend_get_icon_name (backend);
- if (icon_name)
- {
- icon = g_themed_icon_new (icon_name);
- g_file_info_set_icon (info, icon);
- g_object_unref (icon);
- }
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- return TRUE;
- }
-
- if (cache_needs_updating (op_backend))
- return FALSE;
-
- run_query_info (op_backend, job, filename, info, matcher);
-
- return TRUE;
-}
-
-static void
-run_enumerate (GVfsBackendSmbBrowse *backend,
- GVfsJobEnumerate *job,
- const char *filename,
- GFileAttributeMatcher *matcher)
-{
- GList *files, *l;
- GFileInfo *info;
-
- if (!is_root (filename))
- {
- if (has_name (backend, filename))
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
- _("Not a directory"));
- else
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- _("File doesn't exist"));
- return;
- }
-
- /* TODO: limit requested to what we support */
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- files = NULL;
- g_mutex_lock (backend->entries_lock);
- for (l = backend->entries; l != NULL; l = l->next)
- {
- BrowseEntry *entry = l->data;
-
- info = g_file_info_new ();
- get_file_info_from_entry (backend, entry, info);
-
- files = g_list_prepend (files, info);
- }
- g_mutex_unlock (backend->entries_lock);
-
- files = g_list_reverse (files);
-
- g_vfs_job_enumerate_add_infos (job, files);
- g_list_foreach (files, (GFunc)g_object_unref, NULL);
- g_list_free (files);
-
- g_vfs_job_enumerate_done (job);
-}
-
-static void
-do_enumerate (GVfsBackend *backend,
- GVfsJobEnumerate *job,
- const char *filename,
- GFileAttributeMatcher *matcher,
- GFileQueryInfoFlags flags)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
-
- update_cache (op_backend);
-
- run_enumerate (op_backend, job, filename, matcher);
-}
-
-static gboolean
-try_enumerate (GVfsBackend *backend,
- GVfsJobEnumerate *job,
- const char *filename,
- GFileAttributeMatcher *matcher,
- GFileQueryInfoFlags flags)
-{
- GVfsBackendSmbBrowse *op_backend = G_VFS_BACKEND_SMB_BROWSE (backend);
-
- if (cache_needs_updating (op_backend))
- return FALSE;
-
- run_enumerate (op_backend, job, filename, matcher);
-
- return TRUE;
-}
-
-static void
-g_vfs_backend_smb_browse_class_init (GVfsBackendSmbBrowseClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
-#ifdef HAVE_GCONF
- GConfClient *gclient;
-#endif
-
- gobject_class->finalize = g_vfs_backend_smb_browse_finalize;
-
- backend_class->mount = do_mount;
- backend_class->try_mount = try_mount;
- backend_class->mount_mountable = do_mount_mountable;
- backend_class->try_mount_mountable = try_mount_mountable;
- backend_class->open_for_read = do_open_for_read;
- backend_class->try_open_for_read = try_open_for_read;
- backend_class->try_read = try_read;
- backend_class->try_seek_on_read = try_seek_on_read;
- backend_class->try_close_read = try_close_read;
- backend_class->query_info = do_query_info;
- backend_class->try_query_info = try_query_info;
- backend_class->enumerate = do_enumerate;
- backend_class->try_enumerate = try_enumerate;
-
-#ifdef HAVE_GCONF
- gclient = gconf_client_get_default ();
- if (gclient)
- {
- char *workgroup;
-
- workgroup = gconf_client_get_string (gclient,
- PATH_GCONF_GNOME_VFS_SMB_WORKGROUP, NULL);
-
- if (workgroup && workgroup[0])
- default_workgroup = workgroup;
- else
- g_free (workgroup);
-
- g_object_unref (gclient);
- }
-#endif
-
-}
-
-void
-g_vfs_smb_browse_daemon_init (void)
-{
- g_set_application_name (_("Windows Network Filesystem Service"));
-}