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 char *url_params;
350 element = g_new0 (vfs_path_element_t, 1);
351 element->class = class;
352 if (local == NULL)
353 local = "";
354 element->path = vfs_translate_path_n (local);
355
356 element->encoding = vfs_get_encoding (local, -1);
357 element->dir.converter =
358 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
359
360 url_params = strchr (op, ':');
361 if (url_params != NULL)
362 {
363 *url_params = '\0';
364 url_params++;
365 vfs_path_url_split (element, url_params);
366 }
367
368 if (*op != '\0')
369 element->vfs_prefix = g_strdup (op);
370
371 g_array_prepend_val (vpath->path, element);
372 }
373 if (path[0] != '\0')
374 {
375 element = g_new0 (vfs_path_element_t, 1);
376 element->class = g_ptr_array_index (vfs__classes_list, 0);
377 element->path = vfs_translate_path_n (path);
378
379 element->encoding = vfs_get_encoding (path, -1);
380 element->dir.converter =
381 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
382 g_array_prepend_val (vpath->path, element);
383 }
384
385 return vpath;
386 }
387
388
389
390
391
392
393
394
395
396
397 static vfs_path_t *
398 vfs_path_from_str_uri_parser (char *path)
399 {
400 gboolean path_is_absolute;
401 vfs_path_t *vpath;
402 vfs_path_element_t *element;
403 char *url_delimiter;
404
405 if (path == NULL)
406 return vfs_path_new (FALSE);
407
408 path_is_absolute = IS_PATH_SEP (*path);
409 path_is_absolute = path_is_absolute || g_str_has_prefix (path, VFS_ENCODING_PREFIX);
410
411 vpath = vfs_path_new (!path_is_absolute);
412
413 while ((url_delimiter = g_strrstr (path, VFS_PATH_URL_DELIMITER)) != NULL)
414 {
415 char *vfs_prefix_start;
416 char *real_vfs_prefix_start = url_delimiter;
417
418 while (real_vfs_prefix_start > path && !IS_PATH_SEP (*real_vfs_prefix_start))
419 real_vfs_prefix_start--;
420 vfs_prefix_start = real_vfs_prefix_start;
421
422 if (IS_PATH_SEP (*vfs_prefix_start))
423 vfs_prefix_start++;
424
425 *url_delimiter = '\0';
426
427 element = g_new0 (vfs_path_element_t, 1);
428 element->class = vfs_prefix_to_class (vfs_prefix_start);
429 element->vfs_prefix = g_strdup (vfs_prefix_start);
430
431 url_delimiter += strlen (VFS_PATH_URL_DELIMITER);
432
433 if (element->class != NULL && (element->class->flags & VFSF_REMOTE) != 0)
434 {
435 char *slash_pointer;
436
437 slash_pointer = strchr (url_delimiter, PATH_SEP);
438 if (slash_pointer == NULL)
439 element->path = g_strdup ("");
440 else
441 {
442 element->path = vfs_translate_path_n (slash_pointer + 1);
443 element->encoding = vfs_get_encoding (slash_pointer, -1);
444 *slash_pointer = '\0';
445 }
446 vfs_path_url_split (element, url_delimiter);
447 }
448 else
449 {
450 element->path = vfs_translate_path_n (url_delimiter);
451 element->encoding = vfs_get_encoding (url_delimiter, -1);
452 }
453
454 element->dir.converter =
455 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
456 g_array_prepend_val (vpath->path, element);
457
458 if ((real_vfs_prefix_start > path && IS_PATH_SEP (*real_vfs_prefix_start))
459 || (real_vfs_prefix_start == path && !IS_PATH_SEP (*real_vfs_prefix_start)))
460 *real_vfs_prefix_start = '\0';
461 else
462 *(real_vfs_prefix_start + 1) = '\0';
463 }
464
465 if (path[0] != '\0')
466 {
467 element = g_new0 (vfs_path_element_t, 1);
468 element->class = g_ptr_array_index (vfs__classes_list, 0);
469 element->path = vfs_translate_path_n (path);
470 element->encoding = vfs_get_encoding (path, -1);
471 element->dir.converter =
472 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
473 g_array_prepend_val (vpath->path, element);
474 }
475
476 return vpath;
477 }
478
479
480
481
482
483
484
485
486
487
488
489 static void
490 vfs_path_tokens_add_class_info (const vfs_path_element_t *element, GString *ret_tokens,
491 GString *element_tokens)
492 {
493 if (((element->class->flags & VFSF_LOCAL) == 0 || ret_tokens->len > 0)
494 && element_tokens->len > 0)
495 {
496 GString *url_str;
497
498 if (ret_tokens->len > 0 && !IS_PATH_SEP (ret_tokens->str[ret_tokens->len - 1]))
499 g_string_append_c (ret_tokens, PATH_SEP);
500
501 g_string_append (ret_tokens, element->vfs_prefix);
502 g_string_append (ret_tokens, VFS_PATH_URL_DELIMITER);
503
504 url_str = vfs_path_build_url_params_str (element, TRUE);
505 if (url_str != NULL)
506 {
507 g_string_append_len (ret_tokens, url_str->str, url_str->len);
508 g_string_append_c (ret_tokens, PATH_SEP);
509 g_string_free (url_str, TRUE);
510 }
511 }
512
513 if (element->encoding != NULL)
514 {
515 if (ret_tokens->len > 0 && !IS_PATH_SEP (ret_tokens->str[ret_tokens->len - 1]))
516 g_string_append (ret_tokens, PATH_SEP_STR);
517 g_string_append (ret_tokens, VFS_ENCODING_PREFIX);
518 g_string_append (ret_tokens, element->encoding);
519 g_string_append (ret_tokens, PATH_SEP_STR);
520 }
521
522 g_string_append (ret_tokens, element_tokens->str);
523 }
524
525
526
527
528
529
530
531 static char *
532 vfs_path_strip_home (const char *dir)
533 {
534 const char *home_dir = mc_config_get_home_dir ();
535
536 if (home_dir != NULL)
537 {
538 size_t len;
539
540 len = strlen (home_dir);
541
542 if (strncmp (dir, home_dir, len) == 0 && (IS_PATH_SEP (dir[len]) || dir[len] == '\0'))
543 return g_strdup_printf ("~%s", dir + len);
544 }
545
546 return g_strdup (dir);
547 }
548
549
550
551
552
553 #define vfs_append_from_path(appendfrom, is_relative) \
554 { \
555 if ((flags & VPF_STRIP_HOME) && element_index == 0 \
556 && (element->class->flags & VFSF_LOCAL) != 0) \
557 { \
558 char *stripped_home_str; \
559 stripped_home_str = vfs_path_strip_home (appendfrom); \
560 g_string_append (buffer, stripped_home_str); \
561 g_free (stripped_home_str); \
562 } \
563 else \
564 { \
565 if (!is_relative && !IS_PATH_SEP (*appendfrom) && *appendfrom != '\0' \
566 && (buffer->len == 0 || !IS_PATH_SEP (buffer->str[buffer->len - 1]))) \
567 g_string_append_c (buffer, PATH_SEP); \
568 g_string_append (buffer, appendfrom); \
569 } \
570 }
571
572
573
574
575
576
577
578
579
580
581
582 char *
583 vfs_path_to_str_flags (const vfs_path_t *vpath, int elements_count, vfs_path_flag_t flags)
584 {
585 int element_index;
586 GString *buffer;
587 GString *recode_buffer = NULL;
588
589 if (vpath == NULL)
590 return NULL;
591
592 if (elements_count == 0 || elements_count > vfs_path_elements_count (vpath))
593 elements_count = vfs_path_elements_count (vpath);
594
595 if (elements_count < 0)
596 elements_count = vfs_path_elements_count (vpath) + elements_count;
597
598 buffer = g_string_new ("");
599
600 for (element_index = 0; element_index < elements_count; element_index++)
601 {
602 const vfs_path_element_t *element;
603 gboolean is_relative = vpath->relative && (element_index == 0);
604
605 element = vfs_path_get_by_index (vpath, element_index);
606 if (element->vfs_prefix != NULL)
607 {
608 GString *url_str;
609
610 if (!is_relative && (buffer->len == 0 || !IS_PATH_SEP (buffer->str[buffer->len - 1])))
611 g_string_append_c (buffer, PATH_SEP);
612
613 g_string_append (buffer, element->vfs_prefix);
614 g_string_append (buffer, VFS_PATH_URL_DELIMITER);
615
616 url_str = vfs_path_build_url_params_str (element, (flags & VPF_STRIP_PASSWORD) == 0);
617 if (url_str != NULL)
618 {
619 g_string_append_len (buffer, url_str->str, url_str->len);
620 g_string_append_c (buffer, PATH_SEP);
621 g_string_free (url_str, TRUE);
622 }
623 }
624
625 if ((flags & VPF_RECODE) == 0 && vfs_path_element_need_cleanup_converter (element))
626 {
627 if ((flags & VPF_HIDE_CHARSET) == 0)
628 {
629 if ((!is_relative)
630 && (buffer->len == 0 || !IS_PATH_SEP (buffer->str[buffer->len - 1])))
631 g_string_append (buffer, PATH_SEP_STR);
632 g_string_append (buffer, VFS_ENCODING_PREFIX);
633 g_string_append (buffer, element->encoding);
634 }
635
636 if (recode_buffer == NULL)
637 recode_buffer = g_string_sized_new (32);
638 else
639 g_string_set_size (recode_buffer, 0);
640
641 str_vfs_convert_from (element->dir.converter, element->path, recode_buffer);
642 vfs_append_from_path (recode_buffer->str, is_relative);
643 }
644 else
645 {
646 vfs_append_from_path (element->path, is_relative);
647 }
648 }
649
650 if (recode_buffer != NULL)
651 g_string_free (recode_buffer, TRUE);
652
653 return g_string_free (buffer, FALSE);
654 }
655
656 #undef vfs_append_from_path
657
658
659
660
661
662
663
664
665
666
667
668 char *
669 vfs_path_to_str_elements_count (const vfs_path_t *vpath, int elements_count)
670 {
671 return vfs_path_to_str_flags (vpath, elements_count, VPF_NONE);
672 }
673
674
675
676
677
678
679
680
681
682
683
684 vfs_path_t *
685 vfs_path_from_str_flags (const char *path_str, vfs_path_flag_t flags)
686 {
687 vfs_path_t *vpath;
688 char *path;
689
690 if (path_str == NULL)
691 return NULL;
692
693 if ((flags & VPF_NO_CANON) == 0)
694 path = vfs_canon (path_str);
695 else
696 path = g_strdup (path_str);
697
698 if (path == NULL)
699 return NULL;
700
701 if ((flags & VPF_USE_DEPRECATED_PARSER) != 0 && vfs_path_is_str_path_deprecated (path))
702 vpath = vfs_path_from_str_deprecated_parser (path);
703 else
704 vpath = vfs_path_from_str_uri_parser (path);
705
706 vpath->str = vfs_path_to_str_flags (vpath, 0, flags);
707 g_free (path);
708
709 return vpath;
710 }
711
712
713
714
715
716
717
718
719
720
721 vfs_path_t *
722 vfs_path_from_str (const char *path_str)
723 {
724 return vfs_path_from_str_flags (path_str, VPF_NONE);
725 }
726
727
728
729
730
731
732
733
734 vfs_path_t *
735 vfs_path_new (gboolean relative)
736 {
737 vfs_path_t *vpath;
738
739 vpath = g_new0 (vfs_path_t, 1);
740 vpath->path = g_array_new (FALSE, TRUE, sizeof (vfs_path_element_t *));
741 vpath->relative = relative;
742
743 return vpath;
744 }
745
746
747
748
749
750
751
752
753
754
755 int
756 vfs_path_elements_count (const vfs_path_t *vpath)
757 {
758 return (vpath != NULL && vpath->path != NULL) ? vpath->path->len : 0;
759 }
760
761
762
763
764
765
766
767
768 void
769 vfs_path_add_element (vfs_path_t *vpath, const vfs_path_element_t *path_element)
770 {
771 g_array_append_val (vpath->path, path_element);
772 g_free (vpath->str);
773 vpath->str = vfs_path_to_str_flags (vpath, 0, VPF_NONE);
774 }
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789 const vfs_path_element_t *
790 vfs_path_get_by_index (const vfs_path_t *vpath, int element_index)
791 {
792 int n;
793
794 if (vpath == NULL)
795 {
796 errno = 0;
797 return NULL;
798 }
799
800 n = vfs_path_elements_count (vpath);
801
802 if (element_index < 0)
803 element_index += n;
804
805 if (element_index < 0 || element_index > n)
806 {
807 errno = EINVAL;
808 return NULL;
809 }
810
811 return g_array_index (vpath->path, vfs_path_element_t *, element_index);
812 }
813
814
815
816
817
818
819
820
821
822
823 vfs_path_element_t *
824 vfs_path_element_clone (const vfs_path_element_t *element)
825 {
826 vfs_path_element_t *new_element = g_new (vfs_path_element_t, 1);
827
828 new_element->user = g_strdup (element->user);
829 new_element->password = g_strdup (element->password);
830 new_element->host = g_strdup (element->host);
831 new_element->ipv6 = element->ipv6;
832 new_element->port = element->port;
833 new_element->path = g_strdup (element->path);
834 new_element->class = element->class;
835 new_element->vfs_prefix = g_strdup (element->vfs_prefix);
836 new_element->encoding = g_strdup (element->encoding);
837 if (vfs_path_element_need_cleanup_converter (element) && element->encoding != NULL)
838 new_element->dir.converter = str_crt_conv_from (element->encoding);
839 else
840 new_element->dir.converter = element->dir.converter;
841 new_element->dir.info = element->dir.info;
842
843 return new_element;
844 }
845
846
847
848
849
850
851
852
853
854 void
855 vfs_path_element_free (vfs_path_element_t *element)
856 {
857 if (element == NULL)
858 return;
859
860 g_free (element->user);
861 g_free (element->password);
862 g_free (element->host);
863 g_free (element->path);
864 g_free (element->vfs_prefix);
865
866 g_free (element->encoding);
867
868 if (vfs_path_element_need_cleanup_converter (element))
869 str_close_conv (element->dir.converter);
870
871 g_free (element);
872 }
873
874
875
876
877
878
879
880
881
882
883 vfs_path_t *
884 vfs_path_clone (const vfs_path_t *vpath)
885 {
886 vfs_path_t *new_vpath;
887 int vpath_element_index;
888
889 if (vpath == NULL)
890 return NULL;
891
892 new_vpath = vfs_path_new (vpath->relative);
893
894 for (vpath_element_index = 0; vpath_element_index < vfs_path_elements_count (vpath);
895 vpath_element_index++)
896 {
897 vfs_path_element_t *path_element;
898
899 path_element = vfs_path_element_clone (vfs_path_get_by_index (vpath, vpath_element_index));
900 g_array_append_val (new_vpath->path, path_element);
901 }
902 new_vpath->str = g_strdup (vpath->str);
903
904 return new_vpath;
905 }
906
907
908
909
910
911
912
913
914
915
916
917 char *
918 vfs_path_free (vfs_path_t *vpath, gboolean free_str)
919 {
920 int vpath_element_index;
921 char *ret;
922
923 if (vpath == NULL)
924 return NULL;
925
926 for (vpath_element_index = 0; vpath_element_index < vfs_path_elements_count (vpath);
927 vpath_element_index++)
928 {
929 vfs_path_element_t *path_element;
930
931 path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, vpath_element_index);
932 vfs_path_element_free (path_element);
933 }
934
935 g_array_free (vpath->path, TRUE);
936
937 if (!free_str)
938 ret = vpath->str;
939 else
940 {
941 g_free (vpath->str);
942 ret = NULL;
943 }
944
945 g_free (vpath);
946
947 return ret;
948 }
949
950
951
952
953
954
955
956
957
958
959
960 void
961 vfs_path_remove_element_by_index (vfs_path_t *vpath, int element_index)
962 {
963 vfs_path_element_t *element;
964
965 if ((vpath == NULL) || (vfs_path_elements_count (vpath) == 1))
966 return;
967
968 if (element_index < 0)
969 element_index = vfs_path_elements_count (vpath) + element_index;
970
971 element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, element_index);
972 vpath->path = g_array_remove_index (vpath->path, element_index);
973 vfs_path_element_free (element);
974 g_free (vpath->str);
975 vpath->str = vfs_path_to_str_flags (vpath, 0, VPF_NONE);
976 }
977
978
979
980
981 struct vfs_class *
982 vfs_prefix_to_class (const char *prefix)
983 {
984 guint i;
985
986
987 for (i = 1; i < vfs__classes_list->len; i++)
988 {
989 struct vfs_class *vfs;
990
991 vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
992 if (vfs->which != NULL)
993 {
994 if (vfs->which (vfs, prefix) == -1)
995 continue;
996 return vfs;
997 }
998
999 if (vfs->prefix != NULL && strncmp (prefix, vfs->prefix, strlen (vfs->prefix)) == 0)
1000 return vfs;
1001 }
1002
1003 return NULL;
1004 }
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015 char *
1016 vfs_get_encoding (const char *path, ssize_t len)
1017 {
1018 char *semi;
1019
1020
1021 semi = g_strrstr_len (path, len, VFS_ENCODING_PREFIX);
1022 if (semi == NULL)
1023 return NULL;
1024
1025 if (semi == path || IS_PATH_SEP (semi[-1]))
1026 {
1027 char *slash;
1028
1029 semi += strlen (VFS_ENCODING_PREFIX);
1030 slash = strchr (semi, PATH_SEP);
1031 if (slash != NULL)
1032 return g_strndup (semi, slash - semi);
1033 return g_strdup (semi);
1034 }
1035
1036 return vfs_get_encoding (path, semi - path);
1037 }
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 gboolean
1049 vfs_path_element_need_cleanup_converter (const vfs_path_element_t *element)
1050 {
1051 return (element->dir.converter != str_cnv_from_term && element->dir.converter != INVALID_CONV);
1052 }
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063 vfs_path_t *
1064 vfs_path_change_encoding (vfs_path_t *vpath, const char *encoding)
1065 {
1066 vfs_path_element_t *path_element;
1067
1068 path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, -1);
1069
1070 if ((path_element->encoding != NULL) && (strcmp (encoding, path_element->encoding) == 0))
1071 return vpath;
1072
1073 g_free (path_element->encoding);
1074 path_element->encoding = g_strdup (encoding);
1075
1076 if (vfs_path_element_need_cleanup_converter (path_element))
1077 str_close_conv (path_element->dir.converter);
1078
1079 path_element->dir.converter = str_crt_conv_from (path_element->encoding);
1080
1081 g_free (vpath->str);
1082 vpath->str = vfs_path_to_str_flags (vpath, 0, VPF_NONE);
1083 return vpath;
1084 }
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097 char *
1098 vfs_path_serialize (const vfs_path_t *vpath, GError **mcerror)
1099 {
1100 mc_config_t *cpath;
1101 ssize_t element_index;
1102 char *ret_value;
1103
1104 mc_return_val_if_error (mcerror, FALSE);
1105
1106 if ((vpath == NULL) || (vfs_path_elements_count (vpath) == 0))
1107 {
1108 mc_propagate_error (mcerror, 0, "%s", "vpath object is empty");
1109 return NULL;
1110 }
1111
1112 cpath = mc_config_init (NULL, FALSE);
1113
1114 for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
1115 {
1116 char groupname[BUF_TINY];
1117 const vfs_path_element_t *element;
1118
1119 g_snprintf (groupname, sizeof (groupname), "path-element-%zd", element_index);
1120 element = vfs_path_get_by_index (vpath, element_index);
1121
1122
1123 mc_config_set_string_raw (cpath, groupname, "path", element->path);
1124 mc_config_set_string_raw (cpath, groupname, "class-name", element->class->name);
1125 mc_config_set_string_raw (cpath, groupname, "encoding", element->encoding);
1126 mc_config_set_string_raw (cpath, groupname, "vfs_prefix", element->vfs_prefix);
1127
1128 mc_config_set_string_raw (cpath, groupname, "user", element->user);
1129 mc_config_set_string_raw (cpath, groupname, "password", element->password);
1130 mc_config_set_string_raw (cpath, groupname, "host", element->host);
1131 if (element->port != 0)
1132 mc_config_set_int (cpath, groupname, "port", element->port);
1133 }
1134
1135 ret_value = mc_serialize_config (cpath, mcerror);
1136 mc_config_deinit (cpath);
1137 return ret_value;
1138 }
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150 vfs_path_t *
1151 vfs_path_deserialize (const char *data, GError **mcerror)
1152 {
1153 mc_config_t *cpath;
1154 size_t element_index;
1155 vfs_path_t *vpath;
1156
1157 mc_return_val_if_error (mcerror, FALSE);
1158
1159 cpath = mc_deserialize_config (data, mcerror);
1160 if (cpath == NULL)
1161 return NULL;
1162
1163 vpath = vfs_path_new (FALSE);
1164
1165 for (element_index = 0;; element_index++)
1166 {
1167 struct vfs_class *eclass;
1168 vfs_path_element_t *element;
1169 char *cfg_value;
1170 char groupname[BUF_TINY];
1171
1172 g_snprintf (groupname, sizeof (groupname), "path-element-%zu", element_index);
1173 if (!mc_config_has_group (cpath, groupname))
1174 break;
1175
1176 cfg_value = mc_config_get_string_raw (cpath, groupname, "class-name", NULL);
1177 eclass = vfs_get_class_by_name (cfg_value);
1178 if (eclass == NULL)
1179 {
1180 vfs_path_free (vpath, TRUE);
1181 g_set_error (mcerror, MC_ERROR, 0, "Unable to find VFS class by name '%s'", cfg_value);
1182 g_free (cfg_value);
1183 mc_config_deinit (cpath);
1184 return NULL;
1185 }
1186 g_free (cfg_value);
1187
1188 element = g_new0 (vfs_path_element_t, 1);
1189 element->class = eclass;
1190 element->path = mc_config_get_string_raw (cpath, groupname, "path", NULL);
1191
1192 element->encoding = mc_config_get_string_raw (cpath, groupname, "encoding", NULL);
1193 element->dir.converter =
1194 (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
1195
1196 element->vfs_prefix = mc_config_get_string_raw (cpath, groupname, "vfs_prefix", NULL);
1197
1198 element->user = mc_config_get_string_raw (cpath, groupname, "user", NULL);
1199 element->password = mc_config_get_string_raw (cpath, groupname, "password", NULL);
1200 element->host = mc_config_get_string_raw (cpath, groupname, "host", NULL);
1201 element->port = mc_config_get_int (cpath, groupname, "port", 0);
1202
1203 vpath->path = g_array_append_val (vpath->path, element);
1204 }
1205
1206 mc_config_deinit (cpath);
1207 if (vfs_path_elements_count (vpath) == 0)
1208 {
1209 vfs_path_free (vpath, TRUE);
1210 g_set_error (mcerror, MC_ERROR, 0, "No any path elements found");
1211 return NULL;
1212 }
1213 vpath->str = vfs_path_to_str_flags (vpath, 0, VPF_NONE);
1214
1215 return vpath;
1216 }
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228 vfs_path_t *
1229 vfs_path_build_filename (const char *first_element, ...)
1230 {
1231 va_list args;
1232 char *str_path;
1233 vfs_path_t *vpath;
1234
1235 if (first_element == NULL)
1236 return NULL;
1237
1238 va_start (args, first_element);
1239 str_path = mc_build_filenamev (first_element, args);
1240 va_end (args);
1241 vpath = vfs_path_from_str (str_path);
1242 g_free (str_path);
1243 return vpath;
1244 }
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257 vfs_path_t *
1258 vfs_path_append_new (const vfs_path_t *vpath, const char *first_element, ...)
1259 {
1260 va_list args;
1261 char *str_path;
1262 const char *result_str;
1263 vfs_path_t *ret_vpath;
1264
1265 if (vpath == NULL || first_element == NULL)
1266 return NULL;
1267
1268 va_start (args, first_element);
1269 str_path = mc_build_filenamev (first_element, args);
1270 va_end (args);
1271
1272 result_str = vfs_path_as_str (vpath);
1273 ret_vpath = vfs_path_build_filename (result_str, str_path, (char *) NULL);
1274 g_free (str_path);
1275
1276 return ret_vpath;
1277 }
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290 vfs_path_t *
1291 vfs_path_append_vpath_new (const vfs_path_t *first_vpath, ...)
1292 {
1293 va_list args;
1294 vfs_path_t *ret_vpath;
1295 const vfs_path_t *current_vpath = first_vpath;
1296
1297 if (first_vpath == NULL)
1298 return NULL;
1299
1300 ret_vpath = vfs_path_new (FALSE);
1301
1302 va_start (args, first_vpath);
1303 do
1304 {
1305 int vindex;
1306
1307 for (vindex = 0; vindex < vfs_path_elements_count (current_vpath); vindex++)
1308 {
1309 vfs_path_element_t *path_element;
1310
1311 path_element = vfs_path_element_clone (vfs_path_get_by_index (current_vpath, vindex));
1312 g_array_append_val (ret_vpath->path, path_element);
1313 }
1314 current_vpath = va_arg (args, const vfs_path_t *);
1315 }
1316 while (current_vpath != NULL);
1317 va_end (args);
1318
1319 ret_vpath->str = vfs_path_to_str_flags (ret_vpath, 0, VPF_NONE);
1320
1321 return ret_vpath;
1322 }
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334 size_t
1335 vfs_path_tokens_count (const vfs_path_t *vpath)
1336 {
1337 size_t count_tokens = 0;
1338 int element_index;
1339
1340 if (vpath == NULL)
1341 return 0;
1342
1343 for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
1344 {
1345 const vfs_path_element_t *element;
1346 const char *token, *prev_token;
1347
1348 element = vfs_path_get_by_index (vpath, element_index);
1349
1350 for (prev_token = element->path; (token = strchr (prev_token, PATH_SEP)) != NULL;
1351 prev_token = token + 1)
1352 {
1353
1354 if (token != prev_token)
1355 count_tokens++;
1356 }
1357
1358 if (*prev_token != '\0')
1359 count_tokens++;
1360 }
1361
1362 return count_tokens;
1363 }
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378 char *
1379 vfs_path_tokens_get (const vfs_path_t *vpath, ssize_t start_position, ssize_t length)
1380 {
1381 GString *ret_tokens, *element_tokens;
1382 int element_index;
1383 size_t tokens_count = vfs_path_tokens_count (vpath);
1384
1385 if (vpath == NULL)
1386 return NULL;
1387
1388 if (length == 0)
1389 length = tokens_count;
1390
1391 if (length < 0)
1392 length = tokens_count + length;
1393
1394 if (start_position < 0)
1395 start_position = (ssize_t) tokens_count + start_position;
1396
1397 if (start_position < 0)
1398 return NULL;
1399
1400 if (start_position >= (ssize_t) tokens_count)
1401 return NULL;
1402
1403 if (start_position + (ssize_t) length > (ssize_t) tokens_count)
1404 length = tokens_count - start_position;
1405
1406 ret_tokens = g_string_sized_new (32);
1407 element_tokens = g_string_sized_new (32);
1408
1409 for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
1410 {
1411 const vfs_path_element_t *element;
1412 char **path_tokens, **iterator;
1413
1414 g_string_assign (element_tokens, "");
1415 element = vfs_path_get_by_index (vpath, element_index);
1416 path_tokens = g_strsplit (element->path, PATH_SEP_STR, -1);
1417
1418 for (iterator = path_tokens; *iterator != NULL; iterator++)
1419 {
1420 if (**iterator != '\0')
1421 {
1422 if (start_position == 0)
1423 {
1424 if (length == 0)
1425 {
1426 vfs_path_tokens_add_class_info (element, ret_tokens, element_tokens);
1427 g_string_free (element_tokens, TRUE);
1428 g_strfreev (path_tokens);
1429 return g_string_free (ret_tokens, FALSE);
1430 }
1431 length--;
1432 if (element_tokens->len != 0)
1433 g_string_append_c (element_tokens, PATH_SEP);
1434 g_string_append (element_tokens, *iterator);
1435 }
1436 else
1437 start_position--;
1438 }
1439 }
1440 g_strfreev (path_tokens);
1441 vfs_path_tokens_add_class_info (element, ret_tokens, element_tokens);
1442 }
1443
1444 g_string_free (element_tokens, TRUE);
1445 return g_string_free (ret_tokens, !(start_position == 0 && length == 0));
1446 }
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460 vfs_path_t *
1461 vfs_path_vtokens_get (const vfs_path_t *vpath, ssize_t start_position, ssize_t length)
1462 {
1463 char *str_tokens;
1464 vfs_path_t *ret_vpath = NULL;
1465
1466 str_tokens = vfs_path_tokens_get (vpath, start_position, length);
1467 if (str_tokens != NULL)
1468 {
1469 ret_vpath = vfs_path_from_str_flags (str_tokens, VPF_NO_CANON);
1470 g_free (str_tokens);
1471 }
1472 return ret_vpath;
1473 }
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486 GString *
1487 vfs_path_build_url_params_str (const vfs_path_element_t *element, gboolean keep_password)
1488 {
1489 GString *buffer;
1490
1491 if (element == NULL)
1492 return NULL;
1493
1494 buffer = g_string_sized_new (64);
1495
1496 if (element->user != NULL)
1497 g_string_append (buffer, element->user);
1498
1499 if (element->password != NULL && keep_password)
1500 {
1501 g_string_append_c (buffer, ':');
1502 g_string_append (buffer, element->password);
1503 }
1504
1505 if (element->host != NULL)
1506 {
1507 if ((element->user != NULL) || (element->password != NULL))
1508 g_string_append_c (buffer, '@');
1509 if (element->ipv6)
1510 g_string_append_c (buffer, '[');
1511 g_string_append (buffer, element->host);
1512 if (element->ipv6)
1513 g_string_append_c (buffer, ']');
1514
1515 if (element->port != 0)
1516 g_string_append_printf (buffer, ":%d", element->port);
1517 }
1518
1519 if (buffer->len != 0)
1520 return buffer;
1521
1522 g_string_free (buffer, TRUE);
1523 return NULL;
1524 }
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535 GString *
1536 vfs_path_element_build_pretty_path_str (const vfs_path_element_t *element)
1537 {
1538 GString *url_params, *pretty_path;
1539
1540 pretty_path = g_string_new (element->class->prefix);
1541 g_string_append (pretty_path, VFS_PATH_URL_DELIMITER);
1542
1543 url_params = vfs_path_build_url_params_str (element, FALSE);
1544 if (url_params != NULL)
1545 {
1546 g_string_append_len (pretty_path, url_params->str, url_params->len);
1547 g_string_free (url_params, TRUE);
1548 }
1549
1550 if (!IS_PATH_SEP (*element->path))
1551 g_string_append_c (pretty_path, PATH_SEP);
1552
1553 return g_string_append (pretty_path, element->path);
1554 }
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566 gboolean
1567 vfs_path_equal (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
1568 {
1569 const char *path1, *path2;
1570 gboolean ret_val;
1571
1572 if (vpath1 == NULL || vpath2 == NULL)
1573 return FALSE;
1574
1575 path1 = vfs_path_as_str (vpath1);
1576 path2 = vfs_path_as_str (vpath2);
1577
1578 ret_val = strcmp (path1, path2) == 0;
1579
1580 return ret_val;
1581 }
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594 gboolean
1595 vfs_path_equal_len (const vfs_path_t *vpath1, const vfs_path_t *vpath2, size_t len)
1596 {
1597 const char *path1, *path2;
1598 gboolean ret_val;
1599
1600 if (vpath1 == NULL || vpath2 == NULL)
1601 return FALSE;
1602
1603 path1 = vfs_path_as_str (vpath1);
1604 path2 = vfs_path_as_str (vpath2);
1605
1606 ret_val = strncmp (path1, path2, len) == 0;
1607
1608 return ret_val;
1609 }
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620 size_t
1621 vfs_path_len (const vfs_path_t *vpath)
1622 {
1623 if (vpath == NULL)
1624 return 0;
1625
1626 return strlen (vpath->str);
1627 }
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638 vfs_path_t *
1639 vfs_path_to_absolute (const vfs_path_t *vpath)
1640 {
1641 vfs_path_t *absolute_vpath;
1642 const char *path_str;
1643
1644 if (!vpath->relative)
1645 return vfs_path_clone (vpath);
1646
1647 path_str = vfs_path_as_str (vpath);
1648 absolute_vpath = vfs_path_from_str (path_str);
1649 return absolute_vpath;
1650 }
1651
1652