path.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588
  1. /*
  2. Virtual File System path handlers
  3. Copyright (C) 2011
  4. The Free Software Foundation, Inc.
  5. Written by:
  6. Slava Zanko <slavazanko@gmail.com>, 2011
  7. This file is part of the Midnight Commander.
  8. The Midnight Commander is free software: you can redistribute it
  9. and/or modify it under the terms of the GNU General Public License as
  10. published by the Free Software Foundation, either version 3 of the License,
  11. or (at your option) any later version.
  12. The Midnight Commander is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /**
  20. * \file
  21. * \brief Source: Virtual File System: path handlers
  22. * \author Slava Zanko
  23. * \date 2011
  24. */
  25. #include <config.h>
  26. #include "lib/global.h"
  27. #include "lib/strutil.h"
  28. #include "lib/util.h" /* mc_build_filename() */
  29. #include "lib/serialize.h"
  30. #include "vfs.h"
  31. #include "utilvfs.h"
  32. #include "xdirentry.h"
  33. #include "path.h"
  34. extern GPtrArray *vfs__classes_list;
  35. /*** global variables ****************************************************************************/
  36. /*** file scope macro definitions ****************************************************************/
  37. /*** file scope type declarations ****************************************************************/
  38. /*** file scope variables ************************************************************************/
  39. /*** file scope functions ************************************************************************/
  40. /* --------------------------------------------------------------------------------------------- */
  41. static gboolean
  42. path_magic (const char *path)
  43. {
  44. struct stat buf;
  45. return (stat (path, &buf) != 0);
  46. }
  47. /* --------------------------------------------------------------------------------------------- */
  48. /**
  49. * Splits path extracting vfs part.
  50. *
  51. * Splits path
  52. * \verbatim /p1#op/inpath \endverbatim
  53. * into
  54. * \verbatim inpath,op; \endverbatim
  55. * returns which vfs it is.
  56. * What is left in path is p1. You still want to g_free(path), you DON'T
  57. * want to free neither *inpath nor *op
  58. */
  59. static struct vfs_class *
  60. _vfs_split_with_semi_skip_count (char *path, const char **inpath, const char **op,
  61. size_t skip_count)
  62. {
  63. char *semi;
  64. char *slash;
  65. struct vfs_class *ret;
  66. if (path == NULL)
  67. vfs_die ("Cannot split NULL");
  68. semi = strrstr_skip_count (path, "#", skip_count);
  69. if ((semi == NULL) || (!path_magic (path)))
  70. return NULL;
  71. slash = strchr (semi, PATH_SEP);
  72. *semi = '\0';
  73. if (op != NULL)
  74. *op = NULL;
  75. if (inpath != NULL)
  76. *inpath = NULL;
  77. if (slash != NULL)
  78. *slash = '\0';
  79. ret = vfs_prefix_to_class (semi + 1);
  80. if (ret != NULL)
  81. {
  82. if (op != NULL)
  83. *op = semi + 1;
  84. if (inpath != NULL)
  85. *inpath = slash != NULL ? slash + 1 : NULL;
  86. return ret;
  87. }
  88. if (slash != NULL)
  89. *slash = PATH_SEP;
  90. *semi = '#';
  91. ret = _vfs_split_with_semi_skip_count (path, inpath, op, skip_count + 1);
  92. return ret;
  93. }
  94. /* --------------------------------------------------------------------------------------------- */
  95. /**
  96. * remove //, /./ and /../
  97. *
  98. * @return newly allocated string
  99. */
  100. static char *
  101. vfs_canon (const char *path)
  102. {
  103. if (path == NULL)
  104. vfs_die ("Cannot canonicalize NULL");
  105. /* Relative to current directory */
  106. if (*path != PATH_SEP)
  107. {
  108. char *result, *local;
  109. local = tilde_expand (path);
  110. if (*local != PATH_SEP)
  111. {
  112. char *curr_dir;
  113. g_free (local);
  114. curr_dir = vfs_get_current_dir ();
  115. local = mc_build_filename (curr_dir, path, NULL);
  116. g_free (curr_dir);
  117. }
  118. result = vfs_canon (local);
  119. g_free (local);
  120. return result;
  121. }
  122. /*
  123. * So we have path of following form:
  124. * /p1/p2#op/.././././p3#op/p4. Good luck.
  125. */
  126. {
  127. char *result;
  128. result = g_strdup (path);
  129. canonicalize_pathname (result);
  130. return result;
  131. }
  132. }
  133. /* --------------------------------------------------------------------------------------------- */
  134. /** get encoding after last #enc: or NULL, if part does not contain #enc:
  135. *
  136. * @param path string
  137. *
  138. * @return newly allocated string.
  139. */
  140. static char *
  141. vfs_get_encoding (const char *path)
  142. {
  143. char result[16];
  144. char *work;
  145. char *semi;
  146. char *slash;
  147. work = g_strdup (path);
  148. /* try found #enc: */
  149. semi = g_strrstr (work, VFS_ENCODING_PREFIX);
  150. if (semi != NULL && (semi == work || *(semi - 1) == PATH_SEP))
  151. {
  152. semi += strlen (VFS_ENCODING_PREFIX); /* skip "#enc:" */
  153. slash = strchr (semi, PATH_SEP);
  154. if (slash != NULL)
  155. slash[0] = '\0';
  156. g_strlcpy (result, semi, sizeof (result));
  157. g_free (work);
  158. return g_strdup (result);
  159. }
  160. else
  161. {
  162. g_free (work);
  163. return NULL;
  164. }
  165. }
  166. /* --------------------------------------------------------------------------------------------- */
  167. /** Extract the hostname and username from the path
  168. *
  169. * Format of the path is [user@]hostname:port/remote-dir, e.g.:
  170. *
  171. * ftp://sunsite.unc.edu/pub/linux
  172. * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
  173. * ftp://tsx-11.mit.edu:8192/
  174. * ftp://joe@foo.edu:11321/private
  175. * ftp://joe:password@foo.se
  176. *
  177. * @param path_element is an input string to be parsed
  178. * @param path is an input string to be parsed
  179. *
  180. * @return g_malloc()ed url info.
  181. * If the user is empty, e.g. ftp://@roxanne/private, and URL_USE_ANONYMOUS
  182. * is not set, then the current login name is supplied.
  183. * Return value is a g_malloc()ed structure with the pathname relative to the
  184. * host.
  185. */
  186. static void
  187. vfs_path_url_split (vfs_path_element_t * path_element, const char *path)
  188. {
  189. char *pcopy;
  190. const char *pend;
  191. char *dir, *colon, *inner_colon, *at, *rest;
  192. path_element->port = 0;
  193. pcopy = g_strdup (path);
  194. pend = pcopy + strlen (pcopy);
  195. dir = pcopy;
  196. /* search for any possible user */
  197. at = strrchr (pcopy, '@');
  198. /* We have a username */
  199. if (at == NULL)
  200. rest = pcopy;
  201. else
  202. {
  203. *at = '\0';
  204. inner_colon = strchr (pcopy, ':');
  205. if (inner_colon != NULL)
  206. {
  207. *inner_colon = '\0';
  208. inner_colon++;
  209. path_element->password = g_strdup (inner_colon);
  210. }
  211. if (*pcopy != '\0')
  212. path_element->user = g_strdup (pcopy);
  213. if (pend == at + 1)
  214. rest = at;
  215. else
  216. rest = at + 1;
  217. }
  218. /* Check if the host comes with a port spec, if so, chop it */
  219. if (*rest != '[')
  220. colon = strchr (rest, ':');
  221. else
  222. {
  223. colon = strchr (++rest, ']');
  224. if (colon != NULL)
  225. {
  226. colon[0] = '\0';
  227. colon[1] = '\0';
  228. colon++;
  229. path_element->ipv6 = TRUE;
  230. }
  231. }
  232. if (colon != NULL)
  233. {
  234. *colon = '\0';
  235. if (sscanf (colon + 1, "%d", &path_element->port) == 1)
  236. {
  237. if (path_element->port <= 0 || path_element->port >= 65536)
  238. path_element->port = 0;
  239. }
  240. else
  241. while (*(++colon) != '\0')
  242. {
  243. switch (*colon)
  244. {
  245. case 'C':
  246. path_element->port = 1;
  247. break;
  248. case 'r':
  249. path_element->port = 2;
  250. break;
  251. }
  252. }
  253. }
  254. path_element->host = g_strdup (rest);
  255. g_free (pcopy);
  256. }
  257. /* --------------------------------------------------------------------------------------------- */
  258. /**
  259. * get VFS class for the given name
  260. *
  261. * @param class_name name of class
  262. *
  263. * @return pointer to class structure or NULL if class not found
  264. */
  265. static struct vfs_class *
  266. vfs_get_class_by_name (const char *class_name)
  267. {
  268. guint i;
  269. if (class_name == NULL)
  270. return NULL;
  271. for (i = 0; i < vfs__classes_list->len; i++)
  272. {
  273. struct vfs_class *vfs = (struct vfs_class *) g_ptr_array_index (vfs__classes_list, i);
  274. if ((vfs->name != NULL) && (strcmp (vfs->name, class_name) == 0))
  275. return vfs;
  276. }
  277. return NULL;
  278. }
  279. /* --------------------------------------------------------------------------------------------- */
  280. /**
  281. * Check if path string contain URL-like elements
  282. *
  283. * @param path_str path
  284. *
  285. * @return TRUE if path is deprecated or FALSE otherwise
  286. */
  287. static gboolean
  288. vfs_path_is_str_path_deprecated (const char *path_str)
  289. {
  290. return strstr (path_str, VFS_PATH_URL_DELIMITER) == NULL;
  291. }
  292. /* --------------------------------------------------------------------------------------------- */
  293. /** Split path string to path elements by deprecated algorithm.
  294. *
  295. * @param path_str VFS-path
  296. *
  297. * @return pointer to newly created vfs_path_t object with filled path elements array.
  298. */
  299. static vfs_path_t *
  300. vfs_path_from_str_deprecated_parser (char *path, vfs_path_flag_t flags)
  301. {
  302. vfs_path_t *vpath;
  303. vfs_path_element_t *element;
  304. struct vfs_class *class;
  305. const char *local, *op;
  306. (void) flags;
  307. vpath = vfs_path_new ();
  308. while ((class = _vfs_split_with_semi_skip_count (path, &local, &op, 0)) != NULL)
  309. {
  310. char *url_params;
  311. element = g_new0 (vfs_path_element_t, 1);
  312. element->class = class;
  313. if (local == NULL)
  314. local = "";
  315. element->path = vfs_translate_path_n (local);
  316. element->encoding = vfs_get_encoding (local);
  317. element->dir.converter =
  318. (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
  319. url_params = strchr (op, ':'); /* skip VFS prefix */
  320. if (url_params != NULL)
  321. {
  322. *url_params = '\0';
  323. url_params++;
  324. vfs_path_url_split (element, url_params);
  325. }
  326. if (*op != '\0')
  327. element->vfs_prefix = g_strdup (op);
  328. g_array_prepend_val (vpath->path, element);
  329. }
  330. if (path[0] != '\0')
  331. {
  332. element = g_new0 (vfs_path_element_t, 1);
  333. element->class = g_ptr_array_index (vfs__classes_list, 0);
  334. element->path = vfs_translate_path_n (path);
  335. element->encoding = vfs_get_encoding (path);
  336. element->dir.converter =
  337. (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
  338. g_array_prepend_val (vpath->path, element);
  339. }
  340. return vpath;
  341. }
  342. /* --------------------------------------------------------------------------------------------- */
  343. /** Split path string to path elements by URL algorithm.
  344. *
  345. * @param path_str VFS-path
  346. *
  347. * @return pointer to newly created vfs_path_t object with filled path elements array.
  348. */
  349. static vfs_path_t *
  350. vfs_path_from_str_uri_parser (char *path, vfs_path_flag_t flags)
  351. {
  352. vfs_path_t *vpath;
  353. vfs_path_element_t *element;
  354. char *url_delimiter;
  355. vpath = vfs_path_new ();
  356. vpath->relative = (flags & VPF_NO_CANON) != 0;
  357. while ((url_delimiter = g_strrstr (path, VFS_PATH_URL_DELIMITER)) != NULL)
  358. {
  359. char *vfs_prefix_start;
  360. char *real_vfs_prefix_start = url_delimiter;
  361. char *slash_pointer;
  362. struct vfs_s_subclass *sub = NULL;
  363. while (real_vfs_prefix_start > path && *(real_vfs_prefix_start) != PATH_SEP)
  364. real_vfs_prefix_start--;
  365. vfs_prefix_start = real_vfs_prefix_start;
  366. if (*(vfs_prefix_start) == PATH_SEP)
  367. vfs_prefix_start += 1;
  368. *url_delimiter = '\0';
  369. element = g_new0 (vfs_path_element_t, 1);
  370. element->class = vfs_prefix_to_class (vfs_prefix_start);
  371. element->vfs_prefix = g_strdup (vfs_prefix_start);
  372. url_delimiter += strlen (VFS_PATH_URL_DELIMITER);
  373. sub = VFSDATA (element);
  374. if (sub != NULL && (sub->flags & VFS_S_REMOTE) != 0)
  375. {
  376. slash_pointer = strchr (url_delimiter, PATH_SEP);
  377. if (slash_pointer == NULL)
  378. {
  379. element->path = g_strdup ("");
  380. }
  381. else
  382. {
  383. element->path = vfs_translate_path_n (slash_pointer + 1);
  384. element->encoding = vfs_get_encoding (slash_pointer);
  385. *slash_pointer = '\0';
  386. }
  387. vfs_path_url_split (element, url_delimiter);
  388. }
  389. else
  390. {
  391. element->path = vfs_translate_path_n (url_delimiter);
  392. element->encoding = vfs_get_encoding (url_delimiter);
  393. }
  394. element->dir.converter =
  395. (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
  396. g_array_prepend_val (vpath->path, element);
  397. if ((real_vfs_prefix_start > path && *(real_vfs_prefix_start) == PATH_SEP) ||
  398. (real_vfs_prefix_start == path && *(real_vfs_prefix_start) != PATH_SEP))
  399. *real_vfs_prefix_start = '\0';
  400. else
  401. *(real_vfs_prefix_start + 1) = '\0';
  402. }
  403. if (path[0] != '\0')
  404. {
  405. element = g_new0 (vfs_path_element_t, 1);
  406. element->class = g_ptr_array_index (vfs__classes_list, 0);
  407. element->path = vfs_translate_path_n (path);
  408. element->encoding = vfs_get_encoding (path);
  409. element->dir.converter =
  410. (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
  411. g_array_prepend_val (vpath->path, element);
  412. }
  413. return vpath;
  414. }
  415. /* --------------------------------------------------------------------------------------------- */
  416. /**
  417. * Add element's class info to result string (such as VFS name, host, encoding etc)
  418. * This function used as helper only in vfs_path_tokens_get() function
  419. *
  420. * @param element current path element
  421. * @param ret_tokens total tikens for return
  422. * @param element_tokens accumulated element-only tokens
  423. */
  424. static void
  425. vfs_path_tokens_add_class_info (const vfs_path_element_t * element, GString * ret_tokens,
  426. GString * element_tokens)
  427. {
  428. if (((element->class->flags & VFSF_LOCAL) == 0 || ret_tokens->len > 0)
  429. && element_tokens->len > 0)
  430. {
  431. char *url_str;
  432. if (ret_tokens->len > 0 && ret_tokens->str[ret_tokens->len - 1] != PATH_SEP)
  433. g_string_append_c (ret_tokens, PATH_SEP);
  434. g_string_append (ret_tokens, element->vfs_prefix);
  435. g_string_append (ret_tokens, VFS_PATH_URL_DELIMITER);
  436. url_str = vfs_path_build_url_params_str (element, TRUE);
  437. if (*url_str != '\0')
  438. {
  439. g_string_append (ret_tokens, url_str);
  440. g_string_append_c (ret_tokens, PATH_SEP);
  441. }
  442. g_free (url_str);
  443. }
  444. if (element->encoding != NULL)
  445. {
  446. if (ret_tokens->len > 0 && ret_tokens->str[ret_tokens->len - 1] != PATH_SEP)
  447. g_string_append (ret_tokens, PATH_SEP_STR);
  448. g_string_append (ret_tokens, VFS_ENCODING_PREFIX);
  449. g_string_append (ret_tokens, element->encoding);
  450. g_string_append (ret_tokens, PATH_SEP_STR);
  451. }
  452. g_string_append (ret_tokens, element_tokens->str);
  453. }
  454. /* --------------------------------------------------------------------------------------------- */
  455. /**
  456. * Strip path to home dir.
  457. * @param dir pointer to string contains full path
  458. */
  459. static char *
  460. vfs_path_strip_home (const char *dir)
  461. {
  462. const char *home_dir = mc_config_get_home_dir ();
  463. if (home_dir != NULL)
  464. {
  465. size_t len;
  466. len = strlen (home_dir);
  467. if (strncmp (dir, home_dir, len) == 0 && (dir[len] == PATH_SEP || dir[len] == '\0'))
  468. return g_strdup_printf ("~%s", dir + len);
  469. }
  470. return g_strdup (dir);
  471. }
  472. /* --------------------------------------------------------------------------------------------- */
  473. /* --------------------------------------------------------------------------------------------- */
  474. /*** public functions ****************************************************************************/
  475. /* --------------------------------------------------------------------------------------------- */
  476. /**
  477. * Convert first elements_count elements from vfs_path_t to string representation with flags.
  478. *
  479. * @param vpath pointer to vfs_path_t object
  480. * @param elements_count count of first elements for convert
  481. * @param flags flags for converter
  482. *
  483. * @return pointer to newly created string.
  484. */
  485. #define vfs_append_from_path(appendfrom, is_relative) \
  486. { \
  487. if ((flags & VPF_STRIP_HOME) && element_index == 0 && (element->class->flags & VFSF_LOCAL) != 0) \
  488. { \
  489. char *stripped_home_str; \
  490. stripped_home_str = vfs_path_strip_home (appendfrom); \
  491. g_string_append (buffer, stripped_home_str); \
  492. g_free (stripped_home_str); \
  493. } \
  494. else \
  495. { \
  496. if ((!is_relative) && (*appendfrom != PATH_SEP) && (*appendfrom != '\0') \
  497. && (buffer->len == 0 || buffer->str[buffer->len - 1] != PATH_SEP)) \
  498. g_string_append_c (buffer, PATH_SEP); \
  499. g_string_append (buffer, appendfrom); \
  500. } \
  501. }
  502. char *
  503. vfs_path_to_str_flags (const vfs_path_t * vpath, int elements_count, vfs_path_flag_t flags)
  504. {
  505. int element_index;
  506. GString *buffer;
  507. GString *recode_buffer;
  508. if (vpath == NULL)
  509. return NULL;
  510. if (elements_count == 0 || elements_count > vfs_path_elements_count (vpath))
  511. elements_count = vfs_path_elements_count (vpath);
  512. if (elements_count < 0)
  513. elements_count = vfs_path_elements_count (vpath) + elements_count;
  514. buffer = g_string_new ("");
  515. recode_buffer = g_string_new ("");
  516. for (element_index = 0; element_index < elements_count; element_index++)
  517. {
  518. const vfs_path_element_t *element;
  519. gboolean is_relative = vpath->relative && (element_index == 0);
  520. element = vfs_path_get_by_index (vpath, element_index);
  521. if (element->vfs_prefix != NULL)
  522. {
  523. char *url_str;
  524. if ((!is_relative) && (buffer->len == 0 || buffer->str[buffer->len - 1] != PATH_SEP))
  525. g_string_append_c (buffer, PATH_SEP);
  526. g_string_append (buffer, element->vfs_prefix);
  527. g_string_append (buffer, VFS_PATH_URL_DELIMITER);
  528. url_str = vfs_path_build_url_params_str (element, !(flags & VPF_STRIP_PASSWORD));
  529. if (*url_str != '\0')
  530. {
  531. g_string_append (buffer, url_str);
  532. g_string_append_c (buffer, PATH_SEP);
  533. }
  534. g_free (url_str);
  535. }
  536. if ((flags & VPF_RECODE) == 0 && vfs_path_element_need_cleanup_converter (element))
  537. {
  538. if ((flags & VPF_HIDE_CHARSET) == 0)
  539. {
  540. if ((!is_relative)
  541. && (buffer->len == 0 || buffer->str[buffer->len - 1] != PATH_SEP))
  542. g_string_append (buffer, PATH_SEP_STR);
  543. g_string_append (buffer, VFS_ENCODING_PREFIX);
  544. g_string_append (buffer, element->encoding);
  545. }
  546. str_vfs_convert_from (element->dir.converter, element->path, recode_buffer);
  547. vfs_append_from_path (recode_buffer->str, is_relative);
  548. g_string_set_size (recode_buffer, 0);
  549. }
  550. else
  551. {
  552. vfs_append_from_path (element->path, is_relative);
  553. }
  554. }
  555. g_string_free (recode_buffer, TRUE);
  556. return g_string_free (buffer, FALSE);
  557. }
  558. #undef vfs_append_from_path
  559. /* --------------------------------------------------------------------------------------------- */
  560. /**
  561. * Convert first elements_count elements from vfs_path_t to string representation.
  562. *
  563. * @param vpath pointer to vfs_path_t object
  564. * @param elements_count count of first elements for convert
  565. *
  566. * @return pointer to newly created string.
  567. */
  568. char *
  569. vfs_path_to_str_elements_count (const vfs_path_t * vpath, int elements_count)
  570. {
  571. return vfs_path_to_str_flags (vpath, elements_count, VPF_NONE);
  572. }
  573. /* --------------------------------------------------------------------------------------------- */
  574. /**
  575. * Convert vfs_path_t to string representation.
  576. *
  577. * @param vpath pointer to vfs_path_t object
  578. *
  579. * @return pointer to newly created string.
  580. */
  581. char *
  582. vfs_path_to_str (const vfs_path_t * vpath)
  583. {
  584. return vfs_path_to_str_elements_count (vpath, vfs_path_elements_count (vpath));
  585. }
  586. /* --------------------------------------------------------------------------------------------- */
  587. /**
  588. * Split path string to path elements with flags for change parce process.
  589. *
  590. * @param path_str VFS-path
  591. * @param flags flags for parser
  592. *
  593. * @return pointer to newly created vfs_path_t object with filled path elements array.
  594. */
  595. vfs_path_t *
  596. vfs_path_from_str_flags (const char *path_str, vfs_path_flag_t flags)
  597. {
  598. vfs_path_t *vpath;
  599. char *path;
  600. if (path_str == NULL)
  601. return NULL;
  602. if ((flags & VPF_NO_CANON) == 0)
  603. path = vfs_canon (path_str);
  604. else
  605. path = g_strdup (path_str);
  606. if (path == NULL)
  607. return NULL;
  608. if ((flags & VPF_USE_DEPRECATED_PARSER) != 0 && vfs_path_is_str_path_deprecated (path))
  609. vpath = vfs_path_from_str_deprecated_parser (path, flags);
  610. else
  611. vpath = vfs_path_from_str_uri_parser (path, flags);
  612. g_free (path);
  613. return vpath;
  614. }
  615. /* --------------------------------------------------------------------------------------------- */
  616. /**
  617. * Split path string to path elements.
  618. *
  619. * @param path_str VFS-path
  620. *
  621. * @return pointer to newly created vfs_path_t object with filled path elements array.
  622. */
  623. vfs_path_t *
  624. vfs_path_from_str (const char *path_str)
  625. {
  626. return vfs_path_from_str_flags (path_str, VPF_NONE);
  627. }
  628. /* --------------------------------------------------------------------------------------------- */
  629. /*
  630. * Create new vfs_path_t object.
  631. *
  632. * @return pointer to newly created vfs_path_t object.
  633. */
  634. vfs_path_t *
  635. vfs_path_new (void)
  636. {
  637. vfs_path_t *vpath;
  638. vpath = g_new0 (vfs_path_t, 1);
  639. vpath->path = g_array_new (FALSE, TRUE, sizeof (vfs_path_element_t *));
  640. return vpath;
  641. }
  642. /* --------------------------------------------------------------------------------------------- */
  643. /*
  644. * Get count of path elements.
  645. *
  646. * @param vpath pointer to vfs_path_t object
  647. *
  648. * @return count of path elements.
  649. */
  650. int
  651. vfs_path_elements_count (const vfs_path_t * vpath)
  652. {
  653. return (vpath != NULL && vpath->path != NULL) ? vpath->path->len : 0;
  654. }
  655. /* --------------------------------------------------------------------------------------------- */
  656. /**
  657. * Add vfs_path_element_t object to end of list in vfs_path_t object
  658. * @param vpath pointer to vfs_path_t object
  659. * @param path_element pointer to vfs_path_element_t object
  660. */
  661. void
  662. vfs_path_add_element (const vfs_path_t * vpath, const vfs_path_element_t * path_element)
  663. {
  664. g_array_append_val (vpath->path, path_element);
  665. }
  666. /* --------------------------------------------------------------------------------------------- */
  667. /*
  668. * Get one path element by index.
  669. *
  670. * @param vpath pointer to vfs_path_t object
  671. * @param element_index element index. May have negative value (in this case count was started at the end of list).
  672. *
  673. * @return path element.
  674. */
  675. const vfs_path_element_t *
  676. vfs_path_get_by_index (const vfs_path_t * vpath, int element_index)
  677. {
  678. if (vpath == NULL)
  679. return NULL;
  680. if (element_index < 0)
  681. element_index += vfs_path_elements_count (vpath);
  682. if (element_index < 0)
  683. vfs_die ("vfs_path_get_by_index: incorrect index!");
  684. return g_array_index (vpath->path, vfs_path_element_t *, element_index);
  685. }
  686. /* --------------------------------------------------------------------------------------------- */
  687. /*
  688. * Clone one path element
  689. *
  690. * @param element pointer to vfs_path_element_t object
  691. *
  692. * @return Newly allocated path element
  693. */
  694. vfs_path_element_t *
  695. vfs_path_element_clone (const vfs_path_element_t * element)
  696. {
  697. vfs_path_element_t *new_element = g_new (vfs_path_element_t, 1);
  698. new_element->user = g_strdup (element->user);
  699. new_element->password = g_strdup (element->password);
  700. new_element->host = g_strdup (element->host);
  701. new_element->ipv6 = element->ipv6;
  702. new_element->port = element->port;
  703. new_element->path = g_strdup (element->path);
  704. new_element->class = element->class;
  705. new_element->encoding = g_strdup (element->encoding);
  706. new_element->vfs_prefix = g_strdup (element->vfs_prefix);
  707. if (vfs_path_element_need_cleanup_converter (element) && new_element->encoding != NULL)
  708. new_element->dir.converter = str_crt_conv_from (new_element->encoding);
  709. else
  710. new_element->dir.converter = element->dir.converter;
  711. new_element->dir.info = element->dir.info;
  712. return new_element;
  713. }
  714. /* --------------------------------------------------------------------------------------------- */
  715. /*
  716. * Free one path element.
  717. *
  718. * @param element pointer to vfs_path_element_t object
  719. *
  720. */
  721. void
  722. vfs_path_element_free (vfs_path_element_t * element)
  723. {
  724. if (element == NULL)
  725. return;
  726. g_free (element->user);
  727. g_free (element->password);
  728. g_free (element->host);
  729. g_free (element->path);
  730. g_free (element->encoding);
  731. g_free (element->vfs_prefix);
  732. if (vfs_path_element_need_cleanup_converter (element))
  733. {
  734. str_close_conv (element->dir.converter);
  735. }
  736. g_free (element);
  737. }
  738. /* --------------------------------------------------------------------------------------------- */
  739. /*
  740. * Clone path
  741. *
  742. * @param vpath pointer to vfs_path_t object
  743. *
  744. * @return Newly allocated path object
  745. */
  746. vfs_path_t *
  747. vfs_path_clone (const vfs_path_t * vpath)
  748. {
  749. vfs_path_t *new_vpath;
  750. int vpath_element_index;
  751. if (vpath == NULL)
  752. return NULL;
  753. new_vpath = vfs_path_new ();
  754. new_vpath->relative = vpath->relative;
  755. for (vpath_element_index = 0; vpath_element_index < vfs_path_elements_count (vpath);
  756. vpath_element_index++)
  757. {
  758. vfs_path_element_t *path_element;
  759. path_element = vfs_path_element_clone (vfs_path_get_by_index (vpath, vpath_element_index));
  760. g_array_append_val (new_vpath->path, path_element);
  761. }
  762. return new_vpath;
  763. }
  764. /* --------------------------------------------------------------------------------------------- */
  765. /*
  766. * Free vfs_path_t object.
  767. *
  768. * @param vpath pointer to vfs_path_t object
  769. *
  770. */
  771. void
  772. vfs_path_free (vfs_path_t * vpath)
  773. {
  774. int vpath_element_index;
  775. if (vpath == NULL)
  776. return;
  777. for (vpath_element_index = 0; vpath_element_index < vfs_path_elements_count (vpath);
  778. vpath_element_index++)
  779. {
  780. vfs_path_element_t *path_element;
  781. path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, vpath_element_index);
  782. vfs_path_element_free (path_element);
  783. }
  784. g_array_free (vpath->path, TRUE);
  785. g_free (vpath);
  786. }
  787. /* --------------------------------------------------------------------------------------------- */
  788. /*
  789. * Remove one path element by index
  790. *
  791. * @param vpath pointer to vfs_path_t object
  792. * @param element_index element index. May have negative value (in this case count was started at the end of list).
  793. *
  794. */
  795. void
  796. vfs_path_remove_element_by_index (vfs_path_t * vpath, int element_index)
  797. {
  798. vfs_path_element_t *element;
  799. if ((vpath == NULL) || (vfs_path_elements_count (vpath) == 1))
  800. return;
  801. if (element_index < 0)
  802. element_index = vfs_path_elements_count (vpath) + element_index;
  803. element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, element_index);
  804. vpath->path = g_array_remove_index (vpath->path, element_index);
  805. vfs_path_element_free (element);
  806. }
  807. /* --------------------------------------------------------------------------------------------- */
  808. /** Return VFS class for the given prefix */
  809. struct vfs_class *
  810. vfs_prefix_to_class (const char *prefix)
  811. {
  812. guint i;
  813. /* Avoid first class (localfs) that would accept any prefix */
  814. for (i = 1; i < vfs__classes_list->len; i++)
  815. {
  816. struct vfs_class *vfs;
  817. vfs = (struct vfs_class *) g_ptr_array_index (vfs__classes_list, i);
  818. if (vfs->which != NULL)
  819. {
  820. if (vfs->which (vfs, prefix) == -1)
  821. continue;
  822. return vfs;
  823. }
  824. if (vfs->prefix != NULL && strncmp (prefix, vfs->prefix, strlen (vfs->prefix)) == 0)
  825. return vfs;
  826. }
  827. return NULL;
  828. }
  829. /* --------------------------------------------------------------------------------------------- */
  830. /**
  831. * Check if need cleanup charset converter for vfs_path_element_t
  832. *
  833. * @param element part of path
  834. *
  835. * @return TRUE if need cleanup converter or FALSE otherwise
  836. */
  837. gboolean
  838. vfs_path_element_need_cleanup_converter (const vfs_path_element_t * element)
  839. {
  840. return (element->dir.converter != str_cnv_from_term && element->dir.converter != INVALID_CONV);
  841. }
  842. /* --------------------------------------------------------------------------------------------- */
  843. /**
  844. * Serialize vfs_path_t object to string
  845. *
  846. * @param vpath data for serialization
  847. * @param error contain pointer to object for handle error code and message
  848. *
  849. * @return serialized vpath as newly allocated string
  850. */
  851. char *
  852. vfs_path_serialize (const vfs_path_t * vpath, GError ** error)
  853. {
  854. mc_config_t *cpath = mc_config_init (NULL);
  855. ssize_t element_index;
  856. char *ret_value;
  857. if ((vpath == NULL) || (vfs_path_elements_count (vpath) == 0))
  858. {
  859. g_set_error (error, MC_ERROR, -1, "vpath object is empty");
  860. return NULL;
  861. }
  862. for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
  863. {
  864. char *groupname;
  865. const vfs_path_element_t *element;
  866. groupname = g_strdup_printf ("path-element-%zd", element_index);
  867. element = vfs_path_get_by_index (vpath, element_index);
  868. /* convert one element to config group */
  869. mc_config_set_string_raw (cpath, groupname, "path", element->path);
  870. mc_config_set_string_raw (cpath, groupname, "class-name", element->class->name);
  871. mc_config_set_string_raw (cpath, groupname, "encoding", element->encoding);
  872. mc_config_set_string_raw (cpath, groupname, "vfs_prefix", element->vfs_prefix);
  873. mc_config_set_string_raw (cpath, groupname, "user", element->user);
  874. mc_config_set_string_raw (cpath, groupname, "password", element->password);
  875. mc_config_set_string_raw (cpath, groupname, "host", element->host);
  876. if (element->port != 0)
  877. mc_config_set_int (cpath, groupname, "port", element->port);
  878. g_free (groupname);
  879. }
  880. ret_value = mc_serialize_config (cpath, error);
  881. mc_config_deinit (cpath);
  882. return ret_value;
  883. }
  884. /* --------------------------------------------------------------------------------------------- */
  885. /**
  886. * Deserialize string to vfs_path_t object
  887. *
  888. * @param data data for serialization
  889. * @param error contain pointer to object for handle error code and message
  890. *
  891. * @return newly allocated vfs_path_t object
  892. */
  893. vfs_path_t *
  894. vfs_path_deserialize (const char *data, GError ** error)
  895. {
  896. mc_config_t *cpath = mc_deserialize_config (data, error);
  897. size_t element_index = 0;
  898. vfs_path_t *vpath;
  899. if (cpath == NULL)
  900. return NULL;
  901. vpath = vfs_path_new ();
  902. while (TRUE)
  903. {
  904. vfs_path_element_t *element;
  905. char *cfg_value;
  906. char *groupname;
  907. groupname = g_strdup_printf ("path-element-%zd", element_index);
  908. if (!mc_config_has_group (cpath, groupname))
  909. {
  910. g_free (groupname);
  911. break;
  912. }
  913. element = g_new0 (vfs_path_element_t, 1);
  914. cfg_value = mc_config_get_string_raw (cpath, groupname, "class-name", NULL);
  915. element->class = vfs_get_class_by_name (cfg_value);
  916. if (element->class == NULL)
  917. {
  918. g_free (element);
  919. vfs_path_free (vpath);
  920. g_set_error (error, MC_ERROR, -1, "Unable to find VFS class by name '%s'", cfg_value);
  921. g_free (cfg_value);
  922. mc_config_deinit (cpath);
  923. return NULL;
  924. }
  925. g_free (cfg_value);
  926. element->path = mc_config_get_string_raw (cpath, groupname, "path", NULL);
  927. element->encoding = mc_config_get_string_raw (cpath, groupname, "encoding", NULL);
  928. element->dir.converter =
  929. (element->encoding != NULL) ? str_crt_conv_from (element->encoding) : INVALID_CONV;
  930. element->vfs_prefix = mc_config_get_string_raw (cpath, groupname, "vfs_prefix", NULL);
  931. element->user = mc_config_get_string_raw (cpath, groupname, "user", NULL);
  932. element->password = mc_config_get_string_raw (cpath, groupname, "password", NULL);
  933. element->host = mc_config_get_string_raw (cpath, groupname, "host", NULL);
  934. element->port = mc_config_get_int (cpath, groupname, "port", 0);
  935. vpath->path = g_array_append_val (vpath->path, element);
  936. g_free (groupname);
  937. element_index++;
  938. }
  939. mc_config_deinit (cpath);
  940. if (vfs_path_elements_count (vpath) == 0)
  941. {
  942. vfs_path_free (vpath);
  943. g_set_error (error, MC_ERROR, -1, "No any path elements found");
  944. return NULL;
  945. }
  946. return vpath;
  947. }
  948. /* --------------------------------------------------------------------------------------------- */
  949. /**
  950. * Build vfs_path_t object from arguments.
  951. *
  952. * @param ... path tokens, terminated by NULL
  953. *
  954. * @return newly allocated vfs_path_t object
  955. */
  956. vfs_path_t *
  957. vfs_path_build_filename (const char *first_element, ...)
  958. {
  959. va_list args;
  960. char *str_path;
  961. vfs_path_t *vpath;
  962. if (first_element == NULL)
  963. return NULL;
  964. va_start (args, first_element);
  965. str_path = mc_build_filenamev (first_element, args);
  966. va_end (args);
  967. vpath = vfs_path_from_str (str_path);
  968. g_free (str_path);
  969. return vpath;
  970. }
  971. /* --------------------------------------------------------------------------------------------- */
  972. /**
  973. * Append tokens to path object
  974. *
  975. * @param vpath path object
  976. * @param ... NULL-terminated strings
  977. *
  978. * @return newly allocated path object
  979. */
  980. vfs_path_t *
  981. vfs_path_append_new (const vfs_path_t * vpath, const char *first_element, ...)
  982. {
  983. va_list args;
  984. char *str_path, *result_str;
  985. vfs_path_t *ret_vpath;
  986. if (vpath == NULL || first_element == NULL)
  987. return NULL;
  988. va_start (args, first_element);
  989. str_path = mc_build_filenamev (first_element, args);
  990. va_end (args);
  991. result_str = vfs_path_to_str (vpath);
  992. ret_vpath = vfs_path_build_filename (result_str, str_path, NULL);
  993. g_free (result_str);
  994. g_free (str_path);
  995. return ret_vpath;
  996. }
  997. /* --------------------------------------------------------------------------------------------- */
  998. /**
  999. * Append vpath_t tokens to path object
  1000. *
  1001. * @param ... NULL-terminated vpath objects
  1002. *
  1003. * @return newly allocated path object
  1004. */
  1005. vfs_path_t *
  1006. vfs_path_append_vpath_new (const vfs_path_t * first_vpath, ...)
  1007. {
  1008. va_list args;
  1009. vfs_path_t *ret_vpath;
  1010. const vfs_path_t *current_vpath = first_vpath;
  1011. if (first_vpath == NULL)
  1012. return NULL;
  1013. ret_vpath = vfs_path_new ();
  1014. va_start (args, first_vpath);
  1015. do
  1016. {
  1017. int vindex;
  1018. for (vindex = 0; vindex < vfs_path_elements_count (current_vpath); vindex++)
  1019. {
  1020. vfs_path_element_t *path_element;
  1021. path_element = vfs_path_element_clone (vfs_path_get_by_index (current_vpath, vindex));
  1022. g_array_append_val (ret_vpath->path, path_element);
  1023. }
  1024. current_vpath = va_arg (args, const vfs_path_t *);
  1025. }
  1026. while (current_vpath != NULL);
  1027. va_end (args);
  1028. return ret_vpath;
  1029. }
  1030. /* --------------------------------------------------------------------------------------------- */
  1031. /**
  1032. * get tockens count in path.
  1033. *
  1034. * @param vpath path object
  1035. *
  1036. * @return count of tokens
  1037. */
  1038. size_t
  1039. vfs_path_tokens_count (const vfs_path_t * vpath)
  1040. {
  1041. size_t count_tokens = 0;
  1042. int element_index;
  1043. if (vpath == NULL)
  1044. return 0;
  1045. for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
  1046. {
  1047. const vfs_path_element_t *element;
  1048. char **path_tokens, **iterator;
  1049. element = vfs_path_get_by_index (vpath, element_index);
  1050. path_tokens = iterator = g_strsplit (element->path, PATH_SEP_STR, -1);
  1051. while (*iterator != NULL)
  1052. {
  1053. if (**iterator != '\0')
  1054. count_tokens++;
  1055. iterator++;
  1056. }
  1057. g_strfreev (path_tokens);
  1058. }
  1059. return count_tokens;
  1060. }
  1061. /* --------------------------------------------------------------------------------------------- */
  1062. /**
  1063. * Get subpath by tokens
  1064. *
  1065. * @param vpath path object
  1066. * @param start_position first token for got/ Started from 0.
  1067. * If negative, then position will be relative to end of path
  1068. * @param length count of tokens
  1069. *
  1070. * @return newly allocated string with path tokens separated by slash
  1071. */
  1072. char *
  1073. vfs_path_tokens_get (const vfs_path_t * vpath, ssize_t start_position, ssize_t length)
  1074. {
  1075. GString *ret_tokens, *element_tokens;
  1076. int element_index;
  1077. size_t tokens_count = vfs_path_tokens_count (vpath);
  1078. if (vpath == NULL)
  1079. return NULL;
  1080. if (length == 0)
  1081. length = tokens_count;
  1082. if (length < 0)
  1083. length = tokens_count + length;
  1084. if (start_position < 0)
  1085. start_position = (ssize_t) tokens_count + start_position;
  1086. if (start_position < 0)
  1087. return NULL;
  1088. if (start_position >= (ssize_t) tokens_count)
  1089. return NULL;
  1090. if (start_position + (ssize_t) length > (ssize_t) tokens_count)
  1091. length = tokens_count - start_position;
  1092. ret_tokens = g_string_sized_new (32);
  1093. element_tokens = g_string_sized_new (32);
  1094. for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
  1095. {
  1096. const vfs_path_element_t *element;
  1097. char **path_tokens, **iterator;
  1098. g_string_assign (element_tokens, "");
  1099. element = vfs_path_get_by_index (vpath, element_index);
  1100. path_tokens = iterator = g_strsplit (element->path, PATH_SEP_STR, -1);
  1101. while (*iterator != NULL)
  1102. {
  1103. if (**iterator != '\0')
  1104. {
  1105. if (start_position == 0)
  1106. {
  1107. if (length == 0)
  1108. {
  1109. vfs_path_tokens_add_class_info (element, ret_tokens, element_tokens);
  1110. g_string_free (element_tokens, TRUE);
  1111. g_strfreev (path_tokens);
  1112. return g_string_free (ret_tokens, FALSE);
  1113. }
  1114. length--;
  1115. if (element_tokens->len != 0)
  1116. g_string_append_c (element_tokens, PATH_SEP);
  1117. g_string_append (element_tokens, *iterator);
  1118. }
  1119. else
  1120. start_position--;
  1121. }
  1122. iterator++;
  1123. }
  1124. g_strfreev (path_tokens);
  1125. vfs_path_tokens_add_class_info (element, ret_tokens, element_tokens);
  1126. }
  1127. g_string_free (element_tokens, TRUE);
  1128. return g_string_free (ret_tokens, !(start_position == 0 && length == 0));
  1129. }
  1130. /* --------------------------------------------------------------------------------------------- */
  1131. /**
  1132. * Get subpath by tokens
  1133. *
  1134. * @param vpath path object
  1135. * @param start_position first token for got/ Started from 0.
  1136. * If negative, then position will be relative to end of path
  1137. * @param length count of tokens
  1138. *
  1139. * @return newly allocated path object with path tokens separated by slash
  1140. */
  1141. vfs_path_t *
  1142. vfs_path_vtokens_get (const vfs_path_t * vpath, ssize_t start_position, ssize_t length)
  1143. {
  1144. char *str_tokens;
  1145. vfs_path_t *ret_vpath = NULL;
  1146. str_tokens = vfs_path_tokens_get (vpath, start_position, length);
  1147. if (str_tokens != NULL)
  1148. {
  1149. ret_vpath = vfs_path_from_str_flags (str_tokens, VPF_NO_CANON);
  1150. g_free (str_tokens);
  1151. }
  1152. return ret_vpath;
  1153. }
  1154. /* --------------------------------------------------------------------------------------------- */
  1155. /**
  1156. * Build URL parameters (such as user:pass@host:port) from one path element object
  1157. *
  1158. * @param element path element
  1159. *
  1160. * @return newly allocated string
  1161. */
  1162. char *
  1163. vfs_path_build_url_params_str (const vfs_path_element_t * element, gboolean keep_password)
  1164. {
  1165. GString *buffer;
  1166. if (element == NULL)
  1167. return NULL;
  1168. buffer = g_string_new ("");
  1169. if (element->user != NULL)
  1170. g_string_append (buffer, element->user);
  1171. if (element->password != NULL && keep_password)
  1172. {
  1173. g_string_append_c (buffer, ':');
  1174. g_string_append (buffer, element->password);
  1175. }
  1176. if (element->host != NULL)
  1177. {
  1178. if ((element->user != NULL) || (element->password != NULL))
  1179. g_string_append_c (buffer, '@');
  1180. if (element->ipv6)
  1181. g_string_append_c (buffer, '[');
  1182. g_string_append (buffer, element->host);
  1183. if (element->ipv6)
  1184. g_string_append_c (buffer, ']');
  1185. }
  1186. if ((element->port) != 0 && (element->host != NULL))
  1187. {
  1188. g_string_append_c (buffer, ':');
  1189. g_string_append_printf (buffer, "%d", element->port);
  1190. }
  1191. return g_string_free (buffer, FALSE);
  1192. }
  1193. /* --------------------------------------------------------------------------------------------- */
  1194. /**
  1195. * Build pretty string representation of one path_element_t object
  1196. *
  1197. * @param element path element
  1198. *
  1199. * @return newly allocated string
  1200. */
  1201. char *
  1202. vfs_path_element_build_pretty_path_str (const vfs_path_element_t * element)
  1203. {
  1204. char *url_params;
  1205. GString *pretty_path;
  1206. pretty_path = g_string_new (element->class->prefix);
  1207. g_string_append (pretty_path, VFS_PATH_URL_DELIMITER);
  1208. url_params = vfs_path_build_url_params_str (element, FALSE);
  1209. g_string_append (pretty_path, url_params);
  1210. g_free (url_params);
  1211. if (*element->path != PATH_SEP)
  1212. g_string_append_c (pretty_path, PATH_SEP);
  1213. g_string_append (pretty_path, element->path);
  1214. return g_string_free (pretty_path, FALSE);
  1215. }
  1216. /* --------------------------------------------------------------------------------------------- */
  1217. /**
  1218. * Compare two path objects as strings
  1219. *
  1220. * @param vpath1 first path object
  1221. * @param vpath2 second vpath object
  1222. *
  1223. * @return integer value like to strcmp.
  1224. */
  1225. int
  1226. vfs_path_cmp (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
  1227. {
  1228. char *path1;
  1229. char *path2;
  1230. int ret_val;
  1231. if (vpath1 == NULL || vpath2 == NULL)
  1232. return -1;
  1233. path1 = vfs_path_to_str (vpath1);
  1234. path2 = vfs_path_to_str (vpath2);
  1235. ret_val = strcmp (path1, path2);
  1236. g_free (path1);
  1237. g_free (path2);
  1238. return ret_val;
  1239. }
  1240. /* --------------------------------------------------------------------------------------------- */
  1241. /**
  1242. * Compare two path objects as strings
  1243. *
  1244. * @param vpath1 first path object
  1245. * @param vpath2 second vpath object
  1246. * @param len number of first 'len' characters
  1247. *
  1248. * @return integer value like to strcmp.
  1249. */
  1250. int
  1251. vfs_path_ncmp (const vfs_path_t * vpath1, const vfs_path_t * vpath2, size_t len)
  1252. {
  1253. char *path1;
  1254. char *path2;
  1255. int ret_val;
  1256. if (vpath1 == NULL || vpath2 == NULL)
  1257. return -1;
  1258. path1 = vfs_path_to_str (vpath1);
  1259. path2 = vfs_path_to_str (vpath2);
  1260. ret_val = strncmp (path1, path2, len);
  1261. g_free (path1);
  1262. g_free (path2);
  1263. return ret_val;
  1264. }
  1265. /* --------------------------------------------------------------------------------------------- */
  1266. /**
  1267. * Calculate path length in string representation
  1268. *
  1269. * @param vpath path object
  1270. *
  1271. * @return length of path
  1272. */
  1273. size_t
  1274. vfs_path_len (const vfs_path_t * vpath)
  1275. {
  1276. char *path;
  1277. size_t ret_val;
  1278. if (vpath == NULL)
  1279. return 0;
  1280. path = vfs_path_to_str (vpath);
  1281. ret_val = strlen (path);
  1282. g_free (path);
  1283. return ret_val;
  1284. }
  1285. /* --------------------------------------------------------------------------------------------- */
  1286. /**
  1287. * Convert relative vpath object to absolute
  1288. *
  1289. * @param vpath path object
  1290. *
  1291. * @return absolute path object
  1292. */
  1293. vfs_path_t *
  1294. vfs_path_to_absolute (const vfs_path_t * vpath)
  1295. {
  1296. vfs_path_t *absolute_vpath;
  1297. char *path_str;
  1298. if (!vpath->relative)
  1299. return vfs_path_clone (vpath);
  1300. path_str = vfs_path_to_str (vpath);
  1301. absolute_vpath = vfs_path_from_str (path_str);
  1302. g_free (path_str);
  1303. return absolute_vpath;
  1304. }
  1305. /* --------------------------------------------------------------------------------------------- */