[phodav: 2/6] server: add real root to PhodavVirtualDir
- From: Marc-André Lureau <malureau src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [phodav: 2/6] server: add real root to PhodavVirtualDir
- Date: Thu, 27 Aug 2020 11:36:53 +0000 (UTC)
commit 64cf31d90a6aba03548466d1561ed9a1aa4719f8
Author: Jakub Janků <jjanku redhat com>
Date: Wed Jul 8 15:50:00 2020 +0200
server: add real root to PhodavVirtualDir
Signed-off-by: Jakub Janků <jjanku redhat com>
doc/reference/phodav-2.0-sections.txt | 2 +
libphodav/libphodav.syms | 2 +
libphodav/phodav-method-proppatch.c | 8 +++
libphodav/phodav-virtual-dir.c | 130 +++++++++++++++++++++++++++++++---
libphodav/phodav-virtual-dir.h | 4 ++
5 files changed, 136 insertions(+), 10 deletions(-)
---
diff --git a/doc/reference/phodav-2.0-sections.txt b/doc/reference/phodav-2.0-sections.txt
index 6989f56..126b80d 100644
--- a/doc/reference/phodav-2.0-sections.txt
+++ b/doc/reference/phodav-2.0-sections.txt
@@ -17,6 +17,8 @@ phodav_server_get_type
<SECTION>
<FILE>phodav-virtual-dir</FILE>
phodav_virtual_dir_new_root
+phodav_virtual_dir_root_set_real
+phodav_virtual_dir_root_get_real
phodav_virtual_dir_new_dir
phodav_virtual_dir_attach_real_child
diff --git a/libphodav/libphodav.syms b/libphodav/libphodav.syms
index 7b58d58..52b55d6 100644
--- a/libphodav/libphodav.syms
+++ b/libphodav/libphodav.syms
@@ -7,6 +7,8 @@ LIBPHODAV1_0.0 {
phodav_server_quit;
phodav_server_run;
phodav_virtual_dir_new_root;
+ phodav_virtual_dir_root_set_real;
+ phodav_virtual_dir_root_get_real;
phodav_virtual_dir_new_dir;
phodav_virtual_dir_attach_real_child;
phodav_virtual_dir_get_type;
diff --git a/libphodav/phodav-method-proppatch.c b/libphodav/phodav-method-proppatch.c
index 4724bba..4cd8211 100644
--- a/libphodav/phodav-method-proppatch.c
+++ b/libphodav/phodav-method-proppatch.c
@@ -18,6 +18,7 @@
#include "phodav-priv.h"
#include "phodav-multistatus.h"
#include "phodav-utils.h"
+#include "phodav-virtual-dir.h"
#include <sys/types.h>
#ifdef HAVE_SYS_XATTR_H
@@ -50,6 +51,12 @@ set_attr (GFile *file, xmlNodePtr attrnode,
g_return_val_if_fail (attrname, SOUP_STATUS_BAD_REQUEST);
/* https://gitlab.gnome.org/GNOME/glib/issues/1187 */
+ if (PHODAV_IS_VIRTUAL_DIR (file))
+ file = phodav_virtual_dir_root_get_real (PHODAV_VIRTUAL_DIR (file));
+ else
+ g_object_ref (file);
+ if (!file)
+ return SOUP_STATUS_FORBIDDEN;
gchar *path = g_file_get_path (file);
#ifdef HAVE_SYS_XATTR_H
removexattr (path, attrname);
@@ -57,6 +64,7 @@ set_attr (GFile *file, xmlNodePtr attrnode,
g_debug ("cannot remove xattr from %s, not supported", path); /* FIXME? */
#endif
g_free (path);
+ g_object_unref (file);
}
else
{
diff --git a/libphodav/phodav-virtual-dir.c b/libphodav/phodav-virtual-dir.c
index 702ba8c..4162e69 100644
--- a/libphodav/phodav-virtual-dir.c
+++ b/libphodav/phodav-virtual-dir.c
@@ -68,6 +68,7 @@ struct _PhodavVirtualDir {
gboolean dummy;
PhodavVirtualDir *parent;
GList *children;
+ GFile *real_root; /* only set for virtual root, otherwise NULL */
/* TODO: we could store just the base name and build up the path when needed */
gchar *path;
@@ -85,6 +86,7 @@ struct _PhodavVirtualDirEnumerator {
GFileQueryInfoFlags flags;
GList *children;
GList *current;
+ GFileEnumerator *real_root_enumerator;
};
G_DEFINE_TYPE (PhodavVirtualDirEnumerator, phodav_virtual_dir_enumerator, G_TYPE_FILE_ENUMERATOR)
@@ -98,7 +100,11 @@ phodav_virtual_dir_enumerator_next_file (GFileEnumerator *enumerator,
GFile *file;
if (!self->current || !self->current->data)
- return NULL;
+ {
+ if (self->real_root_enumerator)
+ return g_file_enumerator_next_file (self->real_root_enumerator, cancellable, error);
+ return NULL;
+ }
file = G_FILE (self->current->data);
self->current = self->current->next;
@@ -114,6 +120,7 @@ phodav_virtual_dir_enumerator_close (GFileEnumerator *enumerator,
g_clear_pointer (&self->attributes, g_free);
g_list_free_full (self->children, g_object_unref);
self->children = NULL;
+ g_clear_object (&self->real_root_enumerator);
return TRUE;
}
@@ -160,6 +167,8 @@ static gchar *
phodav_virtual_dir_get_path (GFile *file)
{
PhodavVirtualDir *self = PHODAV_VIRTUAL_DIR (file);
+ if (self->real_root)
+ return g_file_get_path (self->real_root);
return g_strdup (self->path);
}
@@ -180,6 +189,9 @@ phodav_virtual_dir_query_info (GFile *file,
return NULL;
}
+ if (self->real_root)
+ return g_file_query_info (self->real_root, attributes, flags, cancellable, error);
+
info = g_file_info_new ();
base = phodav_virtual_dir_get_basename (file);
g_file_info_set_name (info, base);
@@ -206,6 +218,9 @@ phodav_virtual_dir_query_filesystem_info (GFile *file,
return NULL;
}
+ if (self->real_root)
+ return g_file_query_filesystem_info (self->real_root, attributes, cancellable, error);
+
info = g_file_info_new ();
g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, 0);
return info;
@@ -223,6 +238,10 @@ phodav_virtual_dir_measure_disk_usage (GFile *file,
GError **error)
{
/* prop_quota_used in phodav-method-propfind.c is only interested in @disk_usage */
+ PhodavVirtualDir *self = PHODAV_VIRTUAL_DIR (file);
+ if (self->real_root)
+ return g_file_measure_disk_usage (self->real_root, flags, cancellable, progress_callback,
+ progress_data, disk_usage, num_dirs, num_files, error);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Operation not supported");
return FALSE;
}
@@ -256,6 +275,15 @@ phodav_virtual_dir_enumerate_children (GFile *file,
enumerator->flags = flags;
enumerator->children = g_list_copy_deep (self->children, (GCopyFunc) g_object_ref, NULL);
enumerator->current = enumerator->children;
+ if (self->real_root)
+ {
+ enumerator->real_root_enumerator =
+ g_file_enumerate_children(self->real_root,
+ attributes,
+ flags,
+ cancellable,
+ error);
+ }
return G_FILE_ENUMERATOR (enumerator);
}
@@ -290,12 +318,12 @@ phodav_virtual_dir_find_direct_child (PhodavVirtualDir *parent,
* 1) PhodavVirtualDir
* 2) GFile attached to PhodavVirtualDir
* 3) GFile (child of attached GFile)
- * 4) NULL
- * In case 1) and 2), the reference count is incremented by 1,
- * this means that the result should always be freed. */
+ * 4) NULL (when not found)
+ * If returned value is non-NULL, call g_object_unref(). */
static GFile *
phodav_virtual_dir_find_child_recursive (PhodavVirtualDir *parent,
- const gchar *path)
+ const gchar *path,
+ gboolean *common_segment)
{
GFile *current;
gchar **segments, **segment_ptr, *real;
@@ -304,6 +332,9 @@ phodav_virtual_dir_find_child_recursive (PhodavVirtualDir *parent,
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (path[0] != '\0', NULL);
+ if (common_segment)
+ *common_segment = FALSE;
+
segments = g_strsplit (path, "/", -1);
current = G_FILE (parent);
@@ -325,8 +356,15 @@ phodav_virtual_dir_find_child_recursive (PhodavVirtualDir *parent,
return current;
}
current = phodav_virtual_dir_find_direct_child (PHODAV_VIRTUAL_DIR (current), *segment_ptr);
- if (!current)
- break;
+ if (current)
+ {
+ if (common_segment)
+ *common_segment = TRUE;
+ }
+ else
+ {
+ break;
+ }
}
g_strfreev (segments);
@@ -341,15 +379,20 @@ phodav_virtual_dir_resolve_relative_path (GFile *file,
{
PhodavVirtualDir *parent;
GFile *child;
+ gboolean common_segment;
if (relative_path[0] == '\0')
return g_object_ref (file);
- /* try to find the file first */
+ /* try to find the file inside virtual dirs first */
parent = PHODAV_VIRTUAL_DIR (file);
- child = phodav_virtual_dir_find_child_recursive (parent, relative_path);
+ child = phodav_virtual_dir_find_child_recursive (parent, relative_path, &common_segment);
if (child)
return child;
+ if (common_segment)
+ return virtual_dir_dummy_new ();
+ if (parent->real_root)
+ return g_file_resolve_relative_path (parent->real_root, relative_path);
return virtual_dir_dummy_new ();
}
@@ -438,6 +481,23 @@ phodav_virtual_dir_set_display_name (GFile *file,
return NULL;
}
+static gboolean
+phodav_virtual_dir_set_attribute (GFile *file,
+ const char *attribute,
+ GFileAttributeType type,
+ gpointer value_p,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ PhodavVirtualDir *self = PHODAV_VIRTUAL_DIR (file);
+ if (self->real_root)
+ return g_file_set_attribute (self->real_root, attribute, type,
+ value_p, flags, cancellable, error);
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Operation not supported");
+ return FALSE;
+}
+
static gboolean
phodav_virtual_dir_set_attributes_from_info (GFile *file,
GFileInfo *info,
@@ -476,6 +536,7 @@ phodav_virtual_dir_file_interface_init (GFileIface *iface)
iface->get_relative_path = phodav_virtual_dir_get_relative_path;
iface->get_child_for_display_name = phodav_virtual_dir_get_child_for_display_name;
iface->set_display_name = phodav_virtual_dir_set_display_name;
+ iface->set_attribute = phodav_virtual_dir_set_attribute;
iface->set_attributes_from_info = phodav_virtual_dir_set_attributes_from_info;
}
@@ -545,6 +606,55 @@ phodav_virtual_dir_new_root (void)
return root;
}
+/**
+ * phodav_virtual_dir_root_set_real:
+ * @root: #PhodavVirtualDir obtained from phodav_virtual_dir_new_root()
+ * @real_root_path: (nullable): path to a real directory
+ *
+ * If @real_root_path is not %NULL, @root lists all files added with
+ * phodav_virtual_dir_new_dir() and phodav_virtual_dir_attach_real_child()
+ * as well as all files under @real_root_path as its children.
+ *
+ * This enables you to keep the server path to files in @real_root_path unchanged
+ * while also using the virtual folders. (@real_root_path/fileA is still accessible as "/fileA",
+ * if you used phodav_virtual_dir_attach_real_child(),
+ * the path would change to "/real_root-basename/fileA")
+ *
+ * This does not check for any conflicts between the virtual directories and
+ * the real files - virtual directories take precedence (e.g. in g_file_get_child()).
+ **/
+void
+phodav_virtual_dir_root_set_real (PhodavVirtualDir *root,
+ const gchar *real_root_path)
+{
+ g_return_if_fail (root != NULL);
+ g_return_if_fail (is_root(root));
+
+ g_clear_object (&root->real_root);
+ if (real_root_path)
+ root->real_root = g_file_new_for_path (real_root_path);
+ else
+ root->real_root = NULL;
+}
+
+/**
+ * phodav_virtual_dir_root_get_real:
+ * @root: #PhodavVirtualDir obtained from phodav_virtual_dir_new_root()
+ *
+ * Returns: (transfer full): the #GFile previously set by phodav_virtual_dir_root_set_real(),
+ * otherwise NULL.
+ **/
+GFile *
+phodav_virtual_dir_root_get_real (PhodavVirtualDir *root)
+{
+ g_return_val_if_fail (root != NULL, NULL);
+ g_return_val_if_fail (is_root(root), NULL);
+
+ if (root->real_root)
+ return g_object_ref (root->real_root);
+ return NULL;
+}
+
/**
* phodav_virtual_dir_new_dir:
* @root: #PhodavVirtualDir returned by phodav_virtual_dir_new_root()
@@ -583,7 +693,7 @@ phodav_virtual_dir_new_dir (PhodavVirtualDir *root,
goto end;
}
- f = phodav_virtual_dir_find_child_recursive (root, dir);
+ f = phodav_virtual_dir_find_child_recursive (root, dir, NULL);
if (!f)
{
g_set_error_literal (error,
diff --git a/libphodav/phodav-virtual-dir.h b/libphodav/phodav-virtual-dir.h
index bc482ff..86be602 100644
--- a/libphodav/phodav-virtual-dir.h
+++ b/libphodav/phodav-virtual-dir.h
@@ -31,6 +31,10 @@ PhodavVirtualDir * phodav_virtual_dir_new_dir (PhodavVirtualDir
GError **error);
gboolean phodav_virtual_dir_attach_real_child (PhodavVirtualDir *parent,
GFile *child);
+void phodav_virtual_dir_root_set_real (PhodavVirtualDir *root,
+ const gchar *real_root_path);
+
+GFile * phodav_virtual_dir_root_get_real (PhodavVirtualDir *root);
#define PHODAV_TYPE_VIRTUAL_DIR_ENUMERATOR phodav_virtual_dir_enumerator_get_type ()
G_DECLARE_FINAL_TYPE (PhodavVirtualDirEnumerator, phodav_virtual_dir_enumerator,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]