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