vfs.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  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. /* Warning: funtions like extfs_lstat() have right to destroy any
  19. * strings you pass to them. This is acutally ok as you g_strdup what
  20. * you are passing to them, anyway; still, beware. */
  21. /* Namespace: exports *many* functions with vfs_ prefix; exports
  22. parse_ls_lga and friends which do not have that prefix. */
  23. #include <config.h>
  24. #include <stdio.h>
  25. #include <stdlib.h> /* For atol() */
  26. #include <stdarg.h>
  27. #include <string.h>
  28. #include <errno.h>
  29. #include <sys/types.h>
  30. #include <signal.h>
  31. #include <ctype.h> /* is_digit() */
  32. #include "../src/global.h"
  33. #include "../src/tty.h" /* enable/disable interrupt key */
  34. #include "../src/wtools.h" /* message() */
  35. #include "../src/main.h" /* print_vfs_message */
  36. #include "utilvfs.h"
  37. #include "gc.h"
  38. #include "vfs.h"
  39. #ifdef USE_NETCODE
  40. # include "tcputil.h"
  41. #endif
  42. #include "ftpfs.h"
  43. #include "mcfs.h"
  44. #include "smbfs.h"
  45. #include "local.h"
  46. /* They keep track of the current directory */
  47. static struct vfs_class *current_vfs;
  48. static char *current_dir;
  49. struct vfs_openfile {
  50. int handle;
  51. struct vfs_class *vclass;
  52. void *fsinfo;
  53. };
  54. static GSList *vfs_openfiles;
  55. #define VFS_FIRST_HANDLE 100
  56. static struct vfs_class *localfs_class;
  57. /* Create new VFS handle and put it to the list */
  58. static int
  59. vfs_new_handle (struct vfs_class *vclass, void *fsinfo)
  60. {
  61. static int vfs_handle_counter = VFS_FIRST_HANDLE;
  62. struct vfs_openfile *h;
  63. h = g_new (struct vfs_openfile, 1);
  64. h->handle = vfs_handle_counter++;
  65. h->fsinfo = fsinfo;
  66. h->vclass = vclass;
  67. vfs_openfiles = g_slist_prepend (vfs_openfiles, h);
  68. return h->handle;
  69. }
  70. /* Function to match handle, passed to g_slist_find_custom() */
  71. static gint
  72. vfs_cmp_handle (gconstpointer a, gconstpointer b)
  73. {
  74. if (!a)
  75. return 1;
  76. return ((struct vfs_openfile *) a)->handle != (long) b;
  77. }
  78. /* Find VFS class by file handle */
  79. static inline struct vfs_class *
  80. vfs_op (int handle)
  81. {
  82. GSList *l;
  83. struct vfs_openfile *h;
  84. l = g_slist_find_custom (vfs_openfiles, (void *) (long) handle,
  85. vfs_cmp_handle);
  86. if (!l)
  87. return NULL;
  88. h = (struct vfs_openfile *) l->data;
  89. if (!h)
  90. return NULL;
  91. return h->vclass;
  92. }
  93. /* Find private file data by file handle */
  94. static inline void *
  95. vfs_info (int handle)
  96. {
  97. GSList *l;
  98. struct vfs_openfile *h;
  99. l = g_slist_find_custom (vfs_openfiles, (void *) (long) handle,
  100. vfs_cmp_handle);
  101. if (!l)
  102. return NULL;
  103. h = (struct vfs_openfile *) l->data;
  104. if (!h)
  105. return NULL;
  106. return h->fsinfo;
  107. }
  108. /* Free open file data for given file handle */
  109. static inline void
  110. vfs_free_handle (int handle)
  111. {
  112. GSList *l;
  113. l = g_slist_find_custom (vfs_openfiles, (void *) (long) handle,
  114. vfs_cmp_handle);
  115. vfs_openfiles = g_slist_delete_link (vfs_openfiles, l);
  116. }
  117. static struct vfs_class *vfs_list;
  118. int
  119. vfs_register_class (struct vfs_class *vfs)
  120. {
  121. if (vfs->init) /* vfs has own initialization function */
  122. if (!(*vfs->init)(vfs)) /* but it failed */
  123. return 0;
  124. vfs->next = vfs_list;
  125. vfs_list = vfs;
  126. return 1;
  127. }
  128. /* Return VFS class for the given prefix */
  129. static struct vfs_class *
  130. vfs_prefix_to_class (char *prefix)
  131. {
  132. struct vfs_class *vfs;
  133. /* Avoid last class (localfs) that would accept any prefix */
  134. for (vfs = vfs_list; vfs->next; vfs = vfs->next) {
  135. if (vfs->which) {
  136. if ((*vfs->which) (vfs, prefix) == -1)
  137. continue;
  138. return vfs;
  139. }
  140. if (vfs->prefix
  141. && !strncmp (prefix, vfs->prefix, strlen (vfs->prefix)))
  142. return vfs;
  143. }
  144. return NULL;
  145. }
  146. /* Strip known vfs suffixes from a filename (possible improvement: strip
  147. suffix from last path component).
  148. Returns a malloced string which has to be freed. */
  149. char *
  150. vfs_strip_suffix_from_filename (const char *filename)
  151. {
  152. struct vfs_class *vfs;
  153. char *semi;
  154. char *p;
  155. if (!filename)
  156. vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
  157. p = g_strdup (filename);
  158. if (!(semi = strrchr (p, '#')))
  159. return p;
  160. /* Avoid last class (localfs) that would accept any prefix */
  161. for (vfs = vfs_list; vfs->next; vfs = vfs->next) {
  162. if (vfs->which) {
  163. if ((*vfs->which) (vfs, semi + 1) == -1)
  164. continue;
  165. *semi = '\0'; /* Found valid suffix */
  166. return p;
  167. }
  168. if (vfs->prefix
  169. && !strncmp (semi + 1, vfs->prefix, strlen (vfs->prefix))) {
  170. *semi = '\0'; /* Found valid suffix */
  171. return p;
  172. }
  173. }
  174. return p;
  175. }
  176. static inline int
  177. path_magic (const char *path)
  178. {
  179. struct stat buf;
  180. if (!stat(path, &buf))
  181. return 0;
  182. return 1;
  183. }
  184. /*
  185. * Splits path '/p1#op/inpath' into inpath,op; returns which vfs it is.
  186. * What is left in path is p1. You still want to g_free(path), you DON'T
  187. * want to free neither *inpath nor *op
  188. */
  189. struct vfs_class *
  190. vfs_split (char *path, char **inpath, char **op)
  191. {
  192. char *semi;
  193. char *slash;
  194. struct vfs_class *ret;
  195. if (!path)
  196. vfs_die("Cannot split NULL");
  197. semi = strrchr (path, '#');
  198. if (!semi || !path_magic(path))
  199. return NULL;
  200. slash = strchr (semi, PATH_SEP);
  201. *semi = 0;
  202. if (op)
  203. *op = NULL;
  204. if (inpath)
  205. *inpath = NULL;
  206. if (slash)
  207. *slash = 0;
  208. if ((ret = vfs_prefix_to_class (semi+1))){
  209. if (op)
  210. *op = semi + 1;
  211. if (inpath)
  212. *inpath = slash ? slash + 1 : NULL;
  213. return ret;
  214. }
  215. if (slash)
  216. *slash = PATH_SEP;
  217. ret = vfs_split (path, inpath, op);
  218. *semi = '#';
  219. return ret;
  220. }
  221. static struct vfs_class *
  222. _vfs_get_class (char *path)
  223. {
  224. char *semi;
  225. char *slash;
  226. struct vfs_class *ret;
  227. g_return_val_if_fail(path, NULL);
  228. semi = strrchr (path, '#');
  229. if (!semi || !path_magic (path))
  230. return NULL;
  231. slash = strchr (semi, PATH_SEP);
  232. *semi = 0;
  233. if (slash)
  234. *slash = 0;
  235. ret = vfs_prefix_to_class (semi+1);
  236. if (slash)
  237. *slash = PATH_SEP;
  238. if (!ret)
  239. ret = _vfs_get_class (path);
  240. *semi = '#';
  241. return ret;
  242. }
  243. struct vfs_class *
  244. vfs_get_class (const char *pathname)
  245. {
  246. struct vfs_class *vfs;
  247. char *path = g_strdup (pathname);
  248. vfs = _vfs_get_class (path);
  249. g_free (path);
  250. if (!vfs)
  251. vfs = localfs_class;
  252. return vfs;
  253. }
  254. static int
  255. ferrno (struct vfs_class *vfs)
  256. {
  257. return vfs->ferrno ? (*vfs->ferrno)(vfs) : E_UNKNOWN;
  258. /* Hope that error message is obscure enough ;-) */
  259. }
  260. int
  261. mc_open (const char *filename, int flags, ...)
  262. {
  263. int mode;
  264. void *info;
  265. va_list ap;
  266. char *file = vfs_canon (filename);
  267. struct vfs_class *vfs = vfs_get_class (file);
  268. /* Get the mode flag */
  269. if (flags & O_CREAT) {
  270. va_start (ap, flags);
  271. mode = va_arg (ap, int);
  272. va_end (ap);
  273. } else
  274. mode = 0;
  275. if (!vfs->open) {
  276. g_free (file);
  277. errno = -EOPNOTSUPP;
  278. return -1;
  279. }
  280. info = (*vfs->open) (vfs, file, flags, mode); /* open must be supported */
  281. g_free (file);
  282. if (!info){
  283. errno = ferrno (vfs);
  284. return -1;
  285. }
  286. return vfs_new_handle (vfs, info);
  287. }
  288. #define MC_NAMEOP(name, inarg, callarg) \
  289. int mc_##name inarg \
  290. { \
  291. struct vfs_class *vfs; \
  292. int result; \
  293. char *mpath = vfs_canon (path); \
  294. vfs = vfs_get_class (mpath); \
  295. result = vfs->name ? (*vfs->name)callarg : -1; \
  296. g_free (mpath); \
  297. if (result == -1) \
  298. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  299. return result; \
  300. }
  301. MC_NAMEOP (chmod, (const char *path, mode_t mode), (vfs, mpath, mode))
  302. MC_NAMEOP (chown, (const char *path, uid_t owner, gid_t group), (vfs, mpath, owner, group))
  303. MC_NAMEOP (utime, (const char *path, struct utimbuf *times), (vfs, mpath, times))
  304. MC_NAMEOP (readlink, (const char *path, char *buf, int bufsiz), (vfs, mpath, buf, bufsiz))
  305. MC_NAMEOP (unlink, (const char *path), (vfs, mpath))
  306. MC_NAMEOP (symlink, (const char *name1, const char *path), (vfs, name1, mpath))
  307. MC_NAMEOP (mkdir, (const char *path, mode_t mode), (vfs, mpath, mode))
  308. MC_NAMEOP (rmdir, (const char *path), (vfs, mpath))
  309. MC_NAMEOP (mknod, (const char *path, mode_t mode, dev_t dev), (vfs, mpath, mode, dev))
  310. #define MC_HANDLEOP(name, inarg, callarg) \
  311. int mc_##name inarg \
  312. { \
  313. struct vfs_class *vfs; \
  314. int result; \
  315. if (handle == -1) \
  316. return -1; \
  317. vfs = vfs_op (handle); \
  318. result = vfs->name ? (*vfs->name)callarg : -1; \
  319. if (result == -1) \
  320. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  321. return result; \
  322. }
  323. MC_HANDLEOP(read, (int handle, void *buffer, int count), (vfs_info (handle), buffer, count) )
  324. MC_HANDLEOP (write, (int handle, const void *buf, int nbyte), (vfs_info (handle), buf, nbyte))
  325. #define MC_RENAMEOP(name) \
  326. int mc_##name (const char *fname1, const char *fname2) \
  327. { \
  328. struct vfs_class *vfs; \
  329. int result; \
  330. char *name2, *name1 = vfs_canon (fname1); \
  331. vfs = vfs_get_class (name1); \
  332. name2 = vfs_canon (fname2); \
  333. if (vfs != vfs_get_class (name2)){ \
  334. errno = EXDEV; \
  335. g_free (name1); \
  336. g_free (name2); \
  337. return -1; \
  338. } \
  339. result = vfs->name ? (*vfs->name)(vfs, name1, name2) : -1; \
  340. g_free (name1); \
  341. g_free (name2); \
  342. if (result == -1) \
  343. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  344. return result; \
  345. }
  346. MC_RENAMEOP (link)
  347. MC_RENAMEOP (rename)
  348. int
  349. mc_ctl (int handle, int ctlop, void *arg)
  350. {
  351. struct vfs_class *vfs = vfs_op (handle);
  352. return vfs->ctl ? (*vfs->ctl)(vfs_info (handle), ctlop, arg) : 0;
  353. }
  354. int
  355. mc_setctl (const char *path, int ctlop, void *arg)
  356. {
  357. struct vfs_class *vfs;
  358. int result;
  359. char *mpath;
  360. if (!path)
  361. vfs_die("You don't want to pass NULL to mc_setctl.");
  362. mpath = vfs_canon (path);
  363. vfs = vfs_get_class (mpath);
  364. result = vfs->setctl ? (*vfs->setctl)(vfs, mpath, ctlop, arg) : 0;
  365. g_free (mpath);
  366. return result;
  367. }
  368. int
  369. mc_close (int handle)
  370. {
  371. struct vfs_class *vfs;
  372. int result;
  373. if (handle == -1 || !vfs_info (handle))
  374. return -1;
  375. vfs = vfs_op (handle);
  376. if (handle < 3)
  377. return close (handle);
  378. if (!vfs->close)
  379. vfs_die ("VFS must support close.\n");
  380. result = (*vfs->close)(vfs_info (handle));
  381. vfs_free_handle (handle);
  382. if (result == -1)
  383. errno = ferrno (vfs);
  384. return result;
  385. }
  386. DIR *
  387. mc_opendir (const char *dirname)
  388. {
  389. int handle, *handlep;
  390. void *info;
  391. struct vfs_class *vfs;
  392. char *dname;
  393. dname = vfs_canon (dirname);
  394. vfs = vfs_get_class (dname);
  395. info = vfs->opendir ? (*vfs->opendir)(vfs, dname) : NULL;
  396. g_free (dname);
  397. if (!info){
  398. errno = vfs->opendir ? ferrno (vfs) : E_NOTSUPP;
  399. return NULL;
  400. }
  401. handle = vfs_new_handle (vfs, info);
  402. handlep = g_new (int, 1);
  403. *handlep = handle;
  404. return (DIR *) handlep;
  405. }
  406. struct dirent *
  407. mc_readdir (DIR *dirp)
  408. {
  409. int handle;
  410. struct vfs_class *vfs;
  411. struct dirent *result = NULL;
  412. if (!dirp) {
  413. errno = EFAULT;
  414. return NULL;
  415. }
  416. handle = *(int *) dirp;
  417. vfs = vfs_op (handle);
  418. if (vfs->readdir)
  419. result = (*vfs->readdir) (vfs_info (handle));
  420. if (!result)
  421. errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP;
  422. return result;
  423. }
  424. int
  425. mc_closedir (DIR *dirp)
  426. {
  427. int handle = *(int *) dirp;
  428. struct vfs_class *vfs = vfs_op (handle);
  429. int result;
  430. result = vfs->closedir ? (*vfs->closedir)(vfs_info (handle)) : -1;
  431. vfs_free_handle (handle);
  432. g_free (dirp);
  433. return result;
  434. }
  435. int mc_stat (const char *filename, struct stat *buf) {
  436. struct vfs_class *vfs;
  437. int result;
  438. char *path;
  439. path = vfs_canon (filename); vfs = vfs_get_class (path);
  440. result = vfs->stat ? (*vfs->stat) (vfs, path, buf) : -1;
  441. g_free (path);
  442. if (result == -1)
  443. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  444. return result;
  445. }
  446. int mc_lstat (const char *filename, struct stat *buf) {
  447. struct vfs_class *vfs;
  448. int result;
  449. char *path;
  450. path = vfs_canon (filename); vfs = vfs_get_class (path);
  451. result = vfs->lstat ? (*vfs->lstat) (vfs, path, buf) : -1;
  452. g_free (path);
  453. if (result == -1)
  454. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  455. return result;
  456. }
  457. int mc_fstat (int handle, struct stat *buf) {
  458. struct vfs_class *vfs;
  459. int result;
  460. if (handle == -1)
  461. return -1;
  462. vfs = vfs_op (handle);
  463. result = vfs->fstat ? (*vfs->fstat) (vfs_info (handle), buf) : -1;
  464. if (result == -1)
  465. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  466. return result;
  467. }
  468. /*
  469. * Return current directory. If it's local, reread the current directory
  470. * from the OS. You must g_strdup() whatever this function returns.
  471. */
  472. static const char *
  473. _vfs_get_cwd (void)
  474. {
  475. char *p;
  476. struct stat my_stat, my_stat2;
  477. if (!_vfs_get_class (current_dir)) {
  478. p = g_get_current_dir ();
  479. if (!p) /* One of the directories in the path is not readable */
  480. return current_dir;
  481. /* Otherwise check if it is O.K. to use the current_dir */
  482. if (!cd_symlinks || mc_stat (p, &my_stat)
  483. || mc_stat (current_dir, &my_stat2)
  484. || my_stat.st_ino != my_stat2.st_ino
  485. || my_stat.st_dev != my_stat2.st_dev) {
  486. g_free (current_dir);
  487. current_dir = p;
  488. return p;
  489. } /* Otherwise we return current_dir below */
  490. g_free (p);
  491. }
  492. return current_dir;
  493. }
  494. static void
  495. vfs_setup_wd (void)
  496. {
  497. current_dir = g_strdup (PATH_SEP_STR);
  498. _vfs_get_cwd ();
  499. if (strlen (current_dir) > MC_MAXPATHLEN - 2)
  500. vfs_die ("Current dir too long.\n");
  501. current_vfs = vfs_get_class (current_dir);
  502. }
  503. /*
  504. * Return current directory. If it's local, reread the current directory
  505. * from the OS. Put directory to the provided buffer.
  506. */
  507. char *
  508. mc_get_current_wd (char *buffer, int size)
  509. {
  510. const char *cwd = _vfs_get_cwd ();
  511. g_strlcpy (buffer, cwd, size);
  512. return buffer;
  513. }
  514. /*
  515. * Return current directory without any OS calls.
  516. */
  517. char *
  518. vfs_get_current_dir (void)
  519. {
  520. return current_dir;
  521. }
  522. off_t mc_lseek (int fd, off_t offset, int whence)
  523. {
  524. struct vfs_class *vfs;
  525. int result;
  526. if (fd == -1)
  527. return -1;
  528. vfs = vfs_op (fd);
  529. result = vfs->lseek ? (*vfs->lseek)(vfs_info (fd), offset, whence) : -1;
  530. if (result == -1)
  531. errno = vfs->lseek ? ferrno (vfs) : E_NOTSUPP;
  532. return result;
  533. }
  534. /*
  535. * remove //, /./ and /../
  536. */
  537. #define ISSLASH(a) (!a || (a == '/'))
  538. char *
  539. vfs_canon (const char *path)
  540. {
  541. if (!path)
  542. vfs_die("Cannot canonicalize NULL");
  543. /* Relative to current directory */
  544. if (*path != PATH_SEP){
  545. char *local, *result;
  546. local = concat_dir_and_file (current_dir, path);
  547. result = vfs_canon (local);
  548. g_free (local);
  549. return result;
  550. }
  551. /*
  552. * So we have path of following form:
  553. * /p1/p2#op/.././././p3#op/p4. Good luck.
  554. */
  555. {
  556. char *result = g_strdup (path);
  557. canonicalize_pathname (result);
  558. return result;
  559. }
  560. }
  561. /*
  562. * VFS chdir.
  563. * Return 0 on success, -1 on failure.
  564. */
  565. int
  566. mc_chdir (const char *path)
  567. {
  568. char *new_dir;
  569. struct vfs_class *old_vfs, *new_vfs;
  570. vfsid old_vfsid;
  571. int result;
  572. new_dir = vfs_canon (path);
  573. new_vfs = vfs_get_class (new_dir);
  574. if (!new_vfs->chdir) {
  575. g_free (new_dir);
  576. return -1;
  577. }
  578. result = (*new_vfs->chdir) (new_vfs, new_dir);
  579. if (result == -1) {
  580. errno = ferrno (new_vfs);
  581. g_free (new_dir);
  582. return -1;
  583. }
  584. old_vfsid = vfs_getid (current_vfs, current_dir);
  585. old_vfs = current_vfs;
  586. /* Actually change directory */
  587. g_free (current_dir);
  588. current_dir = new_dir;
  589. current_vfs = new_vfs;
  590. /* This function uses the new current_dir implicitly */
  591. vfs_stamp_create (old_vfs, old_vfsid);
  592. /* Sometimes we assume no trailing slash on cwd */
  593. if (*current_dir) {
  594. char *p;
  595. p = strchr (current_dir, 0) - 1;
  596. if (*p == PATH_SEP && p > current_dir)
  597. *p = 0;
  598. }
  599. return 0;
  600. }
  601. /* Return 1 is the current VFS class is local */
  602. int
  603. vfs_current_is_local (void)
  604. {
  605. return (current_vfs->flags & VFSF_LOCAL) != 0;
  606. }
  607. /* Return flags of the VFS class of the given filename */
  608. int
  609. vfs_file_class_flags (const char *filename)
  610. {
  611. struct vfs_class *vfs;
  612. char *fname;
  613. fname = vfs_canon (filename);
  614. vfs = vfs_get_class (fname);
  615. g_free (fname);
  616. return vfs->flags;
  617. }
  618. static char *
  619. mc_def_getlocalcopy (const char *filename)
  620. {
  621. char *tmp;
  622. int fdin, fdout, i;
  623. char buffer[8192];
  624. struct stat mystat;
  625. fdin = mc_open (filename, O_RDONLY | O_LINEAR);
  626. if (fdin == -1)
  627. return NULL;
  628. fdout = vfs_mkstemps (&tmp, "vfs", filename);
  629. if (fdout == -1)
  630. goto fail;
  631. while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0) {
  632. if (write (fdout, buffer, i) != i)
  633. goto fail;
  634. }
  635. if (i == -1)
  636. goto fail;
  637. i = mc_close (fdin);
  638. fdin = -1;
  639. if (i == -1)
  640. goto fail;
  641. if (close (fdout) == -1) {
  642. fdout = -1;
  643. goto fail;
  644. }
  645. if (mc_stat (filename, &mystat) != -1) {
  646. chmod (tmp, mystat.st_mode);
  647. }
  648. return tmp;
  649. fail:
  650. if (fdout != -1)
  651. close (fdout);
  652. if (fdin != -1)
  653. mc_close (fdin);
  654. g_free (tmp);
  655. return NULL;
  656. }
  657. char *
  658. mc_getlocalcopy (const char *pathname)
  659. {
  660. char *result;
  661. char *path = vfs_canon (pathname);
  662. struct vfs_class *vfs = vfs_get_class (path);
  663. result = vfs->getlocalcopy ? (*vfs->getlocalcopy)(vfs, path) :
  664. mc_def_getlocalcopy (path);
  665. g_free (path);
  666. if (!result)
  667. errno = ferrno (vfs);
  668. return result;
  669. }
  670. static int
  671. mc_def_ungetlocalcopy (struct vfs_class *vfs, const char *filename,
  672. const char *local, int has_changed)
  673. {
  674. int fdin = -1, fdout = -1, i;
  675. if (has_changed) {
  676. char buffer[8192];
  677. if (!vfs->write)
  678. goto failed;
  679. fdin = open (local, O_RDONLY);
  680. if (fdin == -1)
  681. goto failed;
  682. fdout = mc_open (filename, O_WRONLY | O_TRUNC);
  683. if (fdout == -1)
  684. goto failed;
  685. while ((i = read (fdin, buffer, sizeof (buffer))) > 0) {
  686. if (mc_write (fdout, buffer, i) != i)
  687. goto failed;
  688. }
  689. if (i == -1)
  690. goto failed;
  691. if (close (fdin) == -1) {
  692. fdin = -1;
  693. goto failed;
  694. }
  695. fdin = -1;
  696. if (mc_close (fdout) == -1) {
  697. fdout = -1;
  698. goto failed;
  699. }
  700. }
  701. unlink (local);
  702. return 0;
  703. failed:
  704. message (1, _("Changes to file lost"), "%s", filename);
  705. if (fdout != -1)
  706. mc_close (fdout);
  707. if (fdin != -1)
  708. close (fdin);
  709. unlink (local);
  710. return -1;
  711. }
  712. int
  713. mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed)
  714. {
  715. int return_value = 0;
  716. char *path = vfs_canon (pathname);
  717. struct vfs_class *vfs = vfs_get_class (path);
  718. return_value = vfs->ungetlocalcopy ?
  719. (*vfs->ungetlocalcopy)(vfs, path, local, has_changed) :
  720. mc_def_ungetlocalcopy (vfs, path, local, has_changed);
  721. g_free (path);
  722. return return_value;
  723. }
  724. void
  725. vfs_init (void)
  726. {
  727. /* localfs needs to be the first one */
  728. init_localfs();
  729. /* fallback value for vfs_get_class() */
  730. localfs_class = vfs_list;
  731. init_extfs ();
  732. init_sfs ();
  733. init_tarfs ();
  734. init_cpiofs ();
  735. #ifdef USE_EXT2FSLIB
  736. init_undelfs ();
  737. #endif /* USE_EXT2FSLIB */
  738. #ifdef USE_NETCODE
  739. tcp_init();
  740. init_ftpfs ();
  741. init_fish ();
  742. #ifdef WITH_SMBFS
  743. init_smbfs ();
  744. #endif /* WITH_SMBFS */
  745. #ifdef WITH_MCFS
  746. init_mcfs ();
  747. #endif /* WITH_MCFS */
  748. #endif /* USE_NETCODE */
  749. vfs_setup_wd ();
  750. }
  751. void
  752. vfs_shut (void)
  753. {
  754. struct vfs_class *vfs;
  755. vfs_gc_done ();
  756. g_free (current_dir);
  757. for (vfs = vfs_list; vfs; vfs = vfs->next)
  758. if (vfs->done)
  759. (*vfs->done) (vfs);
  760. g_slist_free (vfs_openfiles);
  761. }
  762. /*
  763. * These ones grab information from the VFS
  764. * and handles them to an upper layer
  765. */
  766. void
  767. vfs_fill_names (fill_names_f func)
  768. {
  769. struct vfs_class *vfs;
  770. for (vfs=vfs_list; vfs; vfs=vfs->next)
  771. if (vfs->fill_names)
  772. (*vfs->fill_names) (vfs, func);
  773. }
  774. /*
  775. * Returns vfs path corresponding to given url. If passed string is
  776. * not recognized as url, g_strdup(url) is returned.
  777. */
  778. static const struct {
  779. const char *name;
  780. size_t name_len;
  781. const char *substitute;
  782. } url_table[] = { {"ftp://", 6, "/#ftp:"},
  783. {"mc://", 5, "/#mc:"},
  784. {"smb://", 6, "/#smb:"},
  785. {"sh://", 5, "/#sh:"},
  786. {"ssh://", 6, "/#sh:"},
  787. {"a:", 2, "/#a"}
  788. };
  789. char *
  790. vfs_translate_url (const char *url)
  791. {
  792. size_t i;
  793. for (i = 0; i < sizeof (url_table)/sizeof (url_table[0]); i++)
  794. if (strncmp (url, url_table[i].name, url_table[i].name_len) == 0)
  795. return g_strconcat (url_table[i].substitute, url + url_table[i].name_len, (char*) NULL);
  796. return g_strdup (url);
  797. }
  798. int vfs_file_is_local (const char *filename)
  799. {
  800. return vfs_file_class_flags (filename) & VFSF_LOCAL;
  801. }