vfs.c 31 KB

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