summaryrefslogtreecommitdiff
path: root/gvfs/gvfs.c
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2008-08-24 19:13:04 +0200
committerTomas Bzatek <tbzatek@users.sourceforge.net>2008-08-24 19:13:04 +0200
commit2a3ca65418b30afde5580e484d0d49f2b3764b33 (patch)
tree3f574cdebcf3be19e513288d87937c0b55ad7acb /gvfs/gvfs.c
parent78a3ab60cfcfc15baf0c96f25d19f94eba6479e5 (diff)
downloadtuxcmd-modules-2a3ca65418b30afde5580e484d0d49f2b3764b33.tar.xz
GVFS plugin - ininital commit
Missing authentication code at the moment
Diffstat (limited to 'gvfs/gvfs.c')
-rw-r--r--gvfs/gvfs.c1115
1 files changed, 1115 insertions, 0 deletions
diff --git a/gvfs/gvfs.c b/gvfs/gvfs.c
new file mode 100644
index 0000000..3e1a0d8
--- /dev/null
+++ b/gvfs/gvfs.c
@@ -0,0 +1,1115 @@
+/* GVFS plugin for Tux Commander
+ * Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <gio/gio.h>
+#include <glib/gtypes.h>
+
+#include "vfs_types.h"
+
+
+
+#define VERSION "0.0.1"
+#define BUILD_DATE "2008-08-24"
+#define DEFAULT_BLOCK_SIZE 0x10000 /* 64kB */
+
+#define CONST_DEFAULT_QUERY_INFO_ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME "," \
+ G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_SIZE "," \
+ G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET "," G_FILE_ATTRIBUTE_TIME_MODIFIED "," \
+ G_FILE_ATTRIBUTE_TIME_ACCESS "," G_FILE_ATTRIBUTE_TIME_CHANGED "," \
+ G_FILE_ATTRIBUTE_UNIX_MODE "," G_FILE_ATTRIBUTE_UNIX_UID "," \
+ G_FILE_ATTRIBUTE_UNIX_GID
+
+struct TVFSGlobs {
+ TVFSLogFunc log_func;
+ GFile *file;
+ GFileEnumerator *enumerator;
+
+ gboolean break_get_dir_size;
+ guint32 block_size;
+};
+
+
+int
+VFSAllocNeeded ()
+{
+ return sizeof (struct TVFSGlobs);
+}
+
+static TVFSResult
+g_error_to_TVFSResult (GError *error)
+{
+ g_print ("g_error_to_TVFSResult: code = %d\n", error->code);
+ switch (error->code) {
+ case G_IO_ERROR_FAILED:
+ case G_IO_ERROR_NOT_FOUND:
+ return cVFS_Failed;
+ break;
+ case G_IO_ERROR_PERMISSION_DENIED:
+ return cVFS_PermissionDenied;
+ break;
+ case G_IO_ERROR_CANCELLED:
+ return cVFS_Cancelled;
+ break;
+ case G_IO_ERROR_NOT_SUPPORTED:
+ case G_IO_ERROR_FILENAME_TOO_LONG:
+ return cVFS_Not_Supported;
+ break;
+ case G_IO_ERROR_NO_SPACE:
+ return cVFS_NoSpaceLeft;
+ break;
+ case G_IO_ERROR_IS_DIRECTORY:
+ case G_IO_ERROR_NOT_REGULAR_FILE:
+ case G_IO_ERROR_NOT_SYMBOLIC_LINK:
+ case G_IO_ERROR_NOT_MOUNTABLE_FILE:
+ case G_IO_ERROR_INVALID_FILENAME:
+ case G_IO_ERROR_TOO_MANY_LINKS:
+ case G_IO_ERROR_INVALID_ARGUMENT:
+ case G_IO_ERROR_NOT_DIRECTORY:
+ case G_IO_ERROR_NOT_MOUNTED:
+ case G_IO_ERROR_ALREADY_MOUNTED:
+ case G_IO_ERROR_WRONG_ETAG:
+ case G_IO_ERROR_TIMED_OUT:
+ case G_IO_ERROR_WOULD_RECURSE:
+ case G_IO_ERROR_HOST_NOT_FOUND:
+ return cVFS_ReadErr;
+ break;
+ case G_IO_ERROR_EXISTS:
+ case G_IO_ERROR_NOT_EMPTY:
+ case G_IO_ERROR_CLOSED:
+ case G_IO_ERROR_PENDING:
+ case G_IO_ERROR_READ_ONLY:
+ case G_IO_ERROR_CANT_CREATE_BACKUP:
+ case G_IO_ERROR_BUSY:
+ case G_IO_ERROR_WOULD_BLOCK:
+ case G_IO_ERROR_WOULD_MERGE:
+ return cVFS_WriteErr;
+ break;
+ case G_IO_ERROR_FAILED_HANDLED:
+ default:
+ return cVFS_Failed;
+ }
+}
+
+void
+VFSInit (struct TVFSGlobs *globs, TVFSLogFunc log_func)
+{
+ globs->log_func = log_func;
+ globs->log_func ("GVFS plugin: VFSInit");
+
+ globs->file = NULL;
+ globs->enumerator = NULL;
+
+ globs->break_get_dir_size = FALSE;
+ globs->block_size = DEFAULT_BLOCK_SIZE;
+}
+
+void
+VFSDestroy (struct TVFSGlobs *globs)
+{
+ globs->log_func ("GVFS plugin: VFSDestroy");
+}
+
+int
+VFSVersion ()
+{
+ return cVFSVersion;
+}
+
+struct TVFSInfo
+VFSGetInfo ()
+{
+ struct TVFSInfo module_info;
+
+ module_info.Name = "GVFS plugin";
+ module_info.Description = "GVFS plugin";
+ module_info.About = g_strdup_printf ("version %s, build date: %s", VERSION, BUILD_DATE);
+ module_info.Copyright = "Copyright (C) 2008 Tomáš Bžatek";
+ return module_info;
+}
+
+char *
+VFSGetExts ()
+{
+ return "";
+}
+
+char *
+VFSGetServices ()
+{
+ /* FIXME: retrieve list of supported backends from gvfs subsystem */
+ return "http;https;ftp;sftp;smb;network";
+}
+
+char *
+VFSGetPrefix (struct TVFSGlobs *globs)
+{
+ GFile *f;
+ char *s;
+
+ if (globs->file) {
+ f = g_file_resolve_relative_path (globs->file, "/");
+ s = g_file_get_uri (f);
+ g_object_unref (f);
+ return s;
+ }
+ else
+ return NULL;
+}
+
+TVFSResult
+VFSOpen (struct TVFSGlobs *globs, char *sName)
+{
+ GFile *f;
+
+ g_print ("(II) VFSOpen: opening URI '%s'\n", sName);
+ globs->file = NULL;
+
+ f = g_file_new_for_commandline_arg (sName);
+ if (! g_file_query_exists (f, NULL)) {
+ g_print ("(EE) VFSOpen: The URI specified doesn't exist\n");
+ return cVFS_Failed;
+ }
+ else
+ {
+ globs->file = f;
+ return cVFS_OK;
+ }
+}
+
+TVFSResult
+VFSClose (struct TVFSGlobs *globs)
+{
+ g_print ("(II) VFSClose\n");
+
+ if (globs->file)
+ g_object_unref (globs->file);
+ globs->file = NULL;
+
+ return cVFS_OK;
+}
+
+char *
+VFSGetPath (struct TVFSGlobs *globs)
+{
+ if (globs->file)
+ return g_file_get_path (globs->file);
+ else
+ return NULL;
+}
+
+guint64
+VFSGetFileSystemFree (struct TVFSGlobs *globs, char *APath)
+{
+ GFileInfo *info;
+ GError *error;
+ guint64 res;
+
+ if (globs->file == NULL)
+ return 0;
+
+ error = NULL;
+ info = g_file_query_filesystem_info (globs->file, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSGetFileSystemFree: %s\n", error->message);
+ g_error_free (error);
+ return 0;
+ }
+ res = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
+ g_object_unref (info);
+ return res;
+}
+
+guint64
+VFSGetFileSystemSize (struct TVFSGlobs *globs, char *APath)
+{
+ GFileInfo *info;
+ GError *error;
+ guint64 res;
+
+ if (globs->file == NULL)
+ return 0;
+
+ error = NULL;
+ info = g_file_query_filesystem_info (globs->file, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSGetFileSystemSize: %s\n", error->message);
+ g_error_free (error);
+ return 0;
+ }
+ res = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE);
+ g_object_unref (info);
+ return res;
+}
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+
+TVFSResult
+VFSChangeDir (struct TVFSGlobs *globs, char *NewPath)
+{
+ GFile *f;
+ GFileEnumerator *en;
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSChangeDir: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ g_print ("(II) VFSChangeDir: changing dir to '%s'\n", NewPath);
+
+ f = g_file_resolve_relative_path (globs->file, NewPath);
+ if (f == NULL) {
+ g_print ("(EE) VFSChangeDir: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ en = g_file_enumerate_children (f, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSChangeDir: g_file_enumerate_children() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ g_object_unref (f);
+ return res;
+ }
+ globs->enumerator = en;
+ g_object_unref (globs->file);
+ globs->file = f;
+
+ return cVFS_OK;
+}
+
+int
+VFSLogin (struct TVFSGlobs *globs, char *user, char *pass)
+{
+ g_print ("(II) VFSLogin: logging in with '%s'/'%s'\n", user, pass);
+
+ /* FIXME: add auth code */
+
+ return cVFS_Not_Supported;
+}
+
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+
+static void
+g_file_info_to_TVFSItem (GFileInfo *info, struct TVFSItem *Item)
+{
+ g_assert (info != NULL);
+ g_assert (Item != NULL);
+
+ Item->sFileName = g_strdup (g_file_info_get_display_name (info));
+ Item->sLinkTo = g_file_info_get_symlink_target (info) == NULL ? NULL : g_strdup (g_file_info_get_symlink_target (info));
+ Item->iSize = g_file_info_get_size (info);
+ Item->iMode = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);
+
+ Item->m_time = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+ Item->a_time = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
+ Item->c_time = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED);
+ Item->iUID = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID);
+ Item->iGID = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID);
+
+ if (g_file_info_get_is_symlink (info)) {
+ Item->ItemType = vSymlink;
+ }
+ else
+ {
+ switch (g_file_info_get_file_type (info)) {
+ case G_FILE_TYPE_REGULAR:
+ Item->ItemType = vRegular;
+ break;
+ case G_FILE_TYPE_DIRECTORY:
+ case G_FILE_TYPE_MOUNTABLE:
+ Item->ItemType = vDirectory;
+ break;
+ case G_FILE_TYPE_SYMBOLIC_LINK:
+ Item->ItemType = vSymlink;
+ break;
+ case G_FILE_TYPE_SHORTCUT:
+ case G_FILE_TYPE_SPECIAL: /* socket, fifo, blockdev, chardev */
+ Item->ItemType = vBlockdev;
+ break;
+ case G_FILE_TYPE_UNKNOWN:
+ default: Item->ItemType = vRegular;
+ }
+ }
+}
+
+TVFSResult
+VFSListNext (struct TVFSGlobs *globs, char *sDir, struct TVFSItem *Item)
+{
+ GError *error;
+ GFileInfo *info;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSListNext: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+ if (globs->enumerator == NULL) {
+ g_print ("(EE) VFSListNext: globs->enumerator == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ info = g_file_enumerator_next_file (globs->enumerator, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSListNext: g_file_enumerator_next_file() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ return res;
+ }
+ if (! error && ! info)
+ return cVFS_No_More_Files;
+ g_file_info_to_TVFSItem (info, Item);
+ g_object_unref (info);
+ return cVFS_OK;
+}
+
+TVFSResult
+VFSListFirst (struct TVFSGlobs *globs, char *sDir, struct TVFSItem *Item)
+{
+ return VFSListNext (globs, sDir, Item);
+}
+
+TVFSResult
+VFSListClose (struct TVFSGlobs *globs)
+{
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSListClose: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+ if (globs->enumerator == NULL) {
+ g_print ("(EE) VFSListClose: globs->enumerator == NULL !\n");
+ return cVFS_Failed;
+ }
+ g_print ("(II) VFSListClose\n");
+
+ error = NULL;
+ g_file_enumerator_close (globs->enumerator, NULL, &error);
+ g_object_unref (globs->enumerator);
+ globs->enumerator = NULL;
+ if (error) {
+ g_print ("(EE) VFSListClose: g_file_enumerator_close() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ return res;
+ }
+ return cVFS_OK;
+}
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+long
+VFSFileExists (struct TVFSGlobs *globs, const char *FileName, const long Use_lstat)
+{
+ GFile *f;
+ GError *error;
+ GFileInfo *info;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSFileExists: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ f = g_file_resolve_relative_path (globs->file, FileName);
+ if (f == NULL) {
+ g_print ("(EE) VFSMkDir: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ info = g_file_query_info (f, G_FILE_ATTRIBUTE_STANDARD_NAME,
+ Use_lstat ? G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS : G_FILE_QUERY_INFO_NONE, NULL, &error);
+ g_object_unref (f);
+ if (error) {
+ g_print ("(EE) VFSFileExists: g_file_query_info() error: %s\n", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+ g_object_unref (info);
+ return TRUE;
+}
+
+TVFSResult
+VFSFileInfo (struct TVFSGlobs *globs, char *AFileName, struct TVFSItem *Item)
+{
+ GFile *f;
+ GError *error;
+ GFileInfo *info;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSFileInfo: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ f = g_file_resolve_relative_path (globs->file, AFileName);
+ if (f == NULL) {
+ g_print ("(EE) VFSMkDir: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ info = g_file_query_info (f, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
+ g_object_unref (f);
+ if (error) {
+ g_print ("(EE) VFSFileInfo: g_file_query_info() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ return res;
+ }
+ g_file_info_to_TVFSItem (info, Item);
+ g_object_unref (info);
+ return cVFS_OK;
+}
+
+TVFSResult
+VFSMkDir (struct TVFSGlobs *globs, const char *sDirName)
+{
+ GFile *f;
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSMkDir: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ f = g_file_resolve_relative_path (globs->file, sDirName);
+ if (f == NULL) {
+ g_print ("(EE) VFSMkDir: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ g_file_make_directory (f, NULL, &error);
+ g_object_unref (f);
+ if (error) {
+ g_print ("(EE) VFSMkDir: g_file_make_directory() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ return res;
+ }
+ return cVFS_OK;
+}
+
+TVFSResult
+VFSRemove (struct TVFSGlobs *globs, const char *APath)
+{
+ GFile *f;
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSRemove: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ f = g_file_resolve_relative_path (globs->file, APath);
+ if (f == NULL) {
+ g_print ("(EE) VFSRemove: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ g_file_delete (f, NULL, &error);
+ g_object_unref (f);
+ if (error) {
+ g_print ("(EE) VFSRemove: g_file_delete() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ return res;
+ }
+ return cVFS_OK;
+}
+
+TVFSResult
+VFSRename (struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName)
+{
+ GFile *src, *dst;
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSRename: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ src = g_file_resolve_relative_path (globs->file, sSrcName);
+ if (src == NULL) {
+ g_print ("(EE) VFSRename: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ g_print ("VFSRename: '%s' --> '%s'\n", sSrcName, sDstName);
+
+ error = NULL;
+ g_file_set_display_name (src, sDstName, NULL, &error);
+ if (error) {
+ g_print ("(WW) VFSRename: g_file_set_display_name() failed (\"%s\"), using fallback g_file_move()\n", error->message);
+ g_error_free (error);
+
+ dst = g_file_resolve_relative_path (src, sDstName);
+ if (dst == NULL) {
+ g_print ("(EE) VFSRename: g_file_resolve_relative_path() failed.\n");
+ g_object_unref (src);
+ return cVFS_Failed;
+ }
+ error = NULL;
+ g_file_move (src, dst, G_FILE_COPY_NONE | G_FILE_COPY_NO_FALLBACK_FOR_MOVE, NULL, NULL, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSRename: g_file_move() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ g_object_unref (src);
+ g_object_unref (dst);
+ return res;
+ }
+ g_object_unref (dst);
+ }
+
+ g_object_unref (src);
+ return cVFS_OK;
+}
+
+TVFSResult
+VFSMakeSymLink (struct TVFSGlobs *globs, const char *NewFileName, const char *PointTo)
+{
+ GFile *f;
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSMakeSymLink: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ f = g_file_resolve_relative_path (globs->file, NewFileName);
+ if (f == NULL) {
+ g_print ("(EE) VFSMakeSymLink: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ g_file_make_symbolic_link (f, PointTo, NULL, &error);
+ g_object_unref (f);
+ if (error) {
+ g_print ("(EE) VFSMakeSymLink: g_file_make_symbolic_link() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ return res;
+ }
+ return cVFS_OK;
+}
+
+TVFSResult
+VFSChmod (struct TVFSGlobs *globs, const char *FileName, const uint Mode)
+{
+ GFile *f;
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSChmod: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ f = g_file_resolve_relative_path (globs->file, FileName);
+ if (f == NULL) {
+ g_print ("(EE) VFSChmod: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+ g_print ("(II) VFSChmod (%s, %d): Going to set permissions on '%s'\n", FileName, Mode, g_file_get_uri (f));
+
+ error = NULL;
+ g_file_set_attribute_uint32 (f, G_FILE_ATTRIBUTE_UNIX_MODE, Mode, G_FILE_QUERY_INFO_NONE, NULL, &error);
+ g_object_unref (f);
+ if (error) {
+ g_print ("(EE) VFSChmod: g_file_set_attribute_uint32() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ return res;
+ }
+ return cVFS_OK;
+}
+
+TVFSResult
+VFSChown (struct TVFSGlobs *globs, const char *FileName, const uint UID, const uint GID)
+{
+ GFile *f;
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSChown: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ f = g_file_resolve_relative_path (globs->file, FileName);
+ if (f == NULL) {
+ g_print ("(EE) VFSChown: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ g_file_set_attribute_uint32 (f, G_FILE_ATTRIBUTE_UNIX_UID, UID, G_FILE_QUERY_INFO_NONE, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSChown: g_file_set_attribute_uint32() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ g_object_unref (f);
+ return res;
+ }
+ error = NULL;
+ g_file_set_attribute_uint32 (f, G_FILE_ATTRIBUTE_UNIX_GID, GID, G_FILE_QUERY_INFO_NONE, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSChown: g_file_set_attribute_uint32() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ g_object_unref (f);
+ return res;
+ }
+ g_object_unref (f);
+ return cVFS_OK;
+}
+
+TVFSResult
+VFSChangeTimes (struct TVFSGlobs *globs, char *APath, long mtime, long atime)
+{
+ GFile *f;
+ GError *error;
+ TVFSResult res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSChangeTimes: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ f = g_file_resolve_relative_path (globs->file, APath);
+ if (f == NULL) {
+ g_print ("(EE) VFSChangeTimes: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ error = NULL;
+ g_file_set_attribute_uint64 (f, G_FILE_ATTRIBUTE_TIME_MODIFIED, mtime, G_FILE_QUERY_INFO_NONE, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSChangeTimes: g_file_set_attribute_uint64() error: %s\n", error->message);
+ res = g_error_to_TVFSResult (error);
+ g_error_free (error);
+ g_object_unref (f);
+ return res;
+ }
+ error = NULL;
+ g_file_set_attribute_uint64 (f, G_FILE_ATTRIBUTE_TIME_ACCESS, atime, G_FILE_QUERY_INFO_NONE, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSChangeTimes: g_file_set_attribute_uint64() error: %s\n", error->message);
+ g_error_free (error);
+ /* Silently drop the error, atime is not commonly supported on most systems */
+ }
+ g_object_unref (f);
+ return cVFS_OK;
+}
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+
+static void
+VFSGetDirSize_recurse (struct TVFSGlobs *globs, GFile *file, guint64 *size)
+{
+ GFile *f;
+ GFileEnumerator *en;
+ GError *error;
+ GFileInfo *info;
+
+ if (globs->break_get_dir_size)
+ return;
+
+ error = NULL;
+ en = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSGetDirSize_recurse: g_file_enumerate_children() error: %s\n", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ error = NULL;
+ while ((info = g_file_enumerator_next_file (en, NULL, &error))) {
+ if (globs->break_get_dir_size)
+ break;
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ f = g_file_resolve_relative_path (file, g_file_info_get_name (info));
+ if (f == NULL) {
+ g_print ("(EE) VFSGetDirSize_recurse: g_file_resolve_relative_path() failed.\n");
+ return;
+ }
+ VFSGetDirSize_recurse (globs, f, size);
+ g_object_unref (f);
+ }
+ else
+ *size += g_file_info_get_size (info);
+ g_object_unref (info);
+ }
+ if (error) {
+ g_print ("(EE) VFSGetDirSize_recurse: g_file_enumerator_next_file() error: %s\n", error->message);
+ g_error_free (error);
+ }
+ g_file_enumerator_close (en, NULL, &error);
+ g_object_unref (en);
+ if (error) {
+ g_print ("(EE) VFSGetDirSize_recurse: g_file_enumerator_close() error: %s\n", error->message);
+ g_error_free (error);
+ }
+}
+
+guint64
+VFSGetDirSize (struct TVFSGlobs *globs, char *APath)
+{
+ GFile *f;
+ guint64 size;
+
+ if (globs == NULL) return 0;
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSGetDirSize: globs->file == NULL !\n");
+ return 0;
+ }
+ f = g_file_resolve_relative_path (globs->file, APath);
+ if (f == NULL) {
+ g_print ("(EE) VFSGetDirSize: g_file_resolve_relative_path() failed.\n");
+ return 0;
+ }
+
+ size = 0;
+ globs->break_get_dir_size = FALSE;
+ VFSGetDirSize_recurse (globs, f, &size);
+ globs->break_get_dir_size = FALSE;
+ g_object_unref (f);
+
+ return size;
+}
+
+void
+VFSBreakGetDirSize (struct TVFSGlobs *globs)
+{
+ g_print ("(WW) VFSBreakGetDirSize: ################################### calling Break\n");
+ if (globs)
+ globs->break_get_dir_size = TRUE;
+}
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+
+TVFSFileDes
+VFSOpenFile (struct TVFSGlobs *globs, const char *APath, int Mode, int *Error)
+{
+ printf("(WW) VFSOpenFile: Not supported in GVFS plugin.\n");
+ return NULL;
+}
+
+TVFSResult
+VFSCloseFile (struct TVFSGlobs *globs, TVFSFileDes FileDescriptor)
+{
+ printf("(WW) VFSCloseFile: Not supported in GVFS plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+guint64
+VFSFileSeek (struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, guint64 AbsoluteOffset, int *Error)
+{
+ printf("(WW) VFSFileSeek: Not supported in GVFS plugin.\n");
+ return -1;
+}
+
+int
+VFSReadFile (struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, gpointer Buffer, int ABlockSize, int *Error)
+{
+ printf("(WW) VFSReadFile: Not supported in GVFS plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+int
+VFSWriteFile (struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, gpointer Buffer, int BytesCount, int *Error)
+{
+ printf("(WW) VFSWriteFile: Not supported in GVFS plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+void
+VFSSetBlockSize (struct TVFSGlobs *globs, int Value)
+{
+ if (globs)
+ globs->block_size = Value;
+}
+
+gboolean
+VFSIsOnSameFS (struct TVFSGlobs *globs, const char *Path1, const char *Path2)
+{
+ GFile *file1, *file2;
+ GFileInfo *info1, *info2;
+ GError *error;
+ gboolean res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSIsOnSameFS: globs->file == NULL !\n");
+ return FALSE;
+ }
+
+ file1 = g_file_resolve_relative_path (globs->file, Path1);
+ file2 = g_file_resolve_relative_path (globs->file, Path2);
+ if (file1 == NULL) {
+ g_print ("(EE) VFSIsOnSameFS: g_file_resolve_relative_path() failed.\n");
+ return FALSE;
+ }
+ if (file2 == NULL) {
+ g_print ("(EE) VFSIsOnSameFS: g_file_resolve_relative_path() failed.\n");
+ return FALSE;
+ }
+
+ error = NULL;
+ info1 = g_file_query_info (file1, G_FILE_ATTRIBUTE_ID_FILESYSTEM,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSIsOnSameFS: g_file_query_info() error: %s\n", error->message);
+ g_error_free (error);
+ g_object_unref (file1);
+ g_object_unref (file2);
+ return FALSE;
+ }
+ info2 = g_file_query_info (file2, G_FILE_ATTRIBUTE_ID_FILESYSTEM,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
+ if (error) {
+ g_print ("(EE) VFSIsOnSameFS: g_file_query_info() error: %s\n", error->message);
+ g_error_free (error);
+ g_object_unref (info1);
+ g_object_unref (file1);
+ g_object_unref (file2);
+ return FALSE;
+ }
+
+ g_print ("(II) VFSIsOnSameFS: '%s' vs. '%s'\n", g_file_info_get_attribute_string (info1, G_FILE_ATTRIBUTE_ID_FILESYSTEM),
+ g_file_info_get_attribute_string (info2, G_FILE_ATTRIBUTE_ID_FILESYSTEM));
+
+ res = strcmp (g_file_info_get_attribute_string (info1, G_FILE_ATTRIBUTE_ID_FILESYSTEM),
+ g_file_info_get_attribute_string (info2, G_FILE_ATTRIBUTE_ID_FILESYSTEM)) == 0;
+ g_object_unref (file1);
+ g_object_unref (file2);
+ g_object_unref (info1);
+ g_object_unref (info2);
+ return res;
+}
+
+gboolean
+VFSTwoSameFiles (struct TVFSGlobs *globs, const char *Path1, const char *Path2)
+{
+ GFile *file1, *file2;
+ gboolean res;
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSTwoSameFiles: globs->file == NULL !\n");
+ return FALSE;
+ }
+
+ file1 = g_file_resolve_relative_path (globs->file, Path1);
+ file2 = g_file_resolve_relative_path (globs->file, Path2);
+ if (file1 == NULL) {
+ g_print ("(EE) VFSTwoSameFiles: g_file_resolve_relative_path() failed.\n");
+ return FALSE;
+ }
+ if (file2 == NULL) {
+ g_print ("(EE) VFSTwoSameFiles: g_file_resolve_relative_path() failed.\n");
+ return FALSE;
+ }
+
+ /* FIXME: we should do some I/O test, we're esentially comparing strings at the moment */
+ res = g_file_equal (file1, file2);
+ g_object_unref (file1);
+ g_object_unref (file2);
+ return res;
+}
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+
+
+struct CopyJobRef {
+ struct TVFSGlobs *globs;
+ TVFSCopyCallBackFunc callback_func;
+ void *callback_data;
+
+ GCancellable *cancellable;
+};
+
+static void
+vfs_copy_progress_callback (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data)
+{
+ struct CopyJobRef *ref;
+
+ g_print ("(II) vfs_copy_progress_callback spawned: current_num_bytes = %lu, total_num_bytes = %lu\n", current_num_bytes, total_num_bytes);
+
+ if (! user_data)
+ return;
+ ref = (struct CopyJobRef*) user_data;
+
+ if (ref->callback_func) {
+ if (! ref->callback_func (current_num_bytes, total_num_bytes, ref->callback_data))
+ g_cancellable_cancel (ref->cancellable);
+ }
+}
+
+
+TVFSResult
+VFSCopyOut (struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, TVFSCopyCallBackFunc pCallBackProgress, void *data, gboolean Append)
+{
+ GFile *src, *dst;
+ GError *error;
+ struct CopyJobRef *ref;
+ TVFSResult res;
+
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSCopyOut: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ g_print ("(II) VFSCopyOut: '%s' --> '%s'\n", sSrcName, sDstName);
+
+ src = g_file_resolve_relative_path (globs->file, sSrcName);
+ if (src == NULL) {
+ g_print ("(EE) VFSCopyOut: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+ dst = g_file_new_for_path (sDstName);
+ if (dst == NULL) {
+ g_print ("(EE) VFSCopyOut: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ ref = g_slice_new0 (struct CopyJobRef);
+ ref->globs = globs;
+ ref->callback_func = pCallBackProgress;
+ ref->callback_data = data;
+ ref->cancellable = g_cancellable_new ();
+
+ res = cVFS_OK;
+ error = NULL;
+ g_file_copy (src, dst, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS, ref->cancellable, vfs_copy_progress_callback, ref, &error);
+ if (error) {
+ g_print ("(EE) VFSCopyOut: g_file_copy() error: %s\n", error->message);
+// res = g_error_to_TVFSResult (error);
+ if (error->code == G_IO_ERROR_CANCELLED)
+ res = cVFS_Cancelled;
+ else res = cVFS_ReadErr;
+ g_error_free (error);
+ }
+
+ g_object_unref (ref->cancellable);
+ g_slice_free (struct CopyJobRef, ref);
+ g_object_unref (src);
+ g_object_unref (dst);
+ return res;
+}
+
+TVFSResult
+VFSCopyIn (struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, TVFSCopyCallBackFunc pCallBackProgress, void *data, gboolean Append)
+{
+ GFile *src, *dst;
+ GError *error;
+ struct CopyJobRef *ref;
+ TVFSResult res;
+
+
+ if (globs->file == NULL) {
+ g_print ("(EE) VFSCopyIn: globs->file == NULL !\n");
+ return cVFS_Failed;
+ }
+
+ g_print ("(II) VFSCopyIn: '%s' --> '%s'\n", sSrcName, sDstName);
+
+ src = g_file_new_for_path (sSrcName);
+ if (src == NULL) {
+ g_print ("(EE) VFSCopyIn: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+ dst = g_file_resolve_relative_path (globs->file, sDstName);
+ if (dst == NULL) {
+ g_print ("(EE) VFSCopyIn: g_file_resolve_relative_path() failed.\n");
+ return cVFS_Failed;
+ }
+
+ ref = g_slice_new0 (struct CopyJobRef);
+ ref->globs = globs;
+ ref->callback_func = pCallBackProgress;
+ ref->callback_data = data;
+ ref->cancellable = g_cancellable_new ();
+
+ res = cVFS_OK;
+ error = NULL;
+ /* FIXME: Appending not supported */
+ g_file_copy (src, dst, G_FILE_COPY_NOFOLLOW_SYMLINKS, ref->cancellable, vfs_copy_progress_callback, ref, &error);
+ if (error) {
+ g_print ("(EE) VFSCopyIn: g_file_copy() error: %s\n", error->message);
+// res = g_error_to_TVFSResult (error);
+ if (error->code == G_IO_ERROR_CANCELLED)
+ res = cVFS_Cancelled;
+ else res = cVFS_WriteErr;
+ g_error_free (error);
+ }
+
+ g_object_unref (ref->cancellable);
+ g_slice_free (struct CopyJobRef, ref);
+ g_object_unref (src);
+ g_object_unref (dst);
+ return res;
+}
+
+
+
+/**********
+ * TODO:
+ * - block size settings for GIO subsystem
+ * - variable block size for different protocols?
+ * - support for appending in VFSCopyIn
+ *
+ ***/