2 Virtual File System path handlers
5 The Free Software Foundation, Inc.
8 Slava Zanko <slavazanko@gmail.com>, 2011
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * \brief Source: Virtual File System: path handlers
36 #include "lib/global.h"
37 #include "lib/strutil.h"
38 #include "lib/util.h" /* concat_dir_and_file */
39 #include "lib/serialize.h"
43 #include "xdirentry.h"
46 extern GPtrArray
*vfs__classes_list
;
48 /*** global variables ****************************************************************************/
50 /*** file scope macro definitions ****************************************************************/
52 /*** file scope type declarations ****************************************************************/
54 /*** file scope variables ************************************************************************/
56 /*** file scope functions ************************************************************************/
57 /* --------------------------------------------------------------------------------------------- */
60 path_magic (const char *path
)
64 return (stat (path
, &buf
) != 0);
67 /* --------------------------------------------------------------------------------------------- */
70 * Splits path extracting vfs part.
73 * \verbatim /p1#op/inpath \endverbatim
75 * \verbatim inpath,op; \endverbatim
76 * returns which vfs it is.
77 * What is left in path is p1. You still want to g_free(path), you DON'T
78 * want to free neither *inpath nor *op
81 static struct vfs_class
*
82 _vfs_split_with_semi_skip_count (char *path
, const char **inpath
, const char **op
,
87 struct vfs_class
*ret
;
90 vfs_die ("Cannot split NULL");
92 semi
= strrstr_skip_count (path
, "#", skip_count
);
94 if ((semi
== NULL
) || (!path_magic (path
)))
97 slash
= strchr (semi
, PATH_SEP
);
109 ret
= vfs_prefix_to_class (semi
+ 1);
115 *inpath
= slash
!= NULL
? slash
+ 1 : NULL
;
123 ret
= _vfs_split_with_semi_skip_count (path
, inpath
, op
, skip_count
+ 1);
127 /* --------------------------------------------------------------------------------------------- */
129 * remove //, /./ and /../
131 * @return newly allocated string
135 vfs_canon (const char *path
)
138 vfs_die ("Cannot canonicalize NULL");
140 /* Relative to current directory */
141 if (*path
!= PATH_SEP
)
143 char *local
, *result
, *curr_dir
;
145 curr_dir
= vfs_get_current_dir ();
146 local
= concat_dir_and_file (curr_dir
, path
);
149 result
= vfs_canon (local
);
155 * So we have path of following form:
156 * /p1/p2#op/.././././p3#op/p4. Good luck.
159 char *result
= g_strdup (path
);
160 canonicalize_pathname (result
);
165 /* --------------------------------------------------------------------------------------------- */
167 * Build URL parameters (such as user:pass@host:port) from one path element object
169 * @param element path element
171 * @return newly allocated string
175 vfs_path_build_url_params_str (vfs_path_element_t
* element
)
182 buffer
= g_string_new ("");
184 if (element
->user
!= NULL
)
185 g_string_append (buffer
, element
->user
);
187 if (element
->password
!= NULL
)
189 g_string_append_c (buffer
, ':');
190 g_string_append (buffer
, element
->password
);
193 if (element
->host
!= NULL
)
195 if ((element
->user
!= NULL
) || (element
->password
!= NULL
))
196 g_string_append_c (buffer
, '@');
198 g_string_append_c (buffer
, '[');
199 g_string_append (buffer
, element
->host
);
201 g_string_append_c (buffer
, ']');
204 if ((element
->port
) != 0 && (element
->host
!= NULL
))
206 g_string_append_c (buffer
, ':');
207 g_string_append_printf (buffer
, "%d", element
->port
);
210 return g_string_free (buffer
, FALSE
);
213 /* --------------------------------------------------------------------------------------------- */
214 /** get encoding after last #enc: or NULL, if part does not contain #enc:
218 * @return newly allocated string.
222 vfs_get_encoding (const char *path
)
228 work
= g_strdup (path
);
230 /* try found #enc: */
231 semi
= g_strrstr (work
, VFS_ENCODING_PREFIX
);
233 if (semi
!= NULL
&& (semi
== work
|| *(semi
- 1) == PATH_SEP
))
235 semi
+= strlen (VFS_ENCODING_PREFIX
); /* skip "#enc:" */
236 slash
= strchr (semi
, PATH_SEP
);
240 g_strlcpy (result
, semi
, sizeof (result
));
242 return g_strdup (result
);
251 /* --------------------------------------------------------------------------------------------- */
252 /** Extract the hostname and username from the path
254 * Format of the path is [user@]hostname:port/remote-dir, e.g.:
256 * ftp://sunsite.unc.edu/pub/linux
257 * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
258 * ftp://tsx-11.mit.edu:8192/
259 * ftp://joe@foo.edu:11321/private
260 * ftp://joe:password@foo.se
262 * @param path_element is an input string to be parsed
263 * @param path is an input string to be parsed
265 * @return g_malloc()ed url info.
266 * If the user is empty, e.g. ftp://@roxanne/private, and URL_USE_ANONYMOUS
267 * is not set, then the current login name is supplied.
268 * Return value is a g_malloc()ed structure with the pathname relative to the
273 vfs_path_url_split (vfs_path_element_t
* path_element
, const char *path
)
277 char *dir
, *colon
, *inner_colon
, *at
, *rest
;
279 path_element
->port
= 0;
281 pcopy
= g_strdup (path
);
282 pend
= pcopy
+ strlen (pcopy
);
285 /* search for any possible user */
286 at
= strrchr (pcopy
, '@');
288 /* We have a username */
294 inner_colon
= strchr (pcopy
, ':');
295 if (inner_colon
!= NULL
)
299 path_element
->password
= g_strdup (inner_colon
);
303 path_element
->user
= g_strdup (pcopy
);
311 /* Check if the host comes with a port spec, if so, chop it */
313 colon
= strchr (rest
, ':');
316 colon
= strchr (++rest
, ']');
322 path_element
->ipv6
= TRUE
;
329 if (sscanf (colon
+ 1, "%d", &path_element
->port
) == 1)
331 if (path_element
->port
<= 0 || path_element
->port
>= 65536)
332 path_element
->port
= 0;
335 while (*(++colon
) != '\0')
340 path_element
->port
= 1;
343 path_element
->port
= 2;
348 path_element
->host
= g_strdup (rest
);
352 /* --------------------------------------------------------------------------------------------- */
354 * get VFS class for the given name
356 * @param class_name name of class
358 * @return pointer to class structure or NULL if class not found
361 static struct vfs_class
*
362 vfs_get_class_by_name (const char *class_name
)
366 if (class_name
== NULL
)
369 for (i
= 0; i
< vfs__classes_list
->len
; i
++)
371 struct vfs_class
*vfs
= (struct vfs_class
*) g_ptr_array_index (vfs__classes_list
, i
);
372 if ((vfs
->name
!= NULL
) && (strcmp (vfs
->name
, class_name
) == 0))
379 /* --------------------------------------------------------------------------------------------- */
381 * Check if path string contain URL-like elements
383 * @param path_str path
385 * @return TRUE if path is deprecated or FALSE otherwise
389 vfs_path_is_str_path_deprecated (const char *path_str
)
391 return strstr (path_str
, VFS_PATH_URL_DELIMITER
) == NULL
;
394 /* --------------------------------------------------------------------------------------------- */
395 /** Split path string to path elements by deprecated algorithm.
397 * @param path_str VFS-path
399 * @return pointer to newly created vfs_path_t object with filled path elements array.
403 vfs_path_from_str_deprecated_parser (char *path
)
406 vfs_path_element_t
*element
;
407 struct vfs_class
*class;
408 const char *local
, *op
;
410 vpath
= vfs_path_new ();
412 while ((class = _vfs_split_with_semi_skip_count (path
, &local
, &op
, 0)) != NULL
)
415 element
= g_new0 (vfs_path_element_t
, 1);
416 element
->class = class;
419 element
->path
= vfs_translate_path_n (local
);
421 element
->encoding
= vfs_get_encoding (local
);
422 element
->dir
.converter
=
423 (element
->encoding
!= NULL
) ? str_crt_conv_from (element
->encoding
) : INVALID_CONV
;
425 url_params
= strchr (op
, ':'); /* skip VFS prefix */
426 if (url_params
!= NULL
)
430 vfs_path_url_split (element
, url_params
);
434 element
->vfs_prefix
= g_strdup (op
);
436 vpath
->path
= g_list_prepend (vpath
->path
, element
);
440 element
= g_new0 (vfs_path_element_t
, 1);
441 element
->class = g_ptr_array_index (vfs__classes_list
, 0);
442 element
->path
= vfs_translate_path_n (path
);
444 element
->encoding
= vfs_get_encoding (path
);
445 element
->dir
.converter
=
446 (element
->encoding
!= NULL
) ? str_crt_conv_from (element
->encoding
) : INVALID_CONV
;
447 vpath
->path
= g_list_prepend (vpath
->path
, element
);
453 /* --------------------------------------------------------------------------------------------- */
454 /** Split path string to path elements by URL algorithm.
456 * @param path_str VFS-path
458 * @return pointer to newly created vfs_path_t object with filled path elements array.
462 vfs_path_from_str_uri_parser (char *path
)
465 vfs_path_element_t
*element
;
469 vpath
= vfs_path_new ();
471 while ((url_delimiter
= g_strrstr (path
, VFS_PATH_URL_DELIMITER
)) != NULL
)
473 char *vfs_prefix_start
;
474 char *real_vfs_prefix_start
= url_delimiter
;
476 struct vfs_s_subclass
*sub
= NULL
;
478 while (real_vfs_prefix_start
> path
&& *(real_vfs_prefix_start
) != PATH_SEP
)
479 real_vfs_prefix_start
--;
480 vfs_prefix_start
= real_vfs_prefix_start
;
482 if (*(vfs_prefix_start
) == PATH_SEP
)
483 vfs_prefix_start
+= 1;
485 *url_delimiter
= '\0';
487 element
= g_new0 (vfs_path_element_t
, 1);
488 element
->class = vfs_prefix_to_class (vfs_prefix_start
);
489 element
->vfs_prefix
= g_strdup (vfs_prefix_start
);
491 url_delimiter
+= strlen (VFS_PATH_URL_DELIMITER
);
492 sub
= VFSDATA (element
);
493 if (sub
!= NULL
&& sub
->flags
& VFS_S_REMOTE
)
495 slash_pointer
= strchr (url_delimiter
, PATH_SEP
);
496 if (slash_pointer
== NULL
)
498 element
->path
= g_strdup ("");
502 element
->path
= vfs_translate_path_n (slash_pointer
+ 1);
503 element
->encoding
= vfs_get_encoding (slash_pointer
);
505 *slash_pointer
= '\0';
507 vfs_path_url_split (element
, url_delimiter
);
511 element
->path
= vfs_translate_path_n (url_delimiter
);
512 element
->encoding
= vfs_get_encoding (url_delimiter
);
514 element
->dir
.converter
=
515 (element
->encoding
!= NULL
) ? str_crt_conv_from (element
->encoding
) : INVALID_CONV
;
516 vpath
->path
= g_list_prepend (vpath
->path
, element
);
518 if ((real_vfs_prefix_start
> path
&& *(real_vfs_prefix_start
) == PATH_SEP
) ||
519 (real_vfs_prefix_start
== path
&& *(real_vfs_prefix_start
) != PATH_SEP
))
520 *real_vfs_prefix_start
= '\0';
522 *(real_vfs_prefix_start
+ 1) = '\0';
527 element
= g_new0 (vfs_path_element_t
, 1);
528 element
->class = g_ptr_array_index (vfs__classes_list
, 0);
529 element
->path
= vfs_translate_path_n (path
);
530 element
->encoding
= vfs_get_encoding (path
);
531 element
->dir
.converter
=
532 (element
->encoding
!= NULL
) ? str_crt_conv_from (element
->encoding
) : INVALID_CONV
;
533 vpath
->path
= g_list_prepend (vpath
->path
, element
);
539 /* --------------------------------------------------------------------------------------------- */
541 * Add element's class info to result string (such as VFS name, host, encoding etc)
542 * This function used as helper only in vfs_path_tokens_get() function
544 * @param element current path element
545 * @param ret_tokens total tikens for return
546 * @param element_tokens accumulated element-only tokens
550 vfs_path_tokens_add_class_info (vfs_path_element_t
* element
, GString
* ret_tokens
,
551 GString
* element_tokens
)
553 if (((element
->class->flags
& VFSF_LOCAL
) == 0 || ret_tokens
->len
> 0)
554 && element_tokens
->len
> 0)
558 if (ret_tokens
->len
> 0 && ret_tokens
->str
[ret_tokens
->len
- 1] != PATH_SEP
)
559 g_string_append_c (ret_tokens
, PATH_SEP
);
561 g_string_append (ret_tokens
, element
->vfs_prefix
);
562 g_string_append (ret_tokens
, VFS_PATH_URL_DELIMITER
);
564 url_str
= vfs_path_build_url_params_str (element
);
565 if (*url_str
!= '\0')
567 g_string_append (ret_tokens
, url_str
);
568 g_string_append_c (ret_tokens
, PATH_SEP
);
573 if (element
->encoding
!= NULL
)
575 if (ret_tokens
->len
> 0 && ret_tokens
->str
[ret_tokens
->len
- 1] != PATH_SEP
)
576 g_string_append (ret_tokens
, PATH_SEP_STR
);
577 g_string_append (ret_tokens
, VFS_ENCODING_PREFIX
);
578 g_string_append (ret_tokens
, element
->encoding
);
579 g_string_append (ret_tokens
, PATH_SEP_STR
);
582 g_string_append (ret_tokens
, element_tokens
->str
);
585 /* --------------------------------------------------------------------------------------------- */
586 /*** public functions ****************************************************************************/
587 /* --------------------------------------------------------------------------------------------- */
589 * Convert first elements_count elements from vfs_path_t to string representation.
591 * @param vpath pointer to vfs_path_t object
592 * @param elements_count count of first elements for convert
593 * @param flags flags for parser
595 * @return pointer to newly created string.
598 #define vfs_append_from_path(appendfrom) \
600 if ((*appendfrom != PATH_SEP) && (*appendfrom != '\0') \
601 && (buffer->str[buffer->len - 1] != PATH_SEP)) \
602 g_string_append_c (buffer, PATH_SEP); \
603 g_string_append (buffer, appendfrom); \
607 vfs_path_to_str_elements_count (const vfs_path_t
* vpath
, int elements_count
)
611 GString
*recode_buffer
;
616 if (elements_count
> vfs_path_elements_count (vpath
))
617 elements_count
= vfs_path_elements_count (vpath
);
619 if (elements_count
< 0)
620 elements_count
= vfs_path_elements_count (vpath
) + elements_count
;
622 buffer
= g_string_new ("");
623 recode_buffer
= g_string_new ("");
625 for (element_index
= 0; element_index
< elements_count
; element_index
++)
627 vfs_path_element_t
*element
= vfs_path_get_by_index (vpath
, element_index
);
629 if (element
->vfs_prefix
!= NULL
)
633 if (buffer
->len
== 0 || buffer
->str
[buffer
->len
- 1] != PATH_SEP
)
634 g_string_append_c (buffer
, PATH_SEP
);
636 g_string_append (buffer
, element
->vfs_prefix
);
637 g_string_append (buffer
, VFS_PATH_URL_DELIMITER
);
639 url_str
= vfs_path_build_url_params_str (element
);
640 if (*url_str
!= '\0')
641 g_string_append (buffer
, url_str
);
646 if (vfs_path_element_need_cleanup_converter (element
))
648 if (buffer
->str
[buffer
->len
- 1] != PATH_SEP
)
649 g_string_append (buffer
, PATH_SEP_STR
);
650 g_string_append (buffer
, VFS_ENCODING_PREFIX
);
651 g_string_append (buffer
, element
->encoding
);
652 str_vfs_convert_from (element
->dir
.converter
, element
->path
, recode_buffer
);
653 vfs_append_from_path (recode_buffer
->str
);
654 g_string_set_size (recode_buffer
, 0);
658 vfs_append_from_path (element
->path
);
661 g_string_free (recode_buffer
, TRUE
);
662 return g_string_free (buffer
, FALSE
);
665 #undef vfs_append_from_path
667 /* --------------------------------------------------------------------------------------------- */
669 * Convert vfs_path_t to string representation.
671 * @param vpath pointer to vfs_path_t object
673 * @return pointer to newly created string.
677 vfs_path_to_str (const vfs_path_t
* vpath
)
679 return vfs_path_to_str_elements_count (vpath
, vfs_path_elements_count (vpath
));
682 /* --------------------------------------------------------------------------------------------- */
684 * Split path string to path elements with flags for change parce process.
686 * @param path_str VFS-path
687 * @param flags flags for parser
689 * @return pointer to newly created vfs_path_t object with filled path elements array.
693 vfs_path_from_str_flags (const char *path_str
, vfs_path_flag_t flags
)
698 if (path_str
== NULL
)
701 if ((flags
& VPF_NO_CANON
) == 0)
702 path
= vfs_canon (path_str
);
704 path
= g_strdup (path_str
);
709 if ((flags
& VPF_USE_DEPRECATED_PARSER
) != 0 && vfs_path_is_str_path_deprecated (path
))
710 vpath
= vfs_path_from_str_deprecated_parser (path
);
712 vpath
= vfs_path_from_str_uri_parser (path
);
719 /* --------------------------------------------------------------------------------------------- */
721 * Split path string to path elements.
723 * @param path_str VFS-path
725 * @return pointer to newly created vfs_path_t object with filled path elements array.
729 vfs_path_from_str (const char *path_str
)
731 return vfs_path_from_str_flags (path_str
, VPF_NONE
);
734 /* --------------------------------------------------------------------------------------------- */
736 * Create new vfs_path_t object.
738 * @return pointer to newly created vfs_path_t object.
745 vpath
= g_new0 (vfs_path_t
, 1);
749 /* --------------------------------------------------------------------------------------------- */
751 * Get count of path elements.
753 * @param vpath pointer to vfs_path_t object
755 * @return count of path elements.
759 vfs_path_elements_count (const vfs_path_t
* vpath
)
761 return (vpath
!= NULL
&& vpath
->path
!= NULL
) ? g_list_length (vpath
->path
) : 0;
764 /* --------------------------------------------------------------------------------------------- */
766 * Get one path element by index.
768 * @param vpath pointer to vfs_path_t object
769 * @param element_index element index. May have negative value (in this case count was started at the end of list).
771 * @return path element.
775 vfs_path_get_by_index (const vfs_path_t
* vpath
, int element_index
)
777 if (element_index
< 0)
778 element_index
+= vfs_path_elements_count (vpath
);
780 if (element_index
< 0)
781 vfs_die ("vfs_path_get_by_index: incorrect index!");
783 return g_list_nth_data (vpath
->path
, element_index
);
786 /* --------------------------------------------------------------------------------------------- */
788 * Clone one path element
790 * @param element pointer to vfs_path_element_t object
792 * @return Newly allocated path element
796 vfs_path_element_clone (const vfs_path_element_t
* element
)
798 vfs_path_element_t
*new_element
= g_new0 (vfs_path_element_t
, 1);
799 memcpy (new_element
, element
, sizeof (vfs_path_element_t
));
801 new_element
->user
= g_strdup (element
->user
);
802 new_element
->password
= g_strdup (element
->password
);
803 new_element
->host
= g_strdup (element
->host
);
804 new_element
->path
= g_strdup (element
->path
);
805 new_element
->encoding
= g_strdup (element
->encoding
);
806 if (vfs_path_element_need_cleanup_converter (element
) && new_element
->encoding
!= NULL
)
807 new_element
->dir
.converter
= str_crt_conv_from (new_element
->encoding
);
808 new_element
->vfs_prefix
= g_strdup (element
->vfs_prefix
);
813 /* --------------------------------------------------------------------------------------------- */
815 * Free one path element.
817 * @param element pointer to vfs_path_element_t object
822 vfs_path_element_free (vfs_path_element_t
* element
)
827 g_free (element
->user
);
828 g_free (element
->password
);
829 g_free (element
->host
);
830 g_free (element
->path
);
831 g_free (element
->encoding
);
832 g_free (element
->vfs_prefix
);
834 if (vfs_path_element_need_cleanup_converter (element
))
836 str_close_conv (element
->dir
.converter
);
842 /* --------------------------------------------------------------------------------------------- */
846 * @param vpath pointer to vfs_path_t object
848 * @return Newly allocated path object
852 vfs_path_clone (const vfs_path_t
* vpath
)
854 vfs_path_t
*new_vpath
;
855 int vpath_element_index
;
859 new_vpath
= vfs_path_new ();
860 for (vpath_element_index
= 0; vpath_element_index
< vfs_path_elements_count (vpath
);
861 vpath_element_index
++)
864 g_list_append (new_vpath
->path
,
865 vfs_path_element_clone (vfs_path_get_by_index
866 (vpath
, vpath_element_index
)));
872 /* --------------------------------------------------------------------------------------------- */
874 * Free vfs_path_t object.
876 * @param vpath pointer to vfs_path_t object
881 vfs_path_free (vfs_path_t
* path
)
885 g_list_foreach (path
->path
, (GFunc
) vfs_path_element_free
, NULL
);
886 g_list_free (path
->path
);
890 /* --------------------------------------------------------------------------------------------- */
892 * Remove one path element by index
894 * @param vpath pointer to vfs_path_t object
895 * @param element_index element index. May have negative value (in this case count was started at the end of list).
900 vfs_path_remove_element_by_index (vfs_path_t
* vpath
, int element_index
)
902 vfs_path_element_t
*element
;
904 if ((vpath
== NULL
) || (vfs_path_elements_count (vpath
) == 1))
907 if (element_index
< 0)
908 element_index
= vfs_path_elements_count (vpath
) + element_index
;
910 element
= g_list_nth_data (vpath
->path
, element_index
);
911 vpath
->path
= g_list_remove (vpath
->path
, element
);
912 vfs_path_element_free (element
);
915 /* --------------------------------------------------------------------------------------------- */
916 /** Return VFS class for the given prefix */
919 vfs_prefix_to_class (const char *prefix
)
923 /* Avoid first class (localfs) that would accept any prefix */
924 for (i
= 1; i
< vfs__classes_list
->len
; i
++)
926 struct vfs_class
*vfs
= (struct vfs_class
*) g_ptr_array_index (vfs__classes_list
, i
);
927 if (vfs
->which
!= NULL
)
929 if (vfs
->which (vfs
, prefix
) == -1)
934 if (vfs
->prefix
!= NULL
&& strncmp (prefix
, vfs
->prefix
, strlen (vfs
->prefix
)) == 0)
941 /* --------------------------------------------------------------------------------------------- */
943 * Check if need cleanup charset converter for vfs_path_element_t
945 * @param element part of path
947 * @return TRUE if need cleanup converter or FALSE otherwise
951 vfs_path_element_need_cleanup_converter (const vfs_path_element_t
* element
)
953 return (element
->dir
.converter
!= str_cnv_from_term
&& element
->dir
.converter
!= INVALID_CONV
);
956 /* --------------------------------------------------------------------------------------------- */
958 * Serialize vfs_path_t object to string
960 * @param vpath data for serialization
961 * @param error contain pointer to object for handle error code and message
963 * @return serialized vpath as newly allocated string
967 vfs_path_serialize (const vfs_path_t
* vpath
, GError
** error
)
969 mc_config_t
*cpath
= mc_config_init (NULL
);
970 ssize_t element_index
;
973 if ((vpath
== NULL
) || (vfs_path_elements_count (vpath
) == 0))
975 g_set_error (error
, MC_ERROR
, -1, "vpath object is empty");
979 for (element_index
= 0; element_index
< vfs_path_elements_count (vpath
); element_index
++)
981 char *groupname
= g_strdup_printf ("path-element-%zd", element_index
);
982 vfs_path_element_t
*element
= vfs_path_get_by_index (vpath
, element_index
);
984 /* convert one element to config group */
986 mc_config_set_string_raw (cpath
, groupname
, "path", element
->path
);
987 mc_config_set_string_raw (cpath
, groupname
, "class-name", element
->class->name
);
988 mc_config_set_string_raw (cpath
, groupname
, "encoding", element
->encoding
);
990 mc_config_set_string_raw (cpath
, groupname
, "vfs_prefix", element
->vfs_prefix
);
992 mc_config_set_string_raw (cpath
, groupname
, "user", element
->user
);
993 mc_config_set_string_raw (cpath
, groupname
, "password", element
->password
);
994 mc_config_set_string_raw (cpath
, groupname
, "host", element
->host
);
995 if (element
->port
!= 0)
996 mc_config_set_int (cpath
, groupname
, "port", element
->port
);
1001 ret_value
= mc_serialize_config (cpath
, error
);
1002 mc_config_deinit (cpath
);
1006 /* --------------------------------------------------------------------------------------------- */
1008 * Deserialize string to vfs_path_t object
1010 * @param data data for serialization
1011 * @param error contain pointer to object for handle error code and message
1013 * @return newly allocated vfs_path_t object
1017 vfs_path_deserialize (const char *data
, GError
** error
)
1019 mc_config_t
*cpath
= mc_deserialize_config (data
, error
);
1020 size_t element_index
= 0;
1026 vpath
= vfs_path_new ();
1030 vfs_path_element_t
*element
;
1034 groupname
= g_strdup_printf ("path-element-%zd", element_index
);
1035 if (!mc_config_has_group (cpath
, groupname
))
1041 element
= g_new0 (vfs_path_element_t
, 1);
1043 cfg_value
= mc_config_get_string_raw (cpath
, groupname
, "class-name", NULL
);
1044 element
->class = vfs_get_class_by_name (cfg_value
);
1045 if (element
->class == NULL
)
1048 vfs_path_free (vpath
);
1049 g_set_error (error
, MC_ERROR
, -1, "Unable to find VFS class by name '%s'", cfg_value
);
1051 mc_config_deinit (cpath
);
1056 element
->path
= mc_config_get_string_raw (cpath
, groupname
, "path", NULL
);
1057 element
->encoding
= mc_config_get_string_raw (cpath
, groupname
, "encoding", NULL
);
1058 element
->dir
.converter
=
1059 (element
->encoding
!= NULL
) ? str_crt_conv_from (element
->encoding
) : INVALID_CONV
;
1061 element
->vfs_prefix
= mc_config_get_string_raw (cpath
, groupname
, "vfs_prefix", NULL
);
1063 element
->user
= mc_config_get_string_raw (cpath
, groupname
, "user", NULL
);
1064 element
->password
= mc_config_get_string_raw (cpath
, groupname
, "password", NULL
);
1065 element
->host
= mc_config_get_string_raw (cpath
, groupname
, "host", NULL
);
1066 element
->port
= mc_config_get_int (cpath
, groupname
, "port", 0);
1068 vpath
->path
= g_list_append (vpath
->path
, element
);
1074 mc_config_deinit (cpath
);
1075 if (vfs_path_elements_count (vpath
) == 0)
1077 vfs_path_free (vpath
);
1078 g_set_error (error
, MC_ERROR
, -1, "No any path elements found");
1085 /* --------------------------------------------------------------------------------------------- */
1087 * Build vfs_path_t object from arguments.
1089 * @param ... path tokens, terminated by NULL
1091 * @return newly allocated vfs_path_t object
1095 vfs_path_build_filename (const char *first_element
, ...)
1101 if (first_element
== NULL
)
1104 va_start (args
, first_element
);
1105 str_path
= mc_build_filenamev (first_element
, args
);
1107 vpath
= vfs_path_from_str (str_path
);
1112 /* --------------------------------------------------------------------------------------------- */
1114 * Append tokens to path object
1116 * @param vpath path object
1117 * @param ... NULL-terminated strings
1119 * @return newly allocated path object
1123 vfs_path_append_new (const vfs_path_t
* vpath
, const char *first_element
, ...)
1126 char *str_path
, *result_str
;
1127 vfs_path_t
*ret_vpath
;
1129 if (vpath
== NULL
|| first_element
== NULL
)
1132 va_start (args
, first_element
);
1133 str_path
= mc_build_filenamev (first_element
, args
);
1136 result_str
= vfs_path_to_str (vpath
);
1137 ret_vpath
= vfs_path_build_filename (result_str
, str_path
, NULL
);
1138 g_free (result_str
);
1145 /* --------------------------------------------------------------------------------------------- */
1147 * get tockens count in path.
1149 * @param vpath path object
1151 * @return count of tokens
1155 vfs_path_tokens_count (const vfs_path_t
* vpath
)
1157 size_t count_tokens
= 0;
1163 for (element_index
= 0; element_index
< vfs_path_elements_count (vpath
); element_index
++)
1165 vfs_path_element_t
*element
;
1166 char **path_tokens
, **iterator
;
1168 element
= vfs_path_get_by_index (vpath
, element_index
);
1169 path_tokens
= iterator
= g_strsplit (element
->path
, PATH_SEP_STR
, -1);
1171 while (*iterator
!= NULL
)
1173 if (**iterator
!= '\0')
1177 g_strfreev (path_tokens
);
1179 return count_tokens
;
1182 /* --------------------------------------------------------------------------------------------- */
1184 * Get subpath by tokens
1186 * @param vpath path object
1187 * @param start_position first token for got/ Started from 0.
1188 * If negative, then position will be relative to end of path
1189 * @param length count of tokens
1191 * @return newly allocated string with path tokens separated by slash
1195 vfs_path_tokens_get (const vfs_path_t
* vpath
, ssize_t start_position
, size_t length
)
1197 GString
*ret_tokens
, *element_tokens
;
1199 size_t tokens_count
= vfs_path_tokens_count (vpath
);
1202 length
= tokens_count
;
1204 if (start_position
< 0)
1205 start_position
= (ssize_t
) tokens_count
+ start_position
;
1207 if (start_position
< 0)
1210 if (start_position
>= (ssize_t
) tokens_count
)
1213 if (start_position
+ (ssize_t
) length
> (ssize_t
) tokens_count
)
1214 length
= tokens_count
- start_position
;
1216 ret_tokens
= g_string_sized_new (32);
1217 element_tokens
= g_string_sized_new (32);
1219 for (element_index
= 0; element_index
< vfs_path_elements_count (vpath
); element_index
++)
1221 vfs_path_element_t
*element
;
1222 char **path_tokens
, **iterator
;
1224 g_string_assign (element_tokens
, "");
1225 element
= vfs_path_get_by_index (vpath
, element_index
);
1226 path_tokens
= iterator
= g_strsplit (element
->path
, PATH_SEP_STR
, -1);
1228 while (*iterator
!= NULL
)
1230 if (**iterator
!= '\0')
1232 if (start_position
== 0)
1236 vfs_path_tokens_add_class_info (element
, ret_tokens
, element_tokens
);
1237 g_string_free (element_tokens
, TRUE
);
1238 g_strfreev (path_tokens
);
1239 return g_string_free (ret_tokens
, FALSE
);
1242 if (element_tokens
->len
!= 0)
1243 g_string_append_c (element_tokens
, PATH_SEP
);
1244 g_string_append (element_tokens
, *iterator
);
1251 g_strfreev (path_tokens
);
1252 vfs_path_tokens_add_class_info (element
, ret_tokens
, element_tokens
);
1255 g_string_free (element_tokens
, TRUE
);
1256 return g_string_free (ret_tokens
, !(start_position
== 0 && length
== 0));
1259 /* --------------------------------------------------------------------------------------------- */