vfs.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353
  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. if (vfs == NULL)
  569. return 0;
  570. return vfs->ctl ? (*vfs->ctl)(vfs_info (handle), ctlop, arg) : 0;
  571. }
  572. int
  573. mc_setctl (const char *path, int ctlop, void *arg)
  574. {
  575. struct vfs_class *vfs;
  576. int result;
  577. char *mpath;
  578. if (!path)
  579. vfs_die("You don't want to pass NULL to mc_setctl.");
  580. mpath = vfs_canon_and_translate (path);
  581. if (mpath != NULL) {
  582. vfs = vfs_get_class (mpath);
  583. result = vfs->setctl ? (*vfs->setctl)(vfs, mpath, ctlop, arg) : 0;
  584. g_free (mpath);
  585. return result;
  586. } else return -1;
  587. }
  588. int
  589. mc_close (int handle)
  590. {
  591. struct vfs_class *vfs;
  592. int result;
  593. if (handle == -1 || !vfs_info (handle))
  594. return -1;
  595. vfs = vfs_op (handle);
  596. if (vfs == NULL)
  597. return -1;
  598. if (handle < 3)
  599. return close (handle);
  600. if (!vfs->close)
  601. vfs_die ("VFS must support close.\n");
  602. result = (*vfs->close)(vfs_info (handle));
  603. vfs_free_handle (handle);
  604. if (result == -1)
  605. errno = ferrno (vfs);
  606. return result;
  607. }
  608. DIR *
  609. mc_opendir (const char *dirname)
  610. {
  611. int handle, *handlep;
  612. void *info;
  613. struct vfs_class *vfs;
  614. char *canon;
  615. char *dname;
  616. struct vfs_dirinfo *dirinfo;
  617. const char *encoding;
  618. canon = vfs_canon (dirname);
  619. dname = vfs_translate_path_n (canon);
  620. if (dname != NULL) {
  621. vfs = vfs_get_class (dname);
  622. info = vfs->opendir ? (*vfs->opendir)(vfs, dname) : NULL;
  623. g_free (dname);
  624. if (!info){
  625. errno = vfs->opendir ? ferrno (vfs) : E_NOTSUPP;
  626. g_free (canon);
  627. return NULL;
  628. }
  629. dirinfo = g_new (struct vfs_dirinfo, 1);
  630. dirinfo->info = info;
  631. encoding = vfs_get_encoding (canon);
  632. g_free (canon);
  633. dirinfo->converter = (encoding != NULL) ? str_crt_conv_from (encoding) :
  634. str_cnv_from_term;
  635. if (dirinfo->converter == INVALID_CONV) dirinfo->converter =str_cnv_from_term;
  636. handle = vfs_new_handle (vfs, dirinfo);
  637. handlep = g_new (int, 1);
  638. *handlep = handle;
  639. return (DIR *) handlep;
  640. } else {
  641. g_free (canon);
  642. return NULL;
  643. }
  644. }
  645. static struct dirent * mc_readdir_result = NULL;
  646. struct dirent *
  647. mc_readdir (DIR *dirp)
  648. {
  649. int handle;
  650. struct vfs_class *vfs;
  651. struct dirent *entry = NULL;
  652. struct vfs_dirinfo *dirinfo;
  653. estr_t state;
  654. if (!mc_readdir_result)
  655. {
  656. /* We can't just allocate struct dirent as (see man dirent.h)
  657. * struct dirent has VERY nonnaive semantics of allocating
  658. * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
  659. * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
  660. * heap corrupter. So, allocate longliving dirent with at least
  661. * (NAME_MAX + 1) for d_name in it.
  662. * Strictly saying resulting dirent is unusable as we don't adjust internal
  663. * structures, holding dirent size. But we don't use it in libc infrastructure.
  664. * TODO: to make simpler homemade dirent-alike structure.
  665. */
  666. mc_readdir_result = (struct dirent *)malloc(sizeof(struct dirent) + NAME_MAX + 1);
  667. }
  668. if (!dirp) {
  669. errno = EFAULT;
  670. return NULL;
  671. }
  672. handle = *(int *) dirp;
  673. vfs = vfs_op (handle);
  674. if (vfs == NULL)
  675. return NULL;
  676. dirinfo = vfs_info (handle);
  677. if (vfs->readdir) {
  678. entry = (*vfs->readdir) (dirinfo->info);
  679. if (entry == NULL) return NULL;
  680. g_string_set_size(vfs_str_buffer,0);
  681. state = str_vfs_convert_from (dirinfo->converter,
  682. entry->d_name, vfs_str_buffer);
  683. mc_readdir_result->d_ino = entry->d_ino;
  684. g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, NAME_MAX + 1);
  685. }
  686. if (entry == NULL) errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP;
  687. return (entry != NULL) ? mc_readdir_result : NULL;
  688. }
  689. int
  690. mc_closedir (DIR *dirp)
  691. {
  692. int handle = *(int *) dirp;
  693. struct vfs_class *vfs = vfs_op (handle);
  694. int result;
  695. struct vfs_dirinfo *dirinfo;
  696. if (vfs == NULL)
  697. return -1;
  698. dirinfo = vfs_info (handle);
  699. if (dirinfo->converter != str_cnv_from_term) str_close_conv (dirinfo->converter);
  700. result = vfs->closedir ? (*vfs->closedir)(dirinfo->info) : -1;
  701. vfs_free_handle (handle);
  702. g_free (dirinfo);
  703. g_free (dirp);
  704. return result;
  705. }
  706. int mc_stat (const char *filename, struct stat *buf) {
  707. struct vfs_class *vfs;
  708. int result;
  709. char *path;
  710. path = vfs_canon_and_translate (filename);
  711. if (path == NULL)
  712. return -1;
  713. vfs = vfs_get_class (path);
  714. if (vfs == NULL) {
  715. g_free (path);
  716. return -1;
  717. }
  718. result = vfs->stat ? (*vfs->stat) (vfs, path, buf) : -1;
  719. g_free (path);
  720. if (result == -1)
  721. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  722. return result;
  723. }
  724. int mc_lstat (const char *filename, struct stat *buf) {
  725. struct vfs_class *vfs;
  726. int result;
  727. char *path;
  728. path = vfs_canon_and_translate (filename);
  729. if (path == NULL)
  730. return -1;
  731. vfs = vfs_get_class (path);
  732. if (vfs == NULL) {
  733. g_free (path);
  734. return -1;
  735. }
  736. result = vfs->lstat ? (*vfs->lstat) (vfs, path, buf) : -1;
  737. g_free (path);
  738. if (result == -1)
  739. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  740. return result;
  741. }
  742. int mc_fstat (int handle, struct stat *buf) {
  743. struct vfs_class *vfs;
  744. int result;
  745. if (handle == -1)
  746. return -1;
  747. vfs = vfs_op (handle);
  748. if (vfs == NULL)
  749. return -1;
  750. result = vfs->fstat ? (*vfs->fstat) (vfs_info (handle), buf) : -1;
  751. if (result == -1)
  752. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  753. return result;
  754. }
  755. /**
  756. * Return current directory. If it's local, reread the current directory
  757. * from the OS. You must g_strdup() whatever this function returns.
  758. */
  759. static const char *
  760. _vfs_get_cwd (void)
  761. {
  762. char *sys_cwd;
  763. char *trans;
  764. const char *encoding;
  765. char *tmp;
  766. estr_t state;
  767. struct stat my_stat, my_stat2;
  768. trans = vfs_translate_path_n (current_dir); /* add check if NULL */
  769. if (!_vfs_get_class (trans)) {
  770. encoding = vfs_get_encoding (current_dir);
  771. if (encoding == NULL) {
  772. tmp = g_get_current_dir ();
  773. if (tmp != NULL) { /* One of the directories in the path is not readable */
  774. g_string_set_size(vfs_str_buffer,0);
  775. state = str_vfs_convert_from (str_cnv_from_term, tmp, vfs_str_buffer);
  776. g_free (tmp);
  777. sys_cwd = (state == ESTR_SUCCESS) ? g_strdup (vfs_str_buffer->str) : NULL;
  778. if (!sys_cwd)
  779. return current_dir;
  780. /* Otherwise check if it is O.K. to use the current_dir */
  781. if (!cd_symlinks || mc_stat (sys_cwd, &my_stat)
  782. || mc_stat (current_dir, &my_stat2)
  783. || my_stat.st_ino != my_stat2.st_ino
  784. || my_stat.st_dev != my_stat2.st_dev) {
  785. g_free (current_dir);
  786. current_dir = sys_cwd;
  787. return sys_cwd;
  788. }/* Otherwise we return current_dir below */
  789. }
  790. }
  791. }
  792. g_free (trans);
  793. return current_dir;
  794. }
  795. static void
  796. vfs_setup_wd (void)
  797. {
  798. current_dir = g_strdup (PATH_SEP_STR);
  799. _vfs_get_cwd ();
  800. if (strlen (current_dir) > MC_MAXPATHLEN - 2)
  801. vfs_die ("Current dir too long.\n");
  802. current_vfs = vfs_get_class (current_dir);
  803. }
  804. /**
  805. * Return current directory. If it's local, reread the current directory
  806. * from the OS. Put directory to the provided buffer.
  807. */
  808. char *
  809. mc_get_current_wd (char *buffer, int size)
  810. {
  811. const char *cwd = _vfs_get_cwd ();
  812. g_strlcpy (buffer, cwd, size);
  813. return buffer;
  814. }
  815. /**
  816. * Return current directory without any OS calls.
  817. */
  818. char *
  819. vfs_get_current_dir (void)
  820. {
  821. return current_dir;
  822. }
  823. off_t mc_lseek (int fd, off_t offset, int whence)
  824. {
  825. struct vfs_class *vfs;
  826. int result;
  827. if (fd == -1)
  828. return -1;
  829. vfs = vfs_op (fd);
  830. if (vfs == NULL)
  831. return -1;
  832. result = vfs->lseek ? (*vfs->lseek)(vfs_info (fd), offset, whence) : -1;
  833. if (result == -1)
  834. errno = vfs->lseek ? ferrno (vfs) : E_NOTSUPP;
  835. return result;
  836. }
  837. /**
  838. * remove //, /./ and /../
  839. */
  840. #define ISSLASH(a) (!a || (a == '/'))
  841. char *
  842. vfs_canon (const char *path)
  843. {
  844. if (!path)
  845. vfs_die("Cannot canonicalize NULL");
  846. /* Relative to current directory */
  847. if (*path != PATH_SEP){
  848. char *local, *result;
  849. local = concat_dir_and_file (current_dir, path);
  850. result = vfs_canon (local);
  851. g_free (local);
  852. return result;
  853. }
  854. /*
  855. * So we have path of following form:
  856. * /p1/p2#op/.././././p3#op/p4. Good luck.
  857. */
  858. {
  859. char *result = g_strdup (path);
  860. canonicalize_pathname (result);
  861. return result;
  862. }
  863. }
  864. /**
  865. * VFS chdir.
  866. * Return 0 on success, -1 on failure.
  867. */
  868. int
  869. mc_chdir (const char *path)
  870. {
  871. char *new_dir;
  872. char *trans_dir;
  873. struct vfs_class *old_vfs, *new_vfs;
  874. vfsid old_vfsid;
  875. int result;
  876. new_dir = vfs_canon (path);
  877. trans_dir = vfs_translate_path_n (new_dir);
  878. if (trans_dir != NULL) {
  879. new_vfs = vfs_get_class (trans_dir);
  880. if (!new_vfs->chdir) {
  881. g_free (new_dir);
  882. g_free (trans_dir);
  883. return -1;
  884. }
  885. result = (*new_vfs->chdir) (new_vfs, trans_dir);
  886. if (result == -1) {
  887. errno = ferrno (new_vfs);
  888. g_free (new_dir);
  889. g_free (trans_dir);
  890. return -1;
  891. }
  892. old_vfsid = vfs_getid (current_vfs, current_dir);
  893. old_vfs = current_vfs;
  894. /* Actually change directory */
  895. g_free (current_dir);
  896. current_dir = new_dir;
  897. current_vfs = new_vfs;
  898. /* This function uses the new current_dir implicitly */
  899. vfs_stamp_create (old_vfs, old_vfsid);
  900. /* Sometimes we assume no trailing slash on cwd */
  901. if (*current_dir) {
  902. char *p;
  903. p = strchr (current_dir, 0) - 1;
  904. if (*p == PATH_SEP && p > current_dir)
  905. *p = 0;
  906. }
  907. g_free (trans_dir);
  908. return 0;
  909. } else {
  910. g_free (new_dir);
  911. return -1;
  912. }
  913. }
  914. /* Return 1 is the current VFS class is local */
  915. int
  916. vfs_current_is_local (void)
  917. {
  918. return (current_vfs->flags & VFSF_LOCAL) != 0;
  919. }
  920. /* Return flags of the VFS class of the given filename */
  921. int
  922. vfs_file_class_flags (const char *filename)
  923. {
  924. struct vfs_class *vfs;
  925. char *fname;
  926. fname = vfs_canon_and_translate (filename);
  927. if (fname != NULL) {
  928. vfs = vfs_get_class (fname);
  929. g_free (fname);
  930. return vfs->flags;
  931. } else return -1;
  932. }
  933. static char *
  934. mc_def_getlocalcopy (const char *filename)
  935. {
  936. char *tmp;
  937. int fdin, fdout, i;
  938. char buffer[8192];
  939. struct stat mystat;
  940. fdin = mc_open (filename, O_RDONLY | O_LINEAR);
  941. if (fdin == -1)
  942. return NULL;
  943. fdout = vfs_mkstemps (&tmp, "vfs", filename);
  944. if (fdout == -1)
  945. goto fail;
  946. while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0) {
  947. if (write (fdout, buffer, i) != i)
  948. goto fail;
  949. }
  950. if (i == -1)
  951. goto fail;
  952. i = mc_close (fdin);
  953. fdin = -1;
  954. if (i == -1)
  955. goto fail;
  956. if (close (fdout) == -1) {
  957. fdout = -1;
  958. goto fail;
  959. }
  960. if (mc_stat (filename, &mystat) != -1) {
  961. chmod (tmp, mystat.st_mode);
  962. }
  963. return tmp;
  964. fail:
  965. if (fdout != -1)
  966. close (fdout);
  967. if (fdin != -1)
  968. mc_close (fdin);
  969. g_free (tmp);
  970. return NULL;
  971. }
  972. char *
  973. mc_getlocalcopy (const char *pathname)
  974. {
  975. char *result;
  976. char *path;
  977. path = vfs_canon_and_translate (pathname);
  978. if (path != NULL) {
  979. struct vfs_class *vfs = vfs_get_class (path);
  980. result = vfs->getlocalcopy ? (*vfs->getlocalcopy)(vfs, path) :
  981. mc_def_getlocalcopy (path);
  982. g_free (path);
  983. if (!result)
  984. errno = ferrno (vfs);
  985. return result;
  986. } else return NULL;
  987. }
  988. static int
  989. mc_def_ungetlocalcopy (struct vfs_class *vfs, const char *filename,
  990. const char *local, int has_changed)
  991. {
  992. int fdin = -1, fdout = -1, i;
  993. if (has_changed) {
  994. char buffer[8192];
  995. if (!vfs->write)
  996. goto failed;
  997. fdin = open (local, O_RDONLY);
  998. if (fdin == -1)
  999. goto failed;
  1000. fdout = mc_open (filename, O_WRONLY | O_TRUNC);
  1001. if (fdout == -1)
  1002. goto failed;
  1003. while ((i = read (fdin, buffer, sizeof (buffer))) > 0) {
  1004. if (mc_write (fdout, buffer, i) != i)
  1005. goto failed;
  1006. }
  1007. if (i == -1)
  1008. goto failed;
  1009. if (close (fdin) == -1) {
  1010. fdin = -1;
  1011. goto failed;
  1012. }
  1013. fdin = -1;
  1014. if (mc_close (fdout) == -1) {
  1015. fdout = -1;
  1016. goto failed;
  1017. }
  1018. }
  1019. unlink (local);
  1020. return 0;
  1021. failed:
  1022. message (D_ERROR, _("Changes to file lost"), "%s", filename);
  1023. if (fdout != -1)
  1024. mc_close (fdout);
  1025. if (fdin != -1)
  1026. close (fdin);
  1027. unlink (local);
  1028. return -1;
  1029. }
  1030. int
  1031. mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed)
  1032. {
  1033. int return_value = 0;
  1034. char *path;
  1035. path = vfs_canon_and_translate (pathname);
  1036. if (path != NULL) {
  1037. struct vfs_class *vfs = vfs_get_class (path);
  1038. return_value = vfs->ungetlocalcopy ?
  1039. (*vfs->ungetlocalcopy)(vfs, path, local, has_changed) :
  1040. mc_def_ungetlocalcopy (vfs, path, local, has_changed);
  1041. g_free (path);
  1042. return return_value;
  1043. } else return -1;
  1044. }
  1045. void
  1046. vfs_init (void)
  1047. {
  1048. /* create the VFS handle array */
  1049. vfs_openfiles = g_ptr_array_new ();
  1050. vfs_str_buffer = g_string_new("");
  1051. /* localfs needs to be the first one */
  1052. init_localfs();
  1053. /* fallback value for vfs_get_class() */
  1054. localfs_class = vfs_list;
  1055. init_extfs ();
  1056. init_sfs ();
  1057. init_tarfs ();
  1058. init_cpiofs ();
  1059. #ifdef USE_EXT2FSLIB
  1060. init_undelfs ();
  1061. #endif /* USE_EXT2FSLIB */
  1062. #ifdef USE_NETCODE
  1063. tcp_init();
  1064. init_ftpfs ();
  1065. init_fish ();
  1066. #ifdef WITH_SMBFS
  1067. init_smbfs ();
  1068. #endif /* WITH_SMBFS */
  1069. #ifdef ENABLE_VFS_MCFS
  1070. init_mcfs ();
  1071. #endif /* ENABLE_VFS_MCFS */
  1072. #endif /* USE_NETCODE */
  1073. vfs_setup_wd ();
  1074. }
  1075. void
  1076. vfs_shut (void)
  1077. {
  1078. struct vfs_class *vfs;
  1079. vfs_gc_done ();
  1080. g_free (current_dir);
  1081. for (vfs = vfs_list; vfs; vfs = vfs->next)
  1082. if (vfs->done)
  1083. (*vfs->done) (vfs);
  1084. g_ptr_array_free (vfs_openfiles, TRUE);
  1085. g_string_free (vfs_str_buffer, TRUE);
  1086. }
  1087. /*
  1088. * These ones grab information from the VFS
  1089. * and handles them to an upper layer
  1090. */
  1091. void
  1092. vfs_fill_names (fill_names_f func)
  1093. {
  1094. struct vfs_class *vfs;
  1095. for (vfs=vfs_list; vfs; vfs=vfs->next)
  1096. if (vfs->fill_names)
  1097. (*vfs->fill_names) (vfs, func);
  1098. }
  1099. /*
  1100. * Returns vfs path corresponding to given url. If passed string is
  1101. * not recognized as url, g_strdup(url) is returned.
  1102. */
  1103. static const struct {
  1104. const char *name;
  1105. size_t name_len;
  1106. const char *substitute;
  1107. } url_table[] = { {"ftp://", 6, "/#ftp:"},
  1108. {"mc://", 5, "/#mc:"},
  1109. {"smb://", 6, "/#smb:"},
  1110. {"sh://", 5, "/#sh:"},
  1111. {"ssh://", 6, "/#sh:"},
  1112. {"a:", 2, "/#a"}
  1113. };
  1114. char *
  1115. vfs_translate_url (const char *url)
  1116. {
  1117. size_t i;
  1118. for (i = 0; i < sizeof (url_table)/sizeof (url_table[0]); i++)
  1119. if (strncmp (url, url_table[i].name, url_table[i].name_len) == 0)
  1120. return g_strconcat (url_table[i].substitute, url + url_table[i].name_len, (char*) NULL);
  1121. return g_strdup (url);
  1122. }
  1123. int vfs_file_is_local (const char *filename)
  1124. {
  1125. return vfs_file_class_flags (filename) & VFSF_LOCAL;
  1126. }