path.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. /* Virtual File System path handlers
  2. Copyright (C) 2011 Free Software Foundation, Inc.
  3. Written by:
  4. Slava Zanko <slavazanko@gmail.com>, 2011
  5. This file is part of the Midnight Commander.
  6. The Midnight Commander is free software; you can redistribute it
  7. and/or modify it under the terms of the GNU General Public License as
  8. published by the Free Software Foundation; either version 2 of the
  9. License, or (at your option) any later version.
  10. The Midnight Commander is distributed in the hope that it will be
  11. useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  12. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  17. MA 02110-1301, USA.
  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" /* concat_dir_and_file */
  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)
  104. vfs_die ("Cannot canonicalize NULL");
  105. /* Relative to current directory */
  106. if (*path != PATH_SEP)
  107. {
  108. char *local, *result, *curr_dir;
  109. curr_dir = vfs_get_current_dir ();
  110. local = concat_dir_and_file (curr_dir, path);
  111. g_free (curr_dir);
  112. result = vfs_canon (local);
  113. g_free (local);
  114. return result;
  115. }
  116. /*
  117. * So we have path of following form:
  118. * /p1/p2#op/.././././p3#op/p4. Good luck.
  119. */
  120. {
  121. char *result = g_strdup (path);
  122. canonicalize_pathname (result);
  123. return result;
  124. }
  125. }
  126. /* --------------------------------------------------------------------------------------------- */
  127. /**
  128. * Build URL parameters (such as user:pass@host:port) from one path element object
  129. *
  130. * @param element path element
  131. *
  132. * @return newly allocated string
  133. */
  134. static char *
  135. vfs_path_build_url_params_str (vfs_path_element_t * element)
  136. {
  137. GString *buffer;
  138. if (element == NULL)
  139. return NULL;
  140. buffer = g_string_new ("");
  141. if (element->user != NULL)
  142. g_string_append (buffer, element->user);
  143. if (element->password != NULL)
  144. {
  145. g_string_append_c (buffer, ':');
  146. g_string_append (buffer, element->password);
  147. }
  148. if (element->host != NULL)
  149. {
  150. if ((element->user != NULL) || (element->password != NULL))
  151. g_string_append_c (buffer, '@');
  152. if (element->ipv6)
  153. g_string_append_c (buffer, '[');
  154. g_string_append (buffer, element->host);
  155. if (element->ipv6)
  156. g_string_append_c (buffer, ']');
  157. }
  158. if ((element->port) != 0 && (element->host != NULL))
  159. {
  160. g_string_append_c (buffer, ':');
  161. g_string_append_printf (buffer, "%d", element->port);
  162. }
  163. return g_string_free (buffer, FALSE);
  164. }
  165. /* --------------------------------------------------------------------------------------------- */
  166. /** get encoding after last #enc: or NULL, if part does not contain #enc:
  167. *
  168. * @param path string
  169. *
  170. * @return newly allocated string.
  171. */
  172. static char *
  173. vfs_get_encoding (const char *path)
  174. {
  175. char result[16];
  176. char *work;
  177. char *semi;
  178. char *slash;
  179. work = g_strdup (path);
  180. /* try found #enc: */
  181. semi = g_strrstr (work, VFS_ENCODING_PREFIX);
  182. if (semi != NULL && (semi == work || *(semi - 1) == PATH_SEP))
  183. {
  184. semi += strlen (VFS_ENCODING_PREFIX); /* skip "#enc:" */
  185. slash = strchr (semi, PATH_SEP);
  186. if (slash != NULL)
  187. slash[0] = '\0';
  188. g_strlcpy (result, semi, sizeof (result));
  189. g_free (work);
  190. return g_strdup (result);
  191. }
  192. else
  193. {
  194. g_free (work);
  195. return NULL;
  196. }
  197. }
  198. /* --------------------------------------------------------------------------------------------- */
  199. /** Extract the hostname and username from the path
  200. *
  201. * Format of the path is [user@]hostname:port/remote-dir, e.g.:
  202. *
  203. * ftp://sunsite.unc.edu/pub/linux
  204. * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
  205. * ftp://tsx-11.mit.edu:8192/
  206. * ftp://joe@foo.edu:11321/private
  207. * ftp://joe:password@foo.se
  208. *
  209. * @param path_element is an input string to be parsed
  210. * @param path is an input string to be parsed
  211. *
  212. * @return g_malloc()ed url info.
  213. * If the user is empty, e.g. ftp://@roxanne/private, and URL_USE_ANONYMOUS
  214. * is not set, then the current login name is supplied.
  215. * Return value is a g_malloc()ed structure with the pathname relative to the
  216. * host.
  217. */
  218. static void
  219. vfs_path_url_split (vfs_path_element_t * path_element, const char *path)
  220. {
  221. char *pcopy;
  222. const char *pend;
  223. char *dir, *colon, *inner_colon, *at, *rest;
  224. path_element->port = 0;
  225. pcopy = g_strdup (path);
  226. pend = pcopy + strlen (pcopy);
  227. dir = pcopy;
  228. /* search for any possible user */
  229. at = strrchr (pcopy, '@');
  230. /* We have a username */
  231. if (at == NULL)
  232. rest = pcopy;
  233. else
  234. {
  235. *at = '\0';
  236. inner_colon = strchr (pcopy, ':');
  237. if (inner_colon != NULL)
  238. {
  239. *inner_colon = '\0';
  240. inner_colon++;
  241. path_element->password = g_strdup (inner_colon);
  242. }
  243. if (*pcopy != '\0')
  244. path_element->user = g_strdup (pcopy);
  245. if (pend == at + 1)
  246. rest = at;
  247. else
  248. rest = at + 1;
  249. }
  250. /* Check if the host comes with a port spec, if so, chop it */
  251. if (*rest != '[')
  252. colon = strchr (rest, ':');
  253. else
  254. {
  255. colon = strchr (++rest, ']');
  256. if (colon != NULL)
  257. {
  258. colon[0] = '\0';
  259. colon[1] = '\0';
  260. colon++;
  261. path_element->ipv6 = TRUE;
  262. }
  263. }
  264. if (colon != NULL)
  265. {
  266. *colon = '\0';
  267. if (sscanf (colon + 1, "%d", &path_element->port) == 1)
  268. {
  269. if (path_element->port <= 0 || path_element->port >= 65536)
  270. path_element->port = 0;
  271. }
  272. else
  273. while (*(++colon) != '\0')
  274. {
  275. switch (*colon)
  276. {
  277. case 'C':
  278. path_element->port = 1;
  279. break;
  280. case 'r':
  281. path_element->port = 2;
  282. break;
  283. }
  284. }
  285. }
  286. path_element->host = g_strdup (rest);
  287. g_free (pcopy);
  288. }
  289. /* --------------------------------------------------------------------------------------------- */
  290. /**
  291. * get VFS class for the given name
  292. *
  293. * @param class_name name of class
  294. *
  295. * @return pointer to class structure or NULL if class not found
  296. */
  297. static struct vfs_class *
  298. vfs_get_class_by_name (const char *class_name)
  299. {
  300. guint i;
  301. if (class_name == NULL)
  302. return NULL;
  303. for (i = 0; i < vfs__classes_list->len; i++)
  304. {
  305. struct vfs_class *vfs = (struct vfs_class *) g_ptr_array_index (vfs__classes_list, i);
  306. if ((vfs->name != NULL) && (strcmp (vfs->name, class_name) == 0))
  307. return vfs;
  308. }
  309. return NULL;
  310. }
  311. /* --------------------------------------------------------------------------------------------- */
  312. /**
  313. * Check if path string contain URL-like elements
  314. *
  315. * @param path_str path
  316. *
  317. * @return TRUE if path is deprecated or FALSE otherwise
  318. */
  319. static gboolean
  320. vfs_path_is_str_path_deprecated (const char *path_str)
  321. {
  322. return strstr (path_str, VFS_PATH_URL_DELIMITER) == NULL;
  323. }
  324. /* --------------------------------------------------------------------------------------------- */
  325. /** Split path string to path elements by deprecated algorithm.
  326. *
  327. * @param path_str VFS-path
  328. *
  329. * @return pointer to newly created vfs_path_t object with filled path elements array.
  330. */
  331. static vfs_path_t *
  332. vfs_path_from_str_deprecated_parser (char *path)
  333. {
  334. vfs_path_t *vpath;
  335. vfs_path_element_t *element;
  336. struct vfs_class *class;
  337. const char *local, *op;
  338. vpath = vfs_path_new ();
  339. while ((class = _vfs_split_with_semi_skip_count (path, &local, &op, 0)) != NULL)
  340. {
  341. char *url_params;
  342. element = g_new0 (vfs_path_element_t, 1);
  343. element->class = class;
  344. if (local == NULL)
  345. local = "";
  346. element->path = vfs_translate_path_n (local);
  347. element->encoding = vfs_get_encoding (local);
  348. element->dir.converter = INVALID_CONV;
  349. url_params = strchr (op, ':'); /* skip VFS prefix */
  350. if (url_params != NULL)
  351. {
  352. *url_params = '\0';
  353. url_params++;
  354. vfs_path_url_split (element, url_params);
  355. }
  356. if (*op != '\0')
  357. element->vfs_prefix = g_strdup (op);
  358. vpath->path = g_list_prepend (vpath->path, element);
  359. }
  360. if (path[0] != '\0')
  361. {
  362. element = g_new0 (vfs_path_element_t, 1);
  363. element->class = g_ptr_array_index (vfs__classes_list, 0);
  364. element->path = vfs_translate_path_n (path);
  365. element->encoding = vfs_get_encoding (path);
  366. element->dir.converter = INVALID_CONV;
  367. vpath->path = g_list_prepend (vpath->path, element);
  368. }
  369. return vpath;
  370. }
  371. /* --------------------------------------------------------------------------------------------- */
  372. /** Split path string to path elements by URL algorithm.
  373. *
  374. * @param path_str VFS-path
  375. *
  376. * @return pointer to newly created vfs_path_t object with filled path elements array.
  377. */
  378. static vfs_path_t *
  379. vfs_path_from_str_uri_parser (char *path)
  380. {
  381. vfs_path_t *vpath;
  382. vfs_path_element_t *element;
  383. char *url_delimiter;
  384. vpath = vfs_path_new ();
  385. while ((url_delimiter = g_strrstr (path, VFS_PATH_URL_DELIMITER)) != NULL)
  386. {
  387. char *vfs_prefix_start;
  388. char *real_vfs_prefix_start = url_delimiter;
  389. char *slash_pointer;
  390. struct vfs_s_subclass *sub = NULL;
  391. while (real_vfs_prefix_start > path && *(real_vfs_prefix_start) != PATH_SEP)
  392. real_vfs_prefix_start--;
  393. vfs_prefix_start = real_vfs_prefix_start;
  394. if (*(vfs_prefix_start) == PATH_SEP)
  395. vfs_prefix_start += 1;
  396. *url_delimiter = '\0';
  397. element = g_new0 (vfs_path_element_t, 1);
  398. element->class = vfs_prefix_to_class (vfs_prefix_start);
  399. element->vfs_prefix = g_strdup (vfs_prefix_start);
  400. element->dir.converter = INVALID_CONV;
  401. url_delimiter += strlen (VFS_PATH_URL_DELIMITER);
  402. sub = VFSDATA (element);
  403. if (sub != NULL && sub->flags & VFS_S_REMOTE)
  404. {
  405. slash_pointer = strchr (url_delimiter, PATH_SEP);
  406. if (slash_pointer == NULL)
  407. {
  408. element->path = g_strdup ("");
  409. }
  410. else
  411. {
  412. element->path = vfs_translate_path_n (slash_pointer + 1);
  413. element->encoding = vfs_get_encoding (slash_pointer);
  414. *slash_pointer = '\0';
  415. }
  416. vfs_path_url_split (element, url_delimiter);
  417. }
  418. else
  419. {
  420. element->path = vfs_translate_path_n (url_delimiter);
  421. element->encoding = vfs_get_encoding (url_delimiter);
  422. }
  423. vpath->path = g_list_prepend (vpath->path, element);
  424. if (real_vfs_prefix_start > path && *(real_vfs_prefix_start) == PATH_SEP)
  425. *real_vfs_prefix_start = '\0';
  426. else
  427. *(real_vfs_prefix_start + 1) = '\0';
  428. }
  429. if (path[0] != '\0')
  430. {
  431. element = g_new0 (vfs_path_element_t, 1);
  432. element->class = g_ptr_array_index (vfs__classes_list, 0);
  433. element->path = vfs_translate_path_n (path);
  434. element->encoding = vfs_get_encoding (path);
  435. element->dir.converter = INVALID_CONV;
  436. vpath->path = g_list_prepend (vpath->path, element);
  437. }
  438. return vpath;
  439. }
  440. /* --------------------------------------------------------------------------------------------- */
  441. /*** public functions ****************************************************************************/
  442. /* --------------------------------------------------------------------------------------------- */
  443. /**
  444. * Convert first elements_count elements from vfs_path_t to string representation.
  445. *
  446. * @param vpath pointer to vfs_path_t object
  447. * @param elements_count count of first elements for convert
  448. *
  449. * @return pointer to newly created string.
  450. */
  451. char *
  452. vfs_path_to_str_elements_count (const vfs_path_t * vpath, int elements_count)
  453. {
  454. int element_index;
  455. GString *buffer;
  456. if (vpath == NULL)
  457. return NULL;
  458. if (elements_count > vfs_path_elements_count (vpath))
  459. elements_count = vfs_path_elements_count (vpath);
  460. if (elements_count < 0)
  461. elements_count = vfs_path_elements_count (vpath) + elements_count;
  462. buffer = g_string_new ("");
  463. for (element_index = 0; element_index < elements_count; element_index++)
  464. {
  465. vfs_path_element_t *element = vfs_path_get_by_index (vpath, element_index);
  466. if (element->vfs_prefix != NULL)
  467. {
  468. char *url_str;
  469. if (buffer->str[buffer->len - 1] != '/')
  470. g_string_append_c (buffer, '/');
  471. g_string_append (buffer, element->vfs_prefix);
  472. g_string_append (buffer, VFS_PATH_URL_DELIMITER);
  473. url_str = vfs_path_build_url_params_str (element);
  474. if (*url_str != '\0')
  475. g_string_append (buffer, url_str);
  476. g_free (url_str);
  477. }
  478. if (element->encoding != NULL)
  479. {
  480. if (buffer->str[buffer->len - 1] != PATH_SEP)
  481. g_string_append (buffer, PATH_SEP_STR);
  482. g_string_append (buffer, VFS_ENCODING_PREFIX);
  483. g_string_append (buffer, element->encoding);
  484. }
  485. if ((*element->path != PATH_SEP) && (*element->path != '\0')
  486. && (buffer->str[buffer->len - 1] != PATH_SEP))
  487. g_string_append_c (buffer, PATH_SEP);
  488. g_string_append (buffer, element->path);
  489. }
  490. return g_string_free (buffer, FALSE);
  491. }
  492. /* --------------------------------------------------------------------------------------------- */
  493. /**
  494. * Convert vfs_path_t to string representation.
  495. *
  496. * @param vpath pointer to vfs_path_t object
  497. *
  498. * @return pointer to newly created string.
  499. */
  500. char *
  501. vfs_path_to_str (const vfs_path_t * vpath)
  502. {
  503. return vfs_path_to_str_elements_count (vpath, vfs_path_elements_count (vpath));
  504. }
  505. /* --------------------------------------------------------------------------------------------- */
  506. /**
  507. * Split path string to path elements with flags for change parce process.
  508. *
  509. * @param path_str VFS-path
  510. * @param flags flags for parser
  511. *
  512. * @return pointer to newly created vfs_path_t object with filled path elements array.
  513. */
  514. vfs_path_t *
  515. vfs_path_from_str_flags (const char *path_str, vfs_path_flag_t flags)
  516. {
  517. vfs_path_t *vpath;
  518. char *path;
  519. if (path_str == NULL)
  520. return NULL;
  521. if ((flags & VPF_NO_CANON) == 0)
  522. path = vfs_canon (path_str);
  523. else
  524. path = g_strdup (path_str);
  525. if (path == NULL)
  526. return NULL;
  527. if ((flags & VPF_USE_DEPRECATED_PARSER) != 0 && vfs_path_is_str_path_deprecated (path))
  528. vpath = vfs_path_from_str_deprecated_parser (path);
  529. else
  530. vpath = vfs_path_from_str_uri_parser (path);
  531. g_free (path);
  532. return vpath;
  533. }
  534. /* --------------------------------------------------------------------------------------------- */
  535. /**
  536. * Split path string to path elements.
  537. *
  538. * @param path_str VFS-path
  539. *
  540. * @return pointer to newly created vfs_path_t object with filled path elements array.
  541. */
  542. vfs_path_t *
  543. vfs_path_from_str (const char *path_str)
  544. {
  545. return vfs_path_from_str_flags (path_str, VPF_NONE);
  546. }
  547. /* --------------------------------------------------------------------------------------------- */
  548. /*
  549. * Create new vfs_path_t object.
  550. *
  551. * @return pointer to newly created vfs_path_t object.
  552. */
  553. vfs_path_t *
  554. vfs_path_new (void)
  555. {
  556. vfs_path_t *vpath;
  557. vpath = g_new0 (vfs_path_t, 1);
  558. return vpath;
  559. }
  560. /* --------------------------------------------------------------------------------------------- */
  561. /*
  562. * Get count of path elements.
  563. *
  564. * @param vpath pointer to vfs_path_t object
  565. *
  566. * @return count of path elements.
  567. */
  568. int
  569. vfs_path_elements_count (const vfs_path_t * vpath)
  570. {
  571. return (vpath != NULL && vpath->path != NULL) ? g_list_length (vpath->path) : 0;
  572. }
  573. /* --------------------------------------------------------------------------------------------- */
  574. /*
  575. * Get one path element by index.
  576. *
  577. * @param vpath pointer to vfs_path_t object
  578. * @param element_index element index. May have negative value (in this case count was started at the end of list).
  579. *
  580. * @return path element.
  581. */
  582. vfs_path_element_t *
  583. vfs_path_get_by_index (const vfs_path_t * vpath, int element_index)
  584. {
  585. if (element_index < 0)
  586. element_index += vfs_path_elements_count (vpath);
  587. if (element_index < 0)
  588. vfs_die ("vfs_path_get_by_index: incorrect index!");
  589. return g_list_nth_data (vpath->path, element_index);
  590. }
  591. /* --------------------------------------------------------------------------------------------- */
  592. /*
  593. * Clone one path element
  594. *
  595. * @param element pointer to vfs_path_element_t object
  596. *
  597. * @return Newly allocated path element
  598. */
  599. vfs_path_element_t *
  600. vfs_path_element_clone (const vfs_path_element_t * element)
  601. {
  602. vfs_path_element_t *new_element = g_new0 (vfs_path_element_t, 1);
  603. memcpy (new_element, element, sizeof (vfs_path_element_t));
  604. new_element->user = g_strdup (element->user);
  605. new_element->password = g_strdup (element->password);
  606. new_element->host = g_strdup (element->host);
  607. new_element->path = g_strdup (element->path);
  608. new_element->encoding = g_strdup (element->encoding);
  609. if (vfs_path_element_need_cleanup_converter (element) && new_element->encoding != NULL)
  610. new_element->dir.converter = str_crt_conv_from (new_element->encoding);
  611. new_element->vfs_prefix = g_strdup (element->vfs_prefix);
  612. return new_element;
  613. }
  614. /* --------------------------------------------------------------------------------------------- */
  615. /*
  616. * Free one path element.
  617. *
  618. * @param element pointer to vfs_path_element_t object
  619. *
  620. */
  621. void
  622. vfs_path_element_free (vfs_path_element_t * element)
  623. {
  624. if (element == NULL)
  625. return;
  626. g_free (element->user);
  627. g_free (element->password);
  628. g_free (element->host);
  629. g_free (element->path);
  630. g_free (element->encoding);
  631. g_free (element->vfs_prefix);
  632. if (vfs_path_element_need_cleanup_converter (element))
  633. {
  634. str_close_conv (element->dir.converter);
  635. }
  636. g_free (element);
  637. }
  638. /* --------------------------------------------------------------------------------------------- */
  639. /*
  640. * Clone path
  641. *
  642. * @param vpath pointer to vfs_path_t object
  643. *
  644. * @return Newly allocated path object
  645. */
  646. vfs_path_t *
  647. vfs_path_clone (const vfs_path_t * vpath)
  648. {
  649. vfs_path_t *new_vpath;
  650. int vpath_element_index;
  651. if (vpath == NULL)
  652. return NULL;
  653. new_vpath = vfs_path_new ();
  654. for (vpath_element_index = 0; vpath_element_index < vfs_path_elements_count (vpath);
  655. vpath_element_index++)
  656. {
  657. new_vpath->path =
  658. g_list_append (new_vpath->path,
  659. vfs_path_element_clone (vfs_path_get_by_index
  660. (vpath, vpath_element_index)));
  661. }
  662. return new_vpath;
  663. }
  664. /* --------------------------------------------------------------------------------------------- */
  665. /*
  666. * Free vfs_path_t object.
  667. *
  668. * @param vpath pointer to vfs_path_t object
  669. *
  670. */
  671. void
  672. vfs_path_free (vfs_path_t * path)
  673. {
  674. if (path == NULL)
  675. return;
  676. g_list_foreach (path->path, (GFunc) vfs_path_element_free, NULL);
  677. g_list_free (path->path);
  678. g_free (path);
  679. }
  680. /* --------------------------------------------------------------------------------------------- */
  681. /*
  682. * Remove one path element by index
  683. *
  684. * @param vpath pointer to vfs_path_t object
  685. * @param element_index element index. May have negative value (in this case count was started at the end of list).
  686. *
  687. */
  688. void
  689. vfs_path_remove_element_by_index (vfs_path_t * vpath, int element_index)
  690. {
  691. vfs_path_element_t *element;
  692. if ((vpath == NULL) || (vfs_path_elements_count (vpath) == 1))
  693. return;
  694. if (element_index < 0)
  695. element_index = vfs_path_elements_count (vpath) + element_index;
  696. element = g_list_nth_data (vpath->path, element_index);
  697. vpath->path = g_list_remove (vpath->path, element);
  698. vfs_path_element_free (element);
  699. }
  700. /* --------------------------------------------------------------------------------------------- */
  701. /** Return VFS class for the given prefix */
  702. struct vfs_class *
  703. vfs_prefix_to_class (const char *prefix)
  704. {
  705. guint i;
  706. /* Avoid first class (localfs) that would accept any prefix */
  707. for (i = 1; i < vfs__classes_list->len; i++)
  708. {
  709. struct vfs_class *vfs = (struct vfs_class *) g_ptr_array_index (vfs__classes_list, i);
  710. if (vfs->which != NULL)
  711. {
  712. if (vfs->which (vfs, prefix) == -1)
  713. continue;
  714. return vfs;
  715. }
  716. if (vfs->prefix != NULL && strncmp (prefix, vfs->prefix, strlen (vfs->prefix)) == 0)
  717. return vfs;
  718. }
  719. return NULL;
  720. }
  721. /* --------------------------------------------------------------------------------------------- */
  722. /**
  723. * Check if need cleanup charset converter for vfs_path_element_t
  724. *
  725. * @param element part of path
  726. *
  727. * @return TRUE if need cleanup converter or FALSE otherwise
  728. */
  729. gboolean
  730. vfs_path_element_need_cleanup_converter (const vfs_path_element_t * element)
  731. {
  732. return (element->dir.converter != str_cnv_from_term && element->dir.converter != INVALID_CONV);
  733. }
  734. /* --------------------------------------------------------------------------------------------- */
  735. /**
  736. * Serialize vfs_path_t object to string
  737. *
  738. * @param vpath data for serialization
  739. * @param error contain pointer to object for handle error code and message
  740. *
  741. * @return serialized vpath as newly allocated string
  742. */
  743. char *
  744. vfs_path_serialize (const vfs_path_t * vpath, GError ** error)
  745. {
  746. mc_config_t *cpath = mc_config_init (NULL);
  747. ssize_t element_index;
  748. char *ret_value;
  749. if ((vpath == NULL) || (vfs_path_elements_count (vpath) == 0))
  750. {
  751. g_set_error (error, MC_ERROR, -1, "vpath object is empty");
  752. return NULL;
  753. }
  754. for (element_index = 0; element_index < vfs_path_elements_count (vpath); element_index++)
  755. {
  756. char *groupname = g_strdup_printf ("path-element-%zd", element_index);
  757. vfs_path_element_t *element = vfs_path_get_by_index (vpath, element_index);
  758. /* convert one element to config group */
  759. mc_config_set_string_raw (cpath, groupname, "path", element->path);
  760. mc_config_set_string_raw (cpath, groupname, "class-name", element->class->name);
  761. mc_config_set_string_raw (cpath, groupname, "encoding", element->encoding);
  762. mc_config_set_string_raw (cpath, groupname, "vfs_prefix", element->vfs_prefix);
  763. mc_config_set_string_raw (cpath, groupname, "user", element->user);
  764. mc_config_set_string_raw (cpath, groupname, "password", element->password);
  765. mc_config_set_string_raw (cpath, groupname, "host", element->host);
  766. if (element->port != 0)
  767. mc_config_set_int (cpath, groupname, "port", element->port);
  768. g_free (groupname);
  769. }
  770. ret_value = mc_serialize_config (cpath, error);
  771. mc_config_deinit (cpath);
  772. return ret_value;
  773. }
  774. /* --------------------------------------------------------------------------------------------- */
  775. /**
  776. * Deserialize string to vfs_path_t object
  777. *
  778. * @param data data for serialization
  779. * @param error contain pointer to object for handle error code and message
  780. *
  781. * @return newly allocated vfs_path_t object
  782. */
  783. vfs_path_t *
  784. vfs_path_deserialize (const char *data, GError ** error)
  785. {
  786. mc_config_t *cpath = mc_deserialize_config (data, error);
  787. size_t element_index = 0;
  788. vfs_path_t *vpath;
  789. if (cpath == NULL)
  790. return NULL;
  791. vpath = vfs_path_new ();
  792. while (TRUE)
  793. {
  794. vfs_path_element_t *element;
  795. char *cfg_value;
  796. char *groupname;
  797. groupname = g_strdup_printf ("path-element-%zd", element_index);
  798. if (!mc_config_has_group (cpath, groupname))
  799. {
  800. g_free (groupname);
  801. break;
  802. }
  803. element = g_new0 (vfs_path_element_t, 1);
  804. element->dir.converter = INVALID_CONV;
  805. cfg_value = mc_config_get_string_raw (cpath, groupname, "class-name", NULL);
  806. element->class = vfs_get_class_by_name (cfg_value);
  807. if (element->class == NULL)
  808. {
  809. g_free (element);
  810. vfs_path_free (vpath);
  811. g_set_error (error, MC_ERROR, -1, "Unable to find VFS class by name '%s'", cfg_value);
  812. g_free (cfg_value);
  813. mc_config_deinit (cpath);
  814. return NULL;
  815. }
  816. g_free (cfg_value);
  817. element->path = mc_config_get_string_raw (cpath, groupname, "path", NULL);
  818. element->encoding = mc_config_get_string_raw (cpath, groupname, "encoding", NULL);
  819. element->vfs_prefix = mc_config_get_string_raw (cpath, groupname, "vfs_prefix", NULL);
  820. element->user = mc_config_get_string_raw (cpath, groupname, "user", NULL);
  821. element->password = mc_config_get_string_raw (cpath, groupname, "password", NULL);
  822. element->host = mc_config_get_string_raw (cpath, groupname, "host", NULL);
  823. element->port = mc_config_get_int (cpath, groupname, "port", 0);
  824. vpath->path = g_list_append (vpath->path, element);
  825. g_free (groupname);
  826. element_index++;
  827. }
  828. mc_config_deinit (cpath);
  829. if (vfs_path_elements_count (vpath) == 0)
  830. {
  831. vfs_path_free (vpath);
  832. g_set_error (error, MC_ERROR, -1, "No any path elements found");
  833. return NULL;
  834. }
  835. return vpath;
  836. }
  837. /* --------------------------------------------------------------------------------------------- */