Browse Source

VFS: many changes for use vfs_path_t

 * completed vfs_path_from_str();
 * completed vfs_path_to_str() and vfs_path_to_str_elements_count();
 * removed deprecated vfs_split();
 * changes in all related code;
 * new unit tests.

Signed-off-by: Slava Zanko <slavazanko@gmail.com>
Slava Zanko 14 years ago
parent
commit
a12fdfbb0e

+ 3 - 3
lib/tests/vfs/Makefile.am

@@ -6,7 +6,7 @@ TESTS = \
 	vfs_prefix_to_class \
 	get_vfs_class \
 	vfs_split \
-	vfs_path_from_string \
+	vfs_path_string_convert \
 	vfs_s_get_path_mangle
 
 check_PROGRAMS = $(TESTS)
@@ -20,8 +20,8 @@ vfs_split_SOURCES = \
 vfs_prefix_to_class_SOURCES = \
 	vfs_prefix_to_class.c
 
-vfs_path_from_string_SOURCES = \
-	vfs_path_from_string.c
+vfs_path_string_convert_SOURCES = \
+	vfs_path_string_convert.c
 
 vfs_s_get_path_mangle_SOURCES = \
 	vfs_s_get_path_mangle.c

+ 2 - 2
lib/tests/vfs/get_vfs_class.c

@@ -63,7 +63,7 @@ START_TEST (test_register_vfs_class)
     vfs_test_ops.prefix = "test:";
     vfs_register_class (&vfs_test_ops);
 
-    fail_if (vfs_list->len != 2, "Failed to register test VFS module");;
+    fail_if (vfs__classes_list->len != 2, "Failed to register test VFS module");;
 
     {
         struct vfs_class *result;
@@ -104,7 +104,7 @@ START_TEST (test_register_vfs_class2)
     vfs_register_class (&vfs_test_ops2);
 
 
-    fail_if (vfs_list->len != 3, "Failed to register test VFS module");;
+    fail_if (vfs__classes_list->len != 3, "Failed to register test VFS module");;
 
     {
         struct vfs_class *result;

+ 13 - 6
lib/tests/vfs/vfs_path_from_string.c → lib/tests/vfs/vfs_path_string_convert.c

@@ -73,15 +73,22 @@ teardown (void)
 }
 
 /* --------------------------------------------------------------------------------------------- */
-
-START_TEST (test_vfs_path_from_string)
+#define ETALON_PATH_STR "/#test1:/bla-bla/some/path/#test2:/bla-bla/some/path#test3:/111/22/33"
+START_TEST (test_vfs_path_from_to_string)
 {
     vfs_path_t *vpath;
     size_t vpath_len;
-    vpath = vfs_path_from_str ("/#test1://bla-bla/some/path/#test2://bla-bla/some/path#test3:/111/22/33");
+    char *result;
+    vpath = vfs_path_from_str (ETALON_PATH_STR);
+
+
+    vpath_len = vfs_path_elements_count(vpath);
+    fail_unless(vpath_len == 4, "vpath length should be 4 (actial: %d)",vpath_len);
+
+    result = vfs_path_to_str(vpath);
+    fail_unless(strcmp(ETALON_PATH_STR, result) == 0, "expected(%s) doesn't equal to actual(%s)", ETALON_PATH_STR, result);
+    g_free(result);
 
-    vpath_len = vfs_path_length(vpath);
-//    fail_unless(vpath_len == 3, "vpath length should be 3 (actial: %d)",vpath_len);
     vfs_path_free(vpath);
 }
 END_TEST
@@ -100,7 +107,7 @@ main (void)
     tcase_add_checked_fixture (tc_core, setup, teardown);
 
     /* Add new tests here: *************** */
-    tcase_add_test (tc_core, test_vfs_path_from_string);
+    tcase_add_test (tc_core, test_vfs_path_from_to_string);
     /* *********************************** */
 
     suite_add_tcase (s, tc_core);

+ 143 - 0
lib/tests/vfs/vfs_prefix_to_class.c

@@ -0,0 +1,143 @@
+/* lib/vfs - test vfs_prefix_to_class() functionality
+
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   Written by:
+    Slava Zanko <slavazanko@gmail.com>, 2011
+
+   This program 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 program 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 program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#define TEST_SUITE_NAME "/lib/vfs"
+
+#include <check.h>
+
+
+#include "lib/global.h"
+#include "lib/strutil.h"
+#include "lib/vfs/xdirentry.h"
+#include "lib/vfs/vfs.c" /* for testing static methods  */
+
+#include "src/vfs/local/local.c"
+
+struct vfs_s_subclass test_subclass1, test_subclass2, test_subclass3;
+struct vfs_class vfs_test_ops1, vfs_test_ops2, vfs_test_ops3;
+
+
+static int
+test_which (struct vfs_class *me, const char *path)
+{
+    (void) me;
+
+    if (
+        (strcmp(path, "test_1:") == 0) ||
+        (strcmp(path, "test_2:") == 0) ||
+        (strcmp(path, "test_3:") == 0) ||
+        (strcmp(path, "test_4:") == 0)
+    )
+        return 1;
+    return -1;
+}
+
+static void
+setup (void)
+{
+
+    str_init_strings (NULL);
+
+    vfs_init ();
+    init_localfs ();
+    vfs_setup_work_dir ();
+
+
+    test_subclass1.flags = VFS_S_REMOTE;
+    vfs_s_init_class (&vfs_test_ops1, &test_subclass1);
+    vfs_test_ops1.name = "testfs1";
+    vfs_test_ops1.flags = VFSF_NOLINKS;
+    vfs_test_ops1.prefix = "test1:";
+    vfs_test_ops1.which = test_which;
+    vfs_register_class (&vfs_test_ops1);
+
+    vfs_s_init_class (&vfs_test_ops2, &test_subclass2);
+    vfs_test_ops2.name = "testfs2";
+    vfs_test_ops2.prefix = "test2:";
+    vfs_register_class (&vfs_test_ops2);
+
+    vfs_s_init_class (&vfs_test_ops3, &test_subclass3);
+    vfs_test_ops3.name = "testfs3";
+    vfs_test_ops3.prefix = "test3:";
+    vfs_register_class (&vfs_test_ops3);
+
+}
+
+static void
+teardown (void)
+{
+    vfs_shut ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+START_TEST (test_vfs_prefix_to_class_valid)
+{
+    fail_unless(vfs_prefix_to_class((char *) "test_1:") == &vfs_test_ops1, "'test_1:' doesn't transform to vfs_test_ops1");
+    fail_unless(vfs_prefix_to_class((char *) "test_2:") == &vfs_test_ops1, "'test_2:' doesn't transform to vfs_test_ops1");
+    fail_unless(vfs_prefix_to_class((char *) "test_3:") == &vfs_test_ops1, "'test_3:' doesn't transform to vfs_test_ops1");
+    fail_unless(vfs_prefix_to_class((char *) "test_4:") == &vfs_test_ops1, "'test_4:' doesn't transform to vfs_test_ops1");
+
+    fail_unless(vfs_prefix_to_class((char *) "test2:") == &vfs_test_ops2, "'test2:' doesn't transform to vfs_test_ops2");
+
+    fail_unless(vfs_prefix_to_class((char *) "test3:") == &vfs_test_ops3, "'test3:' doesn't transform to vfs_test_ops3");
+}
+END_TEST
+
+/* --------------------------------------------------------------------------------------------- */
+
+START_TEST (test_vfs_prefix_to_class_invalid)
+{
+    fail_unless(vfs_prefix_to_class((char *) "test1:") == NULL, "'test1:' doesn't transform to NULL");
+    fail_unless(vfs_prefix_to_class((char *) "test_5:") == NULL, "'test_5:' doesn't transform to NULL");
+    fail_unless(vfs_prefix_to_class((char *) "test4:") == NULL, "'test4:' doesn't transform to NULL");
+}
+END_TEST
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+main (void)
+{
+    int number_failed;
+
+    Suite *s = suite_create (TEST_SUITE_NAME);
+    TCase *tc_core = tcase_create ("Core");
+    SRunner *sr;
+
+    tcase_add_checked_fixture (tc_core, setup, teardown);
+
+    /* Add new tests here: *************** */
+    tcase_add_test (tc_core, test_vfs_prefix_to_class_valid);
+    tcase_add_test (tc_core, test_vfs_prefix_to_class_invalid);
+    /* *********************************** */
+
+    suite_add_tcase (s, tc_core);
+    sr = srunner_create (s);
+    srunner_set_log (sr, "get_vfs_class.log");
+    srunner_run_all (sr, CK_NORMAL);
+    number_failed = srunner_ntests_failed (sr);
+    srunner_free (sr);
+    return (number_failed == 0) ? 0 : 1;
+}
+
+/* --------------------------------------------------------------------------------------------- */

+ 7 - 10
lib/tests/vfs/vfs_s_get_path_mangle.c

@@ -46,8 +46,8 @@ test1_mock_open_archive(struct vfs_class *me, struct vfs_s_super *super,
 
     (void) op;
 
-    fail_unless(strcmp(ETALON_VFS_NAME ARCH_NAME, archive_name) == 0,
-        "etalon(%s) doesn't equal to actual(%s)", ETALON_VFS_NAME ARCH_NAME, archive_name);
+    fail_unless(strcmp("/" ETALON_VFS_NAME ARCH_NAME, archive_name) == 0,
+        "etalon(%s) doesn't equal to actual(%s)", "/" ETALON_VFS_NAME ARCH_NAME, archive_name);
 
     super->name = g_strdup (archive_name);
     super->data = g_new (char *, 1);
@@ -124,20 +124,17 @@ START_TEST (test_vfs_s_get_path_mangle)
     struct vfs_s_super *archive;
 
     const char *result;
-    char *path = g_strdup(ETALON_VFS_NAME ARCH_NAME"#test1:/"ETALON_PATH);
+    vfs_path_t *vpath = vfs_path_from_str("/" ETALON_VFS_NAME ARCH_NAME "#test1:/" ETALON_PATH);
 
-    struct vfs_class *me;
-    me = vfs_get_class(path);
-
-    result = vfs_s_get_path_mangle (me, path, &archive, 0);
+    result = vfs_s_get_path_mangle (vpath, &archive, 0);
 
     fail_unless(strcmp(ETALON_PATH, result) == 0,
         "expected(%s) doesn't equal to actual(%s)", ETALON_PATH, result);
 
-    fail_unless(strcmp(ETALON_VFS_NAME ARCH_NAME,archive->name) == 0,
-        "expected(%s) doesn't equal to actual(%s)", ETALON_VFS_NAME ARCH_NAME, archive->name);
+    fail_unless(strcmp("/" ETALON_VFS_NAME ARCH_NAME,archive->name) == 0,
+        "expected(%s) doesn't equal to actual(%s)", "/" ETALON_VFS_NAME ARCH_NAME, archive->name);
 
-    g_free(path);
+    g_free(vpath);
 
 }
 END_TEST

+ 22 - 22
lib/tests/vfs/vfs_split.c

@@ -28,7 +28,7 @@
 #include "lib/global.h"
 #include "lib/strutil.h"
 #include "lib/vfs/xdirentry.h"
-#include "lib/vfs/vfs.c" /* for testing static methods  */
+#include "lib/vfs/path.c" /* for testing static methods  */
 
 #include "src/vfs/local/local.c"
 
@@ -76,8 +76,8 @@ teardown (void)
 
 START_TEST (test_vfs_split)
 {
-    char *local, *op, *path;
-    const char *etalon_path, *etalon_local, *etalon_op;
+    char *path;
+    const char *local, *op, *etalon_path, *etalon_local, *etalon_op;
     struct vfs_class *result;
 
     path = g_strdup("#test1:/bla-bla/some/path/#test2:/bla-bla/some/path2/#test3:/qqq/www/eee.rr");
@@ -85,7 +85,7 @@ START_TEST (test_vfs_split)
     etalon_path = "#test1:/bla-bla/some/path/#test2:/bla-bla/some/path2/";
     etalon_local = "qqq/www/eee.rr";
     etalon_op = "test3:";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops3, "Result(%p) doesn't match to vfs_test_ops3(%p)", result, &vfs_test_ops3);
     fail_unless(strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
@@ -94,7 +94,7 @@ START_TEST (test_vfs_split)
     etalon_path = "#test1:/bla-bla/some/path/";
     etalon_local = "bla-bla/some/path2/";
     etalon_op = "test2:";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops2, "Result(%p) doesn't match to vfs_test_ops2(%p)", result, &vfs_test_ops2);
     fail_unless(strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
@@ -103,13 +103,13 @@ START_TEST (test_vfs_split)
     etalon_path = "";
     etalon_local = "bla-bla/some/path/";
     etalon_op = "test1:";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops1, "Result(%p) doesn't match to vfs_test_ops1(%p)", result, &vfs_test_ops2);
     fail_unless(strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
     fail_unless(strcmp (op, etalon_op) == 0, "parsed VFS name ('%s') doesn't match to '%s'", op, etalon_op);
 
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == NULL, "Result(%p) doesn't match to vfs_test_ops1(NULL)", result);
     fail_unless(strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
@@ -123,8 +123,8 @@ END_TEST
 
 START_TEST (test_vfs_split_with_local)
 {
-    char *local, *op, *path;
-    const char *etalon_path, *etalon_local, *etalon_op;
+    char *path;
+    const char *local, *op, *etalon_path, *etalon_local, *etalon_op;
     struct vfs_class *result;
 
     path = g_strdup("/local/path/#test1:/bla-bla/some/path/#test2:/bla-bla/some/path2#test3:/qqq/www/eee.rr");
@@ -132,7 +132,7 @@ START_TEST (test_vfs_split_with_local)
     etalon_path = "/local/path/#test1:/bla-bla/some/path/#test2:/bla-bla/some/path2";
     etalon_local = "qqq/www/eee.rr";
     etalon_op = "test3:";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops3, "Result(%p) doesn't match to vfs_test_ops3(%p)", result, &vfs_test_ops3);
     fail_unless(strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
@@ -141,7 +141,7 @@ START_TEST (test_vfs_split_with_local)
     etalon_path = "/local/path/#test1:/bla-bla/some/path/";
     etalon_local = "bla-bla/some/path2";
     etalon_op = "test2:";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops2, "Result(%p) doesn't match to vfs_test_ops2(%p)", result, &vfs_test_ops2);
     fail_unless(strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
@@ -150,13 +150,13 @@ START_TEST (test_vfs_split_with_local)
     etalon_path = "/local/path/";
     etalon_local = "bla-bla/some/path/";
     etalon_op = "test1:";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops1, "Result(%p) doesn't match to vfs_test_ops1(%p)", result, &vfs_test_ops2);
     fail_unless(strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
     fail_unless(strcmp (op, etalon_op) == 0, "parsed VFS name ('%s') doesn't match to '%s'", op, etalon_op);
 
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == NULL, "Result(%p) doesn't match to vfs_test_ops1(NULL)", result);
 
     g_free(path);
@@ -166,8 +166,8 @@ END_TEST
 /* --------------------------------------------------------------------------------------------- */
 START_TEST (test_vfs_split_url)
 {
-    char *local, *op, *path;
-    const char *etalon_path, *etalon_local, *etalon_op;
+    char *path;
+    const char *local, *op, *etalon_path, *etalon_local, *etalon_op;
     struct vfs_class *result;
 
     path = g_strdup("#test2:username:passwd@somehost.net/bla-bla/some/path2");
@@ -175,7 +175,7 @@ START_TEST (test_vfs_split_url)
     etalon_path = "";
     etalon_local = "bla-bla/some/path2";
     etalon_op = "test2:username:passwd@somehost.net";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops2, "Result(%p) doesn't match to vfs_test_ops2(%p)", result, &vfs_test_ops2);
     fail_unless(path != NULL && strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(local != NULL && strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
@@ -189,8 +189,8 @@ END_TEST
 
 START_TEST (test_vfs_split_url_with_semi)
 {
-    char *local, *op, *path;
-    const char *etalon_path, *etalon_local, *etalon_op;
+    char *path;
+    const char *local, *op, *etalon_path, *etalon_local, *etalon_op;
     struct vfs_class *result;
 
 
@@ -199,7 +199,7 @@ START_TEST (test_vfs_split_url_with_semi)
     etalon_path = "/local/path/#test1:/bla-bla/some/path/";
     etalon_local = "bla-bla/some/path2";
     etalon_op = "test2:username:p!a@s#s$w%d@somehost.net";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops2, "Result(%p) doesn't match to vfs_test_ops2(%p)", result, &vfs_test_ops2);
     fail_unless(path != NULL && strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(local != NULL && strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);
@@ -214,8 +214,8 @@ END_TEST
 
 START_TEST (test_vfs_split_with_semi_in_path)
 {
-    char *local, *op, *path;
-    const char *etalon_path, *etalon_local, *etalon_op;
+    char *path;
+    const char *local, *op, *etalon_path, *etalon_local, *etalon_op;
     struct vfs_class *result;
 
     path = g_strdup("#test2:/bl#a-bl#a/so#me/pa#th2");
@@ -223,7 +223,7 @@ START_TEST (test_vfs_split_with_semi_in_path)
     etalon_path = "";
     etalon_local = "bl#a-bl#a/so#me/pa#th2";
     etalon_op = "test2:";
-    result = vfs_split (path, &local, &op);
+    result = _vfs_split_with_semi_skip_count (path, &local, &op, 0);
     fail_unless(result == &vfs_test_ops2, "Result(%p) doesn't match to vfs_test_ops2(%p)", result, &vfs_test_ops2);
     fail_unless(path != NULL && strcmp (path, etalon_path) == 0, "path('%s') doesn't match to '%s'", path, etalon_path);
     fail_unless(local != NULL && strcmp (local, etalon_local) == 0, "parsed local path('%s') doesn't match to '%s'", local, etalon_local);

+ 47 - 38
lib/vfs/direntry.c

@@ -398,17 +398,9 @@ vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
  */
 
 static char *
-vfs_s_get_path (const vfs_path_t *vpath, struct vfs_s_super **archive, int flags)
+vfs_s_get_path (const vfs_path_t * vpath, struct vfs_s_super **archive, int flags)
 {
-    char *buf, *retval;
-    vfs_path_element_t *path_element;
-
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
-
-    buf = g_strdup (vpath->unparsed);
-    retval = g_strdup (vfs_s_get_path_mangle (path_element->class, buf, archive, flags));
-    g_free (buf);
-    return retval;
+    return g_strdup (vfs_s_get_path_mangle (vpath, archive, flags));
 }
 
 /* --------------------------------------------------------------------------------------------- */
@@ -416,17 +408,18 @@ vfs_s_get_path (const vfs_path_t *vpath, struct vfs_s_super **archive, int flags
 /* ------------------------ readdir & friends ----------------------------- */
 
 static struct vfs_s_inode *
-vfs_s_inode_from_path (const vfs_path_t *vpath, int flags)
+vfs_s_inode_from_path (const vfs_path_t * vpath, int flags)
 {
     struct vfs_s_super *super;
     struct vfs_s_inode *ino;
     char *q;
     vfs_path_element_t *path_element;
 
-    if (!(q = vfs_s_get_path (vpath, &super, 0)))
+    q = vfs_s_get_path (vpath, &super, 0);
+    if (q == NULL)
         return NULL;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     ino =
         vfs_s_find_inode (path_element->class, super, q,
@@ -450,7 +443,7 @@ vfs_s_opendir (const vfs_path_t * vpath)
     struct dirhandle *info;
     vfs_path_element_t *path_element;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     dir = vfs_s_inode_from_path (vpath, FL_DIR | FL_FOLLOW);
     if (dir == NULL)
@@ -576,7 +569,7 @@ vfs_s_readlink (const vfs_path_t * vpath, char *buf, size_t size)
     size_t len;
     vfs_path_element_t *path_element;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     ino = vfs_s_inode_from_path (vpath, 0);
     if (!ino)
@@ -827,13 +820,12 @@ vfs_s_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
 {
     vfs_path_element_t *path_element;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
     switch (ctlop)
     {
     case VFS_SETCTL_STALE_DATA:
         {
-            struct vfs_s_inode *ino =
-                vfs_s_inode_from_path (vpath, 0);
+            struct vfs_s_inode *ino = vfs_s_inode_from_path (vpath, 0);
 
             if (ino == NULL)
                 return 0;
@@ -1056,35 +1048,43 @@ vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super,
  * can be changed and the result may point inside the original string.
  */
 const char *
-vfs_s_get_path_mangle (struct vfs_class *me, char *inname, struct vfs_s_super **archive, int flags)
+vfs_s_get_path_mangle (const vfs_path_t * vpath, struct vfs_s_super **archive, int flags)
 {
     GList *iter;
     const char *retval;
-    char *local, *op;
-    const char *archive_name;
+    char *archive_name;
     int result = -1;
     struct vfs_s_super *super;
     void *cookie = NULL;
+    vfs_path_element_t *path_element;
+    struct vfs_s_subclass *subclass;
+
+    path_element = vfs_path_get_by_index (vpath, -1);
+    subclass = ((struct vfs_s_subclass *) path_element->class->data);
 
-    archive_name = inname;
-    vfs_split (inname, &local, &op);
-    retval = (local != NULL) ? local : "";
+    archive_name = vfs_path_to_str_elements_count (vpath, -1);
+    retval = (path_element->path != NULL) ? path_element->path : "";
 
-    if (MEDATA->archive_check != NULL)
+    if (subclass->archive_check != NULL)
     {
-        cookie = MEDATA->archive_check (me, archive_name, op);
+        cookie =
+            subclass->archive_check (path_element->class, archive_name, path_element->raw_url_str);
         if (cookie == NULL)
+        {
+            g_free (archive_name);
             return NULL;
+        }
     }
 
-    for (iter = MEDATA->supers; iter != NULL; iter = g_list_next (iter))
+    for (iter = subclass->supers; iter != NULL; iter = g_list_next (iter))
     {
         int i;
 
         super = (struct vfs_s_super *) iter->data;
 
         /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
-        i = MEDATA->archive_same (me, super, archive_name, op, cookie);
+        i = subclass->archive_same (path_element->class, super, archive_name,
+                                    path_element->raw_url_str, cookie);
         if (i != 0)
         {
             if (i == 1)
@@ -1094,26 +1094,35 @@ vfs_s_get_path_mangle (struct vfs_class *me, char *inname, struct vfs_s_super **
     }
 
     if (flags & FL_NO_OPEN)
-        ERRNOR (EIO, NULL);
+    {
+        path_element->class->verrno = EIO;
+        g_free (archive_name);
+        return NULL;
+    }
 
-    super = vfs_s_new_super (me);
-    if (MEDATA->open_archive != NULL)
-        result = MEDATA->open_archive (me, super, archive_name, op);
+    super = vfs_s_new_super (path_element->class);
+    if (subclass->open_archive != NULL)
+        result =
+            subclass->open_archive (path_element->class, super, archive_name,
+                                    path_element->raw_url_str);
     if (result == -1)
     {
-        vfs_s_free_super (me, super);
-        ERRNOR (EIO, NULL);
+        vfs_s_free_super (path_element->class, super);
+        path_element->class->verrno = EIO;
+        g_free (archive_name);
+        return NULL;
     }
     if (!super->name)
         vfs_die ("You have to fill name\n");
     if (!super->root)
         vfs_die ("You have to fill root inode\n");
 
-    vfs_s_insert_super (me, super);
-    vfs_stamp_create (me, super);
+    vfs_s_insert_super (path_element->class, super);
+    vfs_stamp_create (path_element->class, super);
 
   return_success:
     *archive = super;
+    g_free (archive_name);
     return retval;
 }
 
@@ -1174,7 +1183,7 @@ vfs_s_open (const vfs_path_t * vpath, int flags, mode_t mode)
     struct vfs_s_inode *ino;
     vfs_path_element_t *path_element;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     q = vfs_s_get_path (vpath, &super, 0);
     if (q == NULL)
@@ -1393,7 +1402,7 @@ vfs_getid (const vfs_path_t * vpath)
 {
     vfs_path_element_t *path_element;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
     if (path_element == NULL || path_element->class->getid == NULL)
         return NULL;
 

+ 3 - 3
lib/vfs/gc.c

@@ -158,7 +158,7 @@ vfs_stamp_path (const char *path)
     vfs_path_element_t *path_element;
 
     vpath = vfs_path_from_str (path);
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     id = vfs_getid (vpath);
     vfs_addstamp (path_element->class, id);
@@ -188,7 +188,7 @@ vfs_stamp_create (struct vfs_class *vclass, vfsid id)
         return;
 
     vpath = vfs_path_from_str (vfs_get_current_dir ());
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     nvfsid = vfs_getid (vpath);
     vfs_rmstamp (path_element->class, nvfsid);
@@ -270,7 +270,7 @@ vfs_release_path (const char *dir)
     vfs_path_element_t *path_element;
 
     vpath = vfs_path_from_str (dir);
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     vfs_stamp_create (path_element->class, vfs_getid (vpath));
 }

+ 12 - 12
lib/vfs/interface.c

@@ -202,7 +202,7 @@ mc_open (const char *filename, int flags, ...)
         va_end (ap);
     }
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
     if (path_element != NULL && path_element->class->open != NULL)
     {
         void *info;
@@ -235,7 +235,7 @@ int mc_##name inarg \
     if (vpath == NULL) \
         return -1; \
 \
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1); \
+    path_element = vfs_path_get_by_index (vpath, -1); \
     if (path_element == NULL) \
     { \
         vfs_path_free(vpath); \
@@ -283,7 +283,7 @@ mc_symlink (const char *name1, const char *path)
     if (vpath2 != NULL)
     {
         vfs_path_element_t *path_element =
-            vfs_path_get_by_index (vpath1, vfs_path_length (vpath1) - 1);
+            vfs_path_get_by_index (vpath1, vfs_path_elements_count (vpath1) - 1);
         if (path_element != NULL)
         {
             result =
@@ -343,8 +343,8 @@ int mc_##name (const char *fname1, const char *fname2) \
         vfs_path_free(vpath1); \
         return -1; \
     }\
-    path_element1 = vfs_path_get_by_index (vpath1, vfs_path_length (vpath1) - 1); \
-    path_element2 = vfs_path_get_by_index (vpath2, vfs_path_length (vpath2) - 1); \
+    path_element1 = vfs_path_get_by_index (vpath1, vfs_path_elements_count (vpath1) - 1); \
+    path_element2 = vfs_path_get_by_index (vpath2, vfs_path_elements_count (vpath2) - 1); \
 \
     if (path_element1->class != path_element2->class) \
     { \
@@ -396,7 +396,7 @@ mc_setctl (const char *path, int ctlop, void *arg)
     if (vpath == NULL)
         vfs_die ("You don't want to pass NULL to mc_setctl.");
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
     if (path_element != NULL && path_element->class != NULL)
         result =
             path_element->class->setctl != NULL ? path_element->class->setctl (vpath,
@@ -450,7 +450,7 @@ mc_opendir (const char *dirname)
     if (vpath == NULL)
         return NULL;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     info = path_element->class->opendir ? (*path_element->class->opendir) (vpath) : NULL;
 
@@ -568,7 +568,7 @@ mc_stat (const char *filename, struct stat *buf)
     if (vpath == NULL)
         return -1;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     if (path_element != NULL && path_element->class != NULL)
     {
@@ -594,7 +594,7 @@ mc_lstat (const char *filename, struct stat *buf)
     if (vpath == NULL)
         return -1;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     if (path_element != NULL && path_element->class != NULL)
     {
@@ -656,7 +656,7 @@ mc_getlocalcopy (const char *pathname)
     if (vpath == NULL)
         return NULL;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
     if (path_element != NULL)
     {
         result = path_element->class->getlocalcopy != NULL ?
@@ -681,7 +681,7 @@ mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed)
     if (vpath == NULL)
         return -1;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
     if (path_element != NULL)
     {
         return_value = path_element->class->ungetlocalcopy != NULL ?
@@ -715,7 +715,7 @@ mc_chdir (const char *path)
     if (vpath == NULL)
         return -1;
 
-    path_element = vfs_path_get_by_index (vpath, vfs_path_length (vpath) - 1);
+    path_element = vfs_path_get_by_index (vpath, -1);
 
     if (!path_element->class->chdir)
         return -1;

+ 219 - 24
lib/vfs/path.c

@@ -33,11 +33,14 @@
 #include <config.h>
 
 #include "lib/global.h"
+#include "lib/strutil.h"
 
 #include "vfs.h"
 #include "utilvfs.h"
 #include "path.h"
 
+extern GPtrArray *vfs__classes_list;
+
 /*** global variables ****************************************************************************/
 
 /*** file scope macro definitions ****************************************************************/
@@ -49,85 +52,245 @@
 /*** file scope functions ************************************************************************/
 /* --------------------------------------------------------------------------------------------- */
 
+static gboolean
+path_magic (const char *path)
+{
+    struct stat buf;
+
+    return (stat (path, &buf) != 0);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/**
+ * Splits path extracting vfs part.
+ *
+ * Splits path
+ * \verbatim /p1#op/inpath \endverbatim
+ * into
+ * \verbatim inpath,op; \endverbatim
+ * returns which vfs it is.
+ * What is left in path is p1. You still want to g_free(path), you DON'T
+ * want to free neither *inpath nor *op
+ */
+
+static struct vfs_class *
+_vfs_split_with_semi_skip_count (char *path, const char **inpath, const char **op,
+                                 size_t skip_count)
+{
+    char *semi;
+    char *slash;
+    struct vfs_class *ret;
+
+    if (path == NULL)
+        vfs_die ("Cannot split NULL");
+
+    semi = strrstr_skip_count (path, "#", skip_count);
+
+    if ((semi == NULL) || (!path_magic (path)))
+        return NULL;
+
+    slash = strchr (semi, PATH_SEP);
+    *semi = '\0';
+
+    if (op != NULL)
+        *op = NULL;
+
+    if (inpath != NULL)
+        *inpath = NULL;
+
+    if (slash != NULL)
+        *slash = '\0';
+
+    ret = vfs_prefix_to_class (semi + 1);
+    if (ret != NULL)
+    {
+        if (op != NULL)
+            *op = semi + 1;
+        if (inpath != NULL)
+            *inpath = slash != NULL ? slash + 1 : NULL;
+        return ret;
+    }
+
+    if (slash != NULL)
+        *slash = PATH_SEP;
+
+    *semi = '#';
+    ret = _vfs_split_with_semi_skip_count (path, inpath, op, skip_count + 1);
+    return ret;
+}
+
 /* --------------------------------------------------------------------------------------------- */
 /*** public functions ****************************************************************************/
 /* --------------------------------------------------------------------------------------------- */
+/**
+ * Convert first elements_count elements from vfs_path_t to string representation.
+ *
+ * @param vpath pointer to vfs_path_t object
+ * @param elements_count count of first elements for convert
+ *
+ * @return pointer to newly created string.
+ */
 
 char *
-vfs_path_to_str (const vfs_path_t * path)
+vfs_path_to_str_elements_count (const vfs_path_t * vpath, int elements_count)
 {
-    size_t element_index;
+    int element_index;
     GString *buffer;
 
-    if (path == NULL)
+    if (vpath == NULL)
         return NULL;
 
+    if (elements_count > vfs_path_elements_count (vpath))
+        elements_count = vfs_path_elements_count (vpath);
+
+    if (elements_count < 0)
+        elements_count = vfs_path_elements_count (vpath) + elements_count;
+
     buffer = g_string_new ("");
 
-    for (element_index = 0; element_index < vfs_path_length (path); element_index++)
+    for (element_index = 0; element_index < elements_count; element_index++)
     {
-        vfs_path_element_t *element = vfs_path_get_by_index (path, element_index);
+        vfs_path_element_t *element = vfs_path_get_by_index (vpath, element_index);
+
+        if (element->raw_url_str != NULL)
+        {
+            g_string_append (buffer, "#");
+            g_string_append (buffer, element->raw_url_str);
+        }
+        if ((*element->path != PATH_SEP) && (*element->path != '\0'))
+            g_string_append_c (buffer, PATH_SEP);
         g_string_append (buffer, element->path);
     }
     return g_string_free (buffer, FALSE);
 }
 
 /* --------------------------------------------------------------------------------------------- */
+/**
+ * Convert vfs_path_t to string representation.
+ *
+ * @param vpath pointer to vfs_path_t object
+ *
+ * @return pointer to newly created string.
+ */
+char *
+vfs_path_to_str (const vfs_path_t * vpath)
+{
+    return vfs_path_to_str_elements_count (vpath, vfs_path_elements_count (vpath));
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * Split path string to path elements.
+ *
+ * @param path_str VFS-path
+ *
+ * @return pointer to newly created vfs_path_t object with filled elements array.
+ */
 
 vfs_path_t *
 vfs_path_from_str (const char *path_str)
 {
-    vfs_path_t *path;
+    vfs_path_t *vpath;
     vfs_path_element_t *element;
+    struct vfs_class *class;
+    const char *local, *op;
+    char *path;
 
     if (path_str == NULL)
         return NULL;
 
-    path = vfs_path_new ();
-    path->unparsed_encoding = g_strdup (vfs_get_encoding (path_str));
+    vpath = vfs_path_new ();
+    vpath->unparsed_encoding = g_strdup (vfs_get_encoding (path_str));
+
+    vpath->unparsed = vfs_canon_and_translate (path_str);
 
-    path->unparsed = vfs_canon_and_translate (path_str);
-    if (path->unparsed == NULL)
+    if (vpath->unparsed == NULL)
     {
-        vfs_path_free (path);
+        vfs_path_free (vpath);
         return NULL;
     }
 
-    element = g_new0 (vfs_path_element_t, 1);
-    element->class = vfs_get_class (path->unparsed);
+    path = g_strdup (vpath->unparsed);
+    while ((class = _vfs_split_with_semi_skip_count (path, &local, &op, 0)) != NULL)
+    {
+        element = g_new0 (vfs_path_element_t, 1);
+        element->class = vfs_prefix_to_class (op);
+        if (local == NULL)
+            local = "";
+        element->path = g_strdup (local);
+        element->raw_url_str = g_strdup (op);
+        vpath->path = g_list_prepend (vpath->path, element);
+    }
+    if (path[0] != '\0')
+    {
+        element = g_new0 (vfs_path_element_t, 1);
+        element->class = g_ptr_array_index (vfs__classes_list, 0);
+        element->path = g_strdup (path);
+        element->raw_url_str = NULL;
+        vpath->path = g_list_prepend (vpath->path, element);
+    }
+    g_free (path);
 
-    g_ptr_array_add (path->path, element);
-    return path;
+    return vpath;
 }
 
 /* --------------------------------------------------------------------------------------------- */
+/*
+ * Create new vfs_path_t object.
+ *
+ * @return pointer to newly created vfs_path_t object.
+ */
 
 vfs_path_t *
 vfs_path_new (void)
 {
     vfs_path_t *vpath;
     vpath = g_new0 (vfs_path_t, 1);
-    vpath->path = g_ptr_array_new ();
     return vpath;
 }
 
 /* --------------------------------------------------------------------------------------------- */
+/*
+ * Get count of path elements.
+ *
+ * @param vpath pointer to vfs_path_t object
+ *
+ * @return count of path elements.
+ */
 
-size_t
-vfs_path_length (const vfs_path_t * vpath)
+int
+vfs_path_elements_count (const vfs_path_t * vpath)
 {
-    return vpath->path->len;
+    return g_list_length (vpath->path);
 }
 
 /* --------------------------------------------------------------------------------------------- */
+/*
+ * Get one path element by index.
+ *
+ * @param vpath pointer to vfs_path_t object
+ * @param element_index element index. May have negative value (in this case count was started at the end of list).
+ *
+ * @return path element.
+ */
 
 vfs_path_element_t *
-vfs_path_get_by_index (const vfs_path_t * path, size_t element_index)
+vfs_path_get_by_index (const vfs_path_t * vpath, int element_index)
 {
-    return g_ptr_array_index (path->path, element_index);
+    if (element_index >= 0)
+        return g_list_nth_data (vpath->path, element_index);
+
+    return g_list_nth_data (vpath->path, vfs_path_elements_count (vpath) + element_index);
 }
 
 /* --------------------------------------------------------------------------------------------- */
+/*
+ * Free one path element.
+ *
+ * @param element pointer to vfs_path_element_t object
+ *
+ */
 
 void
 vfs_path_element_free (vfs_path_element_t * element)
@@ -135,24 +298,56 @@ vfs_path_element_free (vfs_path_element_t * element)
     if (element == NULL)
         return;
 
+    vfs_url_free (element->url);
     g_free (element->path);
     g_free (element->encoding);
     g_free (element);
 }
 
 /* --------------------------------------------------------------------------------------------- */
+/*
+ * Free vfs_path_t object.
+ *
+ * @param vpath pointer to vfs_path_t object
+ *
+ */
 
 void
 vfs_path_free (vfs_path_t * path)
 {
     if (path == NULL)
         return;
-
-    g_ptr_array_foreach (path->path, (GFunc) vfs_path_element_free, NULL);
-    g_ptr_array_free (path->path, TRUE);
+    g_list_foreach (path->path, (GFunc) vfs_path_element_free, NULL);
+    g_list_free (path->path);
     g_free (path->unparsed);
     g_free (path->unparsed_encoding);
     g_free (path);
 }
 
 /* --------------------------------------------------------------------------------------------- */
+
+/** Return VFS class for the given prefix */
+struct vfs_class *
+vfs_prefix_to_class (const char *prefix)
+{
+    guint i;
+
+    /* Avoid first class (localfs) that would accept any prefix */
+    for (i = 1; i < vfs__classes_list->len; i++)
+    {
+        struct vfs_class *vfs = (struct vfs_class *) g_ptr_array_index (vfs__classes_list, i);
+        if (vfs->which != NULL)
+        {
+            if (vfs->which (vfs, prefix) == -1)
+                continue;
+            return vfs;
+        }
+
+        if (vfs->prefix != NULL && strncmp (prefix, vfs->prefix, strlen (vfs->prefix)) == 0)
+            return vfs;
+    }
+
+    return NULL;
+}
+
+/* --------------------------------------------------------------------------------------------- */

Some files were not shown because too many files changed in this diff