vfs.c 31 KB

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