File gnome-vfs2-net-usershare.diff of Package gnome-vfs2
Index: modules/Makefile.am
================================================================================
--- modules/Makefile.am
+++ modules/Makefile.am
@@ -140,7 +140,7 @@
### `network' method
-libnetwork_la_SOURCES = network-method.c
+libnetwork_la_SOURCES = network-method.c shares.c shares.h
libnetwork_la_LDFLAGS = $(module_flags)
libnetwork_la_LIBADD = $(MODULES_FILE_LIBS) ../libgnomevfs/libgnomevfs-2.la
--- modules/network-method.c
+++ modules/network-method.c
@@ -40,6 +40,8 @@
#include <glib/gi18n-lib.h>
+#include "shares.h"
+
#define PATH_GCONF_GNOME_VFS_SMB "/system/smb"
#define PATH_GCONF_GNOME_VFS_SMB_WORKGROUP "/system/smb/workgroup"
#define PATH_GCONF_GNOME_VFS_DNS_SD "/system/dns_sd"
@@ -52,6 +54,7 @@
char *icon;
char *target_uri;
char *filename;
+ char *desktop_item_type;
} NetworkLink;
typedef struct {
@@ -84,6 +87,7 @@
static GList *current_dns_sd_domains = NULL;
+static GSList *current_shares = NULL;
static GList *active_links;
static GList *active_redirects;
@@ -152,26 +156,6 @@
return NETWORK_LOCAL_DISABLED;
}
-static char *
-get_data_for_link (const char *uri,
- const char *display_name,
- const char *icon)
-{
- char *data;
-
- data = g_strdup_printf ("[Desktop Entry]\n"
- "Encoding=UTF-8\n"
- "Name=%s\n"
- "Type=FSDevice\n"
- "Icon=%s\n"
- "URL=%s\n",
- display_name,
- icon,
- uri);
- return data;
-}
-
-
/* Called with lock held */
static void
do_link_event (const char *filename,
@@ -227,6 +211,7 @@
g_free (found->target_uri);
g_free (found->display_name);
g_free (found->icon);
+ g_free (found->desktop_item_type);
g_free (found);
}
}
@@ -236,7 +221,8 @@
add_link (const char *filename,
const char *target_uri,
const char *display_name,
- const char *icon)
+ const char *icon,
+ const char *desktop_item_type)
{
NetworkLink *link;
@@ -245,6 +231,7 @@
link->target_uri = g_strdup (target_uri);
link->display_name = g_strdup (display_name);
link->icon = g_strdup (icon);
+ link->desktop_item_type = g_strdup (desktop_item_type);
active_links = g_list_prepend (active_links, link);
do_link_event (filename,
@@ -265,7 +252,8 @@
add_link (filename,
link_uri,
domain,
- "gnome-fs-network");
+ "gnome-fs-network",
+ "FSDevice");
g_free (filename);
g_free (link_uri);
}
@@ -355,9 +343,20 @@
static char *
network_link_create_data (NetworkLink *link)
{
- return get_data_for_link (link->target_uri,
- link->display_name,
- link->icon);
+ char *data;
+
+ data = g_strdup_printf ("[Desktop Entry]\n"
+ "Encoding=UTF-8\n"
+ "Name=%s\n"
+ "Type=%s\n"
+ "Icon=%s\n"
+ "URL=%s\n",
+ link->display_name,
+ link->desktop_item_type,
+ link->icon,
+ link->target_uri);
+
+ return data;
}
/* Call with lock held */
@@ -754,6 +753,18 @@
dir_handle->filenames = g_list_prepend (dir_handle->filenames, g_strdup (filename));
}
+static char *
+build_fake_share_filename (ShareInfo *share_info)
+{
+ return g_strdup_printf ("share-%s", share_info->share_name);
+}
+
+static char *
+build_share_target_uri (ShareInfo *share_info)
+{
+ return gnome_vfs_get_uri_from_local_path (share_info->path);
+}
+
static GnomeVFSResult
do_open_directory (GnomeVFSMethod *method,
GnomeVFSMethodHandle **method_handle,
@@ -1262,6 +1273,104 @@
}
static void
+diff_sorted_slists (GSList *list1, GSList *list2, GCompareFunc compare,
+ GSList **added, GSList **removed)
+{
+ int order;
+
+ *added = *removed = NULL;
+
+ while (list1 != NULL &&
+ list2 != NULL) {
+ order = (*compare) (list1->data, list2->data);
+ if (order < 0) {
+ *removed = g_slist_prepend (*removed, list1->data);
+ list1 = list1->next;
+ } else if (order > 0) {
+ *added = g_slist_prepend (*added, list2->data);
+ list2 = list2->next;
+ } else { /* same item */
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+ }
+
+ while (list1 != NULL) {
+ *removed = g_slist_prepend (*removed, list1->data);
+ list1 = list1->next;
+ }
+ while (list2 != NULL) {
+ *added = g_slist_prepend (*added, list2->data);
+ list2 = list2->next;
+ }
+}
+
+static gint
+compare_share_info_name_cb (gconstpointer a, gconstpointer b)
+{
+ const ShareInfo *share_a, *share_b;
+
+ share_a = a;
+ share_b = b;
+
+ return g_utf8_collate (share_a->share_name, share_b->share_name);
+}
+
+/* Call with the lock held */
+static void
+refresh_shares_links (void)
+{
+ GSList *share_info_list;
+ GSList *l;
+ GSList *added;
+ GSList *removed;
+
+ G_LOCK (network);
+
+ /* FIXME: NULL GError */
+ if (!shares_get_share_info_list (&share_info_list, NULL)) {
+ goto out;
+ }
+
+ share_info_list = g_slist_sort (share_info_list, compare_share_info_name_cb);
+ diff_sorted_slists (current_shares, share_info_list, compare_share_info_name_cb, &added, &removed);
+
+ for (l = removed; l; l = l->next) {
+ ShareInfo *share_info;
+ char *filename;
+
+ share_info = l->data;
+ filename = build_fake_share_filename (share_info);
+ remove_link (filename);
+ g_free (filename);
+ }
+
+ for (l = added; l; l = l->next) {
+ ShareInfo *share_info;
+ char *filename;
+ char *target_uri;
+
+ share_info = l->data;
+
+ filename = build_fake_share_filename (share_info);
+ target_uri = build_share_target_uri (share_info);
+ add_link (filename, target_uri, share_info->share_name, "gnome-fs-directory", "Link");
+ g_free (filename);
+ g_free (target_uri);
+ }
+
+ g_slist_free (added);
+ g_slist_free (removed);
+
+ shares_free_share_info_list (current_shares);
+ current_shares = share_info_list;
+
+ out:
+
+ G_UNLOCK (network);
+}
+
+static void
refresh_link_lists (void)
{
char hostname[256];
@@ -1330,6 +1439,8 @@
G_UNLOCK (network);
}
+
+ refresh_shares_links ();
}
@@ -1397,7 +1508,8 @@
add_link ("smblink-root",
"smb://",
_("Windows Network"),
- "gnome-fs-network");
+ "gnome-fs-network",
+ "FSDevice");
}
--- modules/shares.c
+++ modules/shares.c
@@ -0,0 +1,890 @@
+#include <config.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <glib/gi18n-lib.h>
+#include "shares.h"
+
+#undef DEBUG_SHARES
+#ifdef DEBUG_SHARES
+# define NET_USERSHARE_ARGV0 "debug-net-usershare"
+#else
+# define NET_USERSHARE_ARGV0 "net"
+#endif
+
+static GHashTable *path_share_info_hash;
+static GHashTable *share_name_share_info_hash;
+
+#define NUM_CALLS_BETWEEN_TIMESTAMP_UPDATES 100
+#define TIMESTAMP_THRESHOLD 10 /* seconds */
+static int refresh_timestamp_update_counter;
+static time_t refresh_timestamp;
+
+#define KEY_PATH "path"
+#define KEY_COMMENT "comment"
+#define KEY_ACL "usershare_acl"
+
+/* Debugging flags */
+static gboolean throw_error_on_refresh;
+static gboolean throw_error_on_add;
+static gboolean throw_error_on_modify;
+static gboolean throw_error_on_remove;
+
+
+
+/* Interface to "net usershare" */
+
+static gboolean
+net_usershare_run (int argc, char **argv, GKeyFile **ret_key_file, GError **error)
+{
+ int real_argc;
+ int i;
+ char **real_argv;
+ gboolean retval;
+ char *stdout_contents;
+ char *stderr_contents;
+ int exit_status;
+ int exit_code;
+ GKeyFile *key_file;
+ GError *real_error;
+
+ g_assert (argc > 0);
+ g_assert (argv != NULL);
+ g_assert (error == NULL || *error == NULL);
+
+ if (ret_key_file)
+ *ret_key_file = NULL;
+
+ /* Build command line */
+
+ real_argc = 2 + argc + 1; /* "net" "usershare" [argv] NULL */
+ real_argv = g_new (char *, real_argc);
+
+ real_argv[0] = NET_USERSHARE_ARGV0;
+ real_argv[1] = "usershare";
+
+ for (i = 0; i < argc; i++) {
+ g_assert (argv[i] != NULL);
+ real_argv[i + 2] = argv[i];
+ }
+
+ real_argv[real_argc - 1] = NULL;
+
+ /* Launch */
+
+ stdout_contents = NULL;
+ stderr_contents = NULL;
+
+ {
+ char **p;
+
+ g_message ("------------------------------------------");
+
+ for (p = real_argv; *p; p++)
+ g_message ("spawn arg \"%s\"", *p);
+
+ g_message ("end of spawn args; SPAWNING\n");
+ }
+
+ real_error = NULL;
+ retval = g_spawn_sync (NULL, /* cwd */
+ real_argv,
+ NULL, /* envp */
+ G_SPAWN_SEARCH_PATH,
+ NULL, /* GSpawnChildSetupFunc */
+ NULL, /* user_data */
+ &stdout_contents,
+ &stderr_contents,
+ &exit_status,
+ &real_error);
+
+ g_message ("returned from spawn: %s: %s", retval ? "SUCCESS" : "FAIL", retval ? "" : real_error->message);
+
+ if (!retval) {
+ g_propagate_error (error, real_error);
+ goto out;
+ }
+
+ if (!WIFEXITED (exit_status)) {
+ g_message ("WIFEXITED(%d) was false!", exit_status);
+ retval = FALSE;
+
+ if (WIFSIGNALED (exit_status)) {
+ int signal_num;
+
+ signal_num = WTERMSIG (exit_status);
+ g_message ("Child got signal %d", signal_num);
+
+ g_set_error (error,
+ SHARES_ERROR,
+ SHARES_ERROR_FAILED,
+ _("%s %s %s returned with signal %d"),
+ real_argv[0],
+ real_argv[1],
+ real_argv[2],
+ signal_num);
+ } else
+ g_set_error (error,
+ SHARES_ERROR,
+ SHARES_ERROR_FAILED,
+ _("%s %s %s failed for an unknown reason"),
+ real_argv[0],
+ real_argv[1],
+ real_argv[2]);
+
+ goto out;
+ }
+
+ exit_code = WEXITSTATUS (exit_status);
+
+ g_message ("exit code %d", exit_code);
+ if (exit_code != 0) {
+ char *str;
+ char *message;
+
+ /* stderr_contents is in the system locale encoding, not UTF-8 */
+
+ str = g_locale_to_utf8 (stderr_contents, -1, NULL, NULL, NULL);
+
+ if (str && str[0])
+ message = g_strdup_printf (_("'net usershare' returned error %d: %s"), exit_code, str);
+ else
+ message = g_strdup_printf (_("'net usershare' returned error %d"), exit_code);
+
+ g_free (str);
+
+ g_set_error (error,
+ G_SPAWN_ERROR,
+ G_SPAWN_ERROR_FAILED,
+ "%s",
+ message);
+
+ g_free (message);
+
+ retval = FALSE;
+ goto out;
+ }
+
+ if (ret_key_file) {
+ g_message ("caller wants GKeyFile");
+
+ *ret_key_file = NULL;
+
+ /* FIXME: jeallison@novell.com says the output of "net usershare" is nearly always
+ * in UTF-8, but that it can be configured in the master smb.conf. We assume
+ * UTF-8 for now.
+ */
+
+ if (!g_utf8_validate (stdout_contents, -1, NULL)) {
+ g_message ("stdout of net usershare was not in valid UTF-8");
+ g_set_error (error,
+ G_SPAWN_ERROR,
+ G_SPAWN_ERROR_FAILED,
+ _("the output of 'net usershare' is not in valid UTF-8 encoding"));
+ retval = FALSE;
+ goto out;
+ }
+
+ key_file = g_key_file_new ();
+
+ real_error = NULL;
+ if (!g_key_file_load_from_data (key_file, stdout_contents, -1, 0, &real_error)) {
+ g_message ("Error when parsing key file {\n%s\n}: %s", stdout_contents, real_error->message);
+ g_propagate_error (error, real_error);
+ g_key_file_free (key_file);
+ retval = FALSE;
+ goto out;
+ }
+
+ retval = TRUE;
+ *ret_key_file = key_file;
+ } else
+ retval = TRUE;
+
+ g_message ("success from calling net usershare and parsing its output");
+
+ out:
+ g_free (real_argv);
+ g_free (stdout_contents);
+ g_free (stderr_contents);
+
+ g_message ("------------------------------------------");
+
+ return retval;
+}
+
+
+
+/* Internals */
+
+static void
+ensure_hashes (void)
+{
+ if (path_share_info_hash == NULL) {
+ g_assert (share_name_share_info_hash == NULL);
+
+ path_share_info_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ share_name_share_info_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ } else
+ g_assert (share_name_share_info_hash != NULL);
+}
+
+static ShareInfo *
+lookup_share_by_path (const char *path)
+{
+ ensure_hashes ();
+ return g_hash_table_lookup (path_share_info_hash, path);
+}
+
+static ShareInfo *
+lookup_share_by_share_name (const char *share_name)
+{
+ ensure_hashes ();
+ return g_hash_table_lookup (share_name_share_info_hash, share_name);
+}
+
+static void
+add_share_info_to_hashes (ShareInfo *info)
+{
+ ensure_hashes ();
+ g_hash_table_insert (path_share_info_hash, info->path, info);
+ g_hash_table_insert (share_name_share_info_hash, info->share_name, info);
+}
+
+static void
+remove_share_info_from_hashes (ShareInfo *info)
+{
+ ensure_hashes ();
+ g_hash_table_remove (path_share_info_hash, info->path);
+ g_hash_table_remove (share_name_share_info_hash, info->share_name);
+}
+
+static gboolean
+remove_from_path_hash_cb (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ ShareInfo *info;
+
+ info = value;
+ shares_free_share_info (info);
+
+ return TRUE;
+}
+
+static gboolean
+remove_from_share_name_hash_cb (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ /* The ShareInfo was already freed in remove_from_path_hash_cb() */
+ return TRUE;
+}
+
+static void
+free_all_shares (void)
+{
+ ensure_hashes ();
+ g_hash_table_foreach_remove (path_share_info_hash, remove_from_path_hash_cb, NULL);
+ g_hash_table_foreach_remove (share_name_share_info_hash, remove_from_share_name_hash_cb, NULL);
+}
+
+static char *
+get_string_from_key_file (GKeyFile *key_file, const char *group, const char *key)
+{
+ GError *error;
+ char *str;
+
+ error = NULL;
+ str = NULL;
+
+ if (g_key_file_has_key (key_file, group, key, &error)) {
+ str = g_key_file_get_string (key_file, group, key, &error);
+ if (!str) {
+ g_assert (!g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)
+ && !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND));
+
+ g_error_free (error);
+ }
+ } else {
+ g_assert (!g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND));
+ g_error_free (error);
+ }
+
+ return str;
+}
+
+static void
+add_key_group_to_hashes (GKeyFile *key_file, const char *group)
+{
+ char *path;
+ char *comment;
+ char *acl;
+ gboolean is_writable;
+ ShareInfo *info;
+ ShareInfo *old_info;
+
+ /* Remove the old share based on the name */
+
+ old_info = lookup_share_by_share_name (group);
+ if (old_info) {
+ remove_share_info_from_hashes (old_info);
+ shares_free_share_info (old_info);
+ }
+
+ /* Start parsing, and remove the old share based on the path */
+
+ path = get_string_from_key_file (key_file, group, KEY_PATH);
+ if (!path) {
+ g_message ("group '%s' doesn't have a '%s' key! Ignoring group.", group, KEY_PATH);
+ return;
+ }
+
+ old_info = lookup_share_by_path (path);
+ if (old_info) {
+ remove_share_info_from_hashes (old_info);
+ shares_free_share_info (old_info);
+ }
+
+ /* Finish parsing */
+
+ comment = get_string_from_key_file (key_file, group, KEY_COMMENT);
+
+ acl = get_string_from_key_file (key_file, group, KEY_ACL);
+ if (acl) {
+ if (strcmp (acl, "Everyone:R") == 0)
+ is_writable = FALSE;
+ else if (strcmp (acl, "Everyone:F") == 0)
+ is_writable = TRUE;
+ else {
+ g_message ("unknown format for key '%s/%s' as it contains '%s'. Assuming that the share is read-only",
+ group, KEY_ACL, acl);
+ is_writable = FALSE;
+ }
+
+ g_free (acl);
+ } else {
+ g_message ("group '%s' doesn't have a '%s' key! Assuming that the share is read-only.", group, KEY_ACL);
+ is_writable = FALSE;
+ }
+
+ g_assert (path != NULL);
+ g_assert (group != NULL);
+
+ info = g_new (ShareInfo, 1);
+ info->path = path;
+ info->share_name = g_strdup (group);
+ info->comment = comment;
+ info->is_writable = is_writable;
+
+ add_share_info_to_hashes (info);
+}
+
+static void
+replace_shares_from_key_file (GKeyFile *key_file)
+{
+ gsize num_groups;
+ char **group_names;
+ gsize i;
+
+ group_names = g_key_file_get_groups (key_file, &num_groups);
+
+ /* FIXME: In add_key_group_to_hashes(), we simply ignore key groups
+ * which have invalid data (i.e. no path). We could probably accumulate a
+ * GError with the list of invalid groups and propagate it upwards.
+ */
+ for (i = 0; i < num_groups; i++) {
+ g_assert (group_names[i] != NULL);
+ add_key_group_to_hashes (key_file, group_names[i]);
+ }
+
+ g_strfreev (group_names);
+}
+
+static gboolean
+refresh_shares (GError **error)
+{
+ GKeyFile *key_file;
+ char *argv[1];
+ GError *real_error;
+
+ free_all_shares ();
+
+ if (throw_error_on_refresh) {
+ g_set_error (error,
+ SHARES_ERROR,
+ SHARES_ERROR_FAILED,
+ _("Failed"));
+ return FALSE;
+ }
+
+ argv[0] = "info";
+
+ real_error = NULL;
+ if (!net_usershare_run (G_N_ELEMENTS (argv), argv, &key_file, &real_error)) {
+ g_message ("Called \"net usershare info\" but it failed: %s", real_error->message);
+ g_propagate_error (error, real_error);
+ return FALSE;
+ }
+
+ g_assert (key_file != NULL);
+
+ replace_shares_from_key_file (key_file);
+ g_key_file_free (key_file);
+
+ return TRUE;
+}
+
+static gboolean
+refresh_if_needed (GError **error)
+{
+ gboolean retval;
+
+ if (refresh_timestamp_update_counter == 0) {
+ time_t new_timestamp;
+
+ refresh_timestamp_update_counter = NUM_CALLS_BETWEEN_TIMESTAMP_UPDATES;
+
+ new_timestamp = time (NULL);
+ if (new_timestamp - refresh_timestamp > TIMESTAMP_THRESHOLD) {
+ g_message ("REFRESHING SHARES");
+ retval = refresh_shares (error);
+ } else
+ retval = TRUE;
+
+ refresh_timestamp = new_timestamp;
+ } else {
+ refresh_timestamp_update_counter--;
+ retval = TRUE;
+ }
+
+ return retval;
+}
+
+static ShareInfo *
+copy_share_info (ShareInfo *info)
+{
+ ShareInfo *copy;
+
+ if (!info)
+ return NULL;
+
+ copy = g_new (ShareInfo, 1);
+ copy->path = g_strdup (info->path);
+ copy->share_name = g_strdup (info->share_name);
+ copy->comment = g_strdup (info->comment);
+ copy->is_writable = info->is_writable;
+
+ return copy;
+}
+
+static gboolean
+add_share (ShareInfo *info, GError **error)
+{
+ char *argv[6];
+ ShareInfo *copy;
+ GKeyFile *key_file;
+ GError *real_error;
+
+ g_message ("add_share() start");
+
+ if (throw_error_on_add) {
+ g_set_error (error,
+ SHARES_ERROR,
+ SHARES_ERROR_FAILED,
+ _("Failed"));
+ g_message ("add_share() end FAIL");
+ return FALSE;
+ }
+
+ argv[0] = "add";
+ argv[1] = "-l";
+ argv[2] = info->share_name;
+ argv[3] = info->path;
+ argv[4] = info->comment;
+ argv[5] = info->is_writable ? "Everyone:F" : "Everyone:R";
+
+ real_error = NULL;
+ if (!net_usershare_run (G_N_ELEMENTS (argv), argv, &key_file, &real_error)) {
+ g_message ("Called \"net usershare add\" but it failed: %s", real_error->message);
+ g_propagate_error (error, real_error);
+ return FALSE;
+ }
+
+ replace_shares_from_key_file (key_file);
+
+ copy = copy_share_info (info);
+ add_share_info_to_hashes (copy);
+
+ g_message ("add_share() end SUCCESS");
+
+ return TRUE;
+}
+
+static gboolean
+remove_share (const char *path, GError **error)
+{
+ ShareInfo *old_info;
+ char *argv[2];
+ GError *real_error;
+
+ g_message ("remove_share() start");
+
+ if (throw_error_on_remove) {
+ g_set_error (error,
+ SHARES_ERROR,
+ SHARES_ERROR_FAILED,
+ "Failed");
+ g_message ("remove_share() end FAIL");
+ return FALSE;
+ }
+
+ old_info = lookup_share_by_path (path);
+ if (!old_info) {
+ char *display_name;
+
+ display_name = g_filename_display_name (path);
+ g_set_error (error,
+ SHARES_ERROR,
+ SHARES_ERROR_NONEXISTENT,
+ _("Cannot remove the share for path %s: that path is not shared"),
+ display_name);
+ g_free (display_name);
+
+ g_message ("remove_share() end FAIL: path %s was not in our hashes", path);
+ return FALSE;
+ }
+
+ argv[0] = "delete";
+ argv[1] = old_info->share_name;
+
+ real_error = NULL;
+ if (!net_usershare_run (G_N_ELEMENTS (argv), argv, NULL, &real_error)) {
+ g_message ("Called \"net usershare delete\" but it failed: %s", real_error->message);
+ g_propagate_error (error, real_error);
+ g_message ("remove_share() end FAIL");
+ return FALSE;
+ }
+
+ remove_share_info_from_hashes (old_info);
+ shares_free_share_info (old_info);
+
+ g_message ("remove_share() end SUCCESS");
+
+ return TRUE;
+}
+
+static gboolean
+modify_share (const char *old_path, ShareInfo *info, GError **error)
+{
+ ShareInfo *old_info;
+
+ g_message ("modify_share() start");
+
+ old_info = lookup_share_by_path (old_path);
+ if (old_info == NULL) {
+ g_message ("modify_share() end; calling add_share() instead");
+ return add_share (info, error);
+ }
+
+ g_assert (old_info != NULL);
+
+ if (strcmp (info->path, old_info->path) != 0) {
+ g_set_error (error,
+ SHARES_ERROR,
+ SHARES_ERROR_FAILED,
+ _("Cannot change the path of an existing share; please remove the old share first and add a new one"));
+ g_message ("modify_share() end FAIL: tried to change the path in a share!");
+ return FALSE;
+ }
+
+ if (throw_error_on_modify) {
+ g_set_error (error,
+ SHARES_ERROR,
+ SHARES_ERROR_FAILED,
+ "Failed");
+ g_message ("modify_share() end FAIL");
+ return FALSE;
+ }
+
+ /* Although "net usershare add" will modify an existing share if it has the same share name
+ * as the one that gets passed in, our semantics are different. We have a one-to-one mapping
+ * between paths and share names; "net usershare" supports a one-to-many mapping from paths
+ * to share names. So, we must first remove the old share and then add the new/modified one.
+ */
+
+ if (!remove_share (old_path, error)) {
+ g_message ("modify_share() end FAIL: error when removing old share");
+ return FALSE;
+ }
+
+ g_message ("modify_share() end: will call add_share() with the new share info");
+ return add_share (info, error);
+}
+
+
+
+/* Public API */
+
+GQuark
+shares_error_quark (void)
+{
+ static GQuark quark;
+
+ if (quark == 0)
+ quark = g_quark_from_string ("nautilus-shares-error-quark"); /* not from_static_string since we are a module */
+
+ return quark;
+}
+
+/**
+ * shares_free_share_info:
+ * @info: A #ShareInfo structure.
+ *
+ * Frees a #ShareInfo structure.
+ **/
+void
+shares_free_share_info (ShareInfo *info)
+{
+ g_assert (info != NULL);
+
+ g_free (info->path);
+ g_free (info->share_name);
+ g_free (info->comment);
+ g_free (info);
+}
+
+/**
+ * shares_get_path_is_shared:
+ * @path: A full path name ("/foo/bar/baz") in file system encoding.
+ * @ret_is_shared: Location to store result value (#TRUE if the path is shared, #FALSE otherwise)
+ * @error: Location to store error, or #NULL.
+ *
+ * Checks whether a path is shared through Samba.
+ *
+ * Return value: #TRUE if the info could be queried successfully, #FALSE
+ * otherwise. If this function returns #FALSE, an error code will be returned in the
+ * @error argument, and *@ret_is_shared will be set to #FALSE.
+ **/
+gboolean
+shares_get_path_is_shared (const char *path, gboolean *ret_is_shared, GError **error)
+{
+ g_assert (ret_is_shared != NULL);
+ g_assert (error == NULL || *error == NULL);
+
+ if (!refresh_if_needed (error)) {
+ *ret_is_shared = FALSE;
+ return FALSE;
+ }
+
+ *ret_is_shared = (lookup_share_by_path (path) != NULL);
+
+ return TRUE;
+}
+
+/**
+ * shares_get_share_info_for_path:
+ * @path: A full path name ("/foo/bar/baz") in file system encoding.
+ * @ret_share_info: Location to store result with the share's info - on return,
+ * will be non-NULL if the path is indeed shared, or #NULL if the path is not
+ * shared. You must free the non-NULL value with shares_free_share_info().
+ * @error: Location to store error, or #NULL.
+ *
+ * Queries the information for a shared path: its share name, its read-only status, etc.
+ *
+ * Return value: #TRUE if the info could be queried successfully, #FALSE
+ * otherwise. If this function returns #FALSE, an error code will be returned in the
+ * @error argument, and *@ret_share_info will be set to #NULL.
+ **/
+gboolean
+shares_get_share_info_for_path (const char *path, ShareInfo **ret_share_info, GError **error)
+{
+ ShareInfo *info;
+
+ g_assert (path != NULL);
+ g_assert (ret_share_info != NULL);
+ g_assert (error == NULL || *error == NULL);
+
+ if (!refresh_if_needed (error)) {
+ *ret_share_info = NULL;
+ return FALSE;
+ }
+
+ info = lookup_share_by_path (path);
+ *ret_share_info = copy_share_info (info);
+
+ return TRUE;
+}
+
+/**
+ * shares_get_share_name_exists:
+ * @share_name: Name of a share.
+ * @ret_exists: Location to store return value; #TRUE if the share name exists, #FALSE otherwise.
+ *
+ * Queries whether a share name already exists in the user's list of shares.
+ *
+ * Return value: #TRUE if the info could be queried successfully, #FALSE
+ * otherwise. If this function returns #FALSE, an error code will be returned in the
+ * @error argument, and *@ret_exists will be set to #FALSE.
+ **/
+gboolean
+shares_get_share_name_exists (const char *share_name, gboolean *ret_exists, GError **error)
+{
+ g_assert (share_name != NULL);
+ g_assert (ret_exists != NULL);
+ g_assert (error == NULL || *error == NULL);
+
+ if (!refresh_if_needed (error)) {
+ *ret_exists = FALSE;
+ return FALSE;
+ }
+
+ *ret_exists = (lookup_share_by_share_name (share_name) != NULL);
+
+ return TRUE;
+}
+
+/**
+ * shares_get_share_info_for_share_name:
+ * @share_name: Name of a share.
+ * @ret_share_info: Location to store result with the share's info - on return,
+ * will be non-NULL if there is a share for the specified name, or #NULL if no
+ * share has such name. You must free the non-NULL value with
+ * shares_free_share_info().
+ * @error: Location to store error, or #NULL.
+ *
+ * Queries the information for the share which has a specific name.
+ *
+ * Return value: #TRUE if the info could be queried successfully, #FALSE
+ * otherwise. If this function returns #FALSE, an error code will be returned in the
+ * @error argument, and *@ret_share_info will be set to #NULL.
+ **/
+gboolean
+shares_get_share_info_for_share_name (const char *share_name, ShareInfo **ret_share_info, GError **error)
+{
+ ShareInfo *info;
+
+ g_assert (share_name != NULL);
+ g_assert (ret_share_info != NULL);
+ g_assert (error == NULL || *error == NULL);
+
+ if (!refresh_if_needed (error)) {
+ *ret_share_info = NULL;
+ return FALSE;
+ }
+
+ info = lookup_share_by_share_name (share_name);
+ *ret_share_info = copy_share_info (info);
+
+ return TRUE;
+}
+
+/**
+ * shares_modify_share:
+ * @old_path: Path of the share to modify, or %NULL.
+ * @info: Info of the share to modify/add, or %NULL to delete a share.
+ * @error: Location to store error, or #NULL.
+ *
+ * Can add, modify, or delete shares. To add a share, pass %NULL for @old_path,
+ * and a non-null @info. To modify a share, pass a non-null @old_path and
+ * non-null @info; in this case, @info->path must have the same contents as
+ * @old_path. To remove a share, pass a non-NULL @old_path and a %NULL @info.
+ *
+ * Return value: TRUE if the share could be modified, FALSE otherwise. If this returns
+ * FALSE, then the error information will be placed in @error.
+ **/
+gboolean
+shares_modify_share (const char *old_path, ShareInfo *info, GError **error)
+{
+ g_assert ((old_path == NULL && info != NULL)
+ || (old_path != NULL && info == NULL)
+ || (old_path != NULL && info != NULL));
+ g_assert (error == NULL || *error == NULL);
+
+ if (!refresh_if_needed (error))
+ return FALSE;
+
+ if (old_path == NULL)
+ return add_share (info, error);
+ else if (info == NULL)
+ return remove_share (old_path, error);
+ else
+ return modify_share (old_path, info, error);
+}
+
+static void
+copy_to_slist_cb (gpointer key, gpointer value, gpointer data)
+{
+ ShareInfo *info;
+ ShareInfo *copy;
+ GSList **list;
+
+ info = value;
+ list = data;
+
+ copy = copy_share_info (info);
+ *list = g_slist_prepend (*list, copy);
+}
+
+/**
+ * shares_get_share_info_list:
+ * @ret_info_list: Location to store the return value, which is a list
+ * of #ShareInfo structures. Free this with shares_free_share_info_list().
+ * @error: Location to store error, or #NULL.
+ *
+ * Gets the list of shared folders and their information.
+ *
+ * Return value: #TRUE if the info could be queried successfully, #FALSE
+ * otherwise. If this function returns #FALSE, an error code will be returned in the
+ * @error argument, and *@ret_info_list will be set to #NULL.
+ **/
+gboolean
+shares_get_share_info_list (GSList **ret_info_list, GError **error)
+{
+ g_assert (ret_info_list != NULL);
+ g_assert (error == NULL || *error == NULL);
+
+ if (!refresh_if_needed (error)) {
+ *ret_info_list = NULL;
+ return FALSE;
+ }
+
+ *ret_info_list = NULL;
+ g_hash_table_foreach (path_share_info_hash, copy_to_slist_cb, ret_info_list);
+
+ return TRUE;
+}
+
+/**
+ * shares_free_share_info_list:
+ * @list: List of #ShareInfo structures, or %NULL.
+ *
+ * Frees a list of #ShareInfo structures as returned by shares_get_share_info_list().
+ **/
+void
+shares_free_share_info_list (GSList *list)
+{
+ GSList *l;
+
+ for (l = list; l; l = l->next) {
+ ShareInfo *info;
+
+ info = l->data;
+ shares_free_share_info (l->data);
+ }
+
+ g_slist_free (list);
+}
+
+void
+shares_set_debug (gboolean error_on_refresh,
+ gboolean error_on_add,
+ gboolean error_on_modify,
+ gboolean error_on_remove)
+{
+ throw_error_on_refresh = error_on_refresh;
+ throw_error_on_add = error_on_add;
+ throw_error_on_modify = error_on_modify;
+ throw_error_on_remove = error_on_remove;
+}
--- modules/shares.h
+++ modules/shares.h
@@ -0,0 +1,43 @@
+#ifndef SHARES_H
+#define SHARES_H
+
+#include <glib.h>
+
+typedef struct {
+ char *path;
+ char *share_name;
+ char *comment;
+ gboolean is_writable;
+} ShareInfo;
+
+#define SHARES_ERROR (shares_error_quark ())
+
+typedef enum {
+ SHARES_ERROR_FAILED,
+ SHARES_ERROR_NONEXISTENT
+} SharesError;
+
+GQuark shares_error_quark (void);
+
+void shares_free_share_info (ShareInfo *info);
+
+gboolean shares_get_path_is_shared (const char *path, gboolean *ret_is_shared, GError **error);
+
+gboolean shares_get_share_info_for_path (const char *path, ShareInfo **ret_share_info, GError **error);
+
+gboolean shares_get_share_name_exists (const char *share_name, gboolean *ret_exists, GError **error);
+
+gboolean shares_get_share_info_for_share_name (const char *share_name, ShareInfo **ret_share_info, GError **error);
+
+gboolean shares_modify_share (const char *old_path, ShareInfo *info, GError **error);
+
+gboolean shares_get_share_info_list (GSList **ret_info_list, GError **error);
+
+void shares_free_share_info_list (GSList *list);
+
+void shares_set_debug (gboolean error_on_refresh,
+ gboolean error_on_add,
+ gboolean error_on_modify,
+ gboolean error_on_remove);
+
+#endif
--- modules/smb-method.c
+++ modules/smb-method.c
@@ -37,6 +37,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <stdio.h>
#include <gconf/gconf-client.h>
#include <libgnomevfs/gnome-vfs.h>
@@ -90,6 +91,17 @@
static GHashTable *user_cache = NULL;
+/* smbcctx->readdir() can give us a struct smbc_dirent that identifies a
+ * printer, but you cannot perform a smbcctx->stat() on a path to know if that
+ * path refers to a printer. So, when doing readdir(), we must remember the
+ * URIs of the printers we have found. Later in our own do_get_file_info(), we
+ * will match the passed URI to this hash table and return a magic "it is a
+ * printer" datum if appropriate.
+ */
+static GHashTable *printer_hash = NULL;
+
+static FILE *debug_file;
+
#define SMB_BLOCK_SIZE (32*1024)
/* Reap unused server connections and user cache after 30 minutes */
@@ -149,32 +161,105 @@
static void init_authentication (SmbAuthContext *actx, GnomeVFSURI *uri);
static int perform_authentication (SmbAuthContext *actx);
+static gboolean is_printer (const char *uri);
+
static SmbAuthContext *current_auth_context = NULL;
static void auth_callback (const char *server_name, const char *share_name,
char *domain, int domainmaxlen,
char *username, int unmaxlen,
char *password, int pwmaxlen);
+
+static void debug_print (const char *format, ...);
+static void debug_indent (int amount);
+static int debug_indentation;
-#if 0
+#if 1
#define DEBUG_SMB_ENABLE
#define DEBUG_SMB_LOCKS
#endif
#ifdef DEBUG_SMB_ENABLE
-#define DEBUG_SMB(x) g_print x
+#define DEBUG_SMB(x) debug_print x
+#define DEBUG_IN() debug_print ("%s() {\n", G_STRFUNC); debug_indent(1)
+#define DEBUG_OUT() debug_indent(-1); debug_print ("} %s()\n", G_STRFUNC)
#else
-#define DEBUG_SMB(x)
+#define DEBUG_SMB(x)
+#define DEBUG_IN()
+#define DEBUG_OUT()
#endif
#ifdef DEBUG_SMB_LOCKS
-#define LOCK_SMB() {g_mutex_lock (smb_lock); g_print ("LOCK %s\n", G_GNUC_PRETTY_FUNCTION);}
-#define UNLOCK_SMB() {g_print ("UNLOCK %s\n", G_GNUC_PRETTY_FUNCTION); g_mutex_unlock (smb_lock);}
+#define LOCK_SMB() {g_mutex_lock (smb_lock); debug_print ("LOCK %s\n", G_STRFUNC);}
+#define UNLOCK_SMB() {debug_print ("UNLOCK %s\n", G_STRFUNC); g_mutex_unlock (smb_lock);}
#else
#define LOCK_SMB() g_mutex_lock (smb_lock)
#define UNLOCK_SMB() g_mutex_unlock (smb_lock)
#endif
+static void
+debug_print (const char *format, ...)
+{
+ va_list args;
+ char *str;
+ int i;
+
+ if (!debug_file)
+ return;
+
+ va_start (args, format);
+ str = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ fprintf (debug_file, "%p: ", g_thread_self ());
+
+ for (i = 0; i < debug_indentation * 4; i++)
+ fputc (' ', debug_file);
+
+ fputs (str, debug_file);
+ g_free (str);
+ fflush (debug_file);
+}
+
+static void
+debug_indent (int amount)
+{
+ debug_indentation += amount;
+ if (debug_indentation < 0)
+ g_error ("You fucked up your indentation");
+}
+
+static void
+DEBUG_DUMP_AUTH_CONTEXT (SmbAuthContext *actx)
+{
+ char *str_uri;
+
+ if (actx->uri)
+ str_uri = gnome_vfs_uri_to_string (actx->uri, 0);
+ else
+ str_uri = g_strdup ("(null)");
+
+ debug_print ("AUTH CONTEXT %p {\n", actx);
+ debug_print (" uri: %s\n", str_uri);
+ debug_print (" vfs_result: %d\n", (int) actx->res);
+ debug_print (" passes: %d\n", actx->passes);
+ debug_print (" state: %x\n", actx->state);
+ debug_print (" save_auth: %d\n", actx->save_auth);
+ debug_print (" keyring: %s\n", actx->keyring);
+ debug_print (" auth_called: %d\n", actx->auth_called);
+ debug_print (" for_server: %s\n", actx->for_server);
+ debug_print (" for_share: %s\n", actx->for_share);
+ debug_print (" use_user: %s\n", actx->use_user);
+ debug_print (" use_domain: %s\n", actx->use_domain);
+ debug_print (" use_password: %s\n", actx->use_password);
+ debug_print (" cache_added: %d\n", actx->cache_added);
+ debug_print (" cache_used: %d\n", actx->cache_used);
+ debug_print (" prompt_flags: %x\n", actx->prompt_flags);
+ debug_print ("}\n");
+
+ g_free (str_uri);
+}
+
static gchar*
string_dup_nzero (const gchar *s)
{
@@ -319,7 +404,8 @@
* sure when we'll be called */
if (!g_mutex_trylock (smb_lock))
return TRUE;
- DEBUG_SMB(("LOCK %s\n", G_GNUC_PRETTY_FUNCTION));
+ DEBUG_IN ();
+ DEBUG_SMB(("LOCK %s\n", G_STRFUNC));
size = g_hash_table_size (server_cache);
servers = g_ptr_array_sized_new (size);
@@ -342,6 +428,7 @@
if (!ret)
cache_reap_timeout = 0;
+ DEBUG_OUT ();
UNLOCK_SMB();
return ret;
@@ -363,6 +450,7 @@
{
SmbServerCacheEntry *entry = NULL;
+ DEBUG_IN ();
DEBUG_SMB(("[auth] adding cached server: server: %s, share: %s, domain: %s, user: %s\n",
server_name ? server_name : "",
share_name ? share_name : "",
@@ -383,6 +471,8 @@
g_hash_table_insert (server_cache, entry, entry);
current_auth_context->cache_added = TRUE;
+
+ DEBUG_OUT ();
return 0;
}
@@ -393,6 +483,7 @@
SmbServerCacheEntry entry;
SmbServerCacheEntry *res;
+ DEBUG_IN ();
DEBUG_SMB(("find_cached_server: server: %s, share: %s, domain: %s, user: %s\n",
server_name ? server_name : "",
share_name ? share_name : "",
@@ -409,9 +500,13 @@
if (res != NULL) {
res->last_time = time (NULL);
+ DEBUG_OUT ();
+ DEBUG_SMB (("found server %p\n", res->server));
return res->server;
- }
+ }
+ DEBUG_SMB (("found nothing; returning NULL\n"));
+ DEBUG_OUT ();
return NULL;
}
@@ -422,6 +517,8 @@
{
SMBCSRV *srv;
+ DEBUG_IN ();
+
srv = find_cached_server (server_name, share_name, domain, username);
if (srv != NULL) {
DEBUG_SMB(("got cached server: server: %s, share: %s, domain: %s, user: %s\n",
@@ -430,8 +527,10 @@
domain ? domain : "",
username ? username : ""));
current_auth_context->cache_used = TRUE;
+ DEBUG_OUT ();
return srv;
}
+ DEBUG_OUT ();
return NULL;
}
@@ -454,9 +553,13 @@
static int remove_cached_server(SMBCCTX * context, SMBCSRV * server)
{
int removed;
+
+ DEBUG_IN ();
removed = g_hash_table_foreach_remove (server_cache, remove_server, server);
+ DEBUG_OUT ();
+
/* return 1 if failed */
return removed == 0;
}
@@ -483,6 +586,8 @@
gboolean could_not_purge_all;
int i;
+ DEBUG_IN ();
+
size = g_hash_table_size (server_cache);
servers = g_ptr_array_sized_new (size);
@@ -499,6 +604,10 @@
}
g_ptr_array_free (servers, TRUE);
+
+ DEBUG_SMB (("returning could_not_purge_all = %d\n", could_not_purge_all));
+
+ DEBUG_OUT ();
return could_not_purge_all;
}
@@ -519,6 +628,8 @@
SMBCFILE *dir = NULL;
time_t t;
struct smbc_dirent *dirent;
+
+ DEBUG_IN ();
t = time (NULL);
@@ -526,6 +637,7 @@
workgroups_timestamp < t &&
t < workgroups_timestamp + WORKGROUP_CACHE_TIMEOUT) {
/* Up to date */
+ DEBUG_OUT ();
return;
}
workgroups_timestamp = t;
@@ -537,15 +649,20 @@
LOCK_SMB();
init_authentication (&actx, NULL);
+ DEBUG_DUMP_AUTH_CONTEXT (&actx);
/* Important: perform_authentication leaves and re-enters the lock! */
while (perform_authentication (&actx) > 0) {
+ DEBUG_SMB (("calling ctx->opendir (\"smb://\")\n"));
dir = smb_context->opendir (smb_context, "smb://");
actx.res = (dir != NULL) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB (("it returned %d\n", (int) actx.res));
}
if (dir != NULL) {
+ DEBUG_SMB (("calling ctx->readdir() in a loop\n"));
while ((dirent = smb_context->readdir (smb_context, dir)) != NULL) {
+ DEBUG_SMB (("got dirent '%s' of type %d\n", dirent->name, dirent->smbc_type));
if (dirent->smbc_type == SMBC_WORKGROUP &&
dirent->name != NULL &&
strlen (dirent->name) > 0) {
@@ -557,9 +674,13 @@
}
}
+ DEBUG_SMB (("calling ctx->closedir()\n"));
smb_context->closedir (smb_context, dir);
}
+ DEBUG_DUMP_AUTH_CONTEXT (&actx);
UNLOCK_SMB();
+
+ DEBUG_OUT ();
}
static SmbUriType
@@ -567,6 +688,9 @@
{
GnomeVFSToplevelURI *toplevel;
char *first_slash;
+ SmbUriType type;
+
+ DEBUG_IN ();
toplevel = (GnomeVFSToplevelURI *)uri;
@@ -575,12 +699,16 @@
if (uri->text == NULL ||
uri->text[0] == 0 ||
strcmp (uri->text, "/") == 0) {
- return SMB_URI_WHOLE_NETWORK;
+ type = SMB_URI_WHOLE_NETWORK;
+ goto out;
}
if (strchr (uri->text + 1, '/')) {
- return SMB_URI_ERROR;
+ type = SMB_URI_ERROR;
+ goto out;
}
- return SMB_URI_WORKGROUP_LINK;
+
+ type = SMB_URI_WORKGROUP_LINK;
+ goto out;
}
if (uri->text == NULL ||
uri->text[0] == 0 ||
@@ -590,9 +718,11 @@
if (!g_ascii_strcasecmp(toplevel->host_name,
DEFAULT_WORKGROUP_NAME) ||
g_hash_table_lookup (workgroups, toplevel->host_name)) {
- return SMB_URI_WORKGROUP;
+ type = SMB_URI_WORKGROUP;
+ goto out;
} else {
- return SMB_URI_SERVER;
+ type = SMB_URI_SERVER;
+ goto out;
}
}
first_slash = strchr (uri->text + 1, '/');
@@ -602,13 +732,21 @@
if (!g_ascii_strcasecmp(toplevel->host_name,
DEFAULT_WORKGROUP_NAME) ||
g_hash_table_lookup (workgroups, toplevel->host_name)) {
- return SMB_URI_SERVER_LINK;
+ type = SMB_URI_SERVER_LINK;
+ goto out;
} else {
- return SMB_URI_SHARE;
+ type = SMB_URI_SHARE;
+ goto out;
}
}
-
- return SMB_URI_SHARE_FILE;
+
+ type = SMB_URI_SHARE_FILE;
+
+ out:
+
+ DEBUG_OUT ();
+
+ return type;
}
@@ -665,42 +803,56 @@
g_free (path);
smb_context = smbc_new_context ();
- if (smb_context != 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;
-
- gclient = gconf_client_get_default ();
- if (gclient) {
- workgroup = gconf_client_get_string (gclient,
- PATH_GCONF_GNOME_VFS_SMB_WORKGROUP, NULL);
-
- /* libsmbclient frees this on it's own, so make sure
- * to use simple system malloc */
- if (workgroup && workgroup[0])
- smb_context->workgroup = strdup (workgroup);
-
- g_free (workgroup);
- g_object_unref (gclient);
- }
+ if (smb_context == NULL)
+ goto out;
- if (!smbc_init_context (smb_context)) {
- smbc_free_context (smb_context, FALSE);
- smb_context = 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;
+
+ DEBUG_SMB (("created the SMBCCTX; it has smbcctx->workgroup=\"%s\"\n",
+ smb_context->workgroup ? smb_context->workgroup : "(null)"));
+
+ gclient = gconf_client_get_default ();
+ if (gclient) {
+ workgroup = gconf_client_get_string (gclient,
+ PATH_GCONF_GNOME_VFS_SMB_WORKGROUP, NULL);
+
+ /* libsmbclient frees this on it's own, so make sure
+ * to use simple system malloc */
+ if (workgroup && workgroup[0])
+ smb_context->workgroup = strdup (workgroup);
+
+ g_free (workgroup);
+ g_object_unref (gclient);
+ }
+
+ DEBUG_SMB (("after reading from gconf, we have smbcctx->workgroup=\"%s\"\n",
+ smb_context->workgroup ? smb_context->workgroup : "(null)"));
+ if (!smbc_init_context (smb_context)) {
+ smbc_free_context (smb_context, FALSE);
+ smb_context = NULL;
+ DEBUG_SMB (("smbc_init_context() failed!\n"));
+ goto out;
+ }
+
+ DEBUG_SMB (("called smbc_init_context(); we have smbcctx->workgroup=\"%s\"\n",
+ smb_context->workgroup ? smb_context->workgroup : "(null)"));
+
#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;
+ 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;
+# if 0
+# if defined(SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON)
+ smb_context->flags |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON;
+# endif
+# endif
#endif
-#endif
- }
server_cache = g_hash_table_new_full (server_hash, server_equal,
(GDestroyNotify)server_free, NULL);
@@ -708,7 +860,10 @@
g_free, NULL);
user_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify)user_free);
-
+ printer_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ out:
UNLOCK_SMB();
if (smb_context == NULL) {
@@ -749,6 +904,8 @@
{
SmbCachedUser *user;
gchar *key;
+
+ DEBUG_IN ();
g_return_if_fail (actx->for_server != NULL);
@@ -772,6 +929,8 @@
user->username = string_realloc (user->username, actx->use_user);
user->password = string_realloc (user->password, actx->use_password);
user->stamp = time (NULL);
+
+ DEBUG_OUT ();
}
static gboolean
@@ -779,9 +938,13 @@
{
SmbCachedUser *user;
gchar *key;
-
+ gboolean retval;
+
g_return_val_if_fail (actx->for_server != NULL, FALSE);
+ DEBUG_IN ();
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
+
key = g_strdup_printf ("%s/%s", actx->for_server, with_share ? actx->for_share : "");
user = (SmbCachedUser*)g_hash_table_lookup (user_cache, key);
g_free (key);
@@ -789,11 +952,16 @@
if (user) {
/* If we already have a user name or domain double check that... */
if (!(actx->prompt_flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME) &&
- !string_compare(user->username, actx->use_user))
- return FALSE;
+ !string_compare(user->username, actx->use_user)) {
+ retval = FALSE;
+ goto out;
+ }
+
if (!(actx->prompt_flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN) &&
- !string_compare(user->domain, actx->use_domain))
- return FALSE;
+ !string_compare(user->domain, actx->use_domain)) {
+ retval = FALSE;
+ goto out;
+ }
actx->use_user = string_realloc (actx->use_user, user->username);
actx->use_domain = string_realloc (actx->use_domain, user->domain);
@@ -802,10 +970,16 @@
actx->use_user ? actx->use_user : "",
actx->use_domain ? actx->use_domain : "",
actx->use_password ? actx->use_password : ""));
- return TRUE;
+ retval = TRUE;
+ goto out;
}
- return FALSE;
+ retval = FALSE;
+
+ out:
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
+ DEBUG_OUT ();
+ return retval;
}
static gboolean
@@ -819,7 +993,10 @@
gboolean found_user = FALSE;
char *tmp;
+ DEBUG_IN ();
+
DEBUG_SMB(("[auth] Initial authentication lookups\n"));
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
toplevel_uri = (GnomeVFSToplevelURI*)actx->uri;
actx->prompt_flags = GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME |
@@ -888,6 +1065,8 @@
}
}
+ DEBUG_OUT ();
+
return found_user;
}
@@ -902,7 +1081,10 @@
gboolean filled = FALSE;
g_return_val_if_fail (actx != NULL, FALSE);
- g_return_val_if_fail (actx->for_server != NULL, FALSE);
+ g_return_val_if_fail (actx->for_server != NULL, FALSE);
+
+ DEBUG_IN ();
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
memset (&in_args, 0, sizeof (in_args));
in_args.uri = get_auth_display_uri (actx, FALSE);
@@ -923,6 +1105,8 @@
&in_args, sizeof (in_args),
&out_args, sizeof (out_args));
+ DEBUG_SMB(("[auth] vfs module callback for FILL_AUTHENTICATION returned invoked=%d\n", invoked));
+
g_free (in_args.uri);
/* If that didn't work then try without the share name */
@@ -949,7 +1133,8 @@
invoked = gnome_vfs_module_callback_invoke
(GNOME_VFS_MODULE_CALLBACK_FILL_AUTHENTICATION,
&in_args, sizeof (in_args),
- &out_args, sizeof (out_args));
+ &out_args, sizeof (out_args));
+ DEBUG_SMB(("[auth] vfs module callback for FILL_AUTHENTICATION returned invoked=%d\n", invoked));
}
if (invoked && out_args.valid) {
@@ -975,6 +1160,9 @@
g_free (out_args.domain);
g_free (out_args.password);
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
+ DEBUG_OUT ();
+
return filled;
}
@@ -990,6 +1178,9 @@
g_return_val_if_fail (actx != NULL, FALSE);
g_return_val_if_fail (actx->for_server != NULL, FALSE);
+
+ DEBUG_IN ();
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
memset (&in_args, 0, sizeof (in_args));
@@ -1009,21 +1200,38 @@
in_args.default_user = actx->use_user;
if (string_compare (in_args.default_user, GUEST_LOGIN))
in_args.default_user = NULL;
- if (!in_args.default_user)
- in_args.default_user = (char*)g_get_user_name ();
-
+ if (!in_args.default_user) {
+ const char *unix_username;
+ const char *backslash;
+
+ unix_username = g_get_user_name ();
+ backslash = strchr (unix_username, '\\');
+ if (!backslash)
+ in_args.default_user = (char *) unix_username;
+ else
+ in_args.default_user = (char *) backslash + 1;
+ }
+
in_args.default_domain = actx->use_domain ? actx->use_domain : smb_context->workgroup;
memset (&out_args, 0, sizeof (out_args));
- DEBUG_SMB(("[auth] Prompting credentials for: %s\n",
- in_args.uri ? in_args.uri : ""));
+ DEBUG_SMB(("[auth] Prompting credentials for: uri=%s, server=%s, object=%s, username=%s, domain=%s, default_user=%s, default_domain=%s\n",
+ in_args.uri,
+ in_args.server,
+ in_args.object,
+ in_args.username,
+ in_args.domain,
+ in_args.default_user,
+ in_args.default_domain));
invoked = gnome_vfs_module_callback_invoke
(GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION,
&in_args, sizeof (in_args),
&out_args, sizeof (out_args));
+ DEBUG_SMB(("[auth] vfs module callback for FULL_AUTHENTICATION returned invoked=%d\n", invoked));
+
if (invoked) {
if (in_args.flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME) {
g_free (actx->use_user);
@@ -1038,10 +1246,7 @@
g_free (actx->keyring);
actx->save_auth = out_args.save_password;
actx->keyring = actx->save_auth && out_args.keyring ? g_strdup (out_args.keyring) : NULL;
- DEBUG_SMB(("[auth] Prompted credentials: %s@%s:%s\n",
- actx->use_user ? actx->use_user : "",
- actx->use_domain ? actx->use_domain : "",
- actx->use_password ? actx->use_password : ""));
+ DEBUG_SMB(("[auth] Prompted credentials: %s@%s:%s keyring=%s\n", actx->use_user, actx->use_domain, actx->use_password, actx->keyring));
}
*cancelled = out_args.abort_auth;
@@ -1055,6 +1260,9 @@
g_free (in_args.uri);
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
+ DEBUG_OUT ();
+
return invoked && !*cancelled;
}
@@ -1065,14 +1273,19 @@
GnomeVFSModuleCallbackSaveAuthenticationOut out_args;
gboolean invoked;
+ DEBUG_IN ();
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
+
/* Add to the user cache both with and without shares */
if (actx->for_server) {
update_user_cache (actx, TRUE);
update_user_cache (actx, FALSE);
}
- if (!actx->save_auth)
+ if (!actx->save_auth) {
+ DEBUG_OUT ();
return;
+ }
/* Save with the domain name */
memset (&in_args, 0, sizeof (in_args));
@@ -1101,6 +1314,8 @@
&in_args, sizeof (in_args),
&out_args, sizeof (out_args));
+ DEBUG_SMB(("[auth] vfs module callback for SAVE_AUTHENTICATION returned invoked=%d\n", invoked));
+
g_free (in_args.uri);
/* Save without the domain name */
@@ -1130,14 +1345,18 @@
&in_args, sizeof (in_args),
&out_args, sizeof (out_args));
+ DEBUG_SMB(("[auth] vfs module callback for SAVE_AUTHENTICATION returned invoked=%d\n", invoked));
+
g_free (in_args.uri);
+
+ DEBUG_OUT ();
}
static void
cleanup_authentication (SmbAuthContext *actx)
{
/* IMPORTANT: We are IN the lock at this point */
-
+ DEBUG_IN ();
DEBUG_SMB(("[auth] Cleaning up Authentication\n"));
g_return_if_fail (actx != NULL);
@@ -1161,6 +1380,9 @@
g_return_if_fail (current_auth_context == actx);
current_auth_context = NULL;
+
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
+ DEBUG_OUT ();
}
/*
@@ -1205,9 +1427,12 @@
{
gboolean cont, auth_failed = FALSE, auth_cancelled = FALSE;
int ret = -1;
+
+ DEBUG_IN ();
/* IMPORTANT: We are IN the lock at this point */
DEBUG_SMB(("[auth] perform_authentication called.\n"));
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
switch (actx->res) {
case GNOME_VFS_OK:
@@ -1223,8 +1448,9 @@
/* Other errors mean we're done */
default:
- DEBUG_SMB(("[auth] Non-authentication error. Leaving auth loop.\n"));
+ DEBUG_SMB(("[auth] Non-authentication VFS error %d. Leaving auth loop.\n", (int) actx->res));
cleanup_authentication (actx);
+ DEBUG_OUT ();
return -1;
}
@@ -1265,7 +1491,7 @@
/* A failed authentication */
} else if (actx->auth_called) {
-
+
/* We need a server to perform any authentication */
g_return_val_if_fail (actx->for_server != NULL, GNOME_VFS_ERROR_INTERNAL);
@@ -1276,9 +1502,12 @@
UNLOCK_SMB();
/* Do we have gnome-keyring credentials for this? */
- if (!(actx->state & SMB_AUTH_STATE_PREFILLED)) {
+ if (!(actx->state & SMB_AUTH_STATE_PREFILLED)) {
+ DEBUG_SMB(("[auth] failed authentication; will prefill from the vfs callback\n"));
actx->state |= SMB_AUTH_STATE_PREFILLED;
cont = prefill_authentication (actx);
+ } else {
+ DEBUG_SMB(("[auth] failed authentication; will prompt the user for authentication\n"));
}
/* Then we try a guest credentials... */
@@ -1303,9 +1532,10 @@
g_return_val_if_fail (current_auth_context == NULL, GNOME_VFS_ERROR_INTERNAL);
current_auth_context = actx;
- if (cont)
+ if (cont) {
+ DEBUG_SMB(("[auth] prefill or prompt returned 1\n"));
ret = 1;
- else {
+ } else {
ret = -1;
if (auth_cancelled) {
@@ -1320,12 +1550,15 @@
/* Weird, don't want authentication, but failed */
} else {
+ DEBUG_SMB(("[auth] don't want authentication, but failed\n"));
ret = -1;
}
}
if (ret <= 0)
cleanup_authentication (actx);
+
+ DEBUG_OUT ();
return ret;
/* IMPORTANT: We need to still be in the lock when returning from this func */
@@ -1341,16 +1574,25 @@
SmbAuthContext *actx;
SMBCSRV *server;
- DEBUG_SMB (("[auth] auth_callback called: server: %s share: %s\n",
+ DEBUG_IN ();
+
+ DEBUG_SMB (("[auth] auth_callback called: server: %s share: %s domain_out: %s, username_out: %s, password_out=%s\n",
server_name ? server_name : "",
- share_name ? share_name : ""));
+ share_name ? share_name : "",
+ domain_out ? domain_out : "",
+ username_out ? username_out : "",
+ password_out ? password_out : ""));
g_return_if_fail (current_auth_context != NULL);
actx = current_auth_context;
+ DEBUG_DUMP_AUTH_CONTEXT (actx);
+
/* We never authenticate for the toplevel (enumerating workgroups) */
- if (!server_name || !server_name[0])
+ if (!server_name || !server_name[0]) {
+ DEBUG_OUT ();
return;
+ }
actx->auth_called = TRUE;
@@ -1361,8 +1603,10 @@
actx->for_share = string_dup_nzero (share_name);
/* The first pass, try the cache, fill in anything we know */
- if (actx->passes == 1)
+ if (actx->passes == 1) {
+ DEBUG_SMB(("[auth] first pass; call initial_authentication()\n"));
initial_authentication (actx);
+ }
/* If we have a valid user then go for it */
if (actx->use_user) {
@@ -1380,9 +1624,9 @@
g_assert (!actx->preset_user);
if (actx->passes == 1)
- DEBUG_SMB(("[auth] No credentials, trying anonymous user login\n"));
+ DEBUG_SMB(("[auth] No credentials, trying anonymous user login with empty password\n"));
else
- DEBUG_SMB(("[auth] No credentials, returning null values\n"));
+ DEBUG_SMB(("[auth] No credentials, returning empty user and password\n"));
strncpy (username_out, "", unmaxlen);
strncpy (password_out, "", pwmaxlen);
@@ -1398,15 +1642,30 @@
* this doesn't make much sense, but such is life with libsmbclient.
*/
if ((actx->state & SMB_AUTH_STATE_PROMPTED) && actx->res != GNOME_VFS_OK) {
+ DEBUG_SMB(("[auth] we had prompted already but auth failed. Calling find_cached_server() again\n"));
server = find_cached_server (server_name, share_name, domain_out, username_out);
if (server) {
DEBUG_SMB (("[auth] auth_callback. Remove the wrong server entry from server_cache.\n"));
g_hash_table_foreach_remove (server_cache, remove_server, server);
}
}
+
+ DEBUG_OUT ();
}
static char *
+get_printer_data (const char *display_name, const char *path)
+{
+ return g_strdup_printf ("[Desktop Entry]\n"
+ "Encoding=UTF-8\n"
+ "Name=%s\n"
+ "Type=Application\n"
+ "Exec=gnome-cups-add --printer=%s\n"
+ "Icon=printer-remote\n", /* per the freedesktop.org icon naming spec */
+ display_name, path);
+}
+
+static char *
get_workgroup_data (const char *display_name, const char *name)
{
return g_strdup_printf ("[Desktop Entry]\n"
@@ -1453,6 +1712,21 @@
GnomeVFSFileOffset file_size;
} FileHandle;
+/* Takes ownership of desktop_file_contents */
+static FileHandle *
+file_handle_new_from_desktop_file_contents (char *desktop_file_contents)
+{
+ FileHandle *handle;
+
+ handle = g_new (FileHandle, 1);
+ handle->is_data = TRUE;
+ handle->offset = 0;
+ handle->file_data = desktop_file_contents;
+ handle->file_size = strlen (handle->file_data);
+
+ return handle;
+}
+
static GnomeVFSResult
do_open (GnomeVFSMethod *method,
GnomeVFSMethodHandle **method_handle,
@@ -1466,59 +1740,84 @@
int type;
mode_t unix_mode;
SMBCFILE *file = NULL;
-
+ GnomeVFSResult result;
+
+ DEBUG_IN ();
DEBUG_SMB(("do_open() %s mode %d\n",
gnome_vfs_uri_to_string (uri, 0), mode));
type = smb_uri_type (uri);
if (type == SMB_URI_ERROR) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_INVALID_URI;
}
+
+ path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
+
+ if (is_printer (path)) {
+ if (mode & GNOME_VFS_OPEN_WRITE) {
+ result = GNOME_VFS_ERROR_READ_ONLY;
+ goto out;
+ }
+
+ unescaped_name = get_base_from_uri (uri);
+ name = gnome_vfs_uri_extract_short_path_name (uri);
+
+ handle = file_handle_new_from_desktop_file_contents (get_printer_data (unescaped_name, path));
+ *method_handle = (GnomeVFSMethodHandle *)handle;
+
+ g_free (unescaped_name);
+ g_free (name);
+
+ result = GNOME_VFS_OK;
+ goto out;
+ }
if (type == SMB_URI_WHOLE_NETWORK ||
type == SMB_URI_WORKGROUP ||
type == SMB_URI_SERVER ||
type == SMB_URI_SHARE) {
- return GNOME_VFS_ERROR_IS_DIRECTORY;
+ result = GNOME_VFS_ERROR_IS_DIRECTORY;
+ goto out;
}
if (type == SMB_URI_WORKGROUP_LINK) {
if (mode & GNOME_VFS_OPEN_WRITE) {
- return GNOME_VFS_ERROR_READ_ONLY;
+ result = GNOME_VFS_ERROR_READ_ONLY;
+ goto out;
}
- handle = g_new (FileHandle, 1);
- handle->is_data = TRUE;
- handle->offset = 0;
+
unescaped_name = get_base_from_uri (uri);
name = gnome_vfs_uri_extract_short_path_name (uri);
- handle->file_data = get_workgroup_data (unescaped_name, name);
- handle->file_size = strlen (handle->file_data);
+
+ handle = file_handle_new_from_desktop_file_contents (get_workgroup_data (unescaped_name, name));
+ *method_handle = (GnomeVFSMethodHandle *)handle;
+
g_free (unescaped_name);
g_free (name);
- *method_handle = (GnomeVFSMethodHandle *)handle;
-
- return GNOME_VFS_OK;
+ result = GNOME_VFS_OK;
+ goto out;
}
if (type == SMB_URI_SERVER_LINK) {
if (mode & GNOME_VFS_OPEN_WRITE) {
- return GNOME_VFS_ERROR_READ_ONLY;
+ result = GNOME_VFS_ERROR_READ_ONLY;
+ goto out;
}
- handle = g_new (FileHandle, 1);
- handle->is_data = TRUE;
- handle->offset = 0;
+
unescaped_name = get_base_from_uri (uri);
name = gnome_vfs_uri_extract_short_path_name (uri);
- handle->file_data = get_computer_data (unescaped_name, name);
- handle->file_size = strlen (handle->file_data);
+
+ handle = file_handle_new_from_desktop_file_contents (get_computer_data (unescaped_name, name));
+ *method_handle = (GnomeVFSMethodHandle *)handle;
+
g_free (unescaped_name);
g_free (name);
- *method_handle = (GnomeVFSMethodHandle *)handle;
-
- return GNOME_VFS_OK;
+ result = GNOME_VFS_OK;
+ goto out;
}
g_assert (type == SMB_URI_SHARE_FILE);
@@ -1531,16 +1830,16 @@
} else {
if (mode & GNOME_VFS_OPEN_WRITE)
unix_mode = O_WRONLY;
- else
- return GNOME_VFS_ERROR_INVALID_OPEN_MODE;
+ else {
+ result = GNOME_VFS_ERROR_INVALID_OPEN_MODE;
+ goto out;
+ }
}
if ((mode & GNOME_VFS_OPEN_TRUNCATE) ||
(!(mode & GNOME_VFS_OPEN_RANDOM) && (mode & GNOME_VFS_OPEN_WRITE)))
unix_mode |= O_TRUNC;
- path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
-
LOCK_SMB();
init_authentication (&actx, uri);
@@ -1548,14 +1847,15 @@
while (perform_authentication (&actx) > 0) {
file = smb_context->open (smb_context, path, unix_mode, 0666);
actx.res = (file != NULL) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->open(\"%s\") returned file %p and error %d\n", path, file, (int) actx.res));
}
UNLOCK_SMB();
- g_free (path);
-
- if (file == NULL)
+ if (file == NULL) {
+ DEBUG_OUT ();
return actx.res;
+ }
handle = g_new (FileHandle, 1);
handle->is_data = FALSE;
@@ -1563,7 +1863,14 @@
*method_handle = (GnomeVFSMethodHandle *)handle;
- return GNOME_VFS_OK;
+ result = GNOME_VFS_OK;
+
+ out:
+
+ g_free (path);
+
+ DEBUG_OUT ();
+ return result;
}
static GnomeVFSResult
@@ -1577,6 +1884,7 @@
GnomeVFSResult res;
int r;
+ DEBUG_IN ();
DEBUG_SMB(("do_close()\n"));
res = GNOME_VFS_OK;
@@ -1595,6 +1903,7 @@
r = smb_context->close_fn (smb_context, handle->file);
#endif
actx.res = (r >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->close(%p) returned error %d\n", handle->file, (int) actx.res));
}
res = actx.res;
@@ -1602,6 +1911,7 @@
}
g_free (handle);
+ DEBUG_OUT ();
return res;
}
@@ -1618,6 +1928,7 @@
SmbAuthContext actx;
ssize_t n = 0;
+ DEBUG_IN ();
DEBUG_SMB(("do_read() %Lu bytes\n", num_bytes));
if (handle->is_data) {
@@ -1643,11 +1954,14 @@
*bytes_read = (n < 0) ? 0 : n;
- if (n == 0)
+ if (n == 0) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_EOF;
+ }
handle->offset += n;
+ DEBUG_OUT ();
return res;
}
@@ -1665,10 +1979,13 @@
SmbAuthContext actx;
ssize_t written = 0;
+ DEBUG_IN ();
DEBUG_SMB (("do_write() %p\n", method_handle));
- if (handle->is_data)
+ if (handle->is_data) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_READ_ONLY;
+ }
LOCK_SMB();
init_authentication (&actx, NULL);
@@ -1682,6 +1999,7 @@
UNLOCK_SMB();
*bytes_written = (written < 0) ? 0 : written;
+ DEBUG_OUT ();
return actx.res;
}
@@ -1700,30 +2018,39 @@
SMBCFILE *file = NULL;
FileHandle *handle;
SmbAuthContext actx;
-
+
+ DEBUG_IN ();
DEBUG_SMB (("do_create() %s mode %d\n",
gnome_vfs_uri_to_string (uri, 0), mode));
type = smb_uri_type (uri);
- if (type == SMB_URI_ERROR)
+ if (type == SMB_URI_ERROR) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_INVALID_URI;
+ }
if (type == SMB_URI_WHOLE_NETWORK ||
type == SMB_URI_WORKGROUP ||
type == SMB_URI_SERVER ||
- type == SMB_URI_SHARE)
+ type == SMB_URI_SHARE) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_IS_DIRECTORY;
+ }
if (type == SMB_URI_WORKGROUP_LINK ||
- type == SMB_URI_SERVER_LINK)
+ type == SMB_URI_SERVER_LINK) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_PERMITTED;
+ }
unix_mode = O_CREAT | O_TRUNC;
- if (!(mode & GNOME_VFS_OPEN_WRITE))
+ if (!(mode & GNOME_VFS_OPEN_WRITE)) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_INVALID_OPEN_MODE;
+ }
if (mode & GNOME_VFS_OPEN_READ)
unix_mode |= O_RDWR;
@@ -1742,24 +2069,44 @@
while (perform_authentication (&actx) > 0) {
file = smb_context->open (smb_context, path, unix_mode, perm);
actx.res = (file != NULL) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->open(\"%s\") returned file %p and error %d\n", path, file, (int) actx.res));
}
UNLOCK_SMB();
g_free (path);
- if (file == NULL)
+ if (file == NULL) {
+ DEBUG_OUT ();
return actx.res;
+ }
handle = g_new (FileHandle, 1);
handle->is_data = FALSE;
handle->file = file;
*method_handle = (GnomeVFSMethodHandle *)handle;
-
+
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
+static void
+set_file_info_to_readonly_desktop_file (GnomeVFSFileInfo *file_info, GnomeVFSURI *uri)
+{
+ file_info->name = get_base_from_uri (uri);
+ file_info->valid_fields = file_info->valid_fields
+ | GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
+ | GNOME_VFS_FILE_INFO_FIELDS_TYPE
+ | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
+ file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
+ file_info->mime_type = g_strdup ("application/x-desktop");
+ file_info->permissions =
+ GNOME_VFS_PERM_USER_READ |
+ GNOME_VFS_PERM_OTHER_READ |
+ GNOME_VFS_PERM_GROUP_READ;
+}
+
static GnomeVFSResult
do_get_file_info (GnomeVFSMethod *method,
GnomeVFSURI *uri,
@@ -1774,19 +2121,34 @@
const char *mime_type;
SmbAuthContext actx;
+ DEBUG_IN ();
DEBUG_SMB (("do_get_file_info() %s\n",
gnome_vfs_uri_to_string (uri, 0)));
type = smb_uri_type (uri);
if (type == SMB_URI_ERROR) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_INVALID_URI;
}
+
+ path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
+
+ if (is_printer (path)) {
+ DEBUG_SMB (("is a printer we already saw; will fill in info\n"));
+
+ set_file_info_to_readonly_desktop_file (file_info, uri);
+ g_free (path);
+
+ DEBUG_OUT ();
+ return GNOME_VFS_OK;
+ }
if (type == SMB_URI_WHOLE_NETWORK ||
type == SMB_URI_WORKGROUP ||
type == SMB_URI_SERVER ||
type == SMB_URI_SHARE) {
+ DEBUG_SMB (("is whole network, workgroup, server, or share\n"));
file_info->name = get_base_from_uri (uri);
file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE |
GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
@@ -1807,29 +2169,22 @@
GNOME_VFS_PERM_OTHER_READ |
GNOME_VFS_PERM_GROUP_READ;
}
+ DEBUG_OUT();
return GNOME_VFS_OK;
}
if (type == SMB_URI_WORKGROUP_LINK ||
type == SMB_URI_SERVER_LINK) {
- file_info->name = get_base_from_uri (uri);
- file_info->valid_fields = file_info->valid_fields
- | GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
- | GNOME_VFS_FILE_INFO_FIELDS_TYPE
- | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
- file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
- file_info->mime_type = g_strdup ("application/x-desktop");
- file_info->permissions =
- GNOME_VFS_PERM_USER_READ |
- GNOME_VFS_PERM_OTHER_READ |
- GNOME_VFS_PERM_GROUP_READ;
+ DEBUG_SMB (("is workgroup link, or server link\n"));
+ set_file_info_to_readonly_desktop_file (file_info, uri);
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
g_assert (type == SMB_URI_SHARE_FILE);
-
- path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
+ DEBUG_SMB (("is share file\n"));
+
LOCK_SMB();
init_authentication (&actx, uri);
@@ -1837,14 +2192,17 @@
while (perform_authentication (&actx) > 0) {
err = smb_context->stat (smb_context, path, &st);
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->stat(\"%s\") returned error %d\n", path, (int) actx.res));
}
UNLOCK_SMB();
g_free (path);
- if (err < 0)
+ if (err < 0) {
+ DEBUG_OUT ();
return actx.res;
+ }
gnome_vfs_stat_to_file_info (file_info, &st);
file_info->name = get_base_from_uri (uri);
@@ -1870,6 +2228,7 @@
file_info->name, type,
file_info->mime_type, file_info->type));
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -1885,6 +2244,7 @@
struct stat st;
int err = -1;
+ DEBUG_IN ();
LOCK_SMB();
init_authentication (&actx, NULL);
@@ -1892,17 +2252,22 @@
while (perform_authentication (&actx) > 0) {
err = smb_context->fstat (smb_context, handle->file, &st);
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->fstat(%p) returned error %d\n", handle->file, (int) actx.res));
}
UNLOCK_SMB();
- if (err < 0)
+ if (err < 0) {
+ DEBUG_OUT ();
return actx.res;
+ }
gnome_vfs_stat_to_file_info (file_info, &st);
file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE;
file_info->io_block_size = SMB_BLOCK_SIZE;
+
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -1910,7 +2275,19 @@
do_is_local (GnomeVFSMethod *method,
const GnomeVFSURI *uri)
{
- return FALSE;
+ char *path;
+ gboolean is_local;
+
+ /* FIXME: This is a hack. In get_printer_data(), we generate data for a desktop item. This item
+ * is a "Type=Application" launcher, which launches gnome-cups-add. However, since we can't execute
+ * .desktop files from remote sites, we only advertise that printers "are local files".
+ */
+
+ path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
+ is_local = is_printer (path);
+ g_free (path);
+
+ return is_local;
}
typedef struct {
@@ -1948,6 +2325,7 @@
SMBCFILE *dir = NULL;
SmbAuthContext actx;
+ DEBUG_IN ();
DEBUG_SMB(("do_open_directory() %s\n",
gnome_vfs_uri_to_string (uri, 0)));
@@ -1959,12 +2337,14 @@
directory_handle = g_new0 (DirectoryHandle, 1);
g_hash_table_foreach (workgroups, add_workgroup, directory_handle);
*method_handle = (GnomeVFSMethodHandle *) directory_handle;
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
if (type == SMB_URI_ERROR ||
type == SMB_URI_WORKGROUP_LINK ||
type == SMB_URI_SERVER_LINK) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_A_DIRECTORY;
}
@@ -1973,11 +2353,22 @@
host_name = gnome_vfs_uri_get_host_name (uri);
if (type == SMB_URI_WORKGROUP && host_name != NULL &&
!g_ascii_strcasecmp(host_name, DEFAULT_WORKGROUP_NAME)) {
+ char *new_workgroup;
+
new_uri = gnome_vfs_uri_dup (uri);
- gnome_vfs_uri_set_host_name (new_uri,
- smb_context->workgroup
- ? smb_context->workgroup
- : "WORKGROUP");
+ if (smb_context->workgroup)
+ new_workgroup = smb_context->workgroup;
+ else
+ new_workgroup = "WORKGROUP";
+
+ DEBUG_SMB (("we are being asked for %s; substituting it for workgroup \"%s\"%s\n",
+ DEFAULT_WORKGROUP_NAME,
+ new_workgroup,
+ (smb_context->workgroup
+ ? " because that is what was in the smbcctx->workgroup"
+ : " because smbcctx->workgroup=NULL, so we use this as a last resort")));
+
+ gnome_vfs_uri_set_host_name (new_uri, new_workgroup);
uri = new_uri;
}
@@ -1992,6 +2383,7 @@
while (perform_authentication (&actx) > 0) {
dir = smb_context->opendir (smb_context, path);
actx.res = (dir != NULL) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->opendir(\"%s\") returned dir %p and error %d\n", path, dir, (int) actx.res));
}
UNLOCK_SMB();
@@ -2001,6 +2393,7 @@
if (dir == NULL) {
g_free (path);
+ DEBUG_OUT ();
return actx.res;
}
@@ -2010,6 +2403,7 @@
directory_handle->path = path;
*method_handle = (GnomeVFSMethodHandle *) directory_handle;
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -2024,10 +2418,13 @@
GList *l;
int err = -1;
+ DEBUG_IN ();
DEBUG_SMB(("do_close_directory: %p\n", directory_handle));
- if (directory_handle == NULL)
+ if (directory_handle == NULL) {
+ DEBUG_OUT ();
return GNOME_VFS_OK;
+ }
if (directory_handle->workgroups != NULL) {
for (l = directory_handle->workgroups; l != NULL; l = l->next) {
@@ -2046,6 +2443,7 @@
while (perform_authentication (&actx) > 0) {
err = smb_context->closedir (smb_context, directory_handle->dir);
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->closedir(%p) returned error %d\n", directory_handle->dir, (int) actx.res));
}
res = actx.res;
@@ -2054,9 +2452,46 @@
g_free (directory_handle->path);
g_free (directory_handle);
+ DEBUG_OUT ();
return res;
}
+static char *
+make_path_from_uri_and_name (const char *path, const char *name)
+{
+ char *escaped_name;
+ char *new_path;
+
+ escaped_name = gnome_vfs_escape_string (name);
+
+ if (path[strlen(path) - 1] == '/') {
+ new_path = g_strconcat (path, escaped_name, NULL);
+ } else {
+ new_path = g_strconcat (path, "/", escaped_name, NULL);
+ }
+
+ g_free (escaped_name);
+
+ return new_path;
+}
+
+static void
+add_printer_to_hash (DirectoryHandle *dh,
+ GnomeVFSFileInfo *file_info)
+{
+ char *path;
+
+ path = make_path_from_uri_and_name (dh->path, file_info->name);
+
+ g_hash_table_insert (printer_hash, path, path);
+}
+
+static gboolean
+is_printer (const char *uri)
+{
+ return g_hash_table_lookup (printer_hash, uri) != NULL;
+}
+
static GnomeVFSResult
do_read_directory (GnomeVFSMethod *method,
GnomeVFSMethodHandle *method_handle,
@@ -2068,14 +2503,15 @@
SmbAuthContext actx;
struct stat st;
char *statpath;
- char *path;
int r = -1;
GList *l;
+ DEBUG_IN ();
DEBUG_SMB (("do_read_directory()\n"));
if (dh->dir == NULL) {
if (dh->workgroups == NULL) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_EOF;
} else {
/* workgroup link */
@@ -2089,6 +2525,7 @@
| GNOME_VFS_FILE_INFO_FIELDS_TYPE;
file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
file_info->mime_type = g_strdup ("application/x-desktop");
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
}
@@ -2112,16 +2549,20 @@
} else {
actx.res = GNOME_VFS_OK;
}
+ DEBUG_SMB(("ctx->readdir(%p) returned entry %p and error %d\n", dh->dir, entry, (int) actx.res));
}
if (entry == NULL) {
UNLOCK_SMB();
+ DEBUG_OUT ();
return actx.res;
}
} while (entry->smbc_type == SMBC_COMMS_SHARE ||
entry->smbc_type == SMBC_IPC_SHARE ||
+#if 0
entry->smbc_type == SMBC_PRINTER_SHARE ||
+#endif
entry->name == NULL ||
strlen (entry->name) == 0 ||
(entry->smbc_type == SMBC_FILE_SHARE &&
@@ -2151,29 +2592,24 @@
file_info->mime_type = g_strdup ("application/x-desktop");
break;
case SMBC_PRINTER_SHARE:
+#if 0
/* Ignored above for now */
+#endif
file_info->valid_fields = file_info->valid_fields
| GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
| GNOME_VFS_FILE_INFO_FIELDS_TYPE;
file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
- file_info->mime_type = g_strdup ("application/x-smb-printer");
+ file_info->mime_type = g_strdup ("application/x-desktop"); /* we'll generate the fake .desktop in do_open() */
+ add_printer_to_hash (dh, file_info);
+ debug_print ("GOT PRINTER: \"%s\"", file_info->name);
+ break;
case SMBC_COMMS_SHARE:
case SMBC_IPC_SHARE:
break;
case SMBC_DIR:
case SMBC_FILE:
- path = dh->path;
-
- if (path[strlen(path)-1] == '/') {
- statpath = g_strconcat (path,
- gnome_vfs_escape_string (file_info->name),
- NULL);
- } else {
- statpath = g_strconcat (path,
- "/",
- gnome_vfs_escape_string (file_info->name),
- NULL);
- }
+ statpath = make_path_from_uri_and_name (dh->path, file_info->name);
+
/* TODO: might give an auth error, but should be rare due
to the succeeding opendir. If this happens and we can't
auth, we should terminate the readdir to avoid multiple
@@ -2187,6 +2623,7 @@
while (perform_authentication (&actx) > 0) {
r = smb_context->stat (smb_context, statpath, &st);
actx.res = (r == 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->stat(\"%s\") returned error %d\n", statpath, (int) actx.res));
}
UNLOCK_SMB();
@@ -2221,6 +2658,7 @@
g_assert_not_reached ();
}
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -2236,6 +2674,8 @@
int meth_whence;
off_t ret = (off_t) -1;
+ DEBUG_IN ();
+
if (handle->is_data) {
switch (whence) {
case GNOME_VFS_SEEK_START:
@@ -2252,8 +2692,11 @@
}
break;
default:
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
+
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -2268,6 +2711,7 @@
meth_whence = SEEK_END;
break;
default:
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
@@ -2280,7 +2724,8 @@
actx.res = (ret != (off_t) -1) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
}
UNLOCK_SMB();
-
+
+ DEBUG_OUT ();
return actx.res;
}
@@ -2293,8 +2738,11 @@
SmbAuthContext actx;
off_t ret = (off_t) -1;
+ DEBUG_IN ();
+
if (handle->is_data) {
*offset_return = handle->offset;
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -2309,6 +2757,8 @@
UNLOCK_SMB();
*offset_return = (ret == (off_t) -1) ? 0 : (GnomeVFSFileOffset) ret;
+
+ DEBUG_OUT ();
return actx.res;
}
@@ -2321,12 +2771,14 @@
SmbAuthContext actx;
int type, err = -1;
+ DEBUG_IN ();
DEBUG_SMB (("do_unlink() %s\n",
gnome_vfs_uri_to_string (uri, 0)));
type = smb_uri_type (uri);
if (type == SMB_URI_ERROR) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_INVALID_URI;
}
@@ -2336,6 +2788,7 @@
type == SMB_URI_SHARE ||
type == SMB_URI_WORKGROUP_LINK ||
type == SMB_URI_SERVER_LINK) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_PERMITTED;
}
@@ -2348,12 +2801,14 @@
while (perform_authentication (&actx) > 0) {
err = smb_context->unlink (smb_context, path);
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->unlink(\"%s\") returned error %d\n", path, (int) actx.res));
}
UNLOCK_SMB();
g_free (path);
-
+
+ DEBUG_OUT ();
return actx.res;
}
@@ -2370,6 +2825,7 @@
char *path2;
char *p1, *p2;
+ DEBUG_IN ();
DEBUG_SMB (("do_check_same_fs()\n"));
server1 =
@@ -2390,6 +2846,7 @@
g_free (path1);
g_free (path2);
*same_fs_return = FALSE;
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -2418,6 +2875,7 @@
g_free (path1);
g_free (path2);
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -2434,7 +2892,7 @@
SmbAuthContext actx;
int old_type, new_type;
-
+ DEBUG_IN ();
DEBUG_SMB (("do_move() %s %s\n",
gnome_vfs_uri_to_string (old_uri, 0),
gnome_vfs_uri_to_string (new_uri, 0)));
@@ -2444,6 +2902,7 @@
if (old_type != SMB_URI_SHARE_FILE ||
new_type != SMB_URI_SHARE_FILE) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_PERMITTED;
}
@@ -2461,6 +2920,7 @@
err = smb_context->rename (smb_context, old_path, smb_context, new_path);
errnox = errno;
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->rename(\"%s\", \"%s\") returned error %d\n", old_path, new_path, (int) actx.res));
}
UNLOCK_SMB();
@@ -2477,6 +2937,7 @@
while (perform_authentication (&actx) > 0) {
err = smb_context->unlink (smb_context, new_path);
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->unlink(\"%s\") returned error %d\n", new_path, (int) actx.res));
}
UNLOCK_SMB();
@@ -2493,6 +2954,7 @@
g_free (old_path);
g_free (new_path);
+ DEBUG_OUT ();
return actx.res;
}
@@ -2517,9 +2979,11 @@
int type, err = -1;
SmbAuthContext actx;
+ DEBUG_IN ();
type = smb_uri_type (uri);
if (type == SMB_URI_ERROR) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_INVALID_URI;
}
@@ -2529,6 +2993,7 @@
type == SMB_URI_SHARE ||
type == SMB_URI_WORKGROUP_LINK ||
type == SMB_URI_SERVER_LINK) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_PERMITTED;
}
@@ -2542,12 +3007,14 @@
while (perform_authentication (&actx) > 0) {
err = smb_context->mkdir (smb_context, path, perm);
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->mkdir(\"%s\") returned error %d\n", path, (int) actx.res));
}
UNLOCK_SMB();
g_free (path);
+ DEBUG_OUT ();
return actx.res;
}
@@ -2560,9 +3027,11 @@
int err = -1, type;
SmbAuthContext actx;
+ DEBUG_IN ();
type = smb_uri_type (uri);
if (type == SMB_URI_ERROR) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_INVALID_URI;
}
@@ -2572,6 +3041,7 @@
type == SMB_URI_SHARE ||
type == SMB_URI_WORKGROUP_LINK ||
type == SMB_URI_SERVER_LINK) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_PERMITTED;
}
@@ -2584,11 +3054,13 @@
while (perform_authentication (&actx) > 0) {
err = smb_context->rmdir (smb_context, path);
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->rmdir(\"%s\") returned error %d\n", path, (int) actx.res));
}
UNLOCK_SMB();
g_free (path);
+ DEBUG_OUT ();
return actx.res;
}
@@ -2603,11 +3075,13 @@
int err = -1, errnox = 0, type;
SmbAuthContext actx;
+ DEBUG_IN ();
DEBUG_SMB (("do_set_file_info: mask %x\n", mask));
type = smb_uri_type (uri);
if (type == SMB_URI_ERROR) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_INVALID_URI;
}
@@ -2617,6 +3091,7 @@
type == SMB_URI_SHARE ||
type == SMB_URI_WORKGROUP_LINK ||
type == SMB_URI_SERVER_LINK) {
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_PERMITTED;
}
@@ -2640,6 +3115,7 @@
err = smb_context->rename (smb_context, path, smb_context, new_path);
errnox = errno;
actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+ DEBUG_SMB(("ctx->rename(\"%s\", \"%s\") returned error %d\n", path, new_path, (int) actx.res));
}
UNLOCK_SMB();
@@ -2652,31 +3128,37 @@
if (actx.res != GNOME_VFS_OK) {
g_free (path);
+ DEBUG_OUT ();
return actx.res;
}
}
if (gnome_vfs_context_check_cancellation (context)) {
g_free (path);
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_CANCELLED;
}
if (mask & GNOME_VFS_SET_FILE_INFO_PERMISSIONS) {
g_free (path);
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
if (mask & GNOME_VFS_SET_FILE_INFO_OWNER) {
g_free (path);
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
if (mask & GNOME_VFS_SET_FILE_INFO_TIME) {
g_free (path);
+ DEBUG_OUT ();
return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
g_free (path);
+ DEBUG_OUT ();
return GNOME_VFS_OK;
}
@@ -2708,11 +3190,50 @@
NULL /* do_create_symbolic_link */
};
+static void
+debug_init (void)
+{
+ char *debug_flag_path;
+ struct stat st;
+
+ LOCK_SMB ();
+
+ debug_flag_path = g_build_filename (g_get_home_dir (), ".debug-gnome-vfs-smb", NULL);
+
+ if (stat (debug_flag_path, &st) == 0) {
+ char *debug_filename;
+
+ debug_filename = g_build_filename (g_get_home_dir (), "debug-gnome-vfs-smb.log", NULL);
+ debug_file = fopen (debug_filename, "w");
+ g_free (debug_filename);
+ } else
+ debug_file = NULL;
+
+ g_free (debug_flag_path);
+
+ UNLOCK_SMB ();
+}
+
+static void
+debug_shutdown (void)
+{
+ LOCK_SMB ();
+
+ if (debug_file) {
+ fclose (debug_file);
+ debug_file = NULL;
+ }
+
+ UNLOCK_SMB ();
+}
+
GnomeVFSMethod *
vfs_module_init (const char *method_name, const char *args)
{
smb_lock = g_mutex_new ();
+ debug_init ();
+
DEBUG_SMB (("<-- smb module init called -->\n"));
if (try_init ()) {
@@ -2735,9 +3256,12 @@
g_hash_table_destroy (server_cache);
g_hash_table_destroy (workgroups);
g_hash_table_destroy (user_cache);
+ g_hash_table_destroy (printer_hash);
g_mutex_free (smb_lock);
DEBUG_SMB (("<-- smb module shutdown called -->\n"));
+
+ debug_shutdown ();
}