vfs.c 33 KB

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