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