vfs.c 33 KB

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