vfs.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544
  1. /* Virtual File System switch code
  2. Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  3. 2007 Free Software Foundation, Inc.
  4. Written by: 1995 Miguel de Icaza
  5. 1995 Jakub Jelinek
  6. 1998 Pavel Machek
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public License
  9. as published by the Free Software Foundation; either version 2 of
  10. the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public
  16. License along with this program; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  18. /**
  19. * \file
  20. * \brief Source: Virtual File System switch code
  21. * \author Miguel de Icaza
  22. * \author Jakub Jelinek
  23. * \author Pavel Machek
  24. * \date 1995, 1998
  25. * \warning funtions like extfs_lstat() have right to destroy any
  26. * strings you pass to them. This is acutally ok as you g_strdup what
  27. * you are passing to them, anyway; still, beware.
  28. *
  29. * Namespace: exports *many* functions with vfs_ prefix; exports
  30. * parse_ls_lga and friends which do not have that prefix.
  31. */
  32. #include <config.h>
  33. #include <stdio.h>
  34. #include <stdlib.h> /* For atol() */
  35. #include <stdarg.h>
  36. #include <string.h>
  37. #include <errno.h>
  38. #include <sys/types.h>
  39. #include <signal.h>
  40. #include <ctype.h> /* is_digit() */
  41. #include <fcntl.h>
  42. #include <sys/stat.h>
  43. #include <unistd.h>
  44. #include <dirent.h>
  45. #include "lib/global.h"
  46. #include "lib/strutil.h"
  47. #include "lib/util.h"
  48. #include "lib/widget.h" /* message() */
  49. #ifdef HAVE_CHARSET
  50. #include "lib/charsets.h"
  51. #endif
  52. #include "src/setup.h" /* cd_symlinks */
  53. #include "vfs-impl.h"
  54. #include "utilvfs.h"
  55. #include "gc.h"
  56. #ifdef ENABLE_VFS_NET
  57. #include "netutil.h"
  58. #endif
  59. #ifdef ENABLE_VFS_FTP
  60. #include "ftpfs.h"
  61. #endif
  62. #ifdef ENABLE_VFS_SMB
  63. #include "smbfs.h"
  64. #endif
  65. #include "local.h"
  66. /*** global variables ****************************************************************************/
  67. /*** file scope macro definitions ****************************************************************/
  68. #if defined(_AIX) && !defined(NAME_MAX)
  69. #define NAME_MAX FILENAME_MAX
  70. #endif
  71. #define VFS_FIRST_HANDLE 100
  72. #define ISSLASH(a) (!a || (a == '/'))
  73. /*** file scope type declarations ****************************************************************/
  74. struct vfs_openfile
  75. {
  76. int handle;
  77. struct vfs_class *vclass;
  78. void *fsinfo;
  79. };
  80. struct vfs_dirinfo
  81. {
  82. DIR *info;
  83. GIConv converter;
  84. };
  85. /*** file scope variables ************************************************************************/
  86. /** They keep track of the current directory */
  87. static struct vfs_class *current_vfs;
  88. static char *current_dir;
  89. static GPtrArray *vfs_openfiles;
  90. static long vfs_free_handle_list = -1;
  91. static struct vfs_class *localfs_class;
  92. static GString *vfs_str_buffer;
  93. static struct vfs_class *vfs_list;
  94. static struct dirent *mc_readdir_result = NULL;
  95. static const struct
  96. {
  97. const char *name;
  98. size_t name_len;
  99. const char *substitute;
  100. } url_table[] =
  101. {
  102. /* *INDENT-OFF* */
  103. #ifdef ENABLE_VFS_FTP
  104. { "ftp://", 6, "/#ftp:" },
  105. #endif
  106. #ifdef ENABLE_VFS_FISH
  107. { "sh://", 5, "/#sh:" },
  108. { "ssh://", 6, "/#sh:" },
  109. #endif
  110. #ifdef ENABLE_VFS_SMB
  111. { "smb://", 6, "/#smb:" },
  112. #endif
  113. { "a:", 2, "/#a" }
  114. /* *INDENT-ON* */
  115. };
  116. /*** file scope functions ************************************************************************/
  117. /* --------------------------------------------------------------------------------------------- */
  118. /**
  119. * Create new VFS handle and put it to the list
  120. */
  121. static int
  122. vfs_new_handle (struct vfs_class *vclass, void *fsinfo)
  123. {
  124. struct vfs_openfile *h;
  125. h = g_new (struct vfs_openfile, 1);
  126. h->fsinfo = fsinfo;
  127. h->vclass = vclass;
  128. /* Allocate the first free handle */
  129. h->handle = vfs_free_handle_list;
  130. if (h->handle == -1)
  131. {
  132. /* No free allocated handles, allocate one */
  133. h->handle = vfs_openfiles->len;
  134. g_ptr_array_add (vfs_openfiles, h);
  135. }
  136. else
  137. {
  138. vfs_free_handle_list = (long) g_ptr_array_index (vfs_openfiles, vfs_free_handle_list);
  139. g_ptr_array_index (vfs_openfiles, h->handle) = h;
  140. }
  141. h->handle += VFS_FIRST_HANDLE;
  142. return h->handle;
  143. }
  144. /* --------------------------------------------------------------------------------------------- */
  145. /** Find VFS class by file handle */
  146. static struct vfs_class *
  147. vfs_op (int handle)
  148. {
  149. struct vfs_openfile *h;
  150. if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len)
  151. return NULL;
  152. h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE);
  153. if (!h)
  154. return NULL;
  155. g_assert (h->handle == handle);
  156. return h->vclass;
  157. }
  158. /* --------------------------------------------------------------------------------------------- */
  159. /** Find private file data by file handle */
  160. static void *
  161. vfs_info (int handle)
  162. {
  163. struct vfs_openfile *h;
  164. if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len)
  165. return NULL;
  166. h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE);
  167. if (!h)
  168. return NULL;
  169. g_assert (h->handle == handle);
  170. return h->fsinfo;
  171. }
  172. /* --------------------------------------------------------------------------------------------- */
  173. /** Free open file data for given file handle */
  174. static void
  175. vfs_free_handle (int handle)
  176. {
  177. const int idx = handle - VFS_FIRST_HANDLE;
  178. if (handle >= VFS_FIRST_HANDLE && (guint) idx < vfs_openfiles->len)
  179. {
  180. struct vfs_openfile *h;
  181. h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, idx);
  182. g_free (h);
  183. g_ptr_array_index (vfs_openfiles, idx) = (void *) vfs_free_handle_list;
  184. vfs_free_handle_list = idx;
  185. }
  186. }
  187. /* --------------------------------------------------------------------------------------------- */
  188. /** Return VFS class for the given prefix */
  189. static struct vfs_class *
  190. vfs_prefix_to_class (char *prefix)
  191. {
  192. struct vfs_class *vfs;
  193. /* Avoid last class (localfs) that would accept any prefix */
  194. for (vfs = vfs_list; vfs->next != NULL; vfs = vfs->next)
  195. {
  196. if (vfs->which != NULL)
  197. {
  198. if ((*vfs->which) (vfs, prefix) == -1)
  199. continue;
  200. return vfs;
  201. }
  202. if (vfs->prefix != NULL && strncmp (prefix, vfs->prefix, strlen (vfs->prefix)) == 0)
  203. return vfs;
  204. }
  205. return NULL;
  206. }
  207. /* --------------------------------------------------------------------------------------------- */
  208. static gboolean
  209. path_magic (const char *path)
  210. {
  211. struct stat buf;
  212. return (stat (path, &buf) != 0);
  213. }
  214. /* --------------------------------------------------------------------------------------------- */
  215. static struct vfs_class *
  216. _vfs_get_class (char *path)
  217. {
  218. char *semi;
  219. char *slash;
  220. struct vfs_class *ret;
  221. g_return_val_if_fail (path, NULL);
  222. semi = strrchr (path, '#');
  223. if (semi == NULL || !path_magic (path))
  224. return NULL;
  225. slash = strchr (semi, PATH_SEP);
  226. *semi = '\0';
  227. if (slash != NULL)
  228. *slash = '\0';
  229. ret = vfs_prefix_to_class (semi + 1);
  230. if (slash != NULL)
  231. *slash = PATH_SEP;
  232. if (ret == NULL)
  233. ret = _vfs_get_class (path);
  234. *semi = '#';
  235. return ret;
  236. }
  237. /* --------------------------------------------------------------------------------------------- */
  238. /* now used only by vfs_translate_path, but could be used in other vfs
  239. * plugin to automatic detect encoding
  240. * path - path to translate
  241. * size - how many bytes from path translate
  242. * defcnv - convertor, that is used as default, when path does not contain any
  243. * #enc: subtring
  244. * buffer - used to store result of translation
  245. */
  246. static estr_t
  247. _vfs_translate_path (const char *path, int size, GIConv defcnv, GString * buffer)
  248. {
  249. const char *semi;
  250. const char *slash;
  251. estr_t state = ESTR_SUCCESS;
  252. if (size == 0)
  253. return ESTR_SUCCESS;
  254. size = (size > 0) ? size : (signed int) strlen (path);
  255. /* try found /#enc: */
  256. semi = g_strrstr_len (path, size, PATH_SEP_STR VFS_ENCODING_PREFIX);
  257. if (semi != NULL)
  258. {
  259. char encoding[16];
  260. GIConv coder = INVALID_CONV;
  261. int ms;
  262. /* first must be translated part before /#enc: */
  263. ms = semi - path;
  264. state = _vfs_translate_path (path, ms, defcnv, buffer);
  265. if (state != ESTR_SUCCESS)
  266. return state;
  267. /* now can be translated part after #enc: */
  268. semi += strlen (VFS_ENCODING_PREFIX) + 1; /* skip "/#enc:" */
  269. slash = strchr (semi, PATH_SEP);
  270. /* ignore slashes after size; */
  271. if (slash - path >= size)
  272. slash = NULL;
  273. ms = (slash != NULL) ? slash - semi : (int) strlen (semi);
  274. ms = min ((unsigned int) ms, sizeof (encoding) - 1);
  275. /* limit encoding size (ms) to path size (size) */
  276. if (semi + ms > path + size)
  277. ms = path + size - semi;
  278. memcpy (encoding, semi, ms);
  279. encoding[ms] = '\0';
  280. #if HAVE_CHARSET
  281. if (is_supported_encoding (encoding))
  282. coder = str_crt_conv_to (encoding);
  283. #endif
  284. if (coder != INVALID_CONV)
  285. {
  286. if (slash != NULL)
  287. state = str_vfs_convert_to (coder, slash, path + size - slash, buffer);
  288. else if (buffer->len == 0)
  289. g_string_append_c (buffer, PATH_SEP);
  290. str_close_conv (coder);
  291. return state;
  292. }
  293. errno = EINVAL;
  294. state = ESTR_FAILURE;
  295. }
  296. else
  297. {
  298. /* path can be translated whole at once */
  299. state = str_vfs_convert_to (defcnv, path, size, buffer);
  300. }
  301. return state;
  302. }
  303. /* --------------------------------------------------------------------------------------------- */
  304. static int
  305. ferrno (struct vfs_class *vfs)
  306. {
  307. return vfs->ferrno ? (*vfs->ferrno) (vfs) : E_UNKNOWN;
  308. /* Hope that error message is obscure enough ;-) */
  309. }
  310. /* --------------------------------------------------------------------------------------------- */
  311. /**
  312. * Return current directory. If it's local, reread the current directory
  313. * from the OS. You must g_strdup() whatever this function returns.
  314. */
  315. static const char *
  316. _vfs_get_cwd (void)
  317. {
  318. char *trans;
  319. trans = vfs_translate_path_n (current_dir);
  320. if (_vfs_get_class (trans) == NULL)
  321. {
  322. const char *encoding = vfs_get_encoding (current_dir);
  323. if (encoding == NULL)
  324. {
  325. char *tmp;
  326. tmp = g_get_current_dir ();
  327. if (tmp != NULL)
  328. { /* One of the directories in the path is not readable */
  329. estr_t state;
  330. char *sys_cwd;
  331. g_string_set_size (vfs_str_buffer, 0);
  332. state = str_vfs_convert_from (str_cnv_from_term, tmp, vfs_str_buffer);
  333. g_free (tmp);
  334. sys_cwd = (state == ESTR_SUCCESS) ? g_strdup (vfs_str_buffer->str) : NULL;
  335. if (sys_cwd != NULL)
  336. {
  337. struct stat my_stat, my_stat2;
  338. /* Check if it is O.K. to use the current_dir */
  339. if (cd_symlinks
  340. && mc_stat (sys_cwd, &my_stat) == 0
  341. && mc_stat (current_dir, &my_stat2) == 0
  342. && my_stat.st_ino == my_stat2.st_ino && my_stat.st_dev == my_stat2.st_dev)
  343. g_free (sys_cwd);
  344. else
  345. {
  346. g_free (current_dir);
  347. current_dir = sys_cwd;
  348. }
  349. }
  350. }
  351. }
  352. }
  353. g_free (trans);
  354. return current_dir;
  355. }
  356. /* --------------------------------------------------------------------------------------------- */
  357. static void
  358. vfs_setup_wd (void)
  359. {
  360. current_dir = g_strdup (PATH_SEP_STR);
  361. _vfs_get_cwd ();
  362. if (strlen (current_dir) > MC_MAXPATHLEN - 2)
  363. vfs_die ("Current dir too long.\n");
  364. current_vfs = vfs_get_class (current_dir);
  365. }
  366. /* --------------------------------------------------------------------------------------------- */
  367. static char *
  368. mc_def_getlocalcopy (const char *filename)
  369. {
  370. char *tmp;
  371. int fdin, fdout;
  372. ssize_t i;
  373. char buffer[8192];
  374. struct stat mystat;
  375. fdin = mc_open (filename, O_RDONLY | O_LINEAR);
  376. if (fdin == -1)
  377. return NULL;
  378. fdout = vfs_mkstemps (&tmp, "vfs", filename);
  379. if (fdout == -1)
  380. goto fail;
  381. while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0)
  382. {
  383. if (write (fdout, buffer, i) != i)
  384. goto fail;
  385. }
  386. if (i == -1)
  387. goto fail;
  388. i = mc_close (fdin);
  389. fdin = -1;
  390. if (i == -1)
  391. goto fail;
  392. if (close (fdout) == -1)
  393. {
  394. fdout = -1;
  395. goto fail;
  396. }
  397. if (mc_stat (filename, &mystat) != -1)
  398. chmod (tmp, mystat.st_mode);
  399. return tmp;
  400. fail:
  401. if (fdout != -1)
  402. close (fdout);
  403. if (fdin != -1)
  404. mc_close (fdin);
  405. g_free (tmp);
  406. return NULL;
  407. }
  408. /* --------------------------------------------------------------------------------------------- */
  409. static int
  410. mc_def_ungetlocalcopy (struct vfs_class *vfs, const char *filename,
  411. const char *local, int has_changed)
  412. {
  413. int fdin = -1, fdout = -1;
  414. if (has_changed)
  415. {
  416. char buffer[8192];
  417. ssize_t i;
  418. if (!vfs->write)
  419. goto failed;
  420. fdin = open (local, O_RDONLY);
  421. if (fdin == -1)
  422. goto failed;
  423. fdout = mc_open (filename, O_WRONLY | O_TRUNC);
  424. if (fdout == -1)
  425. goto failed;
  426. while ((i = read (fdin, buffer, sizeof (buffer))) > 0)
  427. if (mc_write (fdout, buffer, (size_t) i) != i)
  428. goto failed;
  429. if (i == -1)
  430. goto failed;
  431. if (close (fdin) == -1)
  432. {
  433. fdin = -1;
  434. goto failed;
  435. }
  436. fdin = -1;
  437. if (mc_close (fdout) == -1)
  438. {
  439. fdout = -1;
  440. goto failed;
  441. }
  442. }
  443. unlink (local);
  444. return 0;
  445. failed:
  446. message (D_ERROR, _("Changes to file lost"), "%s", filename);
  447. if (fdout != -1)
  448. mc_close (fdout);
  449. if (fdin != -1)
  450. close (fdin);
  451. unlink (local);
  452. return -1;
  453. }
  454. /* --------------------------------------------------------------------------------------------- */
  455. /*** public functions ****************************************************************************/
  456. /* --------------------------------------------------------------------------------------------- */
  457. int
  458. vfs_register_class (struct vfs_class *vfs)
  459. {
  460. if (vfs->init != NULL) /* vfs has own initialization function */
  461. if (!(*vfs->init) (vfs)) /* but it failed */
  462. return 0;
  463. vfs->next = vfs_list;
  464. vfs_list = vfs;
  465. return 1;
  466. }
  467. /* --------------------------------------------------------------------------------------------- */
  468. /** Strip known vfs suffixes from a filename (possible improvement: strip
  469. * suffix from last path component).
  470. * \return a malloced string which has to be freed.
  471. */
  472. char *
  473. vfs_strip_suffix_from_filename (const char *filename)
  474. {
  475. struct vfs_class *vfs;
  476. char *semi;
  477. char *p;
  478. if (filename == NULL)
  479. vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
  480. p = g_strdup (filename);
  481. semi = strrchr (p, '#');
  482. if (semi == NULL)
  483. return p;
  484. /* Avoid last class (localfs) that would accept any prefix */
  485. for (vfs = vfs_list; vfs->next != NULL; vfs = vfs->next)
  486. {
  487. if (vfs->which != NULL)
  488. {
  489. if ((*vfs->which) (vfs, semi + 1) == -1)
  490. continue;
  491. *semi = '\0'; /* Found valid suffix */
  492. return p;
  493. }
  494. if (vfs->prefix != NULL && strncmp (semi + 1, vfs->prefix, strlen (vfs->prefix)) == 0)
  495. {
  496. *semi = '\0'; /* Found valid suffix */
  497. return p;
  498. }
  499. }
  500. return p;
  501. }
  502. /* --------------------------------------------------------------------------------------------- */
  503. /**
  504. * Splits path extracting vfs part.
  505. *
  506. * Splits path
  507. * \verbatim /p1#op/inpath \endverbatim
  508. * into
  509. * \verbatim inpath,op; \endverbatim
  510. * returns which vfs it is.
  511. * What is left in path is p1. You still want to g_free(path), you DON'T
  512. * want to free neither *inpath nor *op
  513. */
  514. struct vfs_class *
  515. vfs_split (char *path, char **inpath, char **op)
  516. {
  517. char *semi;
  518. char *slash;
  519. struct vfs_class *ret;
  520. if (path == NULL)
  521. vfs_die ("Cannot split NULL");
  522. semi = strrchr (path, '#');
  523. if (semi == NULL || !path_magic (path))
  524. return NULL;
  525. slash = strchr (semi, PATH_SEP);
  526. *semi = '\0';
  527. if (op != NULL)
  528. *op = NULL;
  529. if (inpath != NULL)
  530. *inpath = NULL;
  531. if (slash != NULL)
  532. *slash = '\0';
  533. ret = vfs_prefix_to_class (semi + 1);
  534. if (ret != NULL)
  535. {
  536. if (op != NULL)
  537. *op = semi + 1;
  538. if (inpath != NULL)
  539. *inpath = slash != NULL ? slash + 1 : NULL;
  540. return ret;
  541. }
  542. if (slash != NULL)
  543. *slash = PATH_SEP;
  544. ret = vfs_split (path, inpath, op);
  545. *semi = '#';
  546. return ret;
  547. }
  548. /* --------------------------------------------------------------------------------------------- */
  549. struct vfs_class *
  550. vfs_get_class (const char *pathname)
  551. {
  552. struct vfs_class *vfs;
  553. char *path = g_strdup (pathname);
  554. vfs = _vfs_get_class (path);
  555. g_free (path);
  556. if (!vfs)
  557. vfs = localfs_class;
  558. return vfs;
  559. }
  560. /* --------------------------------------------------------------------------------------------- */
  561. const char *
  562. vfs_get_encoding (const char *path)
  563. {
  564. static char result[16];
  565. char *work;
  566. char *semi;
  567. char *slash;
  568. work = g_strdup (path);
  569. /* try found /#enc: */
  570. semi = g_strrstr (work, PATH_SEP_STR VFS_ENCODING_PREFIX);
  571. if (semi != NULL)
  572. {
  573. semi += strlen (VFS_ENCODING_PREFIX) + 1; /* skip "/#enc:" */
  574. slash = strchr (semi, PATH_SEP);
  575. if (slash != NULL)
  576. slash[0] = '\0';
  577. g_strlcpy (result, semi, sizeof (result));
  578. g_free (work);
  579. return result;
  580. }
  581. else
  582. {
  583. g_free (work);
  584. return NULL;
  585. }
  586. }
  587. /* --------------------------------------------------------------------------------------------- */
  588. char *
  589. vfs_translate_path (const char *path)
  590. {
  591. estr_t state;
  592. g_string_set_size (vfs_str_buffer, 0);
  593. state = _vfs_translate_path (path, -1, str_cnv_from_term, vfs_str_buffer);
  594. /*
  595. strict version
  596. return (state == 0) ? vfs_str_buffer->data : NULL;
  597. */
  598. return (state != ESTR_FAILURE) ? vfs_str_buffer->str : NULL;
  599. }
  600. /* --------------------------------------------------------------------------------------------- */
  601. char *
  602. vfs_translate_path_n (const char *path)
  603. {
  604. char *result;
  605. result = vfs_translate_path (path);
  606. return (result != NULL) ? g_strdup (result) : NULL;
  607. }
  608. /* --------------------------------------------------------------------------------------------- */
  609. char *
  610. vfs_canon_and_translate (const char *path)
  611. {
  612. char *canon;
  613. char *result;
  614. if (path == NULL)
  615. canon = g_strdup ("");
  616. else
  617. canon = vfs_canon (path);
  618. result = vfs_translate_path_n (canon);
  619. g_free (canon);
  620. return result;
  621. }
  622. /* --------------------------------------------------------------------------------------------- */
  623. int
  624. mc_open (const char *filename, int flags, ...)
  625. {
  626. int mode = 0;
  627. void *info;
  628. va_list ap;
  629. char *file;
  630. struct vfs_class *vfs;
  631. file = vfs_canon_and_translate (filename);
  632. if (file == NULL)
  633. return -1;
  634. vfs = vfs_get_class (file);
  635. /* Get the mode flag */
  636. if (flags & O_CREAT)
  637. {
  638. va_start (ap, flags);
  639. mode = va_arg (ap, int);
  640. va_end (ap);
  641. }
  642. if (vfs->open == NULL)
  643. {
  644. g_free (file);
  645. errno = -EOPNOTSUPP;
  646. return -1;
  647. }
  648. info = vfs->open (vfs, file, flags, mode); /* open must be supported */
  649. g_free (file);
  650. if (info == NULL)
  651. {
  652. errno = ferrno (vfs);
  653. return -1;
  654. }
  655. return vfs_new_handle (vfs, info);
  656. }
  657. /* --------------------------------------------------------------------------------------------- */
  658. /* *INDENT-OFF* */
  659. #define MC_NAMEOP(name, inarg, callarg) \
  660. int mc_##name inarg \
  661. { \
  662. struct vfs_class *vfs; \
  663. int result; \
  664. char *mpath; \
  665. mpath = vfs_canon_and_translate (path); \
  666. if (mpath == NULL) \
  667. return -1; \
  668. vfs = vfs_get_class (mpath); \
  669. if (vfs == NULL) \
  670. { \
  671. g_free (mpath); \
  672. return -1; \
  673. } \
  674. result = vfs->name != NULL ? vfs->name callarg : -1; \
  675. g_free (mpath); \
  676. if (result == -1) \
  677. errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
  678. return result; \
  679. }
  680. MC_NAMEOP (chmod, (const char *path, mode_t mode), (vfs, mpath, mode))
  681. MC_NAMEOP (chown, (const char *path, uid_t owner, gid_t group), (vfs, mpath, owner, group))
  682. MC_NAMEOP (utime, (const char *path, struct utimbuf * times), (vfs, mpath, times))
  683. MC_NAMEOP (readlink, (const char *path, char *buf, size_t bufsiz), (vfs, mpath, buf, bufsiz))
  684. MC_NAMEOP (unlink, (const char *path), (vfs, mpath))
  685. MC_NAMEOP (mkdir, (const char *path, mode_t mode), (vfs, mpath, mode))
  686. MC_NAMEOP (rmdir, (const char *path), (vfs, mpath))
  687. MC_NAMEOP (mknod, (const char *path, mode_t mode, dev_t dev), (vfs, mpath, mode, dev))
  688. /* *INDENT-ON* */
  689. /* --------------------------------------------------------------------------------------------- */
  690. int
  691. mc_symlink (const char *name1, const char *path)
  692. {
  693. struct vfs_class *vfs;
  694. int result;
  695. char *mpath;
  696. char *lpath;
  697. char *tmp;
  698. mpath = vfs_canon_and_translate (path);
  699. if (mpath == NULL)
  700. return -1;
  701. tmp = g_strdup (name1);
  702. lpath = vfs_translate_path_n (tmp);
  703. g_free (tmp);
  704. if (lpath != NULL)
  705. {
  706. vfs = vfs_get_class (mpath);
  707. result = vfs->symlink != NULL ? vfs->symlink (vfs, lpath, mpath) : -1;
  708. g_free (lpath);
  709. g_free (mpath);
  710. if (result == -1)
  711. errno = vfs->symlink != NULL ? ferrno (vfs) : E_NOTSUPP;
  712. return result;
  713. }
  714. g_free (mpath);
  715. return -1;
  716. }
  717. /* --------------------------------------------------------------------------------------------- */
  718. /* *INDENT-OFF* */
  719. #define MC_HANDLEOP(name, inarg, callarg) \
  720. ssize_t mc_##name inarg \
  721. { \
  722. struct vfs_class *vfs; \
  723. int result; \
  724. if (handle == -1) \
  725. return -1; \
  726. vfs = vfs_op (handle); \
  727. if (vfs == NULL) \
  728. return -1; \
  729. result = vfs->name != NULL ? vfs->name callarg : -1; \
  730. if (result == -1) \
  731. errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
  732. return result; \
  733. }
  734. MC_HANDLEOP (read, (int handle, void *buffer, size_t count), (vfs_info (handle), buffer, count))
  735. MC_HANDLEOP (write, (int handle, const void *buf, size_t nbyte), (vfs_info (handle), buf, nbyte))
  736. /* --------------------------------------------------------------------------------------------- */
  737. #define MC_RENAMEOP(name) \
  738. int mc_##name (const char *fname1, const char *fname2) \
  739. { \
  740. struct vfs_class *vfs; \
  741. int result; \
  742. char *name2, *name1; \
  743. name1 = vfs_canon_and_translate (fname1); \
  744. if (name1 == NULL) \
  745. return -1; \
  746. name2 = vfs_canon_and_translate (fname2); \
  747. if (name2 == NULL) { \
  748. g_free (name1); \
  749. return -1; \
  750. } \
  751. vfs = vfs_get_class (name1); \
  752. if (vfs != vfs_get_class (name2)) \
  753. { \
  754. errno = EXDEV; \
  755. g_free (name1); \
  756. g_free (name2); \
  757. return -1; \
  758. } \
  759. result = vfs->name != NULL ? vfs->name (vfs, name1, name2) : -1; \
  760. g_free (name1); \
  761. g_free (name2); \
  762. if (result == -1) \
  763. errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \
  764. return result; \
  765. }
  766. MC_RENAMEOP (link)
  767. MC_RENAMEOP (rename)
  768. /* *INDENT-ON* */
  769. /* --------------------------------------------------------------------------------------------- */
  770. int
  771. mc_ctl (int handle, int ctlop, void *arg)
  772. {
  773. struct vfs_class *vfs = vfs_op (handle);
  774. if (vfs == NULL)
  775. return 0;
  776. return vfs->ctl ? (*vfs->ctl) (vfs_info (handle), ctlop, arg) : 0;
  777. }
  778. /* --------------------------------------------------------------------------------------------- */
  779. int
  780. mc_setctl (const char *path, int ctlop, void *arg)
  781. {
  782. struct vfs_class *vfs;
  783. int result = -1;
  784. char *mpath;
  785. if (path == NULL)
  786. vfs_die ("You don't want to pass NULL to mc_setctl.");
  787. mpath = vfs_canon_and_translate (path);
  788. if (mpath != NULL)
  789. {
  790. vfs = vfs_get_class (mpath);
  791. result = vfs->setctl != NULL ? vfs->setctl (vfs, mpath, ctlop, arg) : 0;
  792. g_free (mpath);
  793. }
  794. return result;
  795. }
  796. /* --------------------------------------------------------------------------------------------- */
  797. int
  798. mc_close (int handle)
  799. {
  800. struct vfs_class *vfs;
  801. int result;
  802. if (handle == -1 || !vfs_info (handle))
  803. return -1;
  804. vfs = vfs_op (handle);
  805. if (vfs == NULL)
  806. return -1;
  807. if (handle < 3)
  808. return close (handle);
  809. if (!vfs->close)
  810. vfs_die ("VFS must support close.\n");
  811. result = (*vfs->close) (vfs_info (handle));
  812. vfs_free_handle (handle);
  813. if (result == -1)
  814. errno = ferrno (vfs);
  815. return result;
  816. }
  817. /* --------------------------------------------------------------------------------------------- */
  818. DIR *
  819. mc_opendir (const char *dirname)
  820. {
  821. int handle, *handlep;
  822. void *info;
  823. struct vfs_class *vfs;
  824. char *canon;
  825. char *dname;
  826. struct vfs_dirinfo *dirinfo;
  827. const char *encoding;
  828. canon = vfs_canon (dirname);
  829. dname = vfs_translate_path_n (canon);
  830. if (dname != NULL)
  831. {
  832. vfs = vfs_get_class (dname);
  833. info = vfs->opendir ? (*vfs->opendir) (vfs, dname) : NULL;
  834. g_free (dname);
  835. if (info == NULL)
  836. {
  837. errno = vfs->opendir ? ferrno (vfs) : E_NOTSUPP;
  838. g_free (canon);
  839. return NULL;
  840. }
  841. dirinfo = g_new (struct vfs_dirinfo, 1);
  842. dirinfo->info = info;
  843. encoding = vfs_get_encoding (canon);
  844. g_free (canon);
  845. dirinfo->converter = (encoding != NULL) ? str_crt_conv_from (encoding) : str_cnv_from_term;
  846. if (dirinfo->converter == INVALID_CONV)
  847. dirinfo->converter = str_cnv_from_term;
  848. handle = vfs_new_handle (vfs, dirinfo);
  849. handlep = g_new (int, 1);
  850. *handlep = handle;
  851. return (DIR *) handlep;
  852. }
  853. else
  854. {
  855. g_free (canon);
  856. return NULL;
  857. }
  858. }
  859. /* --------------------------------------------------------------------------------------------- */
  860. struct dirent *
  861. mc_readdir (DIR * dirp)
  862. {
  863. int handle;
  864. struct vfs_class *vfs;
  865. struct dirent *entry = NULL;
  866. struct vfs_dirinfo *dirinfo;
  867. estr_t state;
  868. if (!mc_readdir_result)
  869. {
  870. /* We can't just allocate struct dirent as (see man dirent.h)
  871. * struct dirent has VERY nonnaive semantics of allocating
  872. * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
  873. * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
  874. * heap corrupter. So, allocate longliving dirent with at least
  875. * (MAXNAMLEN + 1) for d_name in it.
  876. * Strictly saying resulting dirent is unusable as we don't adjust internal
  877. * structures, holding dirent size. But we don't use it in libc infrastructure.
  878. * TODO: to make simpler homemade dirent-alike structure.
  879. */
  880. mc_readdir_result = (struct dirent *) g_malloc (sizeof (struct dirent) + MAXNAMLEN + 1);
  881. }
  882. if (!dirp)
  883. {
  884. errno = EFAULT;
  885. return NULL;
  886. }
  887. handle = *(int *) dirp;
  888. vfs = vfs_op (handle);
  889. if (vfs == NULL)
  890. return NULL;
  891. dirinfo = vfs_info (handle);
  892. if (vfs->readdir)
  893. {
  894. entry = (*vfs->readdir) (dirinfo->info);
  895. if (entry == NULL)
  896. return NULL;
  897. g_string_set_size (vfs_str_buffer, 0);
  898. state = str_vfs_convert_from (dirinfo->converter, entry->d_name, vfs_str_buffer);
  899. mc_readdir_result->d_ino = entry->d_ino;
  900. g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, MAXNAMLEN + 1);
  901. }
  902. if (entry == NULL)
  903. errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP;
  904. return (entry != NULL) ? mc_readdir_result : NULL;
  905. }
  906. /* --------------------------------------------------------------------------------------------- */
  907. int
  908. mc_closedir (DIR * dirp)
  909. {
  910. int handle = *(int *) dirp;
  911. struct vfs_class *vfs;
  912. int result = -1;
  913. vfs = vfs_op (handle);
  914. if (vfs != NULL)
  915. {
  916. struct vfs_dirinfo *dirinfo;
  917. dirinfo = vfs_info (handle);
  918. if (dirinfo->converter != str_cnv_from_term)
  919. str_close_conv (dirinfo->converter);
  920. result = vfs->closedir ? (*vfs->closedir) (dirinfo->info) : -1;
  921. vfs_free_handle (handle);
  922. g_free (dirinfo);
  923. }
  924. g_free (dirp);
  925. return result;
  926. }
  927. /* --------------------------------------------------------------------------------------------- */
  928. int
  929. mc_stat (const char *filename, struct stat *buf)
  930. {
  931. struct vfs_class *vfs;
  932. int result;
  933. char *path;
  934. path = vfs_canon_and_translate (filename);
  935. if (path == NULL)
  936. return -1;
  937. vfs = vfs_get_class (path);
  938. if (vfs == NULL)
  939. {
  940. g_free (path);
  941. return -1;
  942. }
  943. result = vfs->stat ? (*vfs->stat) (vfs, path, buf) : -1;
  944. g_free (path);
  945. if (result == -1)
  946. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  947. return result;
  948. }
  949. /* --------------------------------------------------------------------------------------------- */
  950. int
  951. mc_lstat (const char *filename, struct stat *buf)
  952. {
  953. struct vfs_class *vfs;
  954. int result;
  955. char *path;
  956. path = vfs_canon_and_translate (filename);
  957. if (path == NULL)
  958. return -1;
  959. vfs = vfs_get_class (path);
  960. if (vfs == NULL)
  961. {
  962. g_free (path);
  963. return -1;
  964. }
  965. result = vfs->lstat ? (*vfs->lstat) (vfs, path, buf) : -1;
  966. g_free (path);
  967. if (result == -1)
  968. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  969. return result;
  970. }
  971. /* --------------------------------------------------------------------------------------------- */
  972. int
  973. mc_fstat (int handle, struct stat *buf)
  974. {
  975. struct vfs_class *vfs;
  976. int result;
  977. if (handle == -1)
  978. return -1;
  979. vfs = vfs_op (handle);
  980. if (vfs == NULL)
  981. return -1;
  982. result = vfs->fstat ? (*vfs->fstat) (vfs_info (handle), buf) : -1;
  983. if (result == -1)
  984. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  985. return result;
  986. }
  987. /* --------------------------------------------------------------------------------------------- */
  988. /**
  989. * Return current directory. If it's local, reread the current directory
  990. * from the OS. Put directory to the provided buffer.
  991. */
  992. char *
  993. mc_get_current_wd (char *buffer, size_t size)
  994. {
  995. const char *cwd = _vfs_get_cwd ();
  996. g_strlcpy (buffer, cwd, size);
  997. return buffer;
  998. }
  999. /* --------------------------------------------------------------------------------------------- */
  1000. /**
  1001. * Return current directory without any OS calls.
  1002. */
  1003. char *
  1004. vfs_get_current_dir (void)
  1005. {
  1006. return current_dir;
  1007. }
  1008. /* --------------------------------------------------------------------------------------------- */
  1009. off_t
  1010. mc_lseek (int fd, off_t offset, int whence)
  1011. {
  1012. struct vfs_class *vfs;
  1013. off_t result;
  1014. if (fd == -1)
  1015. return -1;
  1016. vfs = vfs_op (fd);
  1017. if (vfs == NULL)
  1018. return -1;
  1019. result = vfs->lseek ? (*vfs->lseek) (vfs_info (fd), offset, whence) : -1;
  1020. if (result == -1)
  1021. errno = vfs->lseek ? ferrno (vfs) : E_NOTSUPP;
  1022. return result;
  1023. }
  1024. /* --------------------------------------------------------------------------------------------- */
  1025. /**
  1026. * remove //, /./ and /../
  1027. */
  1028. char *
  1029. vfs_canon (const char *path)
  1030. {
  1031. if (!path)
  1032. vfs_die ("Cannot canonicalize NULL");
  1033. /* Relative to current directory */
  1034. if (*path != PATH_SEP)
  1035. {
  1036. char *local, *result;
  1037. local = g_build_filename (current_dir, path, NULL);
  1038. result = vfs_canon (local);
  1039. g_free (local);
  1040. return result;
  1041. }
  1042. /*
  1043. * So we have path of following form:
  1044. * /p1/p2#op/.././././p3#op/p4. Good luck.
  1045. */
  1046. {
  1047. char *result = g_strdup (path);
  1048. canonicalize_pathname (result);
  1049. return result;
  1050. }
  1051. }
  1052. /* --------------------------------------------------------------------------------------------- */
  1053. /**
  1054. * VFS chdir.
  1055. * Return 0 on success, -1 on failure.
  1056. */
  1057. int
  1058. mc_chdir (const char *path)
  1059. {
  1060. char *new_dir;
  1061. char *trans_dir;
  1062. struct vfs_class *old_vfs, *new_vfs;
  1063. vfsid old_vfsid;
  1064. int result;
  1065. new_dir = vfs_canon (path);
  1066. trans_dir = vfs_translate_path_n (new_dir);
  1067. if (trans_dir != NULL)
  1068. {
  1069. new_vfs = vfs_get_class (trans_dir);
  1070. if (!new_vfs->chdir)
  1071. {
  1072. g_free (new_dir);
  1073. g_free (trans_dir);
  1074. return -1;
  1075. }
  1076. result = (*new_vfs->chdir) (new_vfs, trans_dir);
  1077. if (result == -1)
  1078. {
  1079. errno = ferrno (new_vfs);
  1080. g_free (new_dir);
  1081. g_free (trans_dir);
  1082. return -1;
  1083. }
  1084. old_vfsid = vfs_getid (current_vfs, current_dir);
  1085. old_vfs = current_vfs;
  1086. /* Actually change directory */
  1087. g_free (current_dir);
  1088. current_dir = new_dir;
  1089. current_vfs = new_vfs;
  1090. /* This function uses the new current_dir implicitly */
  1091. vfs_stamp_create (old_vfs, old_vfsid);
  1092. /* Sometimes we assume no trailing slash on cwd */
  1093. if (*current_dir)
  1094. {
  1095. char *p;
  1096. p = strchr (current_dir, 0) - 1;
  1097. if (*p == PATH_SEP && p > current_dir)
  1098. *p = 0;
  1099. }
  1100. g_free (trans_dir);
  1101. return 0;
  1102. }
  1103. else
  1104. {
  1105. g_free (new_dir);
  1106. return -1;
  1107. }
  1108. }
  1109. /* --------------------------------------------------------------------------------------------- */
  1110. /* Return TRUE is the current VFS class is local */
  1111. gboolean
  1112. vfs_current_is_local (void)
  1113. {
  1114. return (current_vfs->flags & VFSF_LOCAL) != 0;
  1115. }
  1116. /* --------------------------------------------------------------------------------------------- */
  1117. /* Return flags of the VFS class of the given filename */
  1118. vfs_class_flags_t
  1119. vfs_file_class_flags (const char *filename)
  1120. {
  1121. struct vfs_class *vfs;
  1122. char *fname;
  1123. fname = vfs_canon_and_translate (filename);
  1124. if (fname == NULL)
  1125. return VFSF_UNKNOWN;
  1126. vfs = vfs_get_class (fname);
  1127. g_free (fname);
  1128. return vfs->flags;
  1129. }
  1130. /* --------------------------------------------------------------------------------------------- */
  1131. char *
  1132. mc_getlocalcopy (const char *pathname)
  1133. {
  1134. char *result = NULL;
  1135. char *path;
  1136. path = vfs_canon_and_translate (pathname);
  1137. if (path != NULL)
  1138. {
  1139. struct vfs_class *vfs = vfs_get_class (path);
  1140. result = vfs->getlocalcopy != NULL ?
  1141. vfs->getlocalcopy (vfs, path) : mc_def_getlocalcopy (path);
  1142. g_free (path);
  1143. if (result == NULL)
  1144. errno = ferrno (vfs);
  1145. }
  1146. return result;
  1147. }
  1148. /* --------------------------------------------------------------------------------------------- */
  1149. int
  1150. mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed)
  1151. {
  1152. int return_value = -1;
  1153. char *path;
  1154. path = vfs_canon_and_translate (pathname);
  1155. if (path != NULL)
  1156. {
  1157. struct vfs_class *vfs = vfs_get_class (path);
  1158. return_value = vfs->ungetlocalcopy != NULL ?
  1159. vfs->ungetlocalcopy (vfs, path, local, has_changed) :
  1160. mc_def_ungetlocalcopy (vfs, path, local, has_changed);
  1161. g_free (path);
  1162. }
  1163. return return_value;
  1164. }
  1165. /* --------------------------------------------------------------------------------------------- */
  1166. void
  1167. vfs_init (void)
  1168. {
  1169. /* create the VFS handle array */
  1170. vfs_openfiles = g_ptr_array_new ();
  1171. vfs_str_buffer = g_string_new ("");
  1172. /* localfs needs to be the first one */
  1173. init_localfs ();
  1174. /* fallback value for vfs_get_class() */
  1175. localfs_class = vfs_list;
  1176. #ifdef ENABLE_VFS_CPIO
  1177. init_cpiofs ();
  1178. #endif /* ENABLE_VFS_CPIO */
  1179. #ifdef ENABLE_VFS_TAR
  1180. init_tarfs ();
  1181. #endif /* ENABLE_VFS_TAR */
  1182. #ifdef ENABLE_VFS_SFS
  1183. init_sfs ();
  1184. #endif /* ENABLE_VFS_SFS */
  1185. #ifdef ENABLE_VFS_EXTFS
  1186. init_extfs ();
  1187. #endif /* ENABLE_VFS_EXTFS */
  1188. #ifdef ENABLE_VFS_UNDELFS
  1189. init_undelfs ();
  1190. #endif /* ENABLE_VFS_UNDELFS */
  1191. #ifdef ENABLE_VFS_FTP
  1192. init_ftpfs ();
  1193. #endif /* ENABLE_VFS_FTP */
  1194. #ifdef ENABLE_VFS_FISH
  1195. init_fish ();
  1196. #endif /* ENABLE_VFS_FISH */
  1197. #ifdef ENABLE_VFS_SMB
  1198. init_smbfs ();
  1199. #endif /* ENABLE_VFS_SMB */
  1200. vfs_setup_wd ();
  1201. }
  1202. /* --------------------------------------------------------------------------------------------- */
  1203. void
  1204. vfs_shut (void)
  1205. {
  1206. struct vfs_class *vfs;
  1207. vfs_gc_done ();
  1208. g_free (current_dir);
  1209. for (vfs = vfs_list; vfs; vfs = vfs->next)
  1210. if (vfs->done)
  1211. (*vfs->done) (vfs);
  1212. g_ptr_array_free (vfs_openfiles, TRUE);
  1213. g_string_free (vfs_str_buffer, TRUE);
  1214. g_free (mc_readdir_result);
  1215. }
  1216. /* --------------------------------------------------------------------------------------------- */
  1217. /**
  1218. * These ones grab information from the VFS
  1219. * and handles them to an upper layer
  1220. */
  1221. void
  1222. vfs_fill_names (fill_names_f func)
  1223. {
  1224. struct vfs_class *vfs;
  1225. for (vfs = vfs_list; vfs; vfs = vfs->next)
  1226. if (vfs->fill_names)
  1227. (*vfs->fill_names) (vfs, func);
  1228. }
  1229. /* --------------------------------------------------------------------------------------------- */
  1230. /**
  1231. * Returns vfs path corresponding to given url. If passed string is
  1232. * not recognized as url, g_strdup(url) is returned.
  1233. */
  1234. char *
  1235. vfs_translate_url (const char *url)
  1236. {
  1237. size_t i;
  1238. for (i = 0; i < sizeof (url_table) / sizeof (url_table[0]); i++)
  1239. if (strncmp (url, url_table[i].name, url_table[i].name_len) == 0)
  1240. return g_strconcat (url_table[i].substitute, url + url_table[i].name_len,
  1241. (char *) NULL);
  1242. return g_strdup (url);
  1243. }
  1244. /* --------------------------------------------------------------------------------------------- */
  1245. gboolean
  1246. vfs_file_is_local (const char *filename)
  1247. {
  1248. return (vfs_file_class_flags (filename) & VFSF_LOCAL) != 0;
  1249. }
  1250. /* --------------------------------------------------------------------------------------------- */