vfs.c 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286
  1. /* Virtual File System switch code
  2. Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  3. 2007 Free Software Foundation, Inc.
  4. Written by: 1995 Miguel de Icaza
  5. 1995 Jakub Jelinek
  6. 1998 Pavel Machek
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public License
  9. as published by the Free Software Foundation; either version 2 of
  10. the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public
  16. License along with this program; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  18. /* Warning: funtions like extfs_lstat() have right to destroy any
  19. * strings you pass to them. This is acutally ok as you g_strdup what
  20. * you are passing to them, anyway; still, beware. */
  21. /* Namespace: exports *many* functions with vfs_ prefix; exports
  22. parse_ls_lga and friends which do not have that prefix. */
  23. #include <config.h>
  24. #include <stdio.h>
  25. #include <stdlib.h> /* For atol() */
  26. #include <stdarg.h>
  27. #include <string.h>
  28. #include <errno.h>
  29. #include <sys/types.h>
  30. #include <signal.h>
  31. #include <ctype.h> /* is_digit() */
  32. #include "../src/global.h"
  33. #include "../src/tty.h" /* enable/disable interrupt key */
  34. #include "../src/wtools.h" /* message() */
  35. #include "../src/main.h" /* print_vfs_message */
  36. #include "../src/strutil.h"
  37. #include "utilvfs.h"
  38. #include "gc.h"
  39. #include "vfs.h"
  40. #ifdef USE_NETCODE
  41. # include "tcputil.h"
  42. #endif
  43. #include "ftpfs.h"
  44. #include "mcfs.h"
  45. #include "smbfs.h"
  46. #include "local.h"
  47. /* They keep track of the current directory */
  48. static struct vfs_class *current_vfs;
  49. static char *current_dir;
  50. struct vfs_openfile {
  51. int handle;
  52. struct vfs_class *vclass;
  53. void *fsinfo;
  54. };
  55. struct vfs_dirinfo{
  56. DIR *info;
  57. GIConv converter;
  58. };
  59. static GSList *vfs_openfiles;
  60. #define VFS_FIRST_HANDLE 100
  61. static struct vfs_class *localfs_class;
  62. static GString *vfs_str_buffer;
  63. static const char *supported_encodings[] = {
  64. "UTF8",
  65. "UTF-8",
  66. "BIG5",
  67. "ASCII",
  68. "ISO8859",
  69. "ISO-8859",
  70. "ISO_8859",
  71. "KOI8",
  72. "CP852",
  73. "CP866",
  74. "CP125",
  75. NULL
  76. };
  77. /* Create new VFS handle and put it to the list */
  78. static int
  79. vfs_new_handle (struct vfs_class *vclass, void *fsinfo)
  80. {
  81. static int vfs_handle_counter = VFS_FIRST_HANDLE;
  82. struct vfs_openfile *h;
  83. h = g_new (struct vfs_openfile, 1);
  84. h->handle = vfs_handle_counter++;
  85. h->fsinfo = fsinfo;
  86. h->vclass = vclass;
  87. vfs_openfiles = g_slist_prepend (vfs_openfiles, h);
  88. return h->handle;
  89. }
  90. /* Function to match handle, passed to g_slist_find_custom() */
  91. static gint
  92. vfs_cmp_handle (gconstpointer a, gconstpointer b)
  93. {
  94. if (!a)
  95. return 1;
  96. return ((struct vfs_openfile *) a)->handle != (long) b;
  97. }
  98. /* Find VFS class by file handle */
  99. static inline struct vfs_class *
  100. vfs_op (int handle)
  101. {
  102. GSList *l;
  103. struct vfs_openfile *h;
  104. l = g_slist_find_custom (vfs_openfiles, (void *) (long) handle,
  105. vfs_cmp_handle);
  106. if (!l)
  107. return NULL;
  108. h = (struct vfs_openfile *) l->data;
  109. if (!h)
  110. return NULL;
  111. return h->vclass;
  112. }
  113. /* Find private file data by file handle */
  114. static inline void *
  115. vfs_info (int handle)
  116. {
  117. GSList *l;
  118. struct vfs_openfile *h;
  119. l = g_slist_find_custom (vfs_openfiles, (void *) (long) handle,
  120. vfs_cmp_handle);
  121. if (!l)
  122. return NULL;
  123. h = (struct vfs_openfile *) l->data;
  124. if (!h)
  125. return NULL;
  126. return h->fsinfo;
  127. }
  128. /* Free open file data for given file handle */
  129. static inline void
  130. vfs_free_handle (int handle)
  131. {
  132. GSList *l;
  133. l = g_slist_find_custom (vfs_openfiles, (void *) (long) handle,
  134. vfs_cmp_handle);
  135. vfs_openfiles = g_slist_delete_link (vfs_openfiles, l);
  136. }
  137. static struct vfs_class *vfs_list;
  138. int
  139. vfs_register_class (struct vfs_class *vfs)
  140. {
  141. if (vfs->init) /* vfs has own initialization function */
  142. if (!(*vfs->init)(vfs)) /* but it failed */
  143. return 0;
  144. vfs->next = vfs_list;
  145. vfs_list = vfs;
  146. return 1;
  147. }
  148. /* Return VFS class for the given prefix */
  149. static struct vfs_class *
  150. vfs_prefix_to_class (char *prefix)
  151. {
  152. struct vfs_class *vfs;
  153. /* Avoid last class (localfs) that would accept any prefix */
  154. for (vfs = vfs_list; vfs->next; vfs = vfs->next) {
  155. if (vfs->which) {
  156. if ((*vfs->which) (vfs, prefix) == -1)
  157. continue;
  158. return vfs;
  159. }
  160. if (vfs->prefix
  161. && !strncmp (prefix, vfs->prefix, strlen (vfs->prefix)))
  162. return vfs;
  163. }
  164. return NULL;
  165. }
  166. /* Strip known vfs suffixes from a filename (possible improvement: strip
  167. suffix from last path component).
  168. Returns a malloced string which has to be freed. */
  169. char *
  170. vfs_strip_suffix_from_filename (const char *filename)
  171. {
  172. struct vfs_class *vfs;
  173. char *semi;
  174. char *p;
  175. if (!filename)
  176. vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
  177. p = g_strdup (filename);
  178. if (!(semi = strrchr (p, '#')))
  179. return p;
  180. /* Avoid last class (localfs) that would accept any prefix */
  181. for (vfs = vfs_list; vfs->next; vfs = vfs->next) {
  182. if (vfs->which) {
  183. if ((*vfs->which) (vfs, semi + 1) == -1)
  184. continue;
  185. *semi = '\0'; /* Found valid suffix */
  186. return p;
  187. }
  188. if (vfs->prefix
  189. && !strncmp (semi + 1, vfs->prefix, strlen (vfs->prefix))) {
  190. *semi = '\0'; /* Found valid suffix */
  191. return p;
  192. }
  193. }
  194. return p;
  195. }
  196. static inline int
  197. path_magic (const char *path)
  198. {
  199. struct stat buf;
  200. if (!stat(path, &buf))
  201. return 0;
  202. return 1;
  203. }
  204. /*
  205. * Splits path '/p1#op/inpath' into inpath,op; returns which vfs it is.
  206. * What is left in path is p1. You still want to g_free(path), you DON'T
  207. * want to free neither *inpath nor *op
  208. */
  209. struct vfs_class *
  210. vfs_split (char *path, char **inpath, char **op)
  211. {
  212. char *semi;
  213. char *slash;
  214. struct vfs_class *ret;
  215. if (!path)
  216. vfs_die("Cannot split NULL");
  217. semi = strrchr (path, '#');
  218. if (!semi || !path_magic(path))
  219. return NULL;
  220. slash = strchr (semi, PATH_SEP);
  221. *semi = 0;
  222. if (op)
  223. *op = NULL;
  224. if (inpath)
  225. *inpath = NULL;
  226. if (slash)
  227. *slash = 0;
  228. if ((ret = vfs_prefix_to_class (semi+1))){
  229. if (op)
  230. *op = semi + 1;
  231. if (inpath)
  232. *inpath = slash ? slash + 1 : NULL;
  233. return ret;
  234. }
  235. if (slash)
  236. *slash = PATH_SEP;
  237. ret = vfs_split (path, inpath, op);
  238. *semi = '#';
  239. return ret;
  240. }
  241. static struct vfs_class *
  242. _vfs_get_class (char *path)
  243. {
  244. char *semi;
  245. char *slash;
  246. struct vfs_class *ret;
  247. g_return_val_if_fail(path, NULL);
  248. semi = strrchr (path, '#');
  249. if (!semi || !path_magic (path))
  250. return NULL;
  251. slash = strchr (semi, PATH_SEP);
  252. *semi = 0;
  253. if (slash)
  254. *slash = 0;
  255. ret = vfs_prefix_to_class (semi+1);
  256. if (slash)
  257. *slash = PATH_SEP;
  258. if (!ret)
  259. ret = _vfs_get_class (path);
  260. *semi = '#';
  261. return ret;
  262. }
  263. struct vfs_class *
  264. vfs_get_class (const char *pathname)
  265. {
  266. struct vfs_class *vfs;
  267. char *path = g_strdup (pathname);
  268. vfs = _vfs_get_class (path);
  269. g_free (path);
  270. if (!vfs)
  271. vfs = localfs_class;
  272. return vfs;
  273. }
  274. const char *
  275. vfs_get_encoding (const char *path)
  276. {
  277. static char result[16];
  278. char *work;
  279. char *semi;
  280. char *slash;
  281. work = g_strdup (path);
  282. semi = g_strrstr (work, "#enc:");
  283. if (semi != NULL) {
  284. semi+= 5 * sizeof (char);
  285. slash = strchr (semi, PATH_SEP);
  286. if (slash != NULL)
  287. slash[0] = '\0';
  288. g_strlcpy (result, semi, sizeof(result));
  289. g_free (work);
  290. return result;
  291. } else {
  292. g_free (work);
  293. return NULL;
  294. }
  295. }
  296. /* return if encoding can by used in vfs (is ascci full compactible) */
  297. /* contains only a few encoding now */
  298. static int
  299. vfs_supported_enconding (const char *encoding) {
  300. int t;
  301. int result = 0;
  302. for (t = 0; supported_encodings[t] != NULL; t++) {
  303. result+= (g_ascii_strncasecmp (encoding, supported_encodings[t],
  304. strlen (supported_encodings[t])) == 0);
  305. }
  306. return result;
  307. }
  308. /* now used only by vfs_translate_path, but could be used in other vfs
  309. * plugin to automatic detect encoding
  310. * path - path to translate
  311. * size - how many bytes from path translate
  312. * defcnv - convertor, that is used as default, when path does not contain any
  313. * #enc: subtring
  314. * buffer - used to store result of translation
  315. */
  316. static estr_t
  317. _vfs_translate_path (const char *path, int size,
  318. GIConv defcnv, GString *buffer)
  319. {
  320. const char *semi;
  321. const char *ps;
  322. const char *slash;
  323. estr_t state = ESTR_SUCCESS;
  324. static char encoding[16];
  325. GIConv coder;
  326. int ms;
  327. if (size == 0) return 0;
  328. size = ( size > 0) ? size : (signed int)strlen (path);
  329. /* try found #end: */
  330. semi = g_strrstr_len (path, size, "#enc:");
  331. if (semi != NULL) {
  332. /* first must be translated part before #enc: */
  333. ms = semi - path;
  334. /* remove '/' before #enc */
  335. ps = str_cget_prev_char (semi);
  336. if (ps[0] == PATH_SEP) ms = ps - path;
  337. state = _vfs_translate_path (path, ms, defcnv, buffer);
  338. if (state != ESTR_SUCCESS)
  339. return state;
  340. /* now can be translated part after #enc: */
  341. semi+= 5;
  342. slash = strchr (semi, PATH_SEP);
  343. /* ignore slashes after size; */
  344. if (slash - path >= size) slash = NULL;
  345. ms = (slash != NULL) ? slash - semi : (int) strlen (semi);
  346. ms = min ((unsigned int) ms, sizeof (encoding) - 1);
  347. /* limit encoding size (ms) to path size (size) */
  348. if (semi + ms > path + size) ms = path + size - semi;
  349. memcpy (encoding, semi, ms);
  350. encoding[ms] = '\0';
  351. switch (vfs_supported_enconding (encoding)) {
  352. case 1:
  353. coder = str_crt_conv_to (encoding);
  354. if (coder != INVALID_CONV) {
  355. if (slash != NULL) {
  356. state = str_vfs_convert_to (coder, slash,
  357. path + size - slash, buffer);
  358. } else if (buffer->str[0] == '\0') {
  359. /* exmaple "/#enc:utf-8" */
  360. g_string_append_c(buffer, PATH_SEP);
  361. }
  362. str_close_conv (coder);
  363. return state;
  364. } else {
  365. errno = EINVAL;
  366. return ESTR_FAILURE;
  367. }
  368. break;
  369. default:
  370. errno = EINVAL;
  371. return ESTR_FAILURE;
  372. }
  373. } else {
  374. /* path can be translated whole at once */
  375. state = str_vfs_convert_to (defcnv, path, size, buffer);
  376. return state;
  377. }
  378. return ESTR_SUCCESS;
  379. }
  380. char *
  381. vfs_translate_path (const char *path)
  382. {
  383. estr_t state;
  384. g_string_set_size(vfs_str_buffer,0);
  385. state = _vfs_translate_path (path, -1, str_cnv_from_term, vfs_str_buffer);
  386. /*
  387. strict version
  388. return (state == 0) ? vfs_str_buffer->data : NULL;
  389. */
  390. return (state != ESTR_FAILURE) ? vfs_str_buffer->str : NULL;
  391. }
  392. char *
  393. vfs_translate_path_n (const char *path)
  394. {
  395. char *result;
  396. result = vfs_translate_path (path);
  397. return (result != NULL) ? g_strdup (result) : NULL;
  398. }
  399. char *
  400. vfs_canon_and_translate (const char *path)
  401. {
  402. char *canon;
  403. char *result;
  404. canon = vfs_canon (path);
  405. result = vfs_translate_path_n (canon);
  406. g_free (canon);
  407. return result;
  408. }
  409. static int
  410. ferrno (struct vfs_class *vfs)
  411. {
  412. return vfs->ferrno ? (*vfs->ferrno)(vfs) : E_UNKNOWN;
  413. /* Hope that error message is obscure enough ;-) */
  414. }
  415. int
  416. mc_open (const char *filename, int flags, ...)
  417. {
  418. int mode;
  419. void *info;
  420. va_list ap;
  421. char *file = vfs_canon_and_translate (filename);
  422. if (file != NULL) {
  423. struct vfs_class *vfs = vfs_get_class (file);
  424. /* Get the mode flag */
  425. if (flags & O_CREAT) {
  426. va_start (ap, flags);
  427. mode = va_arg (ap, int);
  428. va_end (ap);
  429. } else
  430. mode = 0;
  431. if (!vfs->open) {
  432. g_free (file);
  433. errno = -EOPNOTSUPP;
  434. return -1;
  435. }
  436. info = (*vfs->open) (vfs, file, flags, mode); /* open must be supported */
  437. g_free (file);
  438. if (!info){
  439. errno = ferrno (vfs);
  440. return -1;
  441. }
  442. return vfs_new_handle (vfs, info);
  443. } else return -1;
  444. }
  445. #define MC_NAMEOP(name, inarg, callarg) \
  446. int mc_##name inarg \
  447. { \
  448. struct vfs_class *vfs; \
  449. int result; \
  450. char *mpath = vfs_canon_and_translate (path); \
  451. if (mpath != NULL) { \
  452. vfs = vfs_get_class (mpath); \
  453. result = vfs->name ? (*vfs->name)callarg : -1; \
  454. g_free (mpath); \
  455. if (result == -1) \
  456. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  457. return result; \
  458. } else return -1; \
  459. }
  460. MC_NAMEOP (chmod, (const char *path, mode_t mode), (vfs, mpath, mode))
  461. MC_NAMEOP (chown, (const char *path, uid_t owner, gid_t group), (vfs, mpath, owner, group))
  462. MC_NAMEOP (utime, (const char *path, struct utimbuf *times), (vfs, mpath, times))
  463. MC_NAMEOP (readlink, (const char *path, char *buf, int bufsiz), (vfs, mpath, buf, bufsiz))
  464. MC_NAMEOP (unlink, (const char *path), (vfs, mpath))
  465. MC_NAMEOP (mkdir, (const char *path, mode_t mode), (vfs, mpath, mode))
  466. MC_NAMEOP (rmdir, (const char *path), (vfs, mpath))
  467. MC_NAMEOP (mknod, (const char *path, mode_t mode, dev_t dev), (vfs, mpath, mode, dev))
  468. int
  469. mc_symlink (const char *name1, const char *path)
  470. {
  471. struct vfs_class *vfs;
  472. int result;
  473. char *mpath;
  474. char *lpath;
  475. char *tmp;
  476. mpath = vfs_canon_and_translate (path);
  477. if (mpath != NULL) {
  478. tmp = g_strdup (name1);
  479. lpath = vfs_translate_path_n (tmp);
  480. g_free (tmp);
  481. if (lpath != NULL) {
  482. vfs = vfs_get_class (mpath);
  483. result = vfs->symlink ? (*vfs->symlink) (vfs, lpath, mpath) : -1;
  484. g_free (lpath);
  485. if (result == -1)
  486. errno = vfs->symlink ? ferrno (vfs) : E_NOTSUPP;
  487. return result;
  488. }
  489. g_free (mpath);
  490. }
  491. return -1;
  492. }
  493. #define MC_HANDLEOP(name, inarg, callarg) \
  494. ssize_t mc_##name inarg \
  495. { \
  496. struct vfs_class *vfs; \
  497. int result; \
  498. if (handle == -1) \
  499. return -1; \
  500. vfs = vfs_op (handle); \
  501. result = vfs->name ? (*vfs->name)callarg : -1; \
  502. if (result == -1) \
  503. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  504. return result; \
  505. }
  506. MC_HANDLEOP(read, (int handle, void *buffer, int count), (vfs_info (handle), buffer, count))
  507. MC_HANDLEOP(write, (int handle, const void *buf, int nbyte), (vfs_info (handle), buf, nbyte))
  508. #define MC_RENAMEOP(name) \
  509. int mc_##name (const char *fname1, const char *fname2) \
  510. { \
  511. struct vfs_class *vfs; \
  512. int result; \
  513. char *name2, *name1; \
  514. name1 = vfs_canon_and_translate (fname1); \
  515. if (name1 != NULL) { \
  516. name2 = vfs_canon_and_translate (fname2); \
  517. if (name2 != NULL) { \
  518. vfs = vfs_get_class (name1); \
  519. if (vfs != vfs_get_class (name2)){ \
  520. errno = EXDEV; \
  521. g_free (name1); \
  522. g_free (name2); \
  523. return -1; \
  524. } \
  525. result = vfs->name ? (*vfs->name)(vfs, name1, name2) : -1; \
  526. g_free (name1); \
  527. g_free (name2); \
  528. if (result == -1) \
  529. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
  530. return result; \
  531. } else { \
  532. g_free (name1); \
  533. return -1; \
  534. } \
  535. } else return -1; \
  536. }
  537. MC_RENAMEOP (link)
  538. MC_RENAMEOP (rename)
  539. int
  540. mc_ctl (int handle, int ctlop, void *arg)
  541. {
  542. struct vfs_class *vfs = vfs_op (handle);
  543. return vfs->ctl ? (*vfs->ctl)(vfs_info (handle), ctlop, arg) : 0;
  544. }
  545. int
  546. mc_setctl (const char *path, int ctlop, void *arg)
  547. {
  548. struct vfs_class *vfs;
  549. int result;
  550. char *mpath;
  551. if (!path)
  552. vfs_die("You don't want to pass NULL to mc_setctl.");
  553. mpath = vfs_canon_and_translate (path);
  554. if (mpath != NULL) {
  555. vfs = vfs_get_class (mpath);
  556. result = vfs->setctl ? (*vfs->setctl)(vfs, mpath, ctlop, arg) : 0;
  557. g_free (mpath);
  558. return result;
  559. } else return -1;
  560. }
  561. int
  562. mc_close (int handle)
  563. {
  564. struct vfs_class *vfs;
  565. int result;
  566. if (handle == -1 || !vfs_info (handle))
  567. return -1;
  568. vfs = vfs_op (handle);
  569. if (handle < 3)
  570. return close (handle);
  571. if (!vfs->close)
  572. vfs_die ("VFS must support close.\n");
  573. result = (*vfs->close)(vfs_info (handle));
  574. vfs_free_handle (handle);
  575. if (result == -1)
  576. errno = ferrno (vfs);
  577. return result;
  578. }
  579. DIR *
  580. mc_opendir (const char *dirname)
  581. {
  582. int handle, *handlep;
  583. void *info;
  584. struct vfs_class *vfs;
  585. char *canon;
  586. char *dname;
  587. struct vfs_dirinfo *dirinfo;
  588. const char *encoding;
  589. canon = vfs_canon (dirname);
  590. dname = vfs_translate_path_n (canon);
  591. if (dname != NULL) {
  592. vfs = vfs_get_class (dname);
  593. info = vfs->opendir ? (*vfs->opendir)(vfs, dname) : NULL;
  594. g_free (dname);
  595. if (!info){
  596. errno = vfs->opendir ? ferrno (vfs) : E_NOTSUPP;
  597. g_free (canon);
  598. return NULL;
  599. }
  600. dirinfo = g_new (struct vfs_dirinfo, 1);
  601. dirinfo->info = info;
  602. encoding = vfs_get_encoding (canon);
  603. g_free (canon);
  604. dirinfo->converter = (encoding != NULL) ? str_crt_conv_from (encoding) :
  605. str_cnv_from_term;
  606. if (dirinfo->converter == INVALID_CONV) dirinfo->converter =str_cnv_from_term;
  607. handle = vfs_new_handle (vfs, dirinfo);
  608. handlep = g_new (int, 1);
  609. *handlep = handle;
  610. return (DIR *) handlep;
  611. } else {
  612. g_free (canon);
  613. return NULL;
  614. }
  615. }
  616. static struct dirent * mc_readdir_result = NULL;
  617. struct dirent *
  618. mc_readdir (DIR *dirp)
  619. {
  620. int handle;
  621. struct vfs_class *vfs;
  622. struct dirent *entry = NULL;
  623. struct vfs_dirinfo *dirinfo;
  624. estr_t state;
  625. if (!mc_readdir_result)
  626. {
  627. /* We can't just allocate struct dirent as (see man dirent.h)
  628. * struct dirent has VERY nonnaive semantics of allocating
  629. * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
  630. * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
  631. * heap corrupter. So, allocate longliving dirent with at least
  632. * (NAME_MAX + 1) for d_name in it.
  633. * Strictly saying resulting dirent is unusable as we don't adjust internal
  634. * structures, holding dirent size. But we don't use it in libc infrastructure.
  635. * TODO: to make simpler homemade dirent-alike structure.
  636. */
  637. mc_readdir_result = (struct dirent *)malloc(sizeof(struct dirent *) + NAME_MAX + 1);
  638. }
  639. if (!dirp) {
  640. errno = EFAULT;
  641. return NULL;
  642. }
  643. handle = *(int *) dirp;
  644. vfs = vfs_op (handle);
  645. dirinfo = vfs_info (handle);
  646. if (vfs->readdir) {
  647. entry = (*vfs->readdir) (dirinfo->info);
  648. if (entry == NULL) return NULL;
  649. g_string_set_size(vfs_str_buffer,0);
  650. state = str_vfs_convert_from (dirinfo->converter,
  651. entry->d_name, vfs_str_buffer);
  652. mc_readdir_result->d_ino = entry->d_ino;
  653. g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, NAME_MAX + 1);
  654. }
  655. if (entry == NULL) errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP;
  656. return (entry != NULL) ? mc_readdir_result : NULL;
  657. }
  658. int
  659. mc_closedir (DIR *dirp)
  660. {
  661. int handle = *(int *) dirp;
  662. struct vfs_class *vfs = vfs_op (handle);
  663. int result;
  664. struct vfs_dirinfo *dirinfo;
  665. dirinfo = vfs_info (handle);
  666. if (dirinfo->converter != str_cnv_from_term) str_close_conv (dirinfo->converter);
  667. result = vfs->closedir ? (*vfs->closedir)(dirinfo->info) : -1;
  668. vfs_free_handle (handle);
  669. g_free (dirinfo);
  670. g_free (dirp);
  671. return result;
  672. }
  673. int mc_stat (const char *filename, struct stat *buf) {
  674. struct vfs_class *vfs;
  675. int result;
  676. char *path;
  677. path = vfs_canon_and_translate (filename);
  678. if (path != NULL) {
  679. vfs = vfs_get_class (path);
  680. result = vfs->stat ? (*vfs->stat) (vfs, path, buf) : -1;
  681. g_free (path);
  682. if (result == -1)
  683. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  684. return result;
  685. } else return -1;
  686. }
  687. int mc_lstat (const char *filename, struct stat *buf) {
  688. struct vfs_class *vfs;
  689. int result;
  690. char *path;
  691. path = vfs_canon_and_translate (filename);
  692. if (path != NULL) {
  693. vfs = vfs_get_class (path);
  694. result = vfs->lstat ? (*vfs->lstat) (vfs, path, buf) : -1;
  695. g_free (path);
  696. if (result == -1)
  697. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  698. return result;
  699. } else return -1;
  700. }
  701. int mc_fstat (int handle, struct stat *buf) {
  702. struct vfs_class *vfs;
  703. int result;
  704. if (handle == -1)
  705. return -1;
  706. vfs = vfs_op (handle);
  707. result = vfs->fstat ? (*vfs->fstat) (vfs_info (handle), buf) : -1;
  708. if (result == -1)
  709. errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
  710. return result;
  711. }
  712. /*
  713. * Return current directory. If it's local, reread the current directory
  714. * from the OS. You must g_strdup() whatever this function returns.
  715. */
  716. static const char *
  717. _vfs_get_cwd (void)
  718. {
  719. char *sys_cwd;
  720. char *trans;
  721. const char *encoding;
  722. char *tmp;
  723. estr_t state;
  724. struct stat my_stat, my_stat2;
  725. trans = vfs_translate_path_n (current_dir); /* add check if NULL */
  726. if (!_vfs_get_class (trans)) {
  727. encoding = vfs_get_encoding (current_dir);
  728. if (encoding == NULL) {
  729. tmp = g_get_current_dir ();
  730. if (tmp != NULL) { /* One of the directories in the path is not readable */
  731. g_string_set_size(vfs_str_buffer,0);
  732. state = str_vfs_convert_from (str_cnv_from_term, tmp, vfs_str_buffer);
  733. g_free (tmp);
  734. sys_cwd = (state == ESTR_SUCCESS) ? g_strdup (vfs_str_buffer->str) : NULL;
  735. if (!sys_cwd)
  736. return current_dir;
  737. /* Otherwise check if it is O.K. to use the current_dir */
  738. if (!cd_symlinks || mc_stat (sys_cwd, &my_stat)
  739. || mc_stat (current_dir, &my_stat2)
  740. || my_stat.st_ino != my_stat2.st_ino
  741. || my_stat.st_dev != my_stat2.st_dev) {
  742. g_free (current_dir);
  743. current_dir = sys_cwd;
  744. return sys_cwd;
  745. }/* Otherwise we return current_dir below */
  746. }
  747. }
  748. }
  749. g_free (trans);
  750. return current_dir;
  751. }
  752. static void
  753. vfs_setup_wd (void)
  754. {
  755. current_dir = g_strdup (PATH_SEP_STR);
  756. _vfs_get_cwd ();
  757. if (strlen (current_dir) > MC_MAXPATHLEN - 2)
  758. vfs_die ("Current dir too long.\n");
  759. current_vfs = vfs_get_class (current_dir);
  760. }
  761. /*
  762. * Return current directory. If it's local, reread the current directory
  763. * from the OS. Put directory to the provided buffer.
  764. */
  765. char *
  766. mc_get_current_wd (char *buffer, int size)
  767. {
  768. const char *cwd = _vfs_get_cwd ();
  769. g_strlcpy (buffer, cwd, size);
  770. return buffer;
  771. }
  772. /*
  773. * Return current directory without any OS calls.
  774. */
  775. char *
  776. vfs_get_current_dir (void)
  777. {
  778. return current_dir;
  779. }
  780. off_t mc_lseek (int fd, off_t offset, int whence)
  781. {
  782. struct vfs_class *vfs;
  783. int result;
  784. if (fd == -1)
  785. return -1;
  786. vfs = vfs_op (fd);
  787. result = vfs->lseek ? (*vfs->lseek)(vfs_info (fd), offset, whence) : -1;
  788. if (result == -1)
  789. errno = vfs->lseek ? ferrno (vfs) : E_NOTSUPP;
  790. return result;
  791. }
  792. /*
  793. * remove //, /./ and /../
  794. */
  795. #define ISSLASH(a) (!a || (a == '/'))
  796. char *
  797. vfs_canon (const char *path)
  798. {
  799. if (!path)
  800. vfs_die("Cannot canonicalize NULL");
  801. /* Relative to current directory */
  802. if (*path != PATH_SEP){
  803. char *local, *result;
  804. local = concat_dir_and_file (current_dir, path);
  805. result = vfs_canon (local);
  806. g_free (local);
  807. return result;
  808. }
  809. /*
  810. * So we have path of following form:
  811. * /p1/p2#op/.././././p3#op/p4. Good luck.
  812. */
  813. {
  814. char *result = g_strdup (path);
  815. canonicalize_pathname (result);
  816. return result;
  817. }
  818. }
  819. /*
  820. * VFS chdir.
  821. * Return 0 on success, -1 on failure.
  822. */
  823. int
  824. mc_chdir (const char *path)
  825. {
  826. char *new_dir;
  827. char *trans_dir;
  828. struct vfs_class *old_vfs, *new_vfs;
  829. vfsid old_vfsid;
  830. int result;
  831. new_dir = vfs_canon (path);
  832. trans_dir = vfs_translate_path_n (new_dir);
  833. if (trans_dir != NULL) {
  834. new_vfs = vfs_get_class (trans_dir);
  835. if (!new_vfs->chdir) {
  836. g_free (new_dir);
  837. g_free (trans_dir);
  838. return -1;
  839. }
  840. result = (*new_vfs->chdir) (new_vfs, trans_dir);
  841. if (result == -1) {
  842. errno = ferrno (new_vfs);
  843. g_free (new_dir);
  844. g_free (trans_dir);
  845. return -1;
  846. }
  847. old_vfsid = vfs_getid (current_vfs, current_dir);
  848. old_vfs = current_vfs;
  849. /* Actually change directory */
  850. g_free (current_dir);
  851. current_dir = new_dir;
  852. current_vfs = new_vfs;
  853. /* This function uses the new current_dir implicitly */
  854. vfs_stamp_create (old_vfs, old_vfsid);
  855. /* Sometimes we assume no trailing slash on cwd */
  856. if (*current_dir) {
  857. char *p;
  858. p = strchr (current_dir, 0) - 1;
  859. if (*p == PATH_SEP && p > current_dir)
  860. *p = 0;
  861. }
  862. g_free (trans_dir);
  863. return 0;
  864. } else {
  865. g_free (new_dir);
  866. return -1;
  867. }
  868. }
  869. /* Return 1 is the current VFS class is local */
  870. int
  871. vfs_current_is_local (void)
  872. {
  873. return (current_vfs->flags & VFSF_LOCAL) != 0;
  874. }
  875. /* Return flags of the VFS class of the given filename */
  876. int
  877. vfs_file_class_flags (const char *filename)
  878. {
  879. struct vfs_class *vfs;
  880. char *fname;
  881. fname = vfs_canon_and_translate (filename);
  882. if (fname != NULL) {
  883. vfs = vfs_get_class (fname);
  884. g_free (fname);
  885. return vfs->flags;
  886. } else return -1;
  887. }
  888. static char *
  889. mc_def_getlocalcopy (const char *filename)
  890. {
  891. char *tmp;
  892. int fdin, fdout, i;
  893. char buffer[8192];
  894. struct stat mystat;
  895. fdin = mc_open (filename, O_RDONLY | O_LINEAR);
  896. if (fdin == -1)
  897. return NULL;
  898. fdout = vfs_mkstemps (&tmp, "vfs", filename);
  899. if (fdout == -1)
  900. goto fail;
  901. while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0) {
  902. if (write (fdout, buffer, i) != i)
  903. goto fail;
  904. }
  905. if (i == -1)
  906. goto fail;
  907. i = mc_close (fdin);
  908. fdin = -1;
  909. if (i == -1)
  910. goto fail;
  911. if (close (fdout) == -1) {
  912. fdout = -1;
  913. goto fail;
  914. }
  915. if (mc_stat (filename, &mystat) != -1) {
  916. chmod (tmp, mystat.st_mode);
  917. }
  918. return tmp;
  919. fail:
  920. if (fdout != -1)
  921. close (fdout);
  922. if (fdin != -1)
  923. mc_close (fdin);
  924. g_free (tmp);
  925. return NULL;
  926. }
  927. char *
  928. mc_getlocalcopy (const char *pathname)
  929. {
  930. char *result;
  931. char *path;
  932. path = vfs_canon_and_translate (pathname);
  933. if (path != NULL) {
  934. struct vfs_class *vfs = vfs_get_class (path);
  935. result = vfs->getlocalcopy ? (*vfs->getlocalcopy)(vfs, path) :
  936. mc_def_getlocalcopy (path);
  937. g_free (path);
  938. if (!result)
  939. errno = ferrno (vfs);
  940. return result;
  941. } else return NULL;
  942. }
  943. static int
  944. mc_def_ungetlocalcopy (struct vfs_class *vfs, const char *filename,
  945. const char *local, int has_changed)
  946. {
  947. int fdin = -1, fdout = -1, i;
  948. if (has_changed) {
  949. char buffer[8192];
  950. if (!vfs->write)
  951. goto failed;
  952. fdin = open (local, O_RDONLY);
  953. if (fdin == -1)
  954. goto failed;
  955. fdout = mc_open (filename, O_WRONLY | O_TRUNC);
  956. if (fdout == -1)
  957. goto failed;
  958. while ((i = read (fdin, buffer, sizeof (buffer))) > 0) {
  959. if (mc_write (fdout, buffer, i) != i)
  960. goto failed;
  961. }
  962. if (i == -1)
  963. goto failed;
  964. if (close (fdin) == -1) {
  965. fdin = -1;
  966. goto failed;
  967. }
  968. fdin = -1;
  969. if (mc_close (fdout) == -1) {
  970. fdout = -1;
  971. goto failed;
  972. }
  973. }
  974. unlink (local);
  975. return 0;
  976. failed:
  977. message (D_ERROR, _("Changes to file lost"), "%s", filename);
  978. if (fdout != -1)
  979. mc_close (fdout);
  980. if (fdin != -1)
  981. close (fdin);
  982. unlink (local);
  983. return -1;
  984. }
  985. int
  986. mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed)
  987. {
  988. int return_value = 0;
  989. char *path;
  990. path = vfs_canon_and_translate (pathname);
  991. if (path != NULL) {
  992. struct vfs_class *vfs = vfs_get_class (path);
  993. return_value = vfs->ungetlocalcopy ?
  994. (*vfs->ungetlocalcopy)(vfs, path, local, has_changed) :
  995. mc_def_ungetlocalcopy (vfs, path, local, has_changed);
  996. g_free (path);
  997. return return_value;
  998. } else return -1;
  999. }
  1000. void
  1001. vfs_init (void)
  1002. {
  1003. vfs_str_buffer = g_string_new("");
  1004. /* localfs needs to be the first one */
  1005. init_localfs();
  1006. /* fallback value for vfs_get_class() */
  1007. localfs_class = vfs_list;
  1008. init_extfs ();
  1009. init_sfs ();
  1010. init_tarfs ();
  1011. init_cpiofs ();
  1012. #ifdef USE_EXT2FSLIB
  1013. init_undelfs ();
  1014. #endif /* USE_EXT2FSLIB */
  1015. #ifdef USE_NETCODE
  1016. tcp_init();
  1017. init_ftpfs ();
  1018. init_fish ();
  1019. #ifdef WITH_SMBFS
  1020. init_smbfs ();
  1021. #endif /* WITH_SMBFS */
  1022. #ifdef WITH_MCFS
  1023. init_mcfs ();
  1024. #endif /* WITH_MCFS */
  1025. #endif /* USE_NETCODE */
  1026. vfs_setup_wd ();
  1027. }
  1028. void
  1029. vfs_shut (void)
  1030. {
  1031. struct vfs_class *vfs;
  1032. vfs_gc_done ();
  1033. g_free (current_dir);
  1034. for (vfs = vfs_list; vfs; vfs = vfs->next)
  1035. if (vfs->done)
  1036. (*vfs->done) (vfs);
  1037. g_slist_free (vfs_openfiles);
  1038. g_string_free (vfs_str_buffer, TRUE);
  1039. }
  1040. /*
  1041. * These ones grab information from the VFS
  1042. * and handles them to an upper layer
  1043. */
  1044. void
  1045. vfs_fill_names (fill_names_f func)
  1046. {
  1047. struct vfs_class *vfs;
  1048. for (vfs=vfs_list; vfs; vfs=vfs->next)
  1049. if (vfs->fill_names)
  1050. (*vfs->fill_names) (vfs, func);
  1051. }
  1052. /*
  1053. * Returns vfs path corresponding to given url. If passed string is
  1054. * not recognized as url, g_strdup(url) is returned.
  1055. */
  1056. static const struct {
  1057. const char *name;
  1058. size_t name_len;
  1059. const char *substitute;
  1060. } url_table[] = { {"ftp://", 6, "/#ftp:"},
  1061. {"mc://", 5, "/#mc:"},
  1062. {"smb://", 6, "/#smb:"},
  1063. {"sh://", 5, "/#sh:"},
  1064. {"ssh://", 6, "/#sh:"},
  1065. {"a:", 2, "/#a"}
  1066. };
  1067. char *
  1068. vfs_translate_url (const char *url)
  1069. {
  1070. size_t i;
  1071. for (i = 0; i < sizeof (url_table)/sizeof (url_table[0]); i++)
  1072. if (strncmp (url, url_table[i].name, url_table[i].name_len) == 0)
  1073. return g_strconcat (url_table[i].substitute, url + url_table[i].name_len, (char*) NULL);
  1074. return g_strdup (url);
  1075. }
  1076. int vfs_file_is_local (const char *filename)
  1077. {
  1078. return vfs_file_class_flags (filename) & VFSF_LOCAL;
  1079. }