Index: gvfs-1.3.3/configure.ac =================================================================== --- gvfs-1.3.3.orig/configure.ac +++ gvfs-1.3.3/configure.ac @@ -53,6 +53,10 @@ PKG_CHECK_MODULES(DBUS, dbus-1) AC_SUBST(DBUS_CFLAGS) AC_SUBST(DBUS_LIBS) +PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1) +AC_SUBST(DBUS_GLIB_CFLAGS) +AC_SUBST(DBUS_GLIB_LIBS) + AC_ARG_WITH(dbus_service_dir, [ --with-dbus-service-dir=PATH choose directory for dbus service files, [default=PREFIX/share/dbus-1/services]], with_dbus_service_dir="$withval", with_dbus_service_dir=$datadir/dbus-1/services) DBUS_SERVICE_DIR=$with_dbus_service_dir AC_SUBST(DBUS_SERVICE_DIR) Index: gvfs-1.3.3/daemon/dice.mount.in =================================================================== --- /dev/null +++ gvfs-1.3.3/daemon/dice.mount.in @@ -0,0 +1,6 @@ +[Mount] +Type=dice +Exec=@libexecdir@/gvfsd-dice +AutoMount=true +DBusName=org.gtk.vfs.mountpoint.dice + Index: gvfs-1.3.3/daemon/gvfsbackenddice.c =================================================================== --- /dev/null +++ gvfs-1.3.3/daemon/gvfsbackenddice.c @@ -0,0 +1,1989 @@ +/* Novell DICE Backend for GVfs + * + * Copyright (C) 2008 Novell, 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: Boyd Timothy + * Brady Anderson + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "gvfsbackenddice.h" +#include "gvfsmonitor.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 "gvfsjobdelete.h" +#include "gvfsjobqueryfsinfo.h" +#include "gvfsjobqueryattributes.h" +#include "gvfsjobenumerate.h" +#include "gvfsjobcreatemonitor.h" +#include "gvfsdaemonprotocol.h" +#include "gvfsdaemonutils.h" + +#define G_FILE_ATTRIBUTE_DICE_LOCAL_PATH "dice::local-path" +#define G_FILE_ATTRIBUTE_DICE_ID "dice::id" + +static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2); +static void lose_gerror (const char *prefix, GError *error) G_GNUC_NORETURN; +static GFileInfo *create_file_info_from_dbus_array(GValueArray *array_obj); + +struct _GVfsBackendDice +{ + GVfsBackend parent_instance; + DBusGConnection *dbus_connection; + DBusGProxy *dice_proxy; + + GMountSpec *mount_spec; + GList *top_files; /* Files in toplevel dir */ + guint num_top_files; +}; + +struct DiceHandle +{ + char *file_path; + GFileInputStream *input_stream; + GFileOutputStream *output_stream; +} *PDiceHandle; + +G_DEFINE_TYPE (GVfsBackendDice, g_vfs_backend_dice, G_VFS_TYPE_BACKEND) + +#define DBUS_STRUCT_STRING_STRING_STRING (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID)) + +static void +g_vfs_backend_dice_init (GVfsBackendDice *ice_backend) +{ + g_print ("(dice) g_vfs_backend_dice_init \n"); + GVfsBackendDice *backend = G_VFS_BACKEND_DICE (ice_backend); + backend->dbus_connection = NULL; + + DBusGConnection *connection; + GError *error; + DBusGProxy *dice_proxy; + + g_printf(" (dice) connecting to the ICE Daemon via DBus...\n"); + + error = NULL; + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (connection == NULL) + { + g_printerr ( + "Failed to open connection to bus: %s\n", + error->message); + g_error_free (error); + exit (1); + } + + g_printf(" (dice) got a connection to the session bus\n"); + backend->dbus_connection = connection; + + dice_proxy = + dbus_g_proxy_new_for_name ( + backend->dbus_connection, + "Novell.ICEDesktop.Daemon", + "/Novell/ICEDesktop/Daemon", + "Novell.ICEDesktop.Daemon"); + + gboolean ping_successful; + error = NULL; + if (!dbus_g_proxy_call ( + dice_proxy, + "Ping", + &error, + G_TYPE_INVALID, // Input params + G_TYPE_BOOLEAN, + &ping_successful, // Output params + G_TYPE_INVALID)) + { + lose_gerror ("Could not ping the DICE Daemon", error); + exit (-1); + } + + g_printf (" (dice) connected to the DICE Daemon.\n"); + backend->dice_proxy = dice_proxy; +} + +static void +g_vfs_backend_dice_finalize (GObject *object) +{ + GVfsBackendDice *dice; + + dice = G_VFS_BACKEND_DICE (object); + g_mount_spec_unref (dice->mount_spec); + + if (G_OBJECT_CLASS (g_vfs_backend_dice_parent_class)->finalize) + (*G_OBJECT_CLASS (g_vfs_backend_dice_parent_class)->finalize) (object); +} + +/********************* + * Utility Functions * + *********************/ + + +static void +lose (const char *str, ...) +{ + va_list args; + va_start (args, str); + + vfprintf (stderr, str, args); + fputc ('\n', stderr); + + va_end (args); + exit (1); +} + + +static void +lose_gerror (const char *prefix, GError *error) +{ + lose ("%s: %s", prefix, error->message); +} + + +/** + * Caller must free using g_free () if not NULL return. + */ +/* +static char * +get_last_path_component (const char *path) +{ + if (path == NULL) + return NULL; + + g_printf (" (ice) get_last_path_component (%s)\n", path); + char *parsable_path = g_strdup (path); + char *path_component = NULL; + char *last_component = strtok (parsable_path, "/"); + if (last_component != NULL) + { + while ((path_component = strtok (NULL, "/")) != NULL) + { + // Intentionally blank. Tokenize until we've reached + // the last token. + last_component = path_component; + } + + // Make a copy of the last component + last_component = g_strdup (last_component); + } + + g_free (parsable_path); + + g_printf(" (ice) get_last_path_component () returning -> '%s'\n", last_component == NULL ? "(null)" : last_component); + + return last_component; +} +*/ + + +/* +G_IO_ERROR_FAILED, EIO }, + { G_IO_ERROR_NOT_FOUND, ENOENT }, + { G_IO_ERROR_EXISTS, EEXIST }, + { G_IO_ERROR_IS_DIRECTORY, EISDIR }, + { G_IO_ERROR_NOT_DIRECTORY, ENOTDIR }, + { G_IO_ERROR_NOT_EMPTY, ENOTEMPTY }, + { G_IO_ERROR_NOT_REGULAR_FILE, EIO }, + { G_IO_ERROR_NOT_SYMBOLIC_LINK, EIO }, + { G_IO_ERROR_NOT_MOUNTABLE_FILE, EIO }, + { G_IO_ERROR_FILENAME_TOO_LONG, ENAMETOOLONG }, + { G_IO_ERROR_INVALID_FILENAME, EIO }, + { G_IO_ERROR_TOO_MANY_LINKS, ELOOP }, + { G_IO_ERROR_NO_SPACE, ENOSPC }, + { G_IO_ERROR_INVALID_ARGUMENT, EINVAL }, + { G_IO_ERROR_PERMISSION_DENIED, EACCES }, + { G_IO_ERROR_NOT_SUPPORTED, ENOTSUP }, + { G_IO_ERROR_NOT_MOUNTED, EIO }, + { G_IO_ERROR_ALREADY_MOUNTED, EIO }, + { G_IO_ERROR_CLOSED, EIO }, + { G_IO_ERROR_CANCELLED, EIO }, + { G_IO_ERROR_PENDING, EIO }, + { G_IO_ERROR_READ_ONLY, EACCES }, + { G_IO_ERROR_CANT_CREATE_BACKUP, EIO }, + { G_IO_ERROR_WRONG_ETAG, EIO }, + { G_IO_ERROR_TIMED_OUT, EIO }, + { G_IO_ERROR_BUSY, EBUSY }, + { -1, -1 } +*/ + +// Method to convert all DICE Exceptions to an +// equivalent GIO_ERROR. +// The Exception class is returned and contained +// in the error->message field. +GError * convert_dice_error_to_gio_status (GError *dice_error) +{ + GError *error; + + if (strstr (dice_error->message, "PathNotFoundException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("No such file or directory")); + } + else if (strstr (dice_error->message, "NoEntriesException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("No such file or directory")); + } + else if (strstr (dice_error->message, "NoWorkspacesException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("No such file or directory")); + } + else if (strstr (dice_error->message, "NoFoldersException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("No such file or directory")); + } + else if (strstr (dice_error->message, "NoFolderEntriesException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("No such file or directory")); + } + else if (strstr (dice_error->message, "NoFileEntriesException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("No such file or directory")); + } + else if (strstr (dice_error->message, "FolderNotFoundException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("No such file or directory")); + } + else if (strstr (dice_error->message, "FileNotFoundException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("No such file or directory")); + } + else if (strstr (dice_error->message, "NotAFolderException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_DIRECTORY, + _("is not a directory")); + error->code = G_IO_ERROR_NOT_DIRECTORY; + } + else if (strstr (dice_error->message, "NotAFileException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_REGULAR_FILE, + _("is not a file")); + } + else if (strstr (error->message, "NotAuthenticatedException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED, + _("Access denied")); + } + else if (strstr (dice_error->message, "FailedAuthenticationException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED, + _("Access denied")); + } + else if (strstr (dice_error->message, "DiskFullException") != NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NO_SPACE, + _("No available space")); + } + else + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("General failure")); + } + + return error; +} + +static GFileInfo * +create_file_info_from_dbus_array (GValueArray *array_obj) +{ + g_printf (" *** create_file_info_from_dbus_array () ***\n"); + + if (array_obj == NULL) return NULL; + + GFileInfo *info = g_file_info_new (); + + GValue *file_id = g_value_array_get_nth (array_obj, 0); + GValue *file_display_name = g_value_array_get_nth (array_obj, 1); + GValue *file_path = g_value_array_get_nth (array_obj, 2); + GValue *file_local_path = g_value_array_get_nth (array_obj, 3); + GValue *file_type = g_value_array_get_nth (array_obj, 4); + GValue *mime_type = g_value_array_get_nth (array_obj, 5); + GValue *file_access_mask = g_value_array_get_nth (array_obj, 6); + GValue *creation_time = g_value_array_get_nth (array_obj, 7); + GValue *last_access_time = g_value_array_get_nth (array_obj, 8); + GValue *last_modified_time = g_value_array_get_nth (array_obj, 9); + GValue *size = g_value_array_get_nth (array_obj, 10); + GValue *hidden = g_value_array_get_nth (array_obj, 11); + + g_printf (" *** read a file info ***\n"); + g_printf ("\t ID: %s\n", g_value_get_string (file_id)); + g_printf ("\t Display Name: %s\n", g_value_get_string (file_display_name)); + g_printf ("\t Path: %s\n", g_value_get_string (file_path)); + g_printf ("\t Local Path: %s\n", g_value_get_string (file_local_path)); + + struct tm *tmp_time; + char timestr[200]; + gint64 creationDateInSecondsFromEpoch = g_value_get_int64 (creation_time); + g_printf("timestamp: %lld\n", creationDateInSecondsFromEpoch); + tmp_time = localtime ((time_t *)&creationDateInSecondsFromEpoch); + if (strftime(timestr, sizeof (timestr), "%F %T", tmp_time) != 0) + { + g_printf ("\t\tCreation Time: %s\n", timestr); + } + + gint64 modifiedDateInSecondsFromEpoch = g_value_get_int64 (last_modified_time); + g_printf("timestamp: %lld\n", modifiedDateInSecondsFromEpoch); + tmp_time = localtime ((time_t *)&modifiedDateInSecondsFromEpoch); + if (strftime(timestr, sizeof (timestr), "%F %T", tmp_time) != 0) + { + g_printf ("\t\tModifed Time: %s\n", timestr); + } + + // Set the name, display name and the unique id + g_file_info_set_name (info, g_value_get_string (file_display_name)); + g_file_info_set_display_name (info, g_value_get_string (file_display_name)); + g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE, g_value_get_string (file_id)); + + switch (g_value_get_int (file_type)) + { + case 2: + case 3: + g_printf ("\t\tType: Directory\n"); + gvfs_file_info_populate_content_types (info, g_value_get_string (file_path), G_FILE_TYPE_DIRECTORY); + g_file_info_set_content_type (info, "inode/directory"); + g_file_info_set_size (info, 4096); + break; + + case 4: + g_printf ("\t\tType: Regular\n"); + gvfs_file_info_populate_content_types (info, g_value_get_string (file_path), G_FILE_TYPE_REGULAR); + + // Store the local path in the file info + g_printf ("\t\tLocal Path: %s\n", g_value_get_string (file_local_path)); + g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_DICE_LOCAL_PATH, g_value_get_string (file_local_path)); + + // File size + g_printf ("\t\tFile Size: %lu\n", g_value_get_uint64 (size)); + g_file_info_set_size (info, g_value_get_uint64 (size)); + + // Mime type + g_printf ("\t\tMime Type: %s\n", g_value_get_string (mime_type)); + g_file_info_set_content_type (info, g_value_get_string (mime_type)); + + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE); + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, TRUE); + //g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, TRUE); + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, TRUE); + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, TRUE); + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, TRUE); + + break; + + default: + g_printf ("\t\tType: Unknown\n"); + gvfs_file_info_populate_content_types (info, g_value_get_string (file_path), G_FILE_TYPE_UNKNOWN); + break; + } + + // File Access + +/* + uint access_mask = g_value_get_uint (file_access_mask); + g_printf ("\t Access: %X\n", access_mask); + if (access_mask & 1) // Read + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE); + else + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, FALSE); + + if (access_mask & 2) // Write + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, TRUE); + else + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE); + + if (access_mask & 4) // Execute + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, TRUE); + else + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, FALSE); + + if (access_mask & 8) // CanDelete + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, TRUE); + else + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE); + + if (access_mask & 16) // CanTrash + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, TRUE); + else + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE); + + if (access_mask && 32) // CanRename + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, TRUE); + else + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE); + */ + + // Set the creation and modified times + g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CREATED, creationDateInSecondsFromEpoch); + g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED, modifiedDateInSecondsFromEpoch); + + GTimeVal t; + t.tv_sec = modifiedDateInSecondsFromEpoch; + g_file_info_set_modification_time (info, &t); + + g_file_info_set_is_hidden (info, FALSE); + return info; +} + + +static void enumerate_workspaces ( + GVfsBackendDice *dice_backend, + GVfsJob *job) +{ + GPtrArray *files = NULL; + GFileInfo *info; + GError *dbus_error = NULL; + int dbus_status; + + g_print ("(dice) enumerate_workspaces - called"); + + // Read in all the workspaces + dbus_status = + dbus_g_proxy_call ( + dice_backend->dice_proxy, + "EnumerateWorkspaces", + &dbus_error, + // Input params (none) + G_TYPE_INVALID, + // Output params + dbus_g_type_get_collection ( + "GPtrArray", + dbus_g_type_get_struct ( + "GValueArray", + G_TYPE_STRING, // Id + G_TYPE_STRING, // Display Name + G_TYPE_STRING, // Path + G_TYPE_STRING, // Local Path + G_TYPE_INT, // File Type + G_TYPE_STRING, // Mime Type + G_TYPE_UINT, // Access Mask + G_TYPE_INT64, // Creation Time + G_TYPE_INT64, // Last Access Time + G_TYPE_INT64, // Last Modified Time + G_TYPE_UINT64, // Size + G_TYPE_BOOLEAN, // Hidden + G_TYPE_INVALID)), + &files, + G_TYPE_INVALID); + + g_print ("dbus_status: %d\n", dbus_status); + g_print ("dbus_error: 0x%X\n", dbus_error); + + if (dbus_status > 0 && dbus_error == NULL) + { + // You have to say succeeded before you add the infos + g_vfs_job_succeeded (G_VFS_JOB (job)); + + if (files != NULL) + { + int i; + for (i = 0; i < files->len; i++) + { + GValueArray *dbus_array_obj = g_ptr_array_index (files, i); + if (dbus_array_obj != NULL) + { + info = create_file_info_from_dbus_array (dbus_array_obj); + g_vfs_job_enumerate_add_info (job, info); + g_object_unref (info); + } + } + + g_ptr_array_free (files, TRUE); + } + + g_vfs_job_enumerate_done (job); + } + else + { + if (dbus_error != NULL) + { + if (strstr(dbus_error->message, "NoEntries") != NULL || + strstr (dbus_error->message, "NoWorkspaces") != NULL || + strstr (dbus_error->message, "NoFolders") != NULL || + strstr (dbus_error->message, "NoFiles") != NULL) + { + g_printf ("Hit the no more entries case"); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_vfs_job_enumerate_done (job); + } + else + { + g_vfs_job_failed ( + G_VFS_JOB (job), + G_IO_ERROR, + dbus_error->code, + dbus_error->message); + } + } + else + { + g_vfs_job_failed ( + G_VFS_JOB (job), + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Error enumerating a directory")); + + } + + g_error_free (dbus_error); + } + + g_print ("(dice) enumerate_workspaces. \n"); +} + + +/** + * ??? + * + * Note: The returned object should be freed by the caller. + */ +static GFileInfo* +get_g_file_info_from_dice ( + GVfsBackendDice *dice_backend, + const char *filename,// GFile *file, + const char *attributes, + GFileQueryInfoFlags flags, + GVfsJob *job, + GError **error) +{ + g_printf("*** get_g_file_info_from_dice ()\n"); + g_printf("\tfilename: %s\n", filename); + GError *dbus_error = NULL; + GFileInfo *info = NULL; + GValueArray *dbus_file_info = NULL; + + if (strlen (filename) == 1 && filename [0] == '/') + { + // This is the top-level item that will appear in + // Nautilus' sidebar as one of the "Places". + info = g_file_info_new (); + g_file_info_set_name (info, "/"); + g_file_info_set_display_name (info, _("DICE")); + g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY); + return info; + } + + // If we make it this far, we're dealing with either a + // workspace, a directory, or a file. Communicate via DBus + // to the DICE Daemon to determine the information for the + // given path. + if (dice_backend->dice_proxy == NULL) + { + *error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("No connection to the DICE daemon")); + + return NULL; + } + + if (!dbus_g_proxy_call ( + dice_backend->dice_proxy, + "GetFileByPath", + &dbus_error, + // Input Params + G_TYPE_STRING, + filename, + G_TYPE_INVALID, + // Output Params (struct of items) + dbus_g_type_get_struct ( + "GValueArray", + G_TYPE_STRING, // Id + G_TYPE_STRING, // Display Name + G_TYPE_STRING, // Path + G_TYPE_STRING, // Local Path + G_TYPE_INT, // File Type + G_TYPE_STRING, // Mime Type + G_TYPE_UINT, // Access Mask + G_TYPE_INT64, // Creation Time + G_TYPE_INT64, // Last Access Time + G_TYPE_INT64, // Last Modified Time + G_TYPE_UINT64, // Size + G_TYPE_BOOLEAN, // Hidden + G_TYPE_INVALID), + &dbus_file_info, + G_TYPE_INVALID)) + { + *error = convert_dice_error_to_gio_status (dbus_error); + g_error_free (dbus_error); + } + else + if (dbus_file_info != NULL) + { + info = create_file_info_from_dbus_array (dbus_file_info); + g_value_array_free (dbus_file_info); + } + + g_printf(" success - returning from get_g_file_info_from_dice\n"); + return info; +} + +// Caller must free the returned GFileInfo on success +static GFileInfo* +create_g_file_info_in_dice ( + GVfsBackendDice *ice_backend, + const char *filename, + GError **error) +{ + g_printf("*** create_g_file_info_in_dice ()\n"); + g_printf("\tfilename: %s\n", filename); + GFileInfo *info = NULL; + + GError *dbus_error = NULL; + if (ice_backend->dice_proxy == NULL) + { + if (*error != NULL) + *error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("No connection to the DICE daemon")); + + return NULL; + } + + GValueArray *dbus_file_info = NULL; + + if (!dbus_g_proxy_call ( + ice_backend->dice_proxy, + "CreateLocalFile", + &dbus_error, + // Input Params + G_TYPE_STRING, filename, G_TYPE_INVALID, + // Output Params (struct of items) + dbus_g_type_get_struct ( + "GValueArray", + G_TYPE_STRING, // Id + G_TYPE_STRING, // Display Name + G_TYPE_STRING, // Path + G_TYPE_STRING, // Local Path + G_TYPE_INT, // File Type + G_TYPE_STRING, // Mime Type + G_TYPE_UINT, // Access Mask + G_TYPE_INT64, // Creation Time + G_TYPE_INT64, // Last Access Time + G_TYPE_INT64, // Last Modified Time + G_TYPE_UINT64, // Size + G_TYPE_BOOLEAN, // Hidden + G_TYPE_INVALID), + &dbus_file_info, + G_TYPE_INVALID)) + { + if (strstr (dbus_error->message, "Exception:") != NULL) + { + g_printf ("Could not create file '%s': %s\n", filename, dbus_error->message); + dbus_file_info = NULL; + } + + // Convert the returned dice error to an equivalent GIO_ERROR + *error = convert_dice_error_to_gio_status (dbus_error); + g_error_free (dbus_error); + } + else + if (dbus_file_info != NULL) + { + info = create_file_info_from_dbus_array (dbus_file_info); + g_value_array_free (dbus_file_info); + } + + g_printf(" returning from create_g_file_info_in_dice ()\n"); + return info; +} + + +// Returns TRUE if the file was successfully deleted. +// If FALSE, the caller must free the GError that may be set. +static gboolean +delete_local_file_from_dice ( + GVfsBackendDice *dice_backend, + const char *filename, + GError **error) +{ + GError *dbus_error; + g_printf ("*** delete_local_file_from_dice ()\n"); + g_printf ("\tfilename: %s\n", filename); + + if (dice_backend->dice_proxy == NULL) + { + *error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("No connection to the DICE daemon")); + + return FALSE; + } + + if (error != NULL) *error = NULL; + + dbus_error = NULL; + if (!dbus_g_proxy_call ( + dice_backend->dice_proxy, + "DeleteLocalFile", + &dbus_error, + // Input Params + G_TYPE_STRING, + filename, + G_TYPE_INVALID, + G_TYPE_INVALID)) // Output Params (none) + { + if (strstr(dbus_error->message, "Exception:") != NULL) + { + g_printf ("Could not delete file '%s': %s\n", filename, dbus_error->message); + } + else + { + g_printf ("Could not delete the file '%s'\n", filename); + g_printf ("Received an unexpected dbus error: %s\n", dbus_error->message); + } + + *error = convert_dice_error_to_gio_status (dbus_error); + g_error_free (dbus_error); + return FALSE; + } + + g_printf(" success - returning from delete_local_file_from_dice ()\n"); + return TRUE; +} + + +// This should be called any time our provider modifies a +// file. Basically any time we close a file handle. Returns +// TRUE if the file was updated successfully. If FALSE, the +// caller must free the GError that may be set. +static gboolean +update_local_file_in_dice ( + GVfsBackendDice *dice_backend, + const char *filename, + GError **error) +{ + GError *dbus_error; + g_printf ("*** update_local_file_in_dice ()\n"); + g_printf ("\tfilename: %s\n", filename); + + if (dice_backend->dice_proxy == NULL) + { + *error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("No connection to the DICE daemon")); + + return FALSE; + } + + if (error != NULL) *error = NULL; + + dbus_error = NULL; + if (!dbus_g_proxy_call ( + dice_backend->dice_proxy, + "UpdateLocalFile", + &dbus_error, + // Input Params + G_TYPE_STRING, + filename, + G_TYPE_INVALID, + G_TYPE_INVALID)) // Output Params (none) + { + if (strstr(dbus_error->message, "Exception:") != NULL) + { + g_printf ("Could not update file '%s': %s\n", filename, dbus_error->message); + } + + *error = convert_dice_error_to_gio_status (dbus_error); + g_error_free (dbus_error); + return FALSE; + } + + g_printf(" success - returning from update_local_file_in_dice ()\n"); + return TRUE; +} + +// +// Procedure for calling DICE to retrieve +// file system information, creating a +// GFileInfo structure and populating it +// with the correct information. +// +// NOTE! The caller must free the returned +// GFileInfo data structure +// +static GFileInfo * +get_g_filesystem_info_from_dice ( + GVfsBackendDice *dice_backend, + GFile *file, + const char *attributes, + GCancellable *cancellable, + GError **error) +{ + GError *dbus_error; + GValueArray *dbus_filesystem_info = NULL; + + g_printf ("*** get_g_filesystem_info_from_dice ()\n"); + //g_printf ("\tfilename: %s\n", filename); + + if (dice_backend->dice_proxy == NULL) + { + *error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("No connection to the DICE daemon")); + + return NULL; + } + + if (error != NULL) *error = NULL; + + dbus_error = NULL; + + if (!dbus_g_proxy_call ( + dice_backend->dice_proxy, + "GetFileSystemInformation", + &dbus_error, + // Input Params + G_TYPE_STRING, + "/", + G_TYPE_INVALID, + // Output Params (struct of items) + dbus_g_type_get_struct ( + "GValueArray", + G_TYPE_STRING, // Label + G_TYPE_INT, // Attributes (RO,RW) + G_TYPE_INT64, // Total Size (in bytes) + G_TYPE_INT64, // Available Size (in bytes) + G_TYPE_INVALID), + &dbus_filesystem_info, + G_TYPE_INVALID)) + { + if (strstr(dbus_error->message, "Exception:") != NULL) + { + g_printf ("Could not get file system information '%s'\n", dbus_error->message); + } + else + { + g_printf ("Could not call DICE daemon's GetFileSystemInformation ()"); + g_printf ("Received an unexpected dbus error: %s\n", dbus_error->message); + } + + *error = convert_dice_error_to_gio_status (dbus_error); + g_error_free (dbus_error); + return NULL; + } + + GValue *label = g_value_array_get_nth (dbus_filesystem_info, 0); + GValue *fsattributes = g_value_array_get_nth (dbus_filesystem_info, 1); + GValue *total_space = g_value_array_get_nth (dbus_filesystem_info, 2); + GValue *available_space = g_value_array_get_nth (dbus_filesystem_info, 3); + + GFileInfo *info = g_file_info_new (); + if (g_value_get_int (fsattributes) == 1) + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE); + else + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, FALSE); + + gint64 total = 4000000000; + gint64 available = 3000000000; + + g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, total); + g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, available); +// g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, g_value_get_int64 (total_space)); +// g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, g_value_get_int64 (available_space)); + + g_value_array_free (dbus_filesystem_info); + return info; +} + + +/* returned object should be freed in user's function */ +static GFile* +get_g_file_from_local (const char *filename, GVfsJob *job) +{ + GVfs *local_vfs; + GFile *file = NULL; + + local_vfs = g_vfs_get_local (); + if (! local_vfs) + { + g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot get local vfs"); + g_print (" (EE) get_g_file_from_local (filename = '%s'): local_vfs == NULL \n", filename); + return NULL; + } + + file = g_vfs_get_file_for_path (local_vfs, filename); + if (! file) + { + g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot get file from local vfs"); + g_print (" (EE) get_g_file_from_local (filename = '%s'): file == NULL \n", filename); + return NULL; + } + return file; +} + + +/************ + * Mounting * + ************/ + +static void +do_mount ( + GVfsBackend *backend, + GVfsJobMount *job, + GMountSpec *mount_spec, + GMountSource *mount_source, + gboolean is_automount) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + + g_print ("(dice) do_mount \n"); + + g_vfs_backend_set_display_name (backend, _("My Spaces")); + + dice_backend->mount_spec = g_mount_spec_new ("dice"); + g_vfs_backend_set_mount_spec (backend, dice_backend->mount_spec); + + g_vfs_backend_set_icon_name (backend, "network-server"); + + g_vfs_job_succeeded (G_VFS_JOB (job)); +} + +static void +do_unmount (GVfsBackend *backend, GVfsJobUnmount *job) +{ + GVfsBackendDice *dice_backend; + + g_print ("(dice) do_umount \n"); + + dice_backend = G_VFS_BACKEND_DICE (backend); + g_mount_spec_unref (dice_backend->mount_spec); + g_vfs_job_succeeded (G_VFS_JOB (job)); +} + + +/******************* + * Query Functions * + *******************/ + +static void +do_query_info ( + GVfsBackend *backend, + GVfsJobQueryInfo *job, + const char *filename, + GFileQueryInfoFlags flags, + GFileInfo *info, + GFileAttributeMatcher *matcher) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + GFileInfo *info2; + GError *error = NULL; + + g_print ("(dice) (filename = %s)\n", filename); + + // NOTE! get_g_file_info_from_dice is completing the job on failure + // this needs to change + info2 = + get_g_file_info_from_dice ( + dice_backend, + filename, + /*file,*/ "*", + flags, G_VFS_JOB (job), + &error); + if (info2 != NULL && error == NULL) + { + g_file_info_copy_into (info2, info); + g_object_unref (info2); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(dice) do_query_info success. \n"); + } + else + { + g_printf ("Error code: %d\n", error->code); + g_printf ("Error message: %s\n", error->message); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); + g_print ("(dice) do_query_info failed. \n"); + } +} + + +static void +do_query_fs_info ( + GVfsBackend *backend, + GVfsJobQueryFsInfo *job, + const char *filename, + GFileInfo *info, + GFileAttributeMatcher *attribute_matcher) +{ + GFile *file; + GFileInfo *info2; + GError *error = NULL; + + g_print ("(dice) do_query_fs_info (filename = %s) \n", filename); + file = g_file_new_for_path (filename); + if (file != NULL) + { + info2 = get_g_filesystem_info_from_dice (backend, file, "fs:*", G_VFS_JOB (job)->cancellable, &error); + if ((error) || (!info2)) + { + g_print (" (dice) do_query_fs_info (filename = '%s'): g_file_query_filesystem_info failed: %s \n", filename, error->message); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + } + else + { + g_file_info_copy_into (info2, info); + g_object_unref (info2); + g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "dice"); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(dice) do_query_fs_info success. \n"); + } + + g_object_unref (file); + } + else + { + error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, _("Error creating a file info from a path")); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_print ("(dice) do_query_fs_info failed - creating a new path. \n"); + } + + if (error != NULL) g_error_free (error); +} + + +static void +do_enumerate ( + GVfsBackend *backend, + GVfsJobEnumerate *job, + const char *filename, + GFileAttributeMatcher *attribute_matcher, + GFileQueryInfoFlags flags) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + GPtrArray *files = NULL; + GFileInfo *info; + GError *dbus_error = NULL; + int dbus_status; + + g_print ("(dice) do_enumerate (filename = %s) \n", filename); + + if (strlen (filename) == 1 && filename [0] == '/') + { + g_print(" ---> calling EnumerateWorkspaces ()\n"); + + // Read in all the workspaces + dbus_status = + dbus_g_proxy_call ( + dice_backend->dice_proxy, + "EnumerateWorkspaces", + &dbus_error, + // Input params (none) + G_TYPE_INVALID, + // Output params + dbus_g_type_get_collection ( + "GPtrArray", + dbus_g_type_get_struct ( + "GValueArray", + G_TYPE_STRING, // Id + G_TYPE_STRING, // Display Name + G_TYPE_STRING, // Path + G_TYPE_STRING, // Local Path + G_TYPE_INT, // File Type + G_TYPE_STRING, // Mime Type + G_TYPE_UINT, // Access Mask + G_TYPE_INT64, // Creation Time + G_TYPE_INT64, // Last Access Time + G_TYPE_INT64, // Last Modified Time + G_TYPE_UINT64, // Size + G_TYPE_BOOLEAN, // Hidden + G_TYPE_INVALID)), + &files, + G_TYPE_INVALID); + } + else + { + g_print(" ---> calling EnumerateFiles ()\n"); + + // Read in the files contained in a specific directory + int dbus_status = + dbus_g_proxy_call ( + dice_backend->dice_proxy, + "EnumerateFiles", + &dbus_error, + // Input params + G_TYPE_STRING, filename, + G_TYPE_INVALID, + // Output params + dbus_g_type_get_collection ( + "GPtrArray", + dbus_g_type_get_struct ( + "GValueArray", + G_TYPE_STRING, // Id + G_TYPE_STRING, // Display Name + G_TYPE_STRING, // Path + G_TYPE_STRING, // Local Path + G_TYPE_INT, // File Type + G_TYPE_STRING, // Mime Type + G_TYPE_UINT, // Access Mask + G_TYPE_INT64, // Creation Time + G_TYPE_INT64, // Last Access Time + G_TYPE_INT64, // Last Modified Time + G_TYPE_UINT64, // Size + G_TYPE_BOOLEAN, // Hidden + G_TYPE_INVALID)), + &files, + G_TYPE_INVALID); + + } + + g_print (" ---- EnumerateFiles () out of dbus call\n"); + g_print ("dbus_status: %d\n", dbus_status); + g_print ("dbus_error: 0x%X\n", dbus_error); + + if (dbus_status > 0 && dbus_error == NULL) + { + // You have to say succeeded before you add the infos + g_vfs_job_succeeded (G_VFS_JOB (job)); + + if (files != NULL) + { + int i; + for (i = 0; i < files->len; i++) + { + GValueArray *dbus_array_obj = g_ptr_array_index (files, i); + if (dbus_array_obj != NULL) + { + info = create_file_info_from_dbus_array (dbus_array_obj); + g_vfs_job_enumerate_add_info (job, info); + g_object_unref (info); + } + } + + g_ptr_array_free (files, TRUE); + } + + g_vfs_job_enumerate_done (job); + } + else + { + if (dbus_error != NULL) + { + if (strstr (dbus_error->message, "NoEntries") != NULL || + strstr (dbus_error->message, "NoWorkspaces") != NULL || + strstr (dbus_error->message, "NoFolders") != NULL || + strstr (dbus_error->message, "NoFiles") != NULL) + { + g_printf ("Hit the no more entries case"); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_vfs_job_enumerate_done (job); + } + else + { + GError *error = convert_dice_error_to_gio_status (dbus_error); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); + } + } + else + { + g_vfs_job_failed ( + G_VFS_JOB (job), + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Error enumerating a directory")); + + } + + g_error_free (dbus_error); + } + + g_print ("(dice) do_enumerate done. \n"); +} + + +/****************** + * Read Functions * + ******************/ + +static void +do_open_for_read ( + GVfsBackend *backend, + GVfsJobOpenForRead *job, + const char *filename) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + struct DiceHandle *dice_handle; + GFileInputStream *stream; + GError *error = NULL; + GFile *file = NULL; + GFileInfo *info = NULL; + + g_print ("(II) do_open_for_read (filename = '%s') \n", filename); + + if (strcmp (filename, "/") == 0) + { + g_print ("caught the read on / case"); + + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_REGULAR_FILE, + _("Failed to read the root directory")); + goto do_open_for_read_error; + } + + info = + get_g_file_info_from_dice ( + dice_backend, + filename, + "*", + G_FILE_QUERY_INFO_NONE, + G_VFS_JOB (job), + &error); + if (error != NULL) + { + goto do_open_for_read_error; + } + + g_assert (info != NULL); + + // Build a GFile object from the local path + file = + get_g_file_from_local ( + g_file_info_get_attribute_string ( + info, + G_FILE_ATTRIBUTE_DICE_LOCAL_PATH), + G_VFS_JOB (job)); + if (file == NULL) + { + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Unable to create a GFile object")); + goto do_open_for_read_error; + } + + stream = g_file_read (file, G_VFS_JOB (job)->cancellable, &error); + if (stream == NULL) + { + g_print (" (EE) do_open_for_read: stream == NULL, error: %s \n", error->message); + goto do_open_for_read_error; + } + + dice_handle = g_malloc (sizeof (struct DiceHandle)); + dice_handle->input_stream = stream; + dice_handle->file_path = g_strdup (filename); + g_vfs_job_open_for_read_set_can_seek (job, TRUE); + g_vfs_job_open_for_read_set_handle (job, dice_handle); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(II) do_open_for_read success. \n"); + g_object_unref (file); + g_object_unref (info); + return; + +do_open_for_read_error: + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + if (error != NULL) g_error_free (error); + if (info != NULL) g_object_unref (info); + if (file != NULL) g_object_unref (file); + + return; +} + + +static void +do_read ( + GVfsBackend *backend, + GVfsJobRead *job, + GVfsBackendHandle handle, + char *buffer, + gsize bytes_requested) +{ + GError *error; + struct DiceHandle *dice_handle = (struct DiceHandle *)handle; + gssize s; + + g_assert (dice_handle != NULL); + g_assert (dice_handle->input_stream); + + g_print ("(II) do_read (handle = '%lx', buffer = '%lx', bytes_requested = %ld) \n", + (long int)dice_handle->input_stream, (long int)buffer, (long int)bytes_requested); + + error = NULL; + s = g_input_stream_read (G_INPUT_STREAM (dice_handle->input_stream), buffer, bytes_requested, + G_VFS_JOB (job)->cancellable, &error); + if (s >= 0) + { + g_vfs_job_read_set_size (job, s); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(II) do_read success. \n"); + } + else + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_print (" (EE) do_read: g_input_stream_read() failed, error: %s \n", error->message); + g_error_free (error); + } +} + + +static void +do_seek_on_read ( + GVfsBackend *backend, + GVfsJobSeekRead *job, + GVfsBackendHandle handle, + goffset offset, + GSeekType type) +{ + GError *error; + struct DiceHandle *dice_handle = (struct DiceHandle *)handle; + + g_assert (dice_handle != NULL); + g_assert (dice_handle->input_stream != NULL); + + g_print ( + "(II) do_seek_on_read (handle = '%lx', offset = %ld) \n", + (long int)dice_handle->input_stream, + (long int)offset); + + error = NULL; + if (g_seekable_seek ( + G_SEEKABLE (dice_handle->input_stream), + offset, + type, + G_VFS_JOB (job)->cancellable, &error)) + { + g_vfs_job_seek_read_set_offset (job, g_seekable_tell (G_SEEKABLE (dice_handle->input_stream))); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(II) do_seek_on_read success. \n"); + } + else + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_print (" (EE) do_seek_on_read: g_file_input_stream_seek() failed, error: %s \n", error->message); + g_error_free (error); + } +} + + +static void +do_close_read ( + GVfsBackend *backend, + GVfsJobCloseRead *job, + GVfsBackendHandle handle) +{ + GError *error; + struct DiceHandle *dice_handle = (struct DiceHandle *)handle; + + g_assert (dice_handle != NULL); + g_assert (dice_handle->input_stream != NULL); + + g_print ("(II) do_close_read (handle = '%lx') \n", (long int)dice_handle->input_stream); + + error = NULL; + if (g_input_stream_close ( + G_INPUT_STREAM (dice_handle->input_stream), + G_VFS_JOB (job)->cancellable, &error)) + { + g_object_unref (dice_handle->input_stream); + if (dice_handle->file_path != NULL) + g_free (dice_handle->file_path); + g_free (dice_handle); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(II) try_close_read success. \n"); + } + else + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_print (" (EE) try_close_read: g_input_stream_close() failed, error: %s \n", error->message); + g_error_free (error); + } +} + + +/******************* + * Write Functions * + *******************/ + +static void +do_create ( + GVfsBackend *backend, + GVfsJobOpenForWrite *job, + const char *filename, + GFileCreateFlags flags) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + GError *error; + GFileInfo *info = NULL; + GFile *file; + struct DiceHandle *dice_handle; + + info = + get_g_file_info_from_dice ( + dice_backend, + filename, + "*", + G_FILE_QUERY_INFO_NONE, + G_VFS_JOB (job), + &error); + +// g_file_new_for_path (filename); + if (info != NULL) + { + if (error != NULL) g_error_free (error); + g_object_unref (info); + error = g_error_new (G_IO_ERROR, G_IO_ERROR_EXISTS, _("Target file already exists")); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); + return; + } + + // Create a limbo entry in the dice database + info = create_g_file_info_in_dice (dice_backend, filename, &error); + if (info == NULL) + { + // The error returned from the dice create call + // will be converted to the correct GIO_ERROR + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); + return; + } + + g_printf ("Successfully created the file locally"); + + // Open the real local file file! + const char *local_path = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_DICE_LOCAL_PATH); + g_assert (local_path != NULL); + + g_printf ("local path: %s\n", local_path); + file = get_g_file_from_local (local_path, G_VFS_JOB (job)); + g_object_unref (info); + + error = NULL; + GFileOutputStream *stream = g_file_create (file, flags, G_VFS_JOB (job)->cancellable, &error); + if (stream != NULL && !error) + { + g_printf ("g_file_create was successful\n"); + dice_handle = g_malloc (sizeof (struct DiceHandle)); + dice_handle->file_path = g_strdup (filename); + dice_handle->output_stream = stream; + + //g_vfs_job_open_for_write_set_can_seek (job, TRUE); + g_vfs_job_open_for_write_set_handle (job, dice_handle); + + //g_vfs_job_open_for_write_set_handle (G_VFS_JOB_OPEN_FOR_WRITE (job), dice_stream); + //g_vfs_job_open_for_write_set_can_seek (G_VFS_JOB_OPEN_FOR_WRITE (job), g_seekable_can_seek (G_SEEKABLE (stream))); + ////g_vfs_job_succeeded (G_VFS_JOB (job)); + g_printf ("g_vfs_job_succeeded\n"); + } + else + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); + } + + g_object_unref (file); + return; +} + + +static void +do_close_write ( + GVfsBackend *backend, + GVfsJobCloseWrite *job, + GVfsBackendHandle handle) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + GError *error = NULL; + struct DiceHandle *dice_handle = (struct DiceHandle *)handle; + + g_print ("(II) do_close_write (handle = '%lx') \n", (long int)handle); + g_assert (dice_handle != NULL); + g_assert (dice_handle->output_stream != NULL); + g_assert (dice_handle->file_path != NULL); + + if (!g_output_stream_close ( + G_OUTPUT_STREAM(dice_handle->output_stream), + G_VFS_JOB (job)->cancellable, + &error)) + { + g_printf ("Failed closing the output stream\n"); + goto do_close_write_error; + } + + // Notify DICE daemon that the file has been closed/changed + error = NULL; + if (update_local_file_in_dice ( + dice_backend, + dice_handle->file_path, + &error) == FALSE) + { + g_print ("(II) failed updating dice of changes\n"); + goto do_close_write_error; + } + + g_object_unref (dice_handle->output_stream); + if (dice_handle->file_path != NULL) + g_free (dice_handle->file_path); + g_free (dice_handle); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(II) do_close_write success. \n"); + return; + +do_close_write_error: + if (dice_handle != NULL) + { + if (dice_handle->file_path != NULL) + g_free (dice_handle->file_path); + g_free (dice_handle); + } + + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_print (" (EE) do_close_write: failed, error: %s \n", error->message); + g_error_free (error); + return; +} + + +static void +do_write ( + GVfsBackend *backend, + GVfsJobWrite *job, + GVfsBackendHandle handle, + char *buffer, + gsize buffer_size) +{ + GError *error; + struct DiceHandle *dice_handle = (struct DiceHandle *)handle; + gssize s; + + g_print ( + "(II) do_write (handle = '%lx', buffer = '%lx', buffer_size = %ld) \n", + (long int)handle, + (long int)buffer, + (long int)buffer_size); + + g_assert (dice_handle != NULL); + g_assert (dice_handle->output_stream != NULL); + + error = NULL; + s = + g_output_stream_write ( + G_OUTPUT_STREAM (dice_handle->output_stream), + buffer, + buffer_size, + G_VFS_JOB (job)->cancellable, + &error); + if (s >= 0) + { + g_vfs_job_write_set_written_size (job, s); + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(II) do_write success. \n"); + } + else + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_print ( + " (EE) do_write: g_output_stream_write() failed, error: %s \n", + error->message); + g_error_free (error); + } +} + + +static void +do_append ( + GVfsBackend *backend, + GVfsJobOpenForWrite *job, + const char *filename, + GFileCreateFlags flags) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + GError *error; + GFileInfo *info; + GFile *file; + struct DiceHandle *dice_handle = NULL; + + g_print ("(II) do_append (filename = %s) \n", filename); + + info = + get_g_file_info_from_dice ( + dice_backend, + filename, + "*", + G_FILE_QUERY_INFO_NONE, + G_VFS_JOB (job), + &error); + + if (info == NULL) + { + if (error != NULL) g_error_free (error); + // The file must not exist, so just use the create function + do_create (backend, job, filename, flags); + return; + } + + // Get the real local path + const char *local_path = + g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_DICE_LOCAL_PATH); + g_assert (local_path != NULL); + + file = get_g_file_from_local (local_path, G_VFS_JOB (job)); + g_object_unref (info); + + g_assert (file != NULL); + + if (file != NULL) + { + error = NULL; + dice_handle = g_malloc (sizeof (struct DiceHandle)); + dice_handle->output_stream = + g_file_append_to (file, flags, G_VFS_JOB (job)->cancellable, &error); + g_object_unref (file); + if (dice_handle->output_stream) + { + /* Should seek at the end of the file here */ + if ((g_seekable_seek ( + G_SEEKABLE (dice_handle->output_stream), + 0, + G_SEEK_END, + G_VFS_JOB (job)->cancellable, &error)) && (! error)) + { + g_vfs_job_open_for_write_set_initial_offset ( + job, + g_seekable_tell (G_SEEKABLE (dice_handle->output_stream))); + } + else + { + g_print (" (EE) do_append: error during g_file_output_stream_seek(), error: %s \n", error->message); + } + + // Store the filename so we can close properly and notify the DICE Daemon + dice_handle->file_path = g_strdup (filename); + g_vfs_job_open_for_write_set_can_seek ( + job, + g_seekable_can_seek (G_SEEKABLE (dice_handle->output_stream))); + g_vfs_job_open_for_write_set_handle (job, dice_handle); + g_vfs_job_succeeded (G_VFS_JOB (job)); + + g_print ("(II) do_append success. \n"); + } + else + { + g_free (dice_handle); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_print (" (EE) do_append: stream == NULL, error: %s \n", error->message); + g_error_free (error); + } + } + else + { + g_print (" (EE) do_append: file == NULL \n"); + + g_vfs_job_failed ( + G_VFS_JOB (job), + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("Unable to get the local path")); + } +} + + +static void +do_replace ( + GVfsBackend *backend, + GVfsJobOpenForWrite *job, + const char *filename, + const char *etag, + gboolean make_backup, + GFileCreateFlags flags) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + struct DiceHandle *dice_handle = NULL; + GError *error = NULL; + GFile *file = NULL; + GFileInfo *info = NULL; + + g_print ("(II) do_replace (filename = '%s', etag = '%s') \n", filename, etag); + g_print ("\t\t make_backup == %s\n", (make_backup == TRUE) ? "TRUE" : "FALSE"); + g_print ("\t\t create flags == %X\n", flags); + + if (make_backup == TRUE) + { + g_printf ("\t\tcan't create backups yet - fail"); + + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_CANT_CREATE_BACKUP, + _("backup creation is not supported")); + + goto do_replace_error; + } + + + // Check if the file already exists in the DICE namespace + info = + get_g_file_info_from_dice ( + dice_backend, + filename, + "*", + G_FILE_QUERY_INFO_NONE, + G_VFS_JOB (job), + &error); + + if (info == NULL) + { + if (error != NULL) + { + g_error_free (error); + error = NULL; + } + + g_printf ("\t\tfailed to find the filename in the dice namespace"); + + // Create a limbo entry in the dice database + info = create_g_file_info_in_dice (dice_backend, filename, &error); + if (info == NULL) + { + // The error returned from the dice create call + // will be converted to the correct GIO_ERROR + goto do_replace_error; + } + + /* + if (etag == NULL) + etag = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE); + */ + + g_printf ("Successfully created the file locally"); + } + + // Get the real local path + const char *local_path = + g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_DICE_LOCAL_PATH); + + g_assert (local_path != NULL); + g_printf ("local path: %s\n", local_path); + + // Create a GFile object from the local path + file = get_g_file_from_local (local_path, G_VFS_JOB (job)); + if (file == NULL) + { + g_print (" (EE) do_replace: file == NULL \n"); + g_assert (file != NULL); + error = + g_error_new ( + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + _("Unable to get the local path")); + + goto do_replace_error; + } + + dice_handle = g_malloc (sizeof (struct DiceHandle)); + dice_handle->output_stream = + g_file_replace ( + file, + NULL, + make_backup, + flags, + G_VFS_JOB (job)->cancellable, + &error); + + if (dice_handle->output_stream == NULL) + { + g_print (" (EE) do_replace: stream == NULL, error: %s \n", error->message); + goto do_replace_error; + } + + + // Save off the filename so we can notify DICE Daemon during a close + dice_handle->file_path = g_strdup (filename); + g_vfs_job_open_for_write_set_handle (job, dice_handle); + g_object_unref (file); + g_object_unref (info); + g_vfs_job_succeeded (G_VFS_JOB (job)); + + // Call dice with a local update + if (update_local_file_in_dice ( + dice_backend, + filename, + &error) == FALSE) + { + g_error_free (error); + } + + g_print ("(II) do_replace success. \n"); + return; + +do_replace_error: + g_print (" do_replace failed - error message: %s\n", error->message); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + if (error != NULL) g_error_free (error); + if (info != NULL) g_object_unref (info); + if (file != NULL) g_object_unref (file); + if (dice_handle != NULL) g_free (dice_handle); + return; +} + + +static void +do_delete ( + GVfsBackend *backend, + GVfsJobDelete *job, + const char *filename) +{ + GVfsBackendDice *dice_backend = G_VFS_BACKEND_DICE (backend); + GError *error; + + g_print ("(II) do_delete (filename = %s) \n", filename); + + if (filename != NULL) + { + error = NULL; + if (delete_local_file_from_dice (dice_backend, filename, &error)) + { + g_vfs_job_succeeded (G_VFS_JOB (job)); + g_print ("(II) do_delete success. \n"); + } + else + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_print (" (EE) do_delete: g_file_delete == FALSE, error: %s \n", error->message); + g_error_free (error); + } + } + else + { + g_print (" (EE) do_delete: filename == NULL \n"); + } +} + + +static void +g_vfs_backend_dice_class_init (GVfsBackendDiceClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass); + + gobject_class->finalize = g_vfs_backend_dice_finalize; + + backend_class->mount = do_mount; + backend_class->unmount = do_unmount; + backend_class->query_info = do_query_info; + backend_class->query_fs_info = do_query_fs_info; + backend_class->enumerate = do_enumerate; + + 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->close_write = do_close_write; + backend_class->write = do_write; + backend_class->append_to = do_append; + backend_class->replace = do_replace; + + backend_class->delete = do_delete; + +// backend_class->move = do_move; +// backend_class->make_directory = do_make_directory; + +// backend_class->create_dir_monitor = do_create_dir_monitor; +// backend_class->create_file_monitor = do_create_file_monitor; +} Index: gvfs-1.3.3/daemon/gvfsbackenddice.h =================================================================== --- /dev/null +++ gvfs-1.3.3/daemon/gvfsbackenddice.h @@ -0,0 +1,50 @@ +/* Novell IceDesktop Backend for GVfs + * + * Copyright (C) 2008 Novell, 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: Boyd Timothy + */ + +#ifndef __G_VFS_BACKEND_DICE_H__ +#define __G_VFS_BACKEND_DICE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define G_VFS_TYPE_BACKEND_DICE (g_vfs_backend_dice_get_type ()) +#define G_VFS_BACKEND_DICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_BACKEND_DICE, GVfsBackendDice)) +#define G_VFS_BACKEND_DICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_BACKEND_DICE, GVfsBackendDiceClass)) +#define G_VFS_IS_BACKEND_DICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_BACKEND_DICE)) +#define G_VFS_IS_BACKEND_DICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_BACKEND_DICE)) +#define G_VFS_BACKEND_DICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_BACKEND_DICE, GVfsBackendDiceClass)) + +typedef struct _GVfsBackendDice GVfsBackendDice; +typedef struct _GVfsBackendDiceClass GVfsBackendDiceClass; + +struct _GVfsBackendDiceClass +{ + GVfsBackendClass parent_class; +}; + +GType g_vfs_backend_dice_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __G_VFS_BACKEND_DICE_H__ */ Index: gvfs-1.3.3/daemon/Makefile.am =================================================================== --- gvfs-1.3.3.orig/daemon/Makefile.am +++ gvfs-1.3.3/daemon/Makefile.am @@ -10,6 +10,7 @@ INCLUDES = \ -I$(top_srcdir)/common \ -I$(top_builddir) \ $(GLIB_CFLAGS) $(DBUS_CFLAGS) \ + $(DBUS_GLIB_CFLAGS) \ $(OBEXFTP_CFLAGS) $(XML_CFLAGS) \ $(KEYRING_CFLAGS) \ -DDBUS_API_SUBJECT_TO_CHANGE \ @@ -24,7 +25,7 @@ noinst_LTLIBRARIES=libdaemon.la libraries = \ libdaemon.la \ $(top_builddir)/common/libgvfscommon.la \ - $(GLIB_LIBS) $(DBUS_LIBS) $(KEYRING_LIBS) + $(GLIB_LIBS) $(DBUS_LIBS) $(DBUS_GLIB_LIBS) $(KEYRING_LIBS) # D-BUS service file %.service: %.service.in ../config.log @@ -37,10 +38,10 @@ service_DATA = gvfs-daemon.service %.mount: %.mount.in ../config.log sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ -libexec_PROGRAMS=gvfsd gvfsd-sftp gvfsd-trash gvfsd-computer gvfsd-burn gvfsd-localtest gvfsd-ftp +libexec_PROGRAMS=gvfsd gvfsd-sftp gvfsd-trash gvfsd-computer gvfsd-burn gvfsd-localtest gvfsd-ftp gvfsd-dice -mount_in_files = sftp.mount.in trash.mount.in computer.mount.in burn.mount.in localtest.mount.in -mount_DATA = sftp.mount trash.mount computer.mount burn.mount localtest.mount +mount_in_files = sftp.mount.in trash.mount.in computer.mount.in burn.mount.in localtest.mount.in dice.mount.in +mount_DATA = sftp.mount trash.mount computer.mount burn.mount localtest.mount dice.mount mount_in_files += http.mount.in dav.mount.in dav+sd.mount.in ftp.mount.in if HAVE_HTTP @@ -286,6 +287,19 @@ gvfsd_trash_CPPFLAGS = \ gvfsd_trash_LDADD = trashlib/libtrash.a $(libraries) +gvfsd_dice_SOURCES = \ + gvfsbackenddice.c gvfsbackenddice.h \ + daemon-main.c daemon-main.h \ + daemon-main-generic.c + +gvfsd_dice_CPPFLAGS = \ + -DBACKEND_HEADER=gvfsbackenddice.h \ + -DDEFAULT_BACKEND_TYPE=dice \ + -DMAX_JOB_THREADS=10 \ + -DBACKEND_TYPES='"dice", G_VFS_TYPE_BACKEND_DICE,' + +gvfsd_dice_LDADD = $(libraries) + gvfsd_computer_SOURCES = \ gvfsbackendcomputer.c gvfsbackendcomputer.h \ daemon-main.c daemon-main.h \