This source file includes following definitions.
- path_magic
- _vfs_split_with_semi_skip_count
- vfs_canon
- vfs_path_url_split
- vfs_get_class_by_name
- vfs_path_is_str_path_deprecated
- vfs_path_from_str_deprecated_parser
- vfs_path_from_str_uri_parser
- vfs_path_tokens_add_class_info
- vfs_path_strip_home
- vfs_path_to_str_flags
- vfs_path_to_str_elements_count
- vfs_path_from_str_flags
- vfs_path_from_str
- vfs_path_new
- vfs_path_elements_count
- vfs_path_add_element
- vfs_path_get_by_index
- vfs_path_element_clone
- vfs_path_element_free
- vfs_path_clone
- vfs_path_free
- vfs_path_remove_element_by_index
- vfs_prefix_to_class
- vfs_get_encoding
- vfs_path_element_need_cleanup_converter
- vfs_path_change_encoding
- vfs_path_serialize
- vfs_path_deserialize
- vfs_path_build_filename
- vfs_path_append_new
- vfs_path_append_vpath_new
- vfs_path_tokens_count
- vfs_path_tokens_get
- vfs_path_vtokens_get
- vfs_path_build_url_params_str
- vfs_path_element_build_pretty_path_str
- vfs_path_equal
- vfs_path_equal_len
- vfs_path_len
- vfs_path_to_absolute
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <config.h>
35
36 #include <errno.h>
37
38 #include "lib/global.h"
39 #include "lib/strutil.h"
40 #include "lib/util.h"
41 #include "lib/serialize.h"
42
43 #include "vfs.h"
44 #include "utilvfs.h"
45 #include "xdirentry.h"
46 #include "path.h"
47
48 extern GPtrArray *vfs__classes_list;
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 static gboolean
65 path_magic (const char *path)
66 {
67 struct stat buf;
68
69 return (stat (path, &buf) != 0);
70 }
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 static struct vfs_class *
87 _vfs_split_with_semi_skip_count (char *path, const char **inpath, const char **op,
88 size_t skip_count)
89 {
90 char *semi;
91 char *slash;
92 struct vfs_class *ret;
93
94 if (path == NULL)
95 vfs_die ("Cannot split NULL");
96
97 semi = strrstr_skip_count (path, "#", skip_count);
98
99 if ((semi == NULL) || (!path_magic (path)))
100 return NULL;
101
102 slash = strchr (semi, PATH_SEP);
103 *semi = '\0';
104
105 if (op != NULL)
106 *op = NULL;
107
108 if (inpath != NULL)
109 *inpath = NULL;
110
111 if (slash != NULL)
112 *slash = '\0';
113
114 ret = vfs_prefix_to_class (semi + 1);
115 if (ret != NULL)
116 {
117 if (op != NULL)
118 *op = semi + 1;
119 if (inpath != NULL)
120 *inpath = slash != NULL ? slash + 1 : NULL;
121 return ret;
122 }
123
124 if (slash != NULL)
125 *slash = PATH_SEP;
126
127 *semi = '#';
128 ret = _vfs_split_with_semi_skip_count (path, inpath, op, skip_count + 1);
129 return ret;
130 }
131
132
133
134
135
136
137
138
139 static char *
140 vfs_canon (const char *path)
141 {
142 char *result;
143
144 if (path == NULL)
145 vfs_die ("Cannot canonicalize NULL");
146
147 if (!IS_PATH_SEP (*path))
148 {
149
150
151 char *local;
152
153 if (g_str_has_prefix (path, VFS_ENCODING_PREFIX))
154 {
155
156
157
158
159 local = mc_build_filename (PATH_SEP_STR, path, (char *) NULL);
160 }
161 else
162 {
163 const char *curr_dir;
164
165 curr_dir = vfs_get_current_dir ();
166 local = mc_build_filename (curr_dir, path, (char *) NULL);
167 }
168 result = vfs_canon (local);
169 g_free (local);
170 }
171 else
172 {
173
174
175 result = g_strdup (path);
176 canonicalize_pathname (result);
177 }
178
179 return result;
180 }
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 static void
204 vfs_path_url_split (vfs_path_element_t *path_element, const char *path)
205 {
206 char *pcopy;
207 char *colon, *at, *rest;
208
209 path_element->port = 0;
210
211 pcopy = g_strdup (path);
212
213
214 at = strrchr (pcopy, '@');
215
216
217 if (at == NULL)
218 rest = pcopy;
219 else
220 {
221 const char *pend;
222 char *inner_colon;
223
224 pend = strchr (at, '\0');
225 *at = '\0';
226
227 inner_colon = strchr (pcopy, ':');
228 if (inner_colon != NULL)
229 {
230 *inner_colon = '\0';
231 inner_colon++;
232 path_element->password = g_strdup (inner_colon);
233 }
234
235 if (*pcopy != '\0')
236 path_element->user = g_strdup (pcopy);
237
238 if (pend == at + 1)
239 rest = at;
240 else
241 rest = at + 1;
242 }
243
244
245 if (*rest != '[')
246 colon = strchr (rest, ':');
247 else
248 {
249 colon = strchr (++rest, ']');
250 if (colon != NULL)
251 {
252 *colon = '\0';
253 colon++;
254 *colon = '\0';
255 path_element->ipv6 = TRUE;
256 }
257 }
258
259 if (colon != NULL)
260 {
261 *colon = '\0';
262 if (sscanf (colon + 1, "%d", &path_element->port) == 1)
263 {
264 if (path_element->port <= 0 || path_element->port >= 65536)
265 path_element->port = 0;
266 }
267 else
268 while (*(++colon) != '\0')
269 {
270 switch (*colon)
271 {
272 case 'C':
273 path_element->port = 1;
274 break;
275 case 'r':
276 path_element->port = 2;
277 break;
278 default:
279 break;
280 }
281 }
282 }
283 path_element->host = g_strdup (rest);
284 g_free (pcopy);
285 }
286
287
288
289
290
291
292
293
294
295
296 static struct vfs_class *
297 vfs_get_class_by_name (const char *class_name)
298 {
299 guint i;
300
301 if (class_name == NULL)
302 return NULL;
303
304 for (i = 0; i < vfs__classes_list->len; i++)
305 {
306 struct vfs_class *vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
307 if ((vfs->name != NULL) && (strcmp (vfs->name, class_name) == 0))
308 return vfs;
309 }
310
311 return NULL;
312 }
313
314
315
316
317
318
319
320
321
322
323 static gboolean
324 vfs_path_is_str_path_deprecated (const char *path_str)
325 {
326 return strstr (path_str, VFS_PATH_URL_DELIMITER) == NULL;
327 }
328
329
330
331
332
333
334
335
336
337 static vfs_path_t *
338 vfs_path_from_str_deprecated_parser (char *path)
339 {
340 vfs_path_t *vpath;
341 vfs_path_element_t *element;
342 struct vfs_class *class;
343 const char *local, *op;
344
345 vpath = vfs_path_new (FALSE);
346
347 while ((class = _vfs_split_with_semi_skip_count (path, &local, &op, 0)) != NULL)
348 {
349 element = g_new0 (vfs_path_element_t, 1);
350 element->class = class;
351 if (local == NULL)
352 local = "";
353 element->path = vfs_translate_path_n (local);
354
355 element->encoding = vfs_get_encoding (local, -1);
356 element->dir.converter =
357 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
358
359 const char *url_params = strchr (op, ':');
360 if (url_params != NULL)
361 {
362 path[url_params - path] = '\0';
363 url_params++;
364 vfs_path_url_split (element, url_params);
365 }
366
367 if (*op != '\0')
368 element->vfs_prefix = g_strdup (op);
369
370 g_array_prepend_val (vpath->path, element);
371 }
372 if (path[0] != '\0')
373 {
374 element = g_new0 (vfs_path_element_t, 1);
375 element->class = g_ptr_array_index (vfs__classes_list, 0);
376 element->path = vfs_translate_path_n (path);
377
378 element->encoding = vfs_get_encoding (path, -1);
379 element->dir.converter =
380 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
381 g_array_prepend_val (vpath->path, element);
382 }
383
384 return vpath;
385 }
386
387
388
389
390
391
392
393
394
395
396 static vfs_path_t *
397 vfs_path_from_str_uri_parser (char *path)
398 {
399 gboolean path_is_absolute;
400 vfs_path_t *vpath;
401 vfs_path_element_t *element;
402 char *url_delimiter;
403
404 if (path == NULL)
405 return vfs_path_new (FALSE);
406
407 path_is_absolute = IS_PATH_SEP (*path);
408 path_is_absolute = path_is_absolute || g_str_has_prefix (path, VFS_ENCODING_PREFIX);
409
410 vpath = vfs_path_new (!path_is_absolute);
411
412 while ((url_delimiter = g_strrstr (path, VFS_PATH_URL_DELIMITER)) != NULL)
413 {
414 char *vfs_prefix_start;
415 char *real_vfs_prefix_start = url_delimiter;
416
417 while (real_vfs_prefix_start > path && !IS_PATH_SEP (*real_vfs_prefix_start))
418 real_vfs_prefix_start--;
419 vfs_prefix_start = real_vfs_prefix_start;
420
421 if (IS_PATH_SEP (*vfs_prefix_start))
422 vfs_prefix_start++;
423
424 *url_delimiter = '\0';
425
426 element = g_new0 (vfs_path_element_t, 1);
427 element->class = vfs_prefix_to_class (vfs_prefix_start);
428 element->vfs_prefix = g_strdup (vfs_prefix_start);
429
430 url_delimiter += strlen (VFS_PATH_URL_DELIMITER);
431
432 if (element->class != NULL && (element->class->flags & VFSF_REMOTE) != 0)
433 {
434 char *slash_pointer;
435
436 slash_pointer = strchr (url_delimiter, PATH_SEP);
437 if (slash_pointer == NULL)
438 element->path = g_strdup ("");
439 else
440 {
441 element->path = vfs_translate_path_n (slash_pointer + 1);
442 element->encoding = vfs_get_encoding (slash_pointer, -1);
443 *slash_pointer = '\0';
444 }
445 vfs_path_url_split (element, url_delimiter);
446 }
447 else
448 {
449 element->path = vfs_translate_path_n (url_delimiter);
450 element->encoding = vfs_get_encoding (url_delimiter, -1);
451 }
452
453 element->dir.converter =
454 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
455 g_array_prepend_val (vpath->path, element);
456
457 if ((real_vfs_prefix_start > path && IS_PATH_SEP (*real_vfs_prefix_start))
458 || (real_vfs_prefix_start == path && !IS_PATH_SEP (*real_vfs_prefix_start)))
459 *real_vfs_prefix_start = '\0';
460 else
461 *(real_vfs_prefix_start + 1) = '\0';
462 }
463
464 if (path[0] != '\0')
465 {
466 element = g_new0 (vfs_path_element_t, 1);
467 element->class = g_ptr_array_index (vfs__classes_list, 0);
468 element->path = vfs_translate_path_n (path);
469 element->encoding = vfs_get_encoding (path, -1);
470 element->dir.converter =
471 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
472 g_array_prepend_val (vpath->path, element);
473 }
474
475 return vpath;
476 }
477
478
479
480
481
482
483
484
485
486
487
488 static void
489 vfs_path_tokens_add_class_info (const vfs_path_element_t *element, GString *ret_tokens,
490 GString *element_tokens)
491 {
492 if (((element->class->flags & VFSF_LOCAL) == 0 || ret_tokens->len > 0)
493 && element_tokens->len > 0)
494 {
495 GString *url_str;
496
497 if (ret_tokens->len > 0 && !IS_PATH_SEP (ret_tokens->str[ret_tokens->len - 1]))
498 g_string_append_c (ret_tokens, PATH_SEP);
499
500 g_string_append (ret_tokens, element->vfs_prefix);
501 g_string_append (ret_tokens, VFS_PATH_URL_DELIMITER);
502
503 url_str = vfs_path_build_url_params_str (element, TRUE);
504 if (url_str != NULL)
505 {
506 g_string_append_len (ret_tokens, url_str->str, url_str->len);
507 g_string_append_c (ret_tokens, PATH_SEP);
508 g_string_free (url_str, TRUE);
509 }
510 }
511
512 if (element->encoding != NULL)
513 {
514 if (ret_tokens->len > 0 && !IS_PATH_SEP (ret_tokens->str[ret_tokens->len - 1]))
515 g_string_append (ret_tokens, PATH_SEP_STR);
516 g_string_append (ret_tokens, VFS_ENCODING_PREFIX);
517 g_string_append (ret_tokens, element->encoding);
518 g_string_append (ret_tokens, PATH_SEP_STR);
519 }
520
521 g_string_append (ret_tokens, element_tokens->str);
522 }
523
524
525
526
527
528
529
530 static char *
531 vfs_path_strip_home (const char *dir)
532 {
533 const char *home_dir = mc_config_get_home_dir ();
534
535 if (home_dir != NULL)
536 {
537 size_t len;
538
539 len = strlen (home_dir);
540
541 if (strncmp (dir, home_dir, len) == 0 && (IS_PATH_SEP (dir[len]) || dir[len] == '\0'))
542 return g_strdup_printf ("~%s", dir + len);
543 }
544
545 return g_strdup (dir);
546 }
547
548
549
550
551
552 #define vfs_append_from_path(appendfrom, is_relative) \
553 { \
554 if ((flags & VPF_STRIP_HOME) && element_index == 0 \
555 && (element->class->flags & VFSF_LOCAL) != 0) \
556 { \
557 char *stripped_home_str; \
558 stripped_home_str = vfs_path_strip_home (appendfrom); \
559 g_string_append (buffer, stripped_home_str); \
560 g_free (stripped_home_str); \
561 } \
562 else \
563 { \
564 if (!is_relative && !IS_PATH_SEP (*appendfrom) && *appendfrom != '\0' \
565 && (buffer->len == 0 || !IS_PATH_SEP (buffer->str[buffer->len - 1]))) \
566 g_string_append_c (buffer, PATH_SEP); \
567 g_string_append (buffer, appendfrom); \
568 } \
569 }
570
571
572
573
574
575
576
577
578
579
580
581 char *
582 vfs_path_to_str_flags (const vfs_path_t *vpath, int elements_count, vfs_path_flag_t flags)
583 {
584 int element_index;
585 GString *buffer;
586 GString *recode_buffer = NULL;
587
588 if (vpath == NULL)
589 return NULL;
590
591 if (elements_count == 0 || elements_count > vfs_path_elements_count (vpath))
592 elements_count = vfs_path_elements_count (vpath);
593
594 if (elements_count < 0)
595 elements_count = vfs_path_elements_count (vpath) + elements_count;
596
597 buffer = g_string_new ("");
598
599 for (element_index = 0; element_index < elements_count; element_index++)
600 {
601 const vfs_path_element_t *element;
602 gboolean is_relative = vpath->relative && (element_index == 0);
603
604 element = vfs_path_get_by_index (vpath, element_index);
605 if (element->vfs_prefix != NULL)
606 {
607 GString *url_str;
608
609 if (!is_relative && (buffer->len == 0 || !IS_PATH_SEP (buffer->str[buffer->len - 1])))
610 g_string_append_c (buffer, PATH_SEP);
611
612 g_string_append (buffer, element->vfs_prefix);
613 g_string_append (buffer, VFS_PATH_URL_DELIMITER);
614
615 url_str = vfs_path_build_url_params_str (element, (flags & VPF_STRIP_PASSWORD) == 0);
616 if (url_str != NULL)
617 {
618 g_string_append_len (buffer, url_str->str, url_str->len);
619 g_string_append_c (buffer, PATH_SEP);
620 g_string_free (url_str, TRUE);
621 }
622 }
623
624 if ((flags & VPF_RECODE) == 0 && vfs_path_element_need_cleanup_converter (element))
625 {
626 if ((flags & VPF_HIDE_CHARSET) == 0)
627 {
628 if ((!is_relative)
629 && (buffer->len == 0 || !IS_PATH_SEP (buffer->str[buffer->len - 1])))
630 g_string_append (buffer, PATH_SEP_STR);
631 g_string_append (buffer, VFS_ENCODING_PREFIX);
632 g_string_append (buffer, element->encoding);
633 }
634
635 if (recode_buffer == NULL)
636 recode_buffer = g_string_sized_new (32);
637 else
638 g_string_set_size (recode_buffer, 0);
639
640 str_vfs_convert_from (element->dir.converter, element->path, recode_buffer);
641 vfs_append_from_path (recode_buffer->str, is_relative);
642 }
643 else
644 {
645 vfs_append_from_path (element->path, is_relative);
646 }
647 }
648
649 if (recode_buffer != NULL)
650 g_string_free (recode_buffer, TRUE);
651
652 return g_string_free (buffer, FALSE);
653 }
654
655 #undef vfs_append_from_path
656
657
658
659
660
661
662
663
664
665
666
667 char *
668 vfs_path_to_str_elements_count (const vfs_path_t *vpath, int elements_count)
669 {
670 return vfs_path_to_str_flags (vpath, elements_count, VPF_NONE);
671 }
672
673
674
675
676
677
678
679
680
681
682
683 vfs_path_t *
684 vfs_path_from_str_flags (const char *path_str, vfs_path_flag_t flags)
685 {
686 vfs_path_t *vpath;
687 char *path;
688
689 if (path_str == NULL)
690 return NULL;
691
692 if ((flags & VPF_NO_CANON) == 0)
693 path = vfs_canon (path_str);
694 else
695 path = g_strdup (path_str);
696
697 if (path == NULL)
698 return NULL;
699
700 if ((flags & VPF_USE_DEPRECATED_PARSER) != 0 && vfs_path_is_str_path_deprecated (path))
701 vpath = vfs_path_from_str_deprecated_parser (path);
702 else
703 vpath = vfs_path_from_str_uri_parser (path);
704
705 vpath->str = vfs_path_to_str_flags (vpath, 0, flags);
706 g_free (path);
707
708 return vpath;
709 }
710
711
712
713
714
715
716
717
718
719
720 vfs_path_t *
721 vfs_path_from_str (const char *path_str)
722 {
723 return vfs_path_from_str_flags (path_str, VPF_NONE);
724 }
725
726
727
728
729
730
731
732
733 vfs_path_t *
734 vfs_path_new (gboolean relative)
735 {
736 vfs_path_t *vpath;
737
738 vpath = g_new0 (vfs_path_t, 1);
739 vpath->path = g_array_new (FALSE, TRUE, sizeof (vfs_path_element_t *));
740 vpath->relative = relative;
741
742 return vpath;
743 }
744
745
746
747
748
749
750
751
752
753
754 int
755 vfs_path_elements_count (const vfs_path_t *vpath)
756 {
757 return (vpath != NULL && vpath->path != NULL) ? vpath->path->len : 0;
758 }
759
760
761
762
763
764
765
766
767 void
768 vfs_path_add_element (vfs_path_t *vpath, const vfs_path_element_t *path_element)
769 {
770 g_array_append_val (vpath->path, path_element);
771 g_free (vpath->str);
772 vpath->str = vfs_path_to_str_flags (vpath, 0, VPF_NONE);
773 }
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788 const vfs_path_element_t *
789 vfs_path_get_by_index (const vfs_path_t *vpath, int element_index)
790 {
791 int n;
792
793 if (vpath == NULL)
794 {
795 errno = 0;
796 return NULL;
797 }
798
799 n = vfs_path_elements_count (vpath);
800
801 if (element_index < 0)
802 element_index += n;
803
804 if (element_index < 0 || element_index > n)
805 {
806 errno = EINVAL;
807 return NULL;
808 }
809
810 return g_array_index (vpath->path, vfs_path_element_t *, element_index);
811 }
812
813
814
815
816
817
818
819
820
821
822 vfs_path_element_t *
823 vfs_path_element_clone (const vfs_path_element_t *element)
824 {
825 vfs_path_element_t *new_element = g_new (vfs_path_element_t, 1);
826
827 new_element->user = g_strdup (element->user);
828 new_element->password = g_strdup (element->password);
829 new_element->host = g_strdup (element->host);
830 new_element->ipv6 = element->ipv6;
831 new_element->port = element->port;
832 new_element->path = g_strdup (element->path);
833 new_element->class = element->class;
834 new_element->vfs_prefix = g_strdup (element->vfs_prefix);
835 new_element->encoding = g_strdup (element->encoding);
836 if (vfs_path_element_need_cleanup_converter (element) && element->encoding != NULL)
837 new_element->dir.converter = str_crt_conv_from (element->encoding);
838 else
839 new_element->dir.converter = element->dir.converter;
840 new_element->dir.info = element->dir.info;
841
842 return new_element;
843 }
844
845
846
847
848
849
850
851
852
853 void
854 vfs_path_element_free (vfs_path_element_t *element)
855 {
856 if (element == NULL)
857 return;
858
859 g_free (element->user);
860 g_free (element->password);
861 g_free (element->host);
862 g_free (element->path);
863 g_free (element->vfs_prefix);
864
865 g_free (element->encoding);
866
867 if (vfs_path_element_need_cleanup_converter (element))
868 str_close_conv (element->dir.converter);
869
870 g_free (element);
871 }
872
873
874
875
876
877
878
879
880
881
882 vfs_path_t *
883 vfs_path_clone (const vfs_path_t *vpath)
884 {
885 vfs_path_t *new_vpath;
886 int vpath_element_index;
887
888 if (vpath == NULL)
889 return NULL;
890
891 new_vpath = vfs_path_new (vpath->relative);
892
893 for (vpath_element_index = 0; vpath_element_index < vfs_path_elements_count (vpath);
894 vpath_element_index++)
895 {
896 vfs_path_element_t *path_element;
897
898 path_element = vfs_path_element_clone (vfs_path_get_by_index (vpath, vpath_element_index));
899 g_array_append_val (new_vpath->path, path_element);
900 }
901 new_vpath->str = g_strdup (vpath->str);
902
903 return new_vpath;
904 }
905
906
907
908
909
910
911
912
913
914
915
916 char *
917 vfs_path_free (vfs_path_t *vpath, gboolean free_str)
918 {
919 int vpath_element_index;
920 char *ret;
921
922 if (vpath == NULL)
923 return NULL;
924
925 for (vpath_element_index = 0; vpath_element_index < vfs_path_elements_count (vpath);
926 vpath_element_index++)
927 {
928 vfs_path_element_t *path_element;
929
930 path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, vpath_element_index);
931 vfs_path_element_free (path_element);
932 }
933
934 g_array_free (vpath->path, TRUE);
935
936 if (!free_str)
937 ret = vpath->str;
938 else
939 {
940 g_free (vpath->str);
941 ret = NULL;
942 }
943
944 g_free (vpath);
945
946 return ret;
947 }
948
949
950
951
952
953
954
955
956
957
958
959 void
960 vfs_path_remove_element_by_index (vfs_path_t *vpath, int element_index)
961 {
962 vfs_path_element_t *element;
963
964 if ((vpath == NULL) || (vfs_path_elements_count (vpath) == 1))
965 return;
966
967 if (element_index < 0)
968 element_index = vfs_path_elements_count (vpath) + element_index;
969
970 element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, element_index);
971 vpath->path = g_array_remove_index (vpath->path, element_index);
972 vfs_path_element_free (element);
973 g_free (vpath->str);
974 vpath->str = vfs_path_to_str_flags (vpath, 0, VPF_NONE);
975 }
976
977
978
979
980 struct vfs_class *
981 vfs_prefix_to_class (const char *prefix)
982 {
983 guint i;
984
985
986 for (i = 1; i < vfs__classes_list->len; i++)
987 {
988 struct vfs_class *vfs;
989
990 vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
991 if (vfs->which != NULL)
992 {
993 if (vfs->which (vfs, prefix) == -1)
994 continue;
995 return vfs;
996 }
997
998 if (vfs->prefix != NULL && strncmp (prefix, vfs->prefix, strlen (vfs->prefix)) == 0)
999 return vfs;
1000 }
1001
1002 return NULL;
1003 }
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014 char *
1015 vfs_get_encoding (const char *path, ssize_t len)
1016 {
1017 char *semi;
1018
1019
1020 semi = g_strrstr_len (path, len, VFS_ENCODING_PREFIX);
1021 if (semi == NULL)
1022 return NULL;
1023
1024 if (semi == path || IS_PATH_SEP (semi[-1]))
1025 {
1026 char *slash;
1027
1028 semi += strlen (VFS_ENCODING_PREFIX);
1029 slash = strchr (semi, PATH_SEP);
1030 if (slash != NULL)
1031 return g_strndup (semi, slash - semi);
1032 return g_strdup (semi);
1033 }
1034
1035 return vfs_get_encoding (path, semi - path);
1036 }
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047 gboolean
1048 vfs_path_element_need_cleanup_converter (const vfs_path_element_t *element)
1049 {
1050 return (element->dir.converter != str_cnv_from_term && element->dir.converter != INVALID_CONV);
1051 }
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062 vfs_path_t *
1063 vfs_path_change_encoding (vfs_path_t *vpath, const char *encoding)
1064 {
1065 vfs_path_element_t *path_element;
1066
1067 path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, -1);
1068
1069 if ((path_element->encoding != NULL) && (strcmp (encoding, path_element->encoding) == 0))
1070 return vpath;
1071
1072 g_free (path_element->encoding);
1073 path_element->encoding = g_strdup (encoding);
1074
1075 if (vfs_path_element_need_cleanup_converter (path_element))
1076 str_close_conv (path_element->dir.converter);
1077
1078 path_element->dir.converter = str_crt_conv_from (path_element->encoding);
1079
1080 g_free (vpath->str);
1081 vpath->str = vfs_path_to_str_flags (vpath, 0, VPF_NONE);
1082 return vpath;
1083 }
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096 char *
1097 vfs_path_serialize (const vfs_path_t *vpath, GError **mcerror)
1098 {
1099 mc_config_t *cpath;
1100 char *ret_value;
1101
1102 mc_return_val_if_error (mcerror, FALSE);
1103
1104 if ((vpath == NULL) || (vfs_path_elements_count (vpath) == 0))
1105 {
1106 mc_propagate_error (mcerror, 0, "%s", "vpath object is empty");
1107 return NULL;
1108 }
1109
1110 cpath = mc_config_init (NULL, FALSE);
1111
1112 for (int element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
1113 {
1114 char groupname[BUF_TINY];
1115 const vfs_path_element_t *element;
1116
1117 g_snprintf (groupname, sizeof (groupname), "path-element-%d", element_index);
1118 element = vfs_path_get_by_index (vpath, element_index);
1119
1120
1121 mc_config_set_string_raw (cpath, groupname, "path", element->path);
1122 mc_config_set_string_raw (cpath, groupname, "class-name", element->class->name);
1123 mc_config_set_string_raw (cpath, groupname, "encoding", element->encoding);
1124 mc_config_set_string_raw (cpath, groupname, "vfs_prefix", element->vfs_prefix);
1125
1126 mc_config_set_string_raw (cpath, groupname, "user", element->user);
1127 mc_config_set_string_raw (cpath, groupname, "password", element->password);
1128 mc_config_set_string_raw (cpath, groupname, "host", element->host);
1129 if (element->port != 0)
1130 mc_config_set_int (cpath, groupname, "port", element->port);
1131 }
1132
1133 ret_value = mc_serialize_config (cpath, mcerror);
1134 mc_config_deinit (cpath);
1135 return ret_value;
1136 }
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148 vfs_path_t *
1149 vfs_path_deserialize (const char *data, GError **mcerror)
1150 {
1151 mc_config_t *cpath;
1152 size_t element_index;
1153 vfs_path_t *vpath;
1154
1155 mc_return_val_if_error (mcerror, FALSE);
1156
1157 cpath = mc_deserialize_config (data, mcerror);
1158 if (cpath == NULL)
1159 return NULL;
1160
1161 vpath = vfs_path_new (FALSE);
1162
1163 for (element_index = 0;; element_index++)
1164 {
1165 struct vfs_class *eclass;
1166 vfs_path_element_t *element;
1167 char *cfg_value;
1168 char groupname[BUF_TINY];
1169
1170 g_snprintf (groupname, sizeof (groupname), "path-element-%zu", element_index);
1171 if (!mc_config_has_group (cpath, groupname))
1172 break;
1173
1174 cfg_value = mc_config_get_string_raw (cpath, groupname, "class-name", NULL);
1175 eclass = vfs_get_class_by_name (cfg_value);
1176 if (eclass == NULL)
1177 {
1178 vfs_path_free (vpath, TRUE);
1179 g_set_error (mcerror, MC_ERROR, 0, "Unable to find VFS class by name '%s'", cfg_value);
1180 g_free (cfg_value);
1181 mc_config_deinit (cpath);
1182 return NULL;
1183 }
1184 g_free (cfg_value);
1185
1186 element = g_new0 (vfs_path_element_t, 1);
1187 element->class = eclass;
1188 element->path = mc_config_get_string_raw (cpath, groupname, "path", NULL);
1189
1190 element->encoding = mc_config_get_string_raw (cpath, groupname, "encoding", NULL);
1191 element->dir.converter =
1192 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
1193
1194 element->vfs_prefix = mc_config_get_string_raw (cpath, groupname, "vfs_prefix", NULL);
1195
1196 element->user = mc_config_get_string_raw (cpath, groupname, "user", NULL);
1197 element->password = mc_config_get_string_raw (cpath, groupname, "password", NULL);
1198 element->host = mc_config_get_string_raw (cpath, groupname, "host", NULL);
1199 element->port = mc_config_get_int (cpath, groupname, "port", 0);
1200
1201 vpath->path = g_array_append_val (vpath->path, element);
1202 }
1203
1204 mc_config_deinit (cpath);
1205 if (vfs_path_elements_count (vpath) == 0)
1206 {
1207 vfs_path_free (vpath, TRUE);
1208 g_set_error (mcerror, MC_ERROR, 0, "No any path elements found");
1209 return NULL;
1210 }
1211 vpath->str = vfs_path_to_str_flags (vpath, 0, VPF_NONE);
1212
1213 return vpath;
1214 }
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 vfs_path_t *
1227 vfs_path_build_filename (const char *first_element, ...)
1228 {
1229 va_list args;
1230 char *str_path;
1231 vfs_path_t *vpath;
1232
1233 if (first_element == NULL)
1234 return NULL;
1235
1236 va_start (args, first_element);
1237 str_path = mc_build_filenamev (first_element, args);
1238 va_end (args);
1239 vpath = vfs_path_from_str (str_path);
1240 g_free (str_path);
1241 return vpath;
1242 }
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255 vfs_path_t *
1256 vfs_path_append_new (const vfs_path_t *vpath, const char *first_element, ...)
1257 {
1258 va_list args;
1259 char *str_path;
1260 const char *result_str;
1261 vfs_path_t *ret_vpath;
1262
1263 if (vpath == NULL || first_element == NULL)
1264 return NULL;
1265
1266 va_start (args, first_element);
1267 str_path = mc_build_filenamev (first_element, args);
1268 va_end (args);
1269
1270 result_str = vfs_path_as_str (vpath);
1271 ret_vpath = vfs_path_build_filename (result_str, str_path, (char *) NULL);
1272 g_free (str_path);
1273
1274 return ret_vpath;
1275 }
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288 vfs_path_t *
1289 vfs_path_append_vpath_new (const vfs_path_t *first_vpath, ...)
1290 {
1291 va_list args;
1292 vfs_path_t *ret_vpath;
1293 const vfs_path_t *current_vpath = first_vpath;
1294
1295 if (first_vpath == NULL)
1296 return NULL;
1297
1298 ret_vpath = vfs_path_new (FALSE);
1299
1300 va_start (args, first_vpath);
1301 do
1302 {
1303 int vindex;
1304
1305 for (vindex = 0; vindex < vfs_path_elements_count (current_vpath); vindex++)
1306 {
1307 vfs_path_element_t *path_element;
1308
1309 path_element = vfs_path_element_clone (vfs_path_get_by_index (current_vpath, vindex));
1310 g_array_append_val (ret_vpath->path, path_element);
1311 }
1312 current_vpath = va_arg (args, const vfs_path_t *);
1313 }
1314 while (current_vpath != NULL);
1315 va_end (args);
1316
1317 ret_vpath->str = vfs_path_to_str_flags (ret_vpath, 0, VPF_NONE);
1318
1319 return ret_vpath;
1320 }
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332 size_t
1333 vfs_path_tokens_count (const vfs_path_t *vpath)
1334 {
1335 size_t count_tokens = 0;
1336 int element_index;
1337
1338 if (vpath == NULL)
1339 return 0;
1340
1341 for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
1342 {
1343 const vfs_path_element_t *element;
1344 const char *token, *prev_token;
1345
1346 element = vfs_path_get_by_index (vpath, element_index);
1347
1348 for (prev_token = element->path; (token = strchr (prev_token, PATH_SEP)) != NULL;
1349 prev_token = token + 1)
1350 {
1351
1352 if (token != prev_token)
1353 count_tokens++;
1354 }
1355
1356 if (*prev_token != '\0')
1357 count_tokens++;
1358 }
1359
1360 return count_tokens;
1361 }
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376 char *
1377 vfs_path_tokens_get (const vfs_path_t *vpath, ssize_t start_position, ssize_t length)
1378 {
1379 GString *ret_tokens, *element_tokens;
1380 int element_index;
1381 size_t tokens_count = vfs_path_tokens_count (vpath);
1382
1383 if (vpath == NULL)
1384 return NULL;
1385
1386 if (length == 0)
1387 length = tokens_count;
1388
1389 if (length < 0)
1390 length = tokens_count + length;
1391
1392 if (start_position < 0)
1393 start_position = (ssize_t) tokens_count + start_position;
1394
1395 if (start_position < 0)
1396 return NULL;
1397
1398 if (start_position >= (ssize_t) tokens_count)
1399 return NULL;
1400
1401 if (start_position + (ssize_t) length > (ssize_t) tokens_count)
1402 length = tokens_count - start_position;
1403
1404 ret_tokens = g_string_sized_new (32);
1405 element_tokens = g_string_sized_new (32);
1406
1407 for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
1408 {
1409 const vfs_path_element_t *element;
1410 char **path_tokens, **iterator;
1411
1412 g_string_assign (element_tokens, "");
1413 element = vfs_path_get_by_index (vpath, element_index);
1414 path_tokens = g_strsplit (element->path, PATH_SEP_STR, -1);
1415
1416 for (iterator = path_tokens; *iterator != NULL; iterator++)
1417 {
1418 if (**iterator != '\0')
1419 {
1420 if (start_position == 0)
1421 {
1422 if (length == 0)
1423 {
1424 vfs_path_tokens_add_class_info (element, ret_tokens, element_tokens);
1425 g_string_free (element_tokens, TRUE);
1426 g_strfreev (path_tokens);
1427 return g_string_free (ret_tokens, FALSE);
1428 }
1429 length--;
1430 if (element_tokens->len != 0)
1431 g_string_append_c (element_tokens, PATH_SEP);
1432 g_string_append (element_tokens, *iterator);
1433 }
1434 else
1435 start_position--;
1436 }
1437 }
1438 g_strfreev (path_tokens);
1439 vfs_path_tokens_add_class_info (element, ret_tokens, element_tokens);
1440 }
1441
1442 g_string_free (element_tokens, TRUE);
1443 return g_string_free (ret_tokens, !(start_position == 0 && length == 0));
1444 }
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458 vfs_path_t *
1459 vfs_path_vtokens_get (const vfs_path_t *vpath, ssize_t start_position, ssize_t length)
1460 {
1461 char *str_tokens;
1462 vfs_path_t *ret_vpath = NULL;
1463
1464 str_tokens = vfs_path_tokens_get (vpath, start_position, length);
1465 if (str_tokens != NULL)
1466 {
1467 ret_vpath = vfs_path_from_str_flags (str_tokens, VPF_NO_CANON);
1468 g_free (str_tokens);
1469 }
1470 return ret_vpath;
1471 }
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484 GString *
1485 vfs_path_build_url_params_str (const vfs_path_element_t *element, gboolean keep_password)
1486 {
1487 GString *buffer;
1488
1489 if (element == NULL)
1490 return NULL;
1491
1492 buffer = g_string_sized_new (64);
1493
1494 if (element->user != NULL)
1495 g_string_append (buffer, element->user);
1496
1497 if (element->password != NULL && keep_password)
1498 {
1499 g_string_append_c (buffer, ':');
1500 g_string_append (buffer, element->password);
1501 }
1502
1503 if (element->host != NULL)
1504 {
1505 if ((element->user != NULL) || (element->password != NULL))
1506 g_string_append_c (buffer, '@');
1507 if (element->ipv6)
1508 g_string_append_c (buffer, '[');
1509 g_string_append (buffer, element->host);
1510 if (element->ipv6)
1511 g_string_append_c (buffer, ']');
1512
1513 if (element->port != 0)
1514 g_string_append_printf (buffer, ":%d", element->port);
1515 }
1516
1517 if (buffer->len != 0)
1518 return buffer;
1519
1520 g_string_free (buffer, TRUE);
1521 return NULL;
1522 }
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533 GString *
1534 vfs_path_element_build_pretty_path_str (const vfs_path_element_t *element)
1535 {
1536 GString *url_params, *pretty_path;
1537
1538 pretty_path = g_string_new (element->class->prefix);
1539 g_string_append (pretty_path, VFS_PATH_URL_DELIMITER);
1540
1541 url_params = vfs_path_build_url_params_str (element, FALSE);
1542 if (url_params != NULL)
1543 {
1544 g_string_append_len (pretty_path, url_params->str, url_params->len);
1545 g_string_free (url_params, TRUE);
1546 }
1547
1548 if (!IS_PATH_SEP (*element->path))
1549 g_string_append_c (pretty_path, PATH_SEP);
1550
1551 return g_string_append (pretty_path, element->path);
1552 }
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564 gboolean
1565 vfs_path_equal (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
1566 {
1567 const char *path1, *path2;
1568 gboolean ret_val;
1569
1570 if (vpath1 == NULL || vpath2 == NULL)
1571 return FALSE;
1572
1573 path1 = vfs_path_as_str (vpath1);
1574 path2 = vfs_path_as_str (vpath2);
1575
1576 ret_val = strcmp (path1, path2) == 0;
1577
1578 return ret_val;
1579 }
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592 gboolean
1593 vfs_path_equal_len (const vfs_path_t *vpath1, const vfs_path_t *vpath2, size_t len)
1594 {
1595 const char *path1, *path2;
1596 gboolean ret_val;
1597
1598 if (vpath1 == NULL || vpath2 == NULL)
1599 return FALSE;
1600
1601 path1 = vfs_path_as_str (vpath1);
1602 path2 = vfs_path_as_str (vpath2);
1603
1604 ret_val = strncmp (path1, path2, len) == 0;
1605
1606 return ret_val;
1607 }
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618 size_t
1619 vfs_path_len (const vfs_path_t *vpath)
1620 {
1621 if (vpath == NULL)
1622 return 0;
1623
1624 return strlen (vpath->str);
1625 }
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636 vfs_path_t *
1637 vfs_path_to_absolute (const vfs_path_t *vpath)
1638 {
1639 vfs_path_t *absolute_vpath;
1640 const char *path_str;
1641
1642 if (!vpath->relative)
1643 return vfs_path_clone (vpath);
1644
1645 path_str = vfs_path_as_str (vpath);
1646 absolute_vpath = vfs_path_from_str (path_str);
1647 return absolute_vpath;
1648 }
1649
1650