summaryrefslogtreecommitdiff
path: root/gnome-2-24/daemon/gvfsbackendsmb.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnome-2-24/daemon/gvfsbackendsmb.c')
-rw-r--r--gnome-2-24/daemon/gvfsbackendsmb.c1947
1 files changed, 0 insertions, 1947 deletions
diff --git a/gnome-2-24/daemon/gvfsbackendsmb.c b/gnome-2-24/daemon/gvfsbackendsmb.c
deleted file mode 100644
index 63961b14..00000000
--- a/gnome-2-24/daemon/gvfsbackendsmb.c
+++ /dev/null
@@ -1,1947 +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 <stdlib.h>
-
-#include <glib/gstdio.h>
-#include <glib/gi18n.h>
-#include <gio/gio.h>
-
-#include "gvfsbackendsmb.h"
-#include "gvfsjobopenforread.h"
-#include "gvfsjobread.h"
-#include "gvfsjobseekread.h"
-#include "gvfsjobopenforwrite.h"
-#include "gvfsjobwrite.h"
-#include "gvfsjobclosewrite.h"
-#include "gvfsjobseekwrite.h"
-#include "gvfsjobsetdisplayname.h"
-#include "gvfsjobqueryinfo.h"
-#include "gvfsjobqueryfsinfo.h"
-#include "gvfsjobqueryattributes.h"
-#include "gvfsjobenumerate.h"
-#include "gvfsdaemonprotocol.h"
-#include "gvfskeyring.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"
-
-#include <libsmbclient.h>
-#include "libsmb-compat.h"
-
-struct _GVfsBackendSmb
-{
- GVfsBackend parent_instance;
-
- char *server;
- char *share;
- char *user;
- char *domain;
-
- SMBCCTX *smb_context;
-
- char *last_user;
- char *last_domain;
- char *last_password;
-
- GMountSource *mount_source; /* Only used/set during mount */
- int mount_try;
- gboolean mount_try_again;
-
- gboolean password_in_keyring;
- GPasswordSave password_save;
-
- /* Cache */
- char *cached_server_name;
- char *cached_share_name;
- char *cached_domain;
- char *cached_username;
- SMBCSRV *cached_server;
-};
-
-static char *default_workgroup = NULL;
-
-G_DEFINE_TYPE (GVfsBackendSmb, g_vfs_backend_smb, G_VFS_TYPE_BACKEND)
-
-static void
-g_vfs_backend_smb_finalize (GObject *object)
-{
- GVfsBackendSmb *backend;
-
- backend = G_VFS_BACKEND_SMB (object);
-
- g_free (backend->share);
- g_free (backend->server);
- g_free (backend->user);
- g_free (backend->domain);
-
- 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 (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)
-{
- GVfsBackendSmb *backend;
- char *ask_password, *ask_user, *ask_domain;
- gboolean handled, abort;
-
- backend = smbc_getOptionUserData (context);
-
- strncpy (password_out, "", pwmaxlen);
-
- if (backend->domain)
- strncpy (domain_out, backend->domain, domainmaxlen);
- if (backend->user)
- strncpy (username_out, backend->user, unmaxlen);
-
- if (backend->mount_source == NULL)
- {
- /* Not during mount, use last password */
- if (backend->last_user)
- strncpy (username_out, backend->last_user, unmaxlen);
- if (backend->last_domain)
- strncpy (domain_out, backend->last_domain, domainmaxlen);
- if (backend->last_password)
- strncpy (password_out, backend->last_password, pwmaxlen);
-
- return;
- }
-
- if (backend->mount_try == 0 &&
- backend->user == NULL &&
- backend->domain == NULL)
- {
- /* Try again if kerberos login + anonymous fallback fails */
- backend->mount_try_again = TRUE;
- }
- else
- {
- gboolean in_keyring = FALSE;
-
- if (!backend->password_in_keyring)
- {
- in_keyring = g_vfs_keyring_lookup_password (backend->user,
- backend->server,
- backend->domain,
- "smb",
- NULL,
- NULL,
- 0,
- &ask_user,
- &ask_domain,
- &ask_password);
- backend->password_in_keyring = in_keyring;
- }
-
- if (!in_keyring)
- {
- GAskPasswordFlags flags = G_ASK_PASSWORD_NEED_PASSWORD;
- char *message;
-
- if (g_vfs_keyring_is_available ())
- flags |= G_ASK_PASSWORD_SAVING_SUPPORTED;
- if (backend->domain == NULL)
- flags |= G_ASK_PASSWORD_NEED_DOMAIN;
- if (backend->user == NULL)
- flags |= G_ASK_PASSWORD_NEED_USERNAME;
-
- /* translators: First %s is a share name, second is a server name */
- message = g_strdup_printf (_("Password required for share %s on %s"),
- share_name, server_name);
- handled = g_mount_source_ask_password (backend->mount_source,
- message,
- username_out,
- domain_out,
- flags,
- &abort,
- &ask_password,
- &ask_user,
- &ask_domain,
- NULL,
- &(backend->password_save));
- g_free (message);
- if (!handled)
- goto out;
-
- if (abort)
- {
- strncpy (username_out, "ABORT", unmaxlen);
- strncpy (password_out, "", pwmaxlen);
- goto out;
- }
- }
-
- /* Try again if this fails */
- backend->mount_try_again = TRUE;
-
- strncpy (password_out, ask_password, pwmaxlen);
- if (ask_user && *ask_user)
- strncpy (username_out, ask_user, unmaxlen);
- if (ask_domain && *ask_domain)
- strncpy (domain_out, ask_domain, domainmaxlen);
-
- out:
- g_free (ask_password);
- g_free (ask_user);
- g_free (ask_domain);
- }
-
- backend->last_user = g_strdup (username_out);
- backend->last_domain = g_strdup (domain_out);
- backend->last_password = g_strdup (password_out);
-}
-
-/* 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)
-{
- GVfsBackendSmb *backend;
-
- backend = smbc_getOptionUserData (context);
-
- if (backend->cached_server != NULL)
- return 1;
-
- backend->cached_server_name = g_strdup (server_name);
- backend->cached_share_name = g_strdup (share_name);
- backend->cached_domain = g_strdup (domain);
- backend->cached_username = g_strdup (username);
- backend->cached_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)
-{
- GVfsBackendSmb *backend;
-
- backend = smbc_getOptionUserData (context);
-
- if (backend->cached_server == server)
- {
- g_free (backend->cached_server_name);
- backend->cached_server_name = NULL;
- g_free (backend->cached_share_name);
- backend->cached_share_name = NULL;
- g_free (backend->cached_domain);
- backend->cached_domain = NULL;
- g_free (backend->cached_username);
- backend->cached_username = NULL;
- backend->cached_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)
-{
- GVfsBackendSmb *backend;
-
- backend = smbc_getOptionUserData (context);
-
- if (backend->cached_server != NULL &&
- strcmp (backend->cached_server_name, server_name) == 0 &&
- strcmp (backend->cached_share_name, share_name) == 0 &&
- strcmp (backend->cached_domain, domain) == 0 &&
- strcmp (backend->cached_username, username) == 0)
- return backend->cached_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)
-{
- GVfsBackendSmb *backend;
-
- backend = smbc_getOptionUserData (context);
-
- if (backend->cached_server)
- remove_cached_server(context, backend->cached_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 GString *
-create_smb_uri_string (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 ":@/");
- }
-
- while (uri->len > 0 &&
- uri->str[uri->len - 1] == '/')
- g_string_erase (uri, uri->len - 1, 1);
-
- return uri;
-}
-
-static char *
-create_smb_uri (const char *server,
- const char *share,
- const char *path)
-{
- GString *uri;
- uri = create_smb_uri_string (server, share, path);
- return g_string_free (uri, FALSE);
-}
-
-static void
-do_mount (GVfsBackend *backend,
- GVfsJobMount *job,
- GMountSpec *mount_spec,
- GMountSource *mount_source,
- gboolean is_automount)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- SMBCCTX *smb_context;
- struct stat st;
- char *uri;
- int res;
- char *display_name;
- const char *debug;
- int debug_val;
- GMountSpec *smb_mount_spec;
- smbc_stat_fn smbc_stat;
-
- smb_context = smbc_new_context ();
- if (smb_context == NULL)
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Internal Error (%s)"), "Failed to allocate smb context");
- return;
- }
- smbc_setOptionUserData (smb_context, backend);
-
- debug = g_getenv ("GVFS_SMB_DEBUG");
- if (debug)
- debug_val = atoi (debug);
- else
- debug_val = 0;
-
- smbc_setDebug (smb_context, debug_val);
- 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
-
- /* Initial settings:
- * - use Kerberos (always)
- * - in case of no username specified, try anonymous login
- */
- smbc_setOptionUseKerberos (smb_context, 1);
- smbc_setOptionFallbackAfterKerberos (smb_context,
- op_backend->user != NULL);
- smbc_setOptionNoAutoAnonymousLogin (smb_context,
- op_backend->user != NULL);
-
-
-#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,
- _("Internal Error (%s)"), "Failed to initialize smb context");
- smbc_free_context (smb_context, FALSE);
- return;
- }
-
- op_backend->smb_context = smb_context;
-
- /* Set the mountspec according to original uri, no matter whether user changes
- credentials during mount loop. Nautilus and other gio clients depend
- on correct mountspec, setting it to real (different) credentials would
- lead to G_IO_ERROR_NOT_MOUNTED errors
- */
-
- /* Translators: This is "<sharename> on <servername>" and is used as name for an SMB share */
- display_name = g_strdup_printf (_("%s on %s"), op_backend->share, op_backend->server);
- g_vfs_backend_set_display_name (backend, display_name);
- g_free (display_name);
- g_vfs_backend_set_icon_name (backend, "folder-remote");
-
- smb_mount_spec = g_mount_spec_new ("smb-share");
- g_mount_spec_set (smb_mount_spec, "share", op_backend->share);
- g_mount_spec_set (smb_mount_spec, "server", op_backend->server);
- if (op_backend->user)
- g_mount_spec_set (smb_mount_spec, "user", op_backend->user);
- if (op_backend->domain)
- g_mount_spec_set (smb_mount_spec, "domain", op_backend->domain);
-
- g_vfs_backend_set_mount_spec (backend, smb_mount_spec);
- g_mount_spec_unref (smb_mount_spec);
-
- uri = create_smb_uri (op_backend->server, op_backend->share, NULL);
-
-
- /* Samba mount loop */
- op_backend->mount_source = mount_source;
- op_backend->mount_try = 0;
- op_backend->password_save = G_PASSWORD_SAVE_NEVER;
-
- do
- {
- op_backend->mount_try_again = FALSE;
-
- smbc_stat = smbc_getFunctionStat (smb_context);
- res = smbc_stat (smb_context, uri, &st);
-
- if (res == 0 ||
- (errno != EACCES && errno != EPERM))
- break;
-
- /* The first round is Kerberos-only. Only if this fails do we enable
- * NTLMSSP fallback (turning off anonymous fallback, which we've
- * already tried and failed with).
- */
- if (op_backend->mount_try == 0)
- {
- smbc_setOptionFallbackAfterKerberos (op_backend->smb_context, 1);
- smbc_setOptionNoAutoAnonymousLogin (op_backend->smb_context, 1);
- }
- op_backend->mount_try ++;
- }
- while (op_backend->mount_try_again);
-
- g_free (uri);
-
- op_backend->mount_source = NULL;
-
- if (res != 0)
- {
- /* TODO: Error from errno? */
- op_backend->mount_source = NULL;
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_FAILED,
- /* translators: We tried to mount a windows (samba) share, but failed */
- _("Failed to mount Windows share"));
- return;
- }
-
- /* Mount was successful */
-
- g_vfs_keyring_save_password (op_backend->last_user,
- op_backend->server,
- op_backend->last_domain,
- "smb",
- NULL,
- NULL,
- 0,
- op_backend->last_password,
- op_backend->password_save);
-
- 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)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- const char *server, *share, *user, *domain;
-
- server = g_mount_spec_get (mount_spec, "server");
- share = g_mount_spec_get (mount_spec, "share");
-
- if (server == NULL || share == NULL)
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
- _("Invalid mount spec"));
- return TRUE;
- }
-
- user = g_mount_spec_get (mount_spec, "user");
- domain = g_mount_spec_get (mount_spec, "domain");
-
- op_backend->server = g_strdup (server);
- op_backend->share = g_strdup (share);
- op_backend->user = g_strdup (user);
- op_backend->domain = g_strdup (domain);
-
- return FALSE;
-}
-
-static void
-do_open_for_read (GVfsBackend *backend,
- GVfsJobOpenForRead *job,
- const char *filename)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- char *uri;
- SMBCFILE *file;
- struct stat st;
- smbc_open_fn smbc_open;
- smbc_stat_fn smbc_stat;
- int res;
- int olderr;
-
-
- uri = create_smb_uri (op_backend->server, op_backend->share, filename);
- smbc_open = smbc_getFunctionOpen (op_backend->smb_context);
- file = smbc_open (op_backend->smb_context, uri, O_RDONLY, 0);
-
- if (file == NULL)
- {
- olderr = errno;
- smbc_stat = smbc_getFunctionStat (op_backend->smb_context);
- res = smbc_stat (op_backend->smb_context, uri, &st);
- g_free (uri);
- if ((res == 0) && (S_ISDIR (st.st_mode)))
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
- _("Can't open directory"));
- else
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), olderr);
- }
- else
- {
-
- g_vfs_job_open_for_read_set_can_seek (job, TRUE);
- g_vfs_job_open_for_read_set_handle (job, file);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
-}
-
-static void
-do_read (GVfsBackend *backend,
- GVfsJobRead *job,
- GVfsBackendHandle handle,
- char *buffer,
- gsize bytes_requested)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- ssize_t res;
- smbc_read_fn smbc_read;
-
- /* For some reason requests of 65536 bytes broke for me (returned 0)
- * Maybe some smb protocol limit
- */
- if (bytes_requested > 65535)
- bytes_requested = 65535;
-
- smbc_read = smbc_getFunctionRead (op_backend->smb_context);
- res = smbc_read (op_backend->smb_context, (SMBCFILE *)handle, buffer, bytes_requested);
-
- if (res == -1)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- else
- {
- g_vfs_job_read_set_size (job, res);
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- }
-}
-
-static void
-do_seek_on_read (GVfsBackend *backend,
- GVfsJobSeekRead *job,
- GVfsBackendHandle handle,
- goffset offset,
- GSeekType type)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- int whence;
- off_t res;
- smbc_lseek_fn smbc_lseek;
-
- switch (type)
- {
- case G_SEEK_SET:
- whence = SEEK_SET;
- break;
- case G_SEEK_CUR:
- whence = SEEK_CUR;
- break;
- case G_SEEK_END:
- whence = SEEK_END;
- break;
- default:
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("Unsupported seek type"));
- return;
- }
-
- smbc_lseek = smbc_getFunctionLseek (op_backend->smb_context);
- res = smbc_lseek (op_backend->smb_context, (SMBCFILE *)handle, offset, whence);
-
- if (res == (off_t)-1)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- else
- {
- g_vfs_job_seek_read_set_offset (job, res);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
-
- return;
-}
-
-static void
-do_close_read (GVfsBackend *backend,
- GVfsJobCloseRead *job,
- GVfsBackendHandle handle)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- ssize_t res;
- smbc_close_fn smbc_close;
-
- smbc_close = smbc_getFunctionClose (op_backend->smb_context);
- res = smbc_close (op_backend->smb_context, (SMBCFILE *)handle);
- if (res == -1)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- else
- g_vfs_job_succeeded (G_VFS_JOB (job));
-}
-
-typedef struct {
- SMBCFILE *file;
- char *uri;
- char *tmp_uri;
- char *backup_uri;
-} SmbWriteHandle;
-
-static void
-smb_write_handle_free (SmbWriteHandle *handle)
-{
- g_free (handle->uri);
- g_free (handle->tmp_uri);
- g_free (handle->backup_uri);
- g_free (handle);
-}
-
-static void
-do_create (GVfsBackend *backend,
- GVfsJobOpenForWrite *job,
- const char *filename,
- GFileCreateFlags flags)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- char *uri;
- SMBCFILE *file;
- SmbWriteHandle *handle;
- smbc_open_fn smbc_open;
-
- uri = create_smb_uri (op_backend->server, op_backend->share, filename);
- smbc_open = smbc_getFunctionOpen (op_backend->smb_context);
- file = smbc_open (op_backend->smb_context, uri,
- O_CREAT|O_WRONLY|O_EXCL, 0666);
- g_free (uri);
-
- if (file == NULL)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- else
- {
- handle = g_new0 (SmbWriteHandle, 1);
- handle->file = file;
-
- g_vfs_job_open_for_write_set_can_seek (job, TRUE);
- g_vfs_job_open_for_write_set_handle (job, handle);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
-}
-
-static void
-do_append_to (GVfsBackend *backend,
- GVfsJobOpenForWrite *job,
- const char *filename,
- GFileCreateFlags flags)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- char *uri;
- SMBCFILE *file;
- SmbWriteHandle *handle;
- off_t initial_offset;
- smbc_open_fn smbc_open;
- smbc_lseek_fn smbc_lseek;
-
- uri = create_smb_uri (op_backend->server, op_backend->share, filename);
- smbc_open = smbc_getFunctionOpen (op_backend->smb_context);
- file = smbc_open (op_backend->smb_context, uri,
- O_CREAT|O_WRONLY|O_APPEND, 0666);
- g_free (uri);
-
- if (file == NULL)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- else
- {
- handle = g_new0 (SmbWriteHandle, 1);
- handle->file = file;
-
- smbc_lseek = smbc_getFunctionLseek (op_backend->smb_context);
- initial_offset = smbc_lseek (op_backend->smb_context, file,
- 0, SEEK_CUR);
- if (initial_offset == (off_t) -1)
- g_vfs_job_open_for_write_set_can_seek (job, FALSE);
- else
- {
- g_vfs_job_open_for_write_set_initial_offset (job, initial_offset);
- g_vfs_job_open_for_write_set_can_seek (job, TRUE);
- }
- g_vfs_job_open_for_write_set_handle (job, handle);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
-}
-
-
-static void
-random_chars (char *str, int len)
-{
- int i;
- const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
- for (i = 0; i < len; i++)
- str[i] = chars[g_random_int_range (0, strlen(chars))];
-}
-
-static char *
-get_dir_from_uri (const char *uri)
-{
- const char *prefix_end;
-
- prefix_end = uri + strlen (uri);
-
- /* Skip slashes at end */
- while (prefix_end > uri &&
- *(prefix_end - 1) == '/')
- prefix_end--;
-
- /* Skip to next slash */
- while (prefix_end > uri &&
- *(prefix_end - 1) != '/')
- prefix_end--;
-
- return g_strndup (uri, prefix_end - uri);
-}
-
-static SMBCFILE *
-open_tmpfile (GVfsBackendSmb *backend,
- const char *uri,
- char **tmp_uri_out)
-{
- char *dir_uri, *tmp_uri;
- char filename[] = "~gvfXXXX.tmp";
- SMBCFILE *file;
- smbc_open_fn smbc_open;
-
- dir_uri = get_dir_from_uri (uri);
-
- do {
- random_chars (filename + 4, 4);
- tmp_uri = g_strconcat (dir_uri, filename, NULL);
-
- smbc_open = smbc_getFunctionOpen (backend->smb_context);
- file = smbc_open (backend->smb_context, tmp_uri,
- O_CREAT|O_WRONLY|O_EXCL, 0666);
- } while (file == NULL && errno == EEXIST);
-
- g_free (dir_uri);
-
- if (file)
- {
- *tmp_uri_out = tmp_uri;
- return file;
- }
- else
- {
- g_free (tmp_uri);
- return NULL;
- }
-}
-
-static gboolean
-copy_file (GVfsBackendSmb *backend,
- GVfsJob *job,
- const char *from_uri,
- const char *to_uri)
-{
- SMBCFILE *from_file, *to_file;
- char buffer[4096];
- size_t buffer_size;
- ssize_t res;
- char *p;
- gboolean succeeded;
- smbc_open_fn smbc_open;
- smbc_read_fn smbc_read;
- smbc_write_fn smbc_write;
- smbc_close_fn smbc_close;
-
-
- from_file = NULL;
- to_file = NULL;
-
- succeeded = FALSE;
-
- smbc_open = smbc_getFunctionOpen (backend->smb_context);
- smbc_read = smbc_getFunctionRead (backend->smb_context);
- smbc_write = smbc_getFunctionWrite (backend->smb_context);
- smbc_close = smbc_getFunctionClose (backend->smb_context);
-
- from_file = smbc_open (backend->smb_context, from_uri,
- O_RDONLY, 0666);
- if (from_file == NULL || g_vfs_job_is_cancelled (job))
- goto out;
-
- to_file = smbc_open (backend->smb_context, to_uri,
- O_CREAT|O_WRONLY|O_TRUNC, 0666);
-
- if (from_file == NULL || g_vfs_job_is_cancelled (job))
- goto out;
-
- while (1)
- {
-
- res = smbc_read (backend->smb_context, from_file,
- buffer, sizeof(buffer));
- if (res < 0 || g_vfs_job_is_cancelled (job))
- goto out;
- if (res == 0)
- break; /* Succeeded */
-
- buffer_size = res;
- p = buffer;
- while (buffer_size > 0)
- {
- res = smbc_write (backend->smb_context, to_file,
- p, buffer_size);
- if (res < 0 || g_vfs_job_is_cancelled (job))
- goto out;
- buffer_size -= res;
- p += res;
- }
- }
- succeeded = TRUE;
-
- out:
- if (to_file)
- smbc_close (backend->smb_context, to_file);
- if (from_file)
- smbc_close (backend->smb_context, from_file);
- return succeeded;
-}
-
-static char *
-create_etag (struct stat *statbuf)
-{
- return g_strdup_printf ("%lu", (long unsigned int)statbuf->st_mtime);
-}
-
-static void
-do_replace (GVfsBackend *backend,
- GVfsJobOpenForWrite *job,
- const char *filename,
- const char *etag,
- gboolean make_backup,
- GFileCreateFlags flags)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- struct stat original_stat;
- int res;
- char *uri, *tmp_uri, *backup_uri, *current_etag;
- SMBCFILE *file;
- GError *error = NULL;
- SmbWriteHandle *handle;
- smbc_open_fn smbc_open;
- smbc_stat_fn smbc_stat;
-
- uri = create_smb_uri (op_backend->server, op_backend->share, filename);
- tmp_uri = NULL;
- if (make_backup)
- backup_uri = g_strconcat (uri, "~", NULL);
- else
- backup_uri = NULL;
-
- smbc_open = smbc_getFunctionOpen (op_backend->smb_context);
- smbc_stat = smbc_getFunctionStat (op_backend->smb_context);
-
- file = smbc_open (op_backend->smb_context, uri,
- O_CREAT|O_WRONLY|O_EXCL, 0);
- if (file == NULL && errno != EEXIST)
- {
- int errsv = errno;
-
- g_set_error_literal (&error, G_IO_ERROR,
- g_io_error_from_errno (errsv),
- g_strerror (errsv));
- goto error;
- }
- else if (file == NULL && errno == EEXIST)
- {
- if (etag != NULL)
- {
- res = smbc_stat (op_backend->smb_context, uri, &original_stat);
-
- if (res == 0)
- {
- current_etag = create_etag (&original_stat);
- if (strcmp (etag, current_etag) != 0)
- {
- g_free (current_etag);
- g_set_error_literal (&error,
- G_IO_ERROR,
- G_IO_ERROR_WRONG_ETAG,
- _("The file was externally modified"));
- goto error;
- }
- g_free (current_etag);
- }
- }
-
- /* Backup strategy:
- *
- * By default we:
- * 1) save to a tmp file (that doesn't exist already)
- * 2) rename orig file to backup file
- * (or delete it if no backup)
- * 3) rename tmp file to orig file
- *
- * However, this can fail if we can't write to the directory.
- * In that case we just truncate the file, after having
- * copied directly to the backup filename.
- */
-
- file = open_tmpfile (op_backend, uri, &tmp_uri);
- if (file == NULL)
- {
- if (make_backup)
- {
- if (!copy_file (op_backend, G_VFS_JOB (job), uri, backup_uri))
- {
- if (g_vfs_job_is_cancelled (G_VFS_JOB (job)))
- g_set_error_literal (&error,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- _("Operation was cancelled"));
- else
- g_set_error_literal (&error,
- G_IO_ERROR,
- G_IO_ERROR_CANT_CREATE_BACKUP,
- _("Backup file creation failed"));
- goto error;
- }
- g_free (backup_uri);
- backup_uri = NULL;
- }
-
- file = smbc_open (op_backend->smb_context, uri,
- O_CREAT|O_WRONLY|O_TRUNC, 0);
- if (file == NULL)
- {
- int errsv = errno;
-
- g_set_error_literal (&error, G_IO_ERROR,
- g_io_error_from_errno (errsv),
- g_strerror (errsv));
- goto error;
- }
- }
- }
- else
- {
- /* Doesn't exist. Just write away */
- g_free (backup_uri);
- backup_uri = NULL;
- }
-
- handle = g_new (SmbWriteHandle, 1);
- handle->file = file;
- handle->uri = uri;
- handle->tmp_uri = tmp_uri;
- handle->backup_uri = backup_uri;
-
- g_vfs_job_open_for_write_set_can_seek (job, TRUE);
- g_vfs_job_open_for_write_set_handle (job, handle);
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- return;
-
- error:
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
- g_free (backup_uri);
- g_free (tmp_uri);
- g_free (uri);
-}
-
-
-static void
-do_write (GVfsBackend *backend,
- GVfsJobWrite *job,
- GVfsBackendHandle _handle,
- char *buffer,
- gsize buffer_size)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- SmbWriteHandle *handle = _handle;
- ssize_t res;
- smbc_write_fn smbc_write;
-
- smbc_write = smbc_getFunctionWrite (op_backend->smb_context);
- res = smbc_write (op_backend->smb_context, handle->file,
- buffer, buffer_size);
- if (res == -1)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- else
- {
- g_vfs_job_write_set_written_size (job, res);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
-}
-
-static void
-do_seek_on_write (GVfsBackend *backend,
- GVfsJobSeekWrite *job,
- GVfsBackendHandle _handle,
- goffset offset,
- GSeekType type)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- SmbWriteHandle *handle = _handle;
- int whence;
- off_t res;
- smbc_lseek_fn smbc_lseek;
-
- switch (type)
- {
- case G_SEEK_SET:
- whence = SEEK_SET;
- break;
- case G_SEEK_CUR:
- whence = SEEK_CUR;
- break;
- case G_SEEK_END:
- whence = SEEK_END;
- break;
- default:
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("Unsupported seek type"));
- return;
- }
-
- smbc_lseek = smbc_getFunctionLseek (op_backend->smb_context);
- res = smbc_lseek (op_backend->smb_context, handle->file, offset, whence);
-
- if (res == (off_t)-1)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- else
- {
- g_vfs_job_seek_write_set_offset (job, res);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
-
- return;
-}
-
-static void
-do_close_write (GVfsBackend *backend,
- GVfsJobCloseWrite *job,
- GVfsBackendHandle _handle)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- SmbWriteHandle *handle = _handle;
- struct stat stat_at_close;
- int stat_res;
- ssize_t res;
- smbc_fstat_fn smbc_fstat;
- smbc_close_fn smbc_close;
- smbc_unlink_fn smbc_unlink;
- smbc_rename_fn smbc_rename;
-
- smbc_fstat = smbc_getFunctionFstat (op_backend->smb_context);
- smbc_close = smbc_getFunctionClose (op_backend->smb_context);
- smbc_unlink = smbc_getFunctionUnlink (op_backend->smb_context);
- smbc_rename = smbc_getFunctionRename (op_backend->smb_context);
-
- stat_res = smbc_fstat (op_backend->smb_context, handle->file, &stat_at_close);
-
- res = smbc_close (op_backend->smb_context, handle->file);
-
- if (res == -1)
- {
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
-
- if (handle->tmp_uri)
- smbc_unlink (op_backend->smb_context, handle->tmp_uri);
- goto out;
- }
-
- if (handle->tmp_uri)
- {
- if (handle->backup_uri)
- {
- res = smbc_rename (op_backend->smb_context, handle->uri,
- op_backend->smb_context, handle->backup_uri);
- if (res == -1)
- {
- int errsv = errno;
-
- smbc_unlink (op_backend->smb_context, handle->tmp_uri);
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
- _("Backup file creation failed: %s"), g_strerror (errsv));
- goto out;
- }
- }
- else
- smbc_unlink (op_backend->smb_context, handle->uri);
-
- res = smbc_rename (op_backend->smb_context, handle->tmp_uri,
- op_backend->smb_context, handle->uri);
- if (res == -1)
- {
- smbc_unlink (op_backend->smb_context, handle->tmp_uri);
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- goto out;
- }
- }
-
- if (stat_res == 0)
- {
- char *etag;
- etag = create_etag (&stat_at_close);
- g_vfs_job_close_write_set_etag (job, etag);
- g_free (etag);
- }
-
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- out:
- smb_write_handle_free (handle);
-}
-
-static void
-set_info_from_stat (GVfsBackendSmb *backend,
- GFileInfo *info,
- struct stat *statbuf,
- const char *basename,
- GFileAttributeMatcher *matcher)
-{
- GFileType file_type;
- GTimeVal t;
- GIcon *icon;
- char *content_type;
- char *display_name;
-
- if (basename)
- {
- g_file_info_set_name (info, basename);
- if (*basename == '.')
- g_file_info_set_is_hidden (info, TRUE);
- }
-
-
- if (basename != NULL &&
- g_file_attribute_matcher_matches (matcher,
- G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))
- {
- if (strcmp (basename, "/") == 0)
- display_name = g_strdup_printf (_("%s on %s"), backend->share, backend->server);
- else
- display_name = g_filename_display_name (basename);
-
- if (strstr (display_name, "\357\277\275") != NULL)
- {
- char *p = display_name;
- display_name = g_strconcat (display_name, _(" (invalid encoding)"), NULL);
- g_free (p);
- }
- g_file_info_set_display_name (info, display_name);
- g_free (display_name);
- }
-
- if (basename != NULL &&
- g_file_attribute_matcher_matches (matcher,
- G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME))
- {
- char *edit_name = g_filename_display_name (basename);
- g_file_info_set_edit_name (info, edit_name);
- g_free (edit_name);
- }
-
-
- file_type = G_FILE_TYPE_UNKNOWN;
-
- if (S_ISREG (statbuf->st_mode))
- file_type = G_FILE_TYPE_REGULAR;
- else if (S_ISDIR (statbuf->st_mode))
- file_type = G_FILE_TYPE_DIRECTORY;
- else if (S_ISCHR (statbuf->st_mode) ||
- S_ISBLK (statbuf->st_mode) ||
- S_ISFIFO (statbuf->st_mode)
-#ifdef S_ISSOCK
- || S_ISSOCK (statbuf->st_mode)
-#endif
- )
- file_type = G_FILE_TYPE_SPECIAL;
- else if (S_ISLNK (statbuf->st_mode))
- file_type = G_FILE_TYPE_SYMBOLIC_LINK;
-
- g_file_info_set_file_type (info, file_type);
- g_file_info_set_size (info, statbuf->st_size);
-
- t.tv_sec = statbuf->st_mtime;
-#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
- t.tv_usec = statbuf->st_mtimensec / 1000;
-#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
- t.tv_usec = statbuf->st_mtim.tv_nsec / 1000;
-#else
- t.tv_usec = 0;
-#endif
- g_file_info_set_modification_time (info, &t);
-
-
- if (g_file_attribute_matcher_matches (matcher,
- G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE) ||
- g_file_attribute_matcher_matches (matcher,
- G_FILE_ATTRIBUTE_STANDARD_ICON))
- {
- icon = NULL;
- if (S_ISDIR(statbuf->st_mode))
- {
- content_type = g_strdup ("inode/directory");
- if (strcmp (basename, "/") == 0)
- icon = g_themed_icon_new ("folder-remote");
- else
- icon = g_themed_icon_new ("folder");
- }
- else
- {
- content_type = g_content_type_guess (basename, NULL, 0, NULL);
-
- if (content_type)
- {
- icon = g_content_type_get_icon (content_type);
- if (G_IS_THEMED_ICON (icon))
- g_themed_icon_append_name (G_THEMED_ICON (icon), "text-x-generic");
- }
- }
-
- if (content_type)
- {
- g_file_info_set_content_type (info, content_type);
- g_free (content_type);
- }
-
- if (icon == NULL)
- icon = g_themed_icon_new ("text-x-generic");
-
- g_file_info_set_icon (info, icon);
- g_object_unref (icon);
- }
-
- /* Don't trust n_link, uid, gid, etc returned from libsmb, its just made up.
- These are ok though: */
-
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_DEVICE, statbuf->st_dev);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE, statbuf->st_ino);
-
- /* If file is dos-readonly, libsmbclient doesn't set S_IWUSR, we use this to
- trigger ACCESS_WRITE = FALSE: */
- if (!(statbuf->st_mode & S_IWUSR))
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
-
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS, statbuf->st_atime);
-#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, statbuf->st_atimensec / 1000);
-#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000);
-#endif
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED, statbuf->st_ctime);
-#if defined (HAVE_STRUCT_STAT_ST_CTIMENSEC)
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CHANGED_USEC, statbuf->st_ctimensec / 1000);
-#elif defined (HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC)
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CHANGED_USEC, statbuf->st_ctim.tv_nsec / 1000);
-#endif
-
- /* Libsmb sets the X bit on files to indicate some special things: */
- if ((statbuf->st_mode & S_IFDIR) == 0) {
-
- if (statbuf->st_mode & S_IXOTH)
- g_file_info_set_is_hidden (info, TRUE);
-
- if (statbuf->st_mode & S_IXUSR)
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_DOS_IS_ARCHIVE, TRUE);
-
- if (statbuf->st_mode & S_IXGRP)
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_DOS_IS_SYSTEM, TRUE);
- }
-
- if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_ETAG_VALUE))
- {
- char *etag = create_etag (statbuf);
- g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ETAG_VALUE, etag);
- g_free (etag);
- }
-}
-
-static void
-do_query_info (GVfsBackend *backend,
- GVfsJobQueryInfo *job,
- const char *filename,
- GFileQueryInfoFlags flags,
- GFileInfo *info,
- GFileAttributeMatcher *matcher)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- struct stat st = {0};
- char *uri;
- int res, saved_errno;
- char *basename;
- smbc_stat_fn smbc_stat;
-
- uri = create_smb_uri (op_backend->server, op_backend->share, filename);
- smbc_stat = smbc_getFunctionStat (op_backend->smb_context);
- res = smbc_stat (op_backend->smb_context, uri, &st);
- saved_errno = errno;
- g_free (uri);
-
- if (res == 0)
- {
- basename = g_path_get_basename (filename);
- set_info_from_stat (op_backend, info, &st, basename, matcher);
- g_free (basename);
-
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
- else
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), saved_errno);
-
-}
-
-static void
-do_query_fs_info (GVfsBackend *backend,
- GVfsJobQueryFsInfo *job,
- const char *filename,
- GFileInfo *info,
- GFileAttributeMatcher *attribute_matcher)
-{
- g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "cifs");
-
- g_vfs_job_succeeded (G_VFS_JOB (job));
-}
-
-
-static gboolean
-try_query_settable_attributes (GVfsBackend *backend,
- GVfsJobQueryAttributes *job,
- const char *filename)
-{
- GFileAttributeInfoList *list;
-
- list = g_file_attribute_info_list_new ();
-
- /* TODO: Add all settable attributes here */
- /*
- g_file_attribute_info_list_add (list,
- "smb:test",
- G_FILE_ATTRIBUTE_TYPE_UINT32);
- */
-
- g_vfs_job_query_attributes_set_list (job, list);
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- g_file_attribute_info_list_unref (list);
- return TRUE;
-}
-
-static void
-do_enumerate (GVfsBackend *backend,
- GVfsJobEnumerate *job,
- const char *filename,
- GFileAttributeMatcher *matcher,
- GFileQueryInfoFlags flags)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- struct stat st;
- int res;
- GError *error;
- SMBCFILE *dir;
- char dirents[1024*4];
- struct smbc_dirent *dirp;
- GList *files;
- GFileInfo *info;
- GString *uri;
- int uri_start_len;
- smbc_opendir_fn smbc_opendir;
- smbc_getdents_fn smbc_getdents;
- smbc_stat_fn smbc_stat;
- smbc_closedir_fn smbc_closedir;
-
- uri = create_smb_uri_string (op_backend->server, op_backend->share, filename);
-
- smbc_opendir = smbc_getFunctionOpendir (op_backend->smb_context);
- smbc_getdents = smbc_getFunctionGetdents (op_backend->smb_context);
- smbc_stat = smbc_getFunctionStat (op_backend->smb_context);
- smbc_closedir = smbc_getFunctionClosedir (op_backend->smb_context);
-
- dir = smbc_opendir (op_backend->smb_context, uri->str);
-
- if (dir == NULL)
- {
- int errsv = errno;
-
- error = NULL;
- g_set_error_literal (&error, G_IO_ERROR,
- g_io_error_from_errno (errsv),
- g_strerror (errsv));
- goto error;
- }
-
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- if (uri->str[uri->len - 1] != '/')
- g_string_append_c (uri, '/');
- uri_start_len = uri->len;
-
- while (TRUE)
- {
- files = NULL;
-
- res = smbc_getdents (op_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;
-
- /* TODO: Only do stat if required for flags */
-
- if ((dirp->smbc_type == SMBC_DIR ||
- dirp->smbc_type == SMBC_FILE ||
- dirp->smbc_type == SMBC_LINK) &&
- strcmp (dirp->name, ".") != 0 &&
- strcmp (dirp->name, "..") != 0)
- {
- int stat_res;
- g_string_truncate (uri, uri_start_len);
- g_string_append_encoded (uri,
- dirp->name,
- SUB_DELIM_CHARS ":@/");
-
- if (matcher == NULL ||
- g_file_attribute_matcher_matches_only (matcher, G_FILE_ATTRIBUTE_STANDARD_NAME))
- {
- info = g_file_info_new ();
- g_file_info_set_name (info, dirp->name);
- files = g_list_prepend (files, info);
- }
- else
- {
- stat_res = smbc_stat (op_backend->smb_context,
- uri->str, &st);
- if (stat_res == 0)
- {
- info = g_file_info_new ();
- set_info_from_stat (op_backend, info, &st, dirp->name, matcher);
- files = g_list_prepend (files, info);
- }
- }
- }
-
- dirlen = dirp->dirlen;
- dirp = (struct smbc_dirent *) (((char *)dirp) + dirlen);
- res -= dirlen;
- }
-
- if (files)
- {
- 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);
- }
- }
-
- res = smbc_closedir (op_backend->smb_context, dir);
-
- g_vfs_job_enumerate_done (job);
-
- g_string_free (uri, TRUE);
- return;
-
- error:
- g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
- g_error_free (error);
- g_string_free (uri, TRUE);
-}
-
-static void
-do_set_display_name (GVfsBackend *backend,
- GVfsJobSetDisplayName *job,
- const char *filename,
- const char *display_name)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- char *from_uri, *to_uri;
- char *dirname, *new_path;
- int res, errsv;
- smbc_rename_fn smbc_rename;
-
- dirname = g_path_get_dirname (filename);
-
- /* TODO: display name is in utf8, atm we assume libsmb uris
- are in utf8, but this might not be true if the user changed
- the smb.conf file. Can we check this and convert? */
-
- new_path = g_build_filename (dirname, display_name, NULL);
- g_free (dirname);
-
- from_uri = create_smb_uri (op_backend->server, op_backend->share, filename);
- to_uri = create_smb_uri (op_backend->server, op_backend->share, new_path);
-
- smbc_rename = smbc_getFunctionRename (op_backend->smb_context);
- res = smbc_rename (op_backend->smb_context, from_uri,
- op_backend->smb_context, to_uri);
- errsv = errno;
- g_free (from_uri);
- g_free (to_uri);
-
- if (res != 0)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
- else
- {
- g_vfs_job_set_display_name_set_new_path (job, new_path);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
- g_free (new_path);
-}
-
-static void
-do_delete (GVfsBackend *backend,
- GVfsJobDelete *job,
- const char *filename)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- struct stat statbuf;
- char *uri;
- int errsv, res;
- smbc_stat_fn smbc_stat;
- smbc_rmdir_fn smbc_rmdir;
- smbc_unlink_fn smbc_unlink;
-
-
- uri = create_smb_uri (op_backend->server, op_backend->share, filename);
-
- smbc_stat = smbc_getFunctionStat (op_backend->smb_context);
- smbc_rmdir = smbc_getFunctionRmdir (op_backend->smb_context);
- smbc_unlink = smbc_getFunctionUnlink (op_backend->smb_context);
-
- res = smbc_stat (op_backend->smb_context, uri, &statbuf);
- if (res == -1)
- {
- errsv = errno;
-
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,
- g_io_error_from_errno (errsv),
- _("Error deleting file: %s"),
- g_strerror (errsv));
- g_free (uri);
- return;
- }
-
- if (S_ISDIR (statbuf.st_mode))
- res = smbc_rmdir (op_backend->smb_context, uri);
- else
- res = smbc_unlink (op_backend->smb_context, uri);
- errsv = errno;
- g_free (uri);
-
- if (res != 0)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
- else
- g_vfs_job_succeeded (G_VFS_JOB (job));
-}
-
-static void
-do_make_directory (GVfsBackend *backend,
- GVfsJobMakeDirectory *job,
- const char *filename)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- char *uri;
- int errsv, res;
- smbc_mkdir_fn smbc_mkdir;
-
- uri = create_smb_uri (op_backend->server, op_backend->share, filename);
- smbc_mkdir = smbc_getFunctionMkdir (op_backend->smb_context);
- res = smbc_mkdir (op_backend->smb_context, uri, 0666);
- errsv = errno;
- g_free (uri);
-
- if (res != 0)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
- else
- g_vfs_job_succeeded (G_VFS_JOB (job));
-}
-
-static void
-do_move (GVfsBackend *backend,
- GVfsJobMove *job,
- const char *source,
- const char *destination,
- GFileCopyFlags flags,
- GFileProgressCallback progress_callback,
- gpointer progress_callback_data)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- char *source_uri, *dest_uri, *backup_uri;
- gboolean destination_exist, source_is_dir;
- struct stat statbuf;
- int res, errsv;
- smbc_stat_fn smbc_stat;
- smbc_rename_fn smbc_rename;
- smbc_unlink_fn smbc_unlink;
-
-
- source_uri = create_smb_uri (op_backend->server, op_backend->share, source);
-
- smbc_stat = smbc_getFunctionStat (op_backend->smb_context);
- smbc_rename = smbc_getFunctionRename (op_backend->smb_context);
- smbc_unlink = smbc_getFunctionUnlink (op_backend->smb_context);
-
- res = smbc_stat (op_backend->smb_context, source_uri, &statbuf);
- if (res == -1)
- {
- errsv = errno;
-
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,
- g_io_error_from_errno (errsv),
- _("Error moving file: %s"),
- g_strerror (errsv));
- g_free (source_uri);
- return;
- }
- else
- source_is_dir = S_ISDIR (statbuf.st_mode);
-
- dest_uri = create_smb_uri (op_backend->server, op_backend->share, destination);
-
- destination_exist = FALSE;
- res = smbc_stat (op_backend->smb_context, dest_uri, &statbuf);
- if (res == 0)
- {
- destination_exist = TRUE; /* Target file exists */
-
- if (flags & G_FILE_COPY_OVERWRITE)
- {
- /* Always fail on dirs, even with overwrite */
- if (S_ISDIR (statbuf.st_mode))
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,
- G_IO_ERROR_WOULD_MERGE,
- _("Can't move directory over directory"));
- g_free (source_uri);
- g_free (dest_uri);
- return;
- }
- }
- else
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,
- G_IO_ERROR_EXISTS,
- _("Target file already exists"));
- g_free (source_uri);
- g_free (dest_uri);
- return;
- }
- }
-
- if (flags & G_FILE_COPY_BACKUP && destination_exist)
- {
- backup_uri = g_strconcat (dest_uri, "~", NULL);
- res = smbc_rename (op_backend->smb_context, dest_uri,
- op_backend->smb_context, backup_uri);
- if (res == -1)
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,
- G_IO_ERROR_CANT_CREATE_BACKUP,
- _("Backup file creation failed"));
- g_free (source_uri);
- g_free (dest_uri);
- g_free (backup_uri);
- return;
- }
- g_free (backup_uri);
- destination_exist = FALSE; /* It did, but no more */
- }
-
- if (source_is_dir && destination_exist && (flags & G_FILE_COPY_OVERWRITE))
- {
- /* Source is a dir, destination exists (and is not a dir, because that would have failed
- earlier), and we're overwriting. Manually remove the target so we can do the rename. */
- res = smbc_unlink (op_backend->smb_context, dest_uri);
- errsv = errno;
- if (res == -1)
- {
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
- g_io_error_from_errno (errsv),
- _("Error removing target file: %s"),
- g_strerror (errsv));
- g_free (source_uri);
- g_free (dest_uri);
- return;
- }
- }
-
-
- res = smbc_rename (op_backend->smb_context, source_uri,
- op_backend->smb_context, dest_uri);
- errsv = errno;
- g_free (source_uri);
- g_free (dest_uri);
-
- /* Catch moves across device boundaries */
- if (res != 0)
- {
- if (errsv == EXDEV ||
- /* Unfortunately libsmbclient doesn't correctly return EXDEV, but falls back
- to EINVAL, so we try to guess when this happens: */
- (errsv == EINVAL && source_is_dir))
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
- _("Can't recursively move directory"));
- else
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
- }
- else
- g_vfs_job_succeeded (G_VFS_JOB (job));
-}
-
-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);
-#ifdef HAVE_GCONF
- GConfClient *gclient;
-#endif
-
- gobject_class->finalize = g_vfs_backend_smb_finalize;
-
- backend_class->mount = do_mount;
- backend_class->try_mount = try_mount;
- 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->create = do_create;
- backend_class->append_to = do_append_to;
- backend_class->replace = do_replace;
- backend_class->write = do_write;
- backend_class->seek_on_write = do_seek_on_write;
- backend_class->close_write = do_close_write;
- backend_class->query_info = do_query_info;
- backend_class->query_fs_info = do_query_fs_info;
- backend_class->enumerate = do_enumerate;
- backend_class->set_display_name = do_set_display_name;
- backend_class->delete = do_delete;
- backend_class->make_directory = do_make_directory;
- backend_class->move = do_move;
- backend_class->try_query_settable_attributes = try_query_settable_attributes;
-
-#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_daemon_init (void)
-{
- g_set_application_name (_("Windows Shares Filesystem Service"));
-}