vfs.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  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 "lib/global.h"
  46. #include "lib/strutil.h"
  47. #include "src/wtools.h" /* message() */
  48. #include "src/main.h" /* print_vfs_message */
  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. #if defined(_AIX) && !defined(NAME_MAX)
  60. # define NAME_MAX FILENAME_MAX
  61. #endif
  62. /** They keep track of the current directory */
  63. static struct vfs_class *current_vfs;
  64. static char *current_dir;
  65. struct vfs_openfile {
  66. int handle;
  67. struct vfs_class *vclass;
  68. void *fsinfo;
  69. };
  70. struct vfs_dirinfo{
  71. DIR *info;
  72. GIConv converter;
  73. };
  74. static GPtrArray *vfs_openfiles;
  75. static long vfs_free_handle_list = -1;
  76. #define VFS_FIRST_HANDLE 100
  77. static struct vfs_class *localfs_class;
  78. static GString *vfs_str_buffer;
  79. static const char *supported_encodings[] = {
  80. "UTF8",
  81. "UTF-8",
  82. "BIG5",
  83. "ASCII",
  84. "ISO8859",
  85. "ISO-8859",
  86. "ISO_8859",
  87. "KOI8",
  88. "CP852",
  89. "CP866",
  90. "CP125",
  91. NULL
  92. };
  93. /** Create new VFS handle and put it to the list */
  94. static int
  95. vfs_new_handle (struct vfs_class *vclass, void *fsinfo)
  96. {
  97. struct vfs_openfile *h;
  98. h = g_new (struct vfs_openfile, 1);
  99. h->fsinfo = fsinfo;
  100. h->vclass = vclass;
  101. /* Allocate the first free handle */
  102. h->handle = vfs_free_handle_list;
  103. if (h->handle == -1) {
  104. /* No free allocated handles, allocate one */
  105. h->handle = vfs_openfiles->len;
  106. g_ptr_array_add (vfs_openfiles, h);
  107. } else {
  108. vfs_free_handle_list = (long) g_ptr_array_index (vfs_openfiles, vfs_free_handle_list);
  109. g_ptr_array_index (vfs_openfiles, h->handle) = h;
  110. }
  111. h->handle += VFS_FIRST_HANDLE;
  112. return h->handle;
  113. }
  114. /** Find VFS class by file handle */
  115. static struct vfs_class *
  116. vfs_op (int handle)
  117. {
  118. struct vfs_openfile *h;
  119. if (handle < VFS_FIRST_HANDLE ||
  120. (guint)(handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len)
  121. return NULL;
  122. h = (struct vfs_openfile *) g_ptr_array_index (
  123. vfs_openfiles, handle - VFS_FIRST_HANDLE);
  124. if (!h)
  125. return NULL;
  126. g_assert (h->handle == handle);
  127. return h->vclass;
  128. }
  129. /** Find private file data by file handle */
  130. static void *
  131. vfs_info (int handle)
  132. {
  133. struct vfs_openfile *h;
  134. if (handle < VFS_FIRST_HANDLE ||
  135. (guint)(handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len)
  136. return NULL;
  137. h = (struct vfs_openfile *) g_ptr_array_index (
  138. vfs_openfiles, handle - VFS_FIRST_HANDLE);
  139. if (!h)
  140. return NULL;
  141. g_assert (h->handle == handle);
  142. return h->fsinfo;
  143. }
  144. /** Free open file data for given file handle */
  145. static void
  146. vfs_free_handle (int handle)
  147. {
  148. if (handle < VFS_FIRST_HANDLE ||
  149. (guint)(handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len)
  150. return;
  151. g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE) =
  152. (void *) vfs_free_handle_list;
  153. vfs_free_handle_list = handle - VFS_FIRST_HANDLE;
  154. }
  155. static struct vfs_class *vfs_list;
  156. int
  157. vfs_register_class (struct vfs_class *vfs)
  158. {
  159. if (vfs->init) /* vfs has own initialization function */
  160. if (!(*vfs->init)(vfs)) /* but it failed */
  161. return 0;
  162. vfs->next = vfs_list;
  163. vfs_list = vfs;
  164. return 1;
  165. }
  166. /** Return VFS class for the given prefix */
  167. static struct vfs_class *
  168. vfs_prefix_to_class (char *prefix)
  169. {
  170. struct vfs_class *vfs;
  171. /* Avoid last class (localfs) that would accept any prefix */
  172. for (vfs = vfs_list; vfs->next; vfs = vfs->next) {
  173. if (vfs->which) {
  174. if ((*vfs->which) (vfs, prefix) == -1)
  175. continue;
  176. return vfs;
  177. }
  178. if (vfs->prefix
  179. && !strncmp (prefix, vfs->prefix, strlen (vfs->prefix)))
  180. return vfs;
  181. }
  182. return NULL;
  183. }
  184. /** Strip known vfs suffixes from a filename (possible improvement: strip
  185. * suffix from last path component).
  186. * \return a malloced string which has to be freed.
  187. */
  188. char *
  189. vfs_strip_suffix_from_filename (const char *filename)
  190. {
  191. struct vfs_class *vfs;
  192. char *semi;
  193. char *p;
  194. if (!filename)
  195. vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
  196. p = g_strdup (filename);
  197. if (!(semi = strrchr (p, '#')))
  198. return p;
  199. /* Avoid last class (localfs) that would accept any prefix */
  200. for (vfs = vfs_list; vfs->next; vfs = vfs->next) {
  201. if (vfs->which) {
  202. if ((*vfs->which) (vfs, semi + 1) == -1)
  203. continue;
  204. *semi = '\0'; /* Found valid suffix */
  205. return p;
  206. }
  207. if (vfs->prefix
  208. && !strncmp (semi + 1, vfs->prefix, strlen (vfs->prefix))) {
  209. *semi = '\0'; /* Found valid suffix */
  210. return p;
  211. }
  212. }
  213. return p;
  214. }
  215. static int
  216. path_magic (const char *path)
  217. {
  218. struct stat buf;
  219. if (!stat(path, &buf))
  220. return 0;
  221. return 1;
  222. }
  223. /**
  224. * Splits path extracting vfs part.
  225. *
  226. * Splits path
  227. * \verbatim /p1#op/inpath \endverbatim
  228. * into
  229. * \verbatim inpath,op; \endverbatim
  230. * returns which vfs it is.
  231. * What is left in path is p1. You still want to g_free(path), you DON'T
  232. * want to free neither *inpath nor *op
  233. */
  234. struct vfs_class *
  235. vfs_split (char *path, char **inpath, char **op)
  236. {
  237. char *semi;
  238. char *slash;
  239. struct vfs_class *ret;
  240. if (!path)
  241. vfs_die("Cannot split NULL");
  242. semi = strrchr (path, '#');
  243. if (!semi || !path_magic(path))
  244. return NULL;
  245. slash = strchr (semi, PATH_SEP);
  246. *semi = 0;
  247. if (op)
  248. *op = NULL;
  249. if (inpath)
  250. *inpath = NULL;
  251. if (slash)
  252. *slash = 0;
  253. if ((ret = vfs_prefix_to_class (semi+1))){
  254. if (op)
  255. *op = semi + 1;
  256. if (inpath)
  257. *inpath = slash ? slash + 1 : NULL;
  258. return ret;
  259. }
  260. if (slash)
  261. *slash = PATH_SEP;
  262. ret = vfs_split (path, inpath, op);
  263. *semi = '#';
  264. return ret;
  265. }
  266. static struct vfs_class *
  267. _vfs_get_class (char *path)
  268. {
  269. char *semi;
  270. char *slash;
  271. struct vfs_class *ret;
  272. g_return_val_if_fail(path, NULL);
  273. semi = strrchr (path, '#');
  274. if (!semi || !path_magic (path))
  275. return NULL;
  276. slash = strchr (semi, PATH_SEP);
  277. *semi = 0;
  278. if (slash)
  279. *slash = 0;
  280. ret = vfs_prefix_to_class (semi+1);
  281. if (slash)
  282. *slash = PATH_SEP;
  283. if (!ret)
  284. ret = _vfs_get_class (path);
  285. *semi = '#';
  286. return ret;
  287. }
  288. struct vfs_class *
  289. vfs_get_class (const char *pathname)
  290. {
  291. struct vfs_class *vfs;
  292. char *path = g_strdup (pathname);
  293. vfs = _vfs_get_class (path);
  294. g_free (path);
  295. if (!vfs)
  296. vfs = localfs_class;
  297. return vfs;
  298. }
  299. const char *
  300. vfs_get_encoding (const char *path)
  301. {
  302. static char result[16];
  303. char *work;
  304. char *semi;
  305. char *slash;
  306. work = g_strdup (path);
  307. semi = g_strrstr (work, "#enc:");
  308. if (semi != NULL) {
  309. semi+= 5 * sizeof (char);
  310. slash = strchr (semi, PATH_SEP);
  311. if (slash != NULL)
  312. slash[0] = '\0';
  313. g_strlcpy (result, semi, sizeof(result));
  314. g_free (work);
  315. return result;
  316. } else {
  317. g_free (work);
  318. return NULL;
  319. }
  320. }
  321. /* return if encoding can by used in vfs (is ascci full compactible) */
  322. /* contains only a few encoding now */
  323. static int
  324. vfs_supported_enconding (const char *encoding) {
  325. int t;
  326. int result = 0;
  327. for (t = 0; supported_encodings[t] != NULL; t++) {
  328. result+= (g_ascii_strncasecmp (encoding, supported_encodings[t],
  329. strlen (supported_encodings[t])) == 0);
  330. }
  331. return result;
  332. }
  333. /* now used only by vfs_translate_path, but could be used in other vfs
  334. * plugin to automatic detect encoding
  335. * path - path to translate
  336. * size - how many bytes from path translate
  337. * defcnv - convertor, that is used as default, when path does not contain any
  338. * #enc: subtring
  339. * buffer - used to store result of translation
  340. */
  341. static estr_t
  342. _vfs_translate_path (const char *path, int size,
  343. GIConv defcnv, GString *buffer)
  344. {
  345. const char *semi;
  346. const char *ps;
  347. const char *slash;
  348. estr_t state = ESTR_SUCCESS;
  349. static char encoding[16];
  350. GIConv coder;
  351. int ms;
  352. if (size == 0) return 0;
  353. size = ( size > 0) ? size : (signed int)strlen (path);
  354. /* try found #end: */
  355. semi = g_strrstr_len (path, size, "#enc:");
  356. if (semi != NULL) {
  357. /* first must be translated part before #enc: */
  358. ms = semi - path;
  359. /* remove '/' before #enc */
  360. ps = str_cget_prev_char (semi);
  361. if (ps[0] == PATH_SEP) ms = ps - path;
  362. state = _vfs_translate_path (path, ms, defcnv, buffer);
  363. if (state != ESTR_SUCCESS)
  364. return state;
  365. /* now can be translated part after #enc: */
  366. semi+= 5;
  367. slash = strchr (semi, PATH_SEP);
  368. /* ignore slashes after size; */
  369. if (slash - path >= size) slash = NULL;
  370. ms = (slash != NULL) ? slash - semi : (int) strlen (semi);
  371. ms = min ((unsigned int) ms, sizeof (encoding) - 1);
  372. /* limit encoding size (ms) to path size (size) */
  373. if (semi + ms > path + size) ms = path + size - semi;
  374. memcpy (encoding, semi, ms);
  375. encoding[ms] = '\0';
  376. switch (vfs_supported_enconding (encoding)) {
  377. case 1:
  378. coder = str_crt_conv_to (encoding);
  379. if (coder != INVALID_CONV) {
  380. if (slash != NULL) {
  381. state = str_vfs_convert_to (coder, slash,
  382. path + size - slash, buffer);
  383. } else if (buffer->str[0] == '\0') {
  384. /* exmaple "/#enc:utf-8" */
  385. g_string_append_c(buffer, PATH_SEP);
  386. }
  387. str_close_conv (coder);
  388. return state;
  389. } else {
  390. errno = EINVAL;
  391. return ESTR_FAILURE;
  392. }
  393. break;
  394. default:
  395. errno = EINVAL;
  396. return ESTR_FAILURE;
  397. }
  398. } else {
  399. /* path can be translated whole at once */
  400. state = str_vfs_convert_to (defcnv, path, size, buffer);
  401. return state;
  402. }
  403. return ESTR_SUCCESS;
  404. }
  405. char *
  406. vfs_translate_path (const char *path)
  407. {
  408. estr_t state;
  409. g_string_set_size(vfs_str_buffer,0);
  410. state = _vfs_translate_path (path, -1, str_cnv_from_term, vfs_str_buffer);
  411. /*
  412. strict version
  413. return (state == 0) ? vfs_str_buffer->data : NULL;
  414. */
  415. return (state != ESTR_FAILURE) ? vfs_str_buffer->str : NULL;
  416. }
  417. char *
  418. vfs_translate_path_n (const char *path)
  419. {
  420. char *result;
  421. result = vfs_translate_path (path);
  422. return (result != NULL) ? g_strdup (result) : NULL;
  423. }
  424. char *
  425. vfs_canon_and_translate (const char *path)
  426. {
  427. char *canon;
  428. char *result;
  429. if (path == NULL)
  430. canon = g_strdup ("");
  431. else
  432. canon = vfs_canon (path);
  433. result = vfs_translate_path_n (canon);
  434. g_free (canon);
  435. return result;
  436. }
  437. static int
  438. ferrno (struct vfs_class *vfs)
  439. {
  440. return vfs->ferrno ? (*vfs->ferrno)(vfs) : E_UNKNOWN;
  441. /* Hope that error message is obscure enough ;-) */
  442. }
  443. int
  444. mc_open (const char *filename, int flags, ...)
  445. {
  446. int mode;
  447. void *info;
  448. va_list ap;
  449. char *file = vfs_canon_and_translate (filename);
  450. if (file != NULL) {
  451. struct vfs_class *vfs = vfs_get_class (file);
  452. /* Get the mode flag */
  453. if (flags & O_CREAT) {
  454. va_start (ap, flags);
  455. mode = va_arg (ap, int);
  456. va_end (ap);
  457. } else
  458. mode = 0;
  459. if (!vfs->open) {
  460. g_free (file);
  461. errno = -EOPNOTSUPP;
  462. return -1;
  463. }
  464. info = (*vfs->open) (vfs, file, flags, mode); /* open must be supported */
  465. g_free (file);
  466. if (!info){
  467. errno = ferrno (vfs);
  468. return -1;
  469. }
  470. return vfs_new_handle (vfs, info);
  471. } else return -1;
  472. }
  473. #define MC_NAMEOP(name, inarg, callarg) \
  474. int mc_##name inarg \
  475. { \
  476. struct vfs_class *vfs; \
  477. int result; \
  478. char *mpath = vfs_canon_and_translate (path); \
  479. if (mpath != NULL) { \
  480. vfs = vfs_get_class (mpath); \
  481. if (vfs == NULL){ \
  482. g_free (mpath); \
  483. return -1; \
  484. } \
  485. result = vfs->name ? (*vfs->name)callarg : -1; \
  486. g_free (mpath); \
  487. if (result == -1) \
  488. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  489. return result; \
  490. } else return -1; \
  491. }
  492. MC_NAMEOP (chmod, (const char *path, mode_t mode), (vfs, mpath, mode))
  493. MC_NAMEOP (chown, (const char *path, uid_t owner, gid_t group), (vfs, mpath, owner, group))
  494. MC_NAMEOP (utime, (const char *path, struct utimbuf *times), (vfs, mpath, times))
  495. MC_NAMEOP (readlink, (const char *path, char *buf, int bufsiz), (vfs, mpath, buf, bufsiz))
  496. MC_NAMEOP (unlink, (const char *path), (vfs, mpath))
  497. MC_NAMEOP (mkdir, (const char *path, mode_t mode), (vfs, mpath, mode))
  498. MC_NAMEOP (rmdir, (const char *path), (vfs, mpath))
  499. MC_NAMEOP (mknod, (const char *path, mode_t mode, dev_t dev), (vfs, mpath, mode, dev))
  500. int
  501. mc_symlink (const char *name1, const char *path)
  502. {
  503. struct vfs_class *vfs;
  504. int result;
  505. char *mpath;
  506. char *lpath;
  507. char *tmp;
  508. mpath = vfs_canon_and_translate (path);
  509. if (mpath != NULL) {
  510. tmp = g_strdup (name1);
  511. lpath = vfs_translate_path_n (tmp);
  512. g_free (tmp);
  513. if (lpath != NULL) {
  514. vfs = vfs_get_class (mpath);
  515. result = vfs->symlink ? (*vfs->symlink) (vfs, lpath, mpath) : -1;
  516. g_free (lpath);
  517. g_free (mpath);
  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. * (MAXNAMLEN + 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) + MAXNAMLEN + 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, MAXNAMLEN + 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 *trans;
  773. trans = vfs_translate_path_n (current_dir);
  774. if (_vfs_get_class (trans) == NULL) {
  775. const char *encoding = vfs_get_encoding (current_dir);
  776. if (encoding == NULL) {
  777. char *tmp;
  778. tmp = g_get_current_dir ();
  779. if (tmp != NULL) { /* One of the directories in the path is not readable */
  780. estr_t state;
  781. char *sys_cwd;
  782. g_string_set_size (vfs_str_buffer, 0);
  783. state = str_vfs_convert_from (str_cnv_from_term, tmp, vfs_str_buffer);
  784. g_free (tmp);
  785. sys_cwd = (state == ESTR_SUCCESS) ? g_strdup (vfs_str_buffer->str) : NULL;
  786. if (sys_cwd != NULL) {
  787. struct stat my_stat, my_stat2;
  788. /* Check if it is O.K. to use the current_dir */
  789. if (cd_symlinks
  790. && mc_stat (sys_cwd, &my_stat) == 0
  791. && mc_stat (current_dir, &my_stat2) == 0
  792. && my_stat.st_ino == my_stat2.st_ino
  793. && my_stat.st_dev == my_stat2.st_dev)
  794. g_free (sys_cwd);
  795. else {
  796. g_free (current_dir);
  797. current_dir = sys_cwd;
  798. }
  799. }
  800. }
  801. }
  802. }
  803. g_free (trans);
  804. return current_dir;
  805. }
  806. static void
  807. vfs_setup_wd (void)
  808. {
  809. current_dir = g_strdup (PATH_SEP_STR);
  810. _vfs_get_cwd ();
  811. if (strlen (current_dir) > MC_MAXPATHLEN - 2)
  812. vfs_die ("Current dir too long.\n");
  813. current_vfs = vfs_get_class (current_dir);
  814. }
  815. /**
  816. * Return current directory. If it's local, reread the current directory
  817. * from the OS. Put directory to the provided buffer.
  818. */
  819. char *
  820. mc_get_current_wd (char *buffer, int size)
  821. {
  822. const char *cwd = _vfs_get_cwd ();
  823. g_strlcpy (buffer, cwd, size);
  824. return buffer;
  825. }
  826. /**
  827. * Return current directory without any OS calls.
  828. */
  829. char *
  830. vfs_get_current_dir (void)
  831. {
  832. return current_dir;
  833. }
  834. off_t mc_lseek (int fd, off_t offset, int whence)
  835. {
  836. struct vfs_class *vfs;
  837. int result;
  838. if (fd == -1)
  839. return -1;
  840. vfs = vfs_op (fd);
  841. if (vfs == NULL)
  842. return -1;
  843. result = vfs->lseek ? (*vfs->lseek)(vfs_info (fd), offset, whence) : -1;
  844. if (result == -1)
  845. errno = vfs->lseek ? ferrno (vfs) : E_NOTSUPP;
  846. return result;
  847. }
  848. /**
  849. * remove //, /./ and /../
  850. */
  851. #define ISSLASH(a) (!a || (a == '/'))
  852. char *
  853. vfs_canon (const char *path)
  854. {
  855. if (!path)
  856. vfs_die("Cannot canonicalize NULL");
  857. /* Relative to current directory */
  858. if (*path != PATH_SEP){
  859. char *local, *result;
  860. local = concat_dir_and_file (current_dir, path);
  861. result = vfs_canon (local);
  862. g_free (local);
  863. return result;
  864. }
  865. /*
  866. * So we have path of following form:
  867. * /p1/p2#op/.././././p3#op/p4. Good luck.
  868. */
  869. {
  870. char *result = g_strdup (path);
  871. canonicalize_pathname (result);
  872. return result;
  873. }
  874. }
  875. /**
  876. * VFS chdir.
  877. * Return 0 on success, -1 on failure.
  878. */
  879. int
  880. mc_chdir (const char *path)
  881. {
  882. char *new_dir;
  883. char *trans_dir;
  884. struct vfs_class *old_vfs, *new_vfs;
  885. vfsid old_vfsid;
  886. int result;
  887. new_dir = vfs_canon (path);
  888. trans_dir = vfs_translate_path_n (new_dir);
  889. if (trans_dir != NULL) {
  890. new_vfs = vfs_get_class (trans_dir);
  891. if (!new_vfs->chdir) {
  892. g_free (new_dir);
  893. g_free (trans_dir);
  894. return -1;
  895. }
  896. result = (*new_vfs->chdir) (new_vfs, trans_dir);
  897. if (result == -1) {
  898. errno = ferrno (new_vfs);
  899. g_free (new_dir);
  900. g_free (trans_dir);
  901. return -1;
  902. }
  903. old_vfsid = vfs_getid (current_vfs, current_dir);
  904. old_vfs = current_vfs;
  905. /* Actually change directory */
  906. g_free (current_dir);
  907. current_dir = new_dir;
  908. current_vfs = new_vfs;
  909. /* This function uses the new current_dir implicitly */
  910. vfs_stamp_create (old_vfs, old_vfsid);
  911. /* Sometimes we assume no trailing slash on cwd */
  912. if (*current_dir) {
  913. char *p;
  914. p = strchr (current_dir, 0) - 1;
  915. if (*p == PATH_SEP && p > current_dir)
  916. *p = 0;
  917. }
  918. g_free (trans_dir);
  919. return 0;
  920. } else {
  921. g_free (new_dir);
  922. return -1;
  923. }
  924. }
  925. /* Return 1 is the current VFS class is local */
  926. int
  927. vfs_current_is_local (void)
  928. {
  929. return (current_vfs->flags & VFSF_LOCAL) != 0;
  930. }
  931. /* Return flags of the VFS class of the given filename */
  932. int
  933. vfs_file_class_flags (const char *filename)
  934. {
  935. struct vfs_class *vfs;
  936. char *fname;
  937. fname = vfs_canon_and_translate (filename);
  938. if (fname != NULL) {
  939. vfs = vfs_get_class (fname);
  940. g_free (fname);
  941. return vfs->flags;
  942. } else return -1;
  943. }
  944. static char *
  945. mc_def_getlocalcopy (const char *filename)
  946. {
  947. char *tmp;
  948. int fdin, fdout;
  949. ssize_t i;
  950. char buffer[8192];
  951. struct stat mystat;
  952. fdin = mc_open (filename, O_RDONLY | O_LINEAR);
  953. if (fdin == -1)
  954. return NULL;
  955. fdout = vfs_mkstemps (&tmp, "vfs", filename);
  956. if (fdout == -1)
  957. goto fail;
  958. while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0) {
  959. if (write (fdout, buffer, i) != i)
  960. goto fail;
  961. }
  962. if (i == -1)
  963. goto fail;
  964. i = mc_close (fdin);
  965. fdin = -1;
  966. if (i == -1)
  967. goto fail;
  968. if (close (fdout) == -1) {
  969. fdout = -1;
  970. goto fail;
  971. }
  972. if (mc_stat (filename, &mystat) != -1) {
  973. chmod (tmp, mystat.st_mode);
  974. }
  975. return tmp;
  976. fail:
  977. if (fdout != -1)
  978. close (fdout);
  979. if (fdin != -1)
  980. mc_close (fdin);
  981. g_free (tmp);
  982. return NULL;
  983. }
  984. char *
  985. mc_getlocalcopy (const char *pathname)
  986. {
  987. char *result;
  988. char *path;
  989. path = vfs_canon_and_translate (pathname);
  990. if (path != NULL) {
  991. struct vfs_class *vfs = vfs_get_class (path);
  992. result = vfs->getlocalcopy ? (*vfs->getlocalcopy)(vfs, path) :
  993. mc_def_getlocalcopy (path);
  994. g_free (path);
  995. if (!result)
  996. errno = ferrno (vfs);
  997. return result;
  998. } else return NULL;
  999. }
  1000. static int
  1001. mc_def_ungetlocalcopy (struct vfs_class *vfs, const char *filename,
  1002. const char *local, int has_changed)
  1003. {
  1004. int fdin = -1, fdout = -1, i;
  1005. if (has_changed) {
  1006. char buffer[8192];
  1007. if (!vfs->write)
  1008. goto failed;
  1009. fdin = open (local, O_RDONLY);
  1010. if (fdin == -1)
  1011. goto failed;
  1012. fdout = mc_open (filename, O_WRONLY | O_TRUNC);
  1013. if (fdout == -1)
  1014. goto failed;
  1015. while ((i = read (fdin, buffer, sizeof (buffer))) > 0) {
  1016. if (mc_write (fdout, buffer, i) != i)
  1017. goto failed;
  1018. }
  1019. if (i == -1)
  1020. goto failed;
  1021. if (close (fdin) == -1) {
  1022. fdin = -1;
  1023. goto failed;
  1024. }
  1025. fdin = -1;
  1026. if (mc_close (fdout) == -1) {
  1027. fdout = -1;
  1028. goto failed;
  1029. }
  1030. }
  1031. unlink (local);
  1032. return 0;
  1033. failed:
  1034. message (D_ERROR, _("Changes to file lost"), "%s", filename);
  1035. if (fdout != -1)
  1036. mc_close (fdout);
  1037. if (fdin != -1)
  1038. close (fdin);
  1039. unlink (local);
  1040. return -1;
  1041. }
  1042. int
  1043. mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed)
  1044. {
  1045. int return_value = 0;
  1046. char *path;
  1047. path = vfs_canon_and_translate (pathname);
  1048. if (path != NULL) {
  1049. struct vfs_class *vfs = vfs_get_class (path);
  1050. return_value = vfs->ungetlocalcopy ?
  1051. (*vfs->ungetlocalcopy)(vfs, path, local, has_changed) :
  1052. mc_def_ungetlocalcopy (vfs, path, local, has_changed);
  1053. g_free (path);
  1054. return return_value;
  1055. } else return -1;
  1056. }
  1057. void
  1058. vfs_init (void)
  1059. {
  1060. /* create the VFS handle array */
  1061. vfs_openfiles = g_ptr_array_new ();
  1062. vfs_str_buffer = g_string_new("");
  1063. /* localfs needs to be the first one */
  1064. init_localfs();
  1065. /* fallback value for vfs_get_class() */
  1066. localfs_class = vfs_list;
  1067. init_extfs ();
  1068. init_sfs ();
  1069. init_tarfs ();
  1070. init_cpiofs ();
  1071. #ifdef USE_EXT2FSLIB
  1072. init_undelfs ();
  1073. #endif /* USE_EXT2FSLIB */
  1074. #ifdef USE_NETCODE
  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. }