vfs.c 31 KB

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