fish.c 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759
  1. /*
  2. Virtual File System: FISH implementation for transfering files over
  3. shell connections.
  4. Copyright (C) 1998-2018
  5. Free Software Foundation, Inc.
  6. Written by:
  7. Pavel Machek, 1998
  8. Michal Svec, 2000
  9. Andrew Borodin <aborodin@vmail.ru>, 2010
  10. Slava Zanko <slavazanko@gmail.com>, 2010, 2013
  11. Ilia Maslakov <il.smind@gmail.com>, 2010
  12. Derived from ftpfs.c.
  13. This file is part of the Midnight Commander.
  14. The Midnight Commander is free software: you can redistribute it
  15. and/or modify it under the terms of the GNU General Public License as
  16. published by the Free Software Foundation, either version 3 of the License,
  17. or (at your option) any later version.
  18. The Midnight Commander is distributed in the hope that it will be useful,
  19. but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. GNU General Public License for more details.
  22. You should have received a copy of the GNU General Public License
  23. along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. */
  25. /**
  26. * \file
  27. * \brief Source: Virtual File System: FISH implementation for transfering files over
  28. * shell connections
  29. * \author Pavel Machek
  30. * \author Michal Svec
  31. * \date 1998, 2000
  32. *
  33. * Derived from ftpfs.c
  34. * Read README.fish for protocol specification.
  35. *
  36. * Syntax of path is: \verbatim sh://user@host[:Cr]/path \endverbatim
  37. * where C means you want compressed connection,
  38. * and r means you want to use rsh
  39. *
  40. * Namespace: fish_vfs_ops exported.
  41. */
  42. /* Define this if your ssh can take -I option */
  43. #include <config.h>
  44. #include <errno.h>
  45. #include <pwd.h>
  46. #include <grp.h>
  47. #include <sys/time.h> /* gettimeofday() */
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <inttypes.h> /* uintmax_t */
  51. #include "lib/global.h"
  52. #include "lib/tty/tty.h" /* enable/disable interrupt key */
  53. #include "lib/strescape.h"
  54. #include "lib/unixcompat.h"
  55. #include "lib/fileloc.h"
  56. #include "lib/util.h" /* my_exit() */
  57. #include "lib/mcconfig.h"
  58. #include "src/execute.h" /* pre_exec, post_exec */
  59. #include "lib/vfs/vfs.h"
  60. #include "lib/vfs/utilvfs.h"
  61. #include "lib/vfs/netutil.h"
  62. #include "lib/vfs/xdirentry.h"
  63. #include "lib/vfs/gc.h" /* vfs_stamp_create */
  64. #include "fish.h"
  65. #include "fishdef.h"
  66. /*** global variables ****************************************************************************/
  67. int fish_directory_timeout = 900;
  68. /*** file scope macro definitions ****************************************************************/
  69. #define DO_RESOLVE_SYMLINK 1
  70. #define DO_OPEN 2
  71. #define DO_FREE_RESOURCE 4
  72. #define FISH_FLAG_COMPRESSED 1
  73. #define FISH_FLAG_RSH 2
  74. #define OPT_FLUSH 1
  75. #define OPT_IGNORE_ERROR 2
  76. /*
  77. * Reply codes.
  78. */
  79. #define PRELIM 1 /* positive preliminary */
  80. #define COMPLETE 2 /* positive completion */
  81. #define CONTINUE 3 /* positive intermediate */
  82. #define TRANSIENT 4 /* transient negative completion */
  83. #define ERROR 5 /* permanent negative completion */
  84. /* command wait_flag: */
  85. #define NONE 0x00
  86. #define WAIT_REPLY 0x01
  87. #define WANT_STRING 0x02
  88. /* environment flags */
  89. #define FISH_HAVE_HEAD 1
  90. #define FISH_HAVE_SED 2
  91. #define FISH_HAVE_AWK 4
  92. #define FISH_HAVE_PERL 8
  93. #define FISH_HAVE_LSQ 16
  94. #define FISH_HAVE_DATE_MDYT 32
  95. #define FISH_HAVE_TAIL 64
  96. #define SUP ((fish_super_data_t *) super->data)
  97. /*** file scope type declarations ****************************************************************/
  98. typedef struct
  99. {
  100. int sockr;
  101. int sockw;
  102. char *scr_ls;
  103. char *scr_chmod;
  104. char *scr_utime;
  105. char *scr_exists;
  106. char *scr_mkdir;
  107. char *scr_unlink;
  108. char *scr_chown;
  109. char *scr_rmdir;
  110. char *scr_ln;
  111. char *scr_mv;
  112. char *scr_hardlink;
  113. char *scr_get;
  114. char *scr_send;
  115. char *scr_append;
  116. char *scr_info;
  117. int host_flags;
  118. char *scr_env;
  119. } fish_super_data_t;
  120. typedef struct
  121. {
  122. off_t got;
  123. off_t total;
  124. gboolean append;
  125. } fish_fh_data_t;
  126. /*** file scope variables ************************************************************************/
  127. static char reply_str[80];
  128. static struct vfs_class vfs_fish_ops;
  129. /* --------------------------------------------------------------------------------------------- */
  130. /*** file scope functions ************************************************************************/
  131. /* --------------------------------------------------------------------------------------------- */
  132. static void
  133. fish_set_blksize (struct stat *s)
  134. {
  135. #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
  136. /* redefine block size */
  137. s->st_blksize = 64 * 1024; /* FIXME */
  138. #endif
  139. }
  140. /* --------------------------------------------------------------------------------------------- */
  141. static struct stat *
  142. fish_default_stat (struct vfs_class *me)
  143. {
  144. struct stat *s;
  145. s = vfs_s_default_stat (me, S_IFDIR | 0755);
  146. fish_set_blksize (s);
  147. vfs_adjust_stat (s);
  148. return s;
  149. }
  150. /* --------------------------------------------------------------------------------------------- */
  151. static char *
  152. fish_load_script_from_file (const char *hostname, const char *script_name, const char *def_content)
  153. {
  154. char *scr_filename = NULL;
  155. char *scr_content;
  156. gsize scr_len = 0;
  157. /* 1st: scan user directory */
  158. scr_filename = g_build_path (PATH_SEP_STR, mc_config_get_data_path (), FISH_PREFIX, hostname,
  159. script_name, (char *) NULL);
  160. /* silent about user dir */
  161. g_file_get_contents (scr_filename, &scr_content, &scr_len, NULL);
  162. g_free (scr_filename);
  163. /* 2nd: scan system dir */
  164. if (scr_content == NULL)
  165. {
  166. scr_filename =
  167. g_build_path (PATH_SEP_STR, LIBEXECDIR, FISH_PREFIX, script_name, (char *) NULL);
  168. g_file_get_contents (scr_filename, &scr_content, &scr_len, NULL);
  169. g_free (scr_filename);
  170. }
  171. if (scr_content != NULL)
  172. return scr_content;
  173. return g_strdup (def_content);
  174. }
  175. /* --------------------------------------------------------------------------------------------- */
  176. static int
  177. fish_decode_reply (char *s, gboolean was_garbage)
  178. {
  179. int code;
  180. /* cppcheck-suppress invalidscanf */
  181. if (sscanf (s, "%d", &code) == 0)
  182. {
  183. code = 500;
  184. return 5;
  185. }
  186. if (code < 100)
  187. return was_garbage ? ERROR : (code == 0 ? COMPLETE : PRELIM);
  188. return code / 100;
  189. }
  190. /* --------------------------------------------------------------------------------------------- */
  191. /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
  192. static int
  193. fish_get_reply (struct vfs_class *me, int sock, char *string_buf, int string_len)
  194. {
  195. char answer[BUF_1K];
  196. gboolean was_garbage = FALSE;
  197. while (TRUE)
  198. {
  199. if (!vfs_s_get_line (me, sock, answer, sizeof (answer), '\n'))
  200. {
  201. if (string_buf != NULL)
  202. *string_buf = '\0';
  203. return 4;
  204. }
  205. if (strncmp (answer, "### ", 4) == 0)
  206. return fish_decode_reply (answer + 4, was_garbage ? 1 : 0);
  207. was_garbage = TRUE;
  208. if (string_buf != NULL)
  209. g_strlcpy (string_buf, answer, string_len);
  210. }
  211. }
  212. /* --------------------------------------------------------------------------------------------- */
  213. static int
  214. G_GNUC_PRINTF (4, 5)
  215. fish_command (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *fmt, ...)
  216. {
  217. va_list ap;
  218. char *str;
  219. ssize_t status;
  220. FILE *logfile = MEDATA->logfile;
  221. va_start (ap, fmt);
  222. str = g_strdup_vprintf (fmt, ap);
  223. va_end (ap);
  224. if (logfile != NULL)
  225. {
  226. size_t ret;
  227. ret = fwrite (str, strlen (str), 1, logfile);
  228. ret = fflush (logfile);
  229. (void) ret;
  230. }
  231. tty_enable_interrupt_key ();
  232. status = write (SUP->sockw, str, strlen (str));
  233. g_free (str);
  234. tty_disable_interrupt_key ();
  235. if (status < 0)
  236. return TRANSIENT;
  237. if (wait_reply)
  238. return fish_get_reply (me, SUP->sockr,
  239. (wait_reply & WANT_STRING) ? reply_str :
  240. NULL, sizeof (reply_str) - 1);
  241. return COMPLETE;
  242. }
  243. /* --------------------------------------------------------------------------------------------- */
  244. static void
  245. fish_free_archive (struct vfs_class *me, struct vfs_s_super *super)
  246. {
  247. if ((SUP->sockw != -1) || (SUP->sockr != -1))
  248. {
  249. vfs_print_message (_("fish: Disconnecting from %s"), super->name ? super->name : "???");
  250. fish_command (me, super, NONE, "%s", "#BYE\nexit\n");
  251. close (SUP->sockw);
  252. close (SUP->sockr);
  253. SUP->sockw = SUP->sockr = -1;
  254. }
  255. g_free (SUP->scr_ls);
  256. g_free (SUP->scr_exists);
  257. g_free (SUP->scr_mkdir);
  258. g_free (SUP->scr_unlink);
  259. g_free (SUP->scr_chown);
  260. g_free (SUP->scr_chmod);
  261. g_free (SUP->scr_utime);
  262. g_free (SUP->scr_rmdir);
  263. g_free (SUP->scr_ln);
  264. g_free (SUP->scr_mv);
  265. g_free (SUP->scr_hardlink);
  266. g_free (SUP->scr_get);
  267. g_free (SUP->scr_send);
  268. g_free (SUP->scr_append);
  269. g_free (SUP->scr_info);
  270. g_free (SUP->scr_env);
  271. g_free (SUP);
  272. super->data = NULL;
  273. }
  274. /* --------------------------------------------------------------------------------------------- */
  275. static void
  276. fish_pipeopen (struct vfs_s_super *super, const char *path, const char *argv[])
  277. {
  278. int fileset1[2], fileset2[2];
  279. int res;
  280. if ((pipe (fileset1) < 0) || (pipe (fileset2) < 0))
  281. vfs_die ("Cannot pipe(): %m.");
  282. res = fork ();
  283. if (res != 0)
  284. {
  285. if (res < 0)
  286. vfs_die ("Cannot fork(): %m.");
  287. /* We are the parent */
  288. close (fileset1[0]);
  289. SUP->sockw = fileset1[1];
  290. close (fileset2[1]);
  291. SUP->sockr = fileset2[0];
  292. }
  293. else
  294. {
  295. res = dup2 (fileset1[0], STDIN_FILENO);
  296. close (fileset1[0]);
  297. close (fileset1[1]);
  298. res = dup2 (fileset2[1], STDOUT_FILENO);
  299. close (STDERR_FILENO);
  300. /* stderr to /dev/null */
  301. res = open ("/dev/null", O_WRONLY);
  302. close (fileset2[0]);
  303. close (fileset2[1]);
  304. execvp (path, (char **) argv);
  305. my_exit (3);
  306. }
  307. }
  308. /* --------------------------------------------------------------------------------------------- */
  309. static char *
  310. fish_set_env (int flags)
  311. {
  312. GString *tmp;
  313. tmp = g_string_sized_new (250);
  314. g_string_assign (tmp, "");
  315. if ((flags & FISH_HAVE_HEAD) != 0)
  316. g_string_append (tmp, "FISH_HAVE_HEAD=1 export FISH_HAVE_HEAD; ");
  317. if ((flags & FISH_HAVE_SED) != 0)
  318. g_string_append (tmp, "FISH_HAVE_SED=1 export FISH_HAVE_SED; ");
  319. if ((flags & FISH_HAVE_AWK) != 0)
  320. g_string_append (tmp, "FISH_HAVE_AWK=1 export FISH_HAVE_AWK; ");
  321. if ((flags & FISH_HAVE_PERL) != 0)
  322. g_string_append (tmp, "FISH_HAVE_PERL=1 export FISH_HAVE_PERL; ");
  323. if ((flags & FISH_HAVE_LSQ) != 0)
  324. g_string_append (tmp, "FISH_HAVE_LSQ=1 export FISH_HAVE_LSQ; ");
  325. if ((flags & FISH_HAVE_DATE_MDYT) != 0)
  326. g_string_append (tmp, "FISH_HAVE_DATE_MDYT=1 export FISH_HAVE_DATE_MDYT; ");
  327. if ((flags & FISH_HAVE_TAIL) != 0)
  328. g_string_append (tmp, "FISH_HAVE_TAIL=1 export FISH_HAVE_TAIL; ");
  329. return g_string_free (tmp, FALSE);
  330. }
  331. /* --------------------------------------------------------------------------------------------- */
  332. static gboolean
  333. fish_info (struct vfs_class *me, struct vfs_s_super *super)
  334. {
  335. if (fish_command (me, super, NONE, "%s", SUP->scr_info) == COMPLETE)
  336. {
  337. while (TRUE)
  338. {
  339. int res;
  340. char buffer[BUF_8K];
  341. res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP->sockr);
  342. if ((res == 0) || (res == EINTR))
  343. ERRNOR (ECONNRESET, FALSE);
  344. if (strncmp (buffer, "### ", 4) == 0)
  345. break;
  346. SUP->host_flags = atol (buffer);
  347. }
  348. return TRUE;
  349. }
  350. ERRNOR (E_PROTO, FALSE);
  351. }
  352. /* --------------------------------------------------------------------------------------------- */
  353. static void
  354. fish_open_archive_pipeopen (struct vfs_s_super *super)
  355. {
  356. char gbuf[10];
  357. const char *argv[10]; /* All of 10 is used now */
  358. const char *xsh = (super->path_element->port == FISH_FLAG_RSH ? "rsh" : "ssh");
  359. int i = 0;
  360. argv[i++] = xsh;
  361. if (super->path_element->port == FISH_FLAG_COMPRESSED)
  362. argv[i++] = "-C";
  363. if (super->path_element->port > FISH_FLAG_RSH)
  364. {
  365. argv[i++] = "-p";
  366. g_snprintf (gbuf, sizeof (gbuf), "%d", super->path_element->port);
  367. argv[i++] = gbuf;
  368. }
  369. /*
  370. * Add the user name to the ssh command line only if it was explicitly
  371. * set in vfs URL. rsh/ssh will get current user by default
  372. * plus we can set convenient overrides in ~/.ssh/config (explicit -l
  373. * option breaks it for some)
  374. */
  375. if (super->path_element->user != NULL)
  376. {
  377. argv[i++] = "-l";
  378. argv[i++] = super->path_element->user;
  379. }
  380. else
  381. {
  382. /* The rest of the code assumes it to be a valid username */
  383. super->path_element->user = vfs_get_local_username ();
  384. }
  385. argv[i++] = super->path_element->host;
  386. argv[i++] = "echo FISH:; /bin/sh";
  387. argv[i++] = NULL;
  388. fish_pipeopen (super, xsh, argv);
  389. }
  390. /* --------------------------------------------------------------------------------------------- */
  391. static gboolean
  392. fish_open_archive_talk (struct vfs_class *me, struct vfs_s_super *super)
  393. {
  394. char answer[2048];
  395. printf ("\n%s\n", _("fish: Waiting for initial line..."));
  396. if (vfs_s_get_line (me, SUP->sockr, answer, sizeof (answer), ':') == 0)
  397. return FALSE;
  398. if (strstr (answer, "assword") != NULL)
  399. {
  400. /* Currently, this does not work. ssh reads passwords from
  401. /dev/tty, not from stdin :-(. */
  402. printf ("\n%s\n", _("Sorry, we cannot do password authenticated connections for now."));
  403. return FALSE;
  404. #if 0
  405. if (super->path_element->password == NULL)
  406. {
  407. char *p, *op;
  408. p = g_strdup_printf (_("fish: Password is required for %s"), super->path_element->user);
  409. op = vfs_get_password (p);
  410. g_free (p);
  411. if (op == NULL)
  412. return FALSE;
  413. super->path_element->password = op;
  414. }
  415. printf ("\n%s\n", _("fish: Sending password..."));
  416. {
  417. size_t str_len;
  418. str_len = strlen (super->path_element->password);
  419. if ((write (SUP.sockw, super->path_element->password, str_len) != (ssize_t) str_len)
  420. || (write (SUP->sockw, "\n", 1) != 1))
  421. return FALSE;
  422. }
  423. #endif
  424. }
  425. return TRUE;
  426. }
  427. /* --------------------------------------------------------------------------------------------- */
  428. static int
  429. fish_open_archive_int (struct vfs_class *me, struct vfs_s_super *super)
  430. {
  431. gboolean ftalk;
  432. /* hide panels */
  433. pre_exec ();
  434. /* open pipe */
  435. fish_open_archive_pipeopen (super);
  436. /* Start talk with ssh-server (password prompt, etc ) */
  437. ftalk = fish_open_archive_talk (me, super);
  438. /* show panels */
  439. post_exec ();
  440. if (!ftalk)
  441. ERRNOR (E_PROTO, -1);
  442. vfs_print_message ("%s", _("fish: Sending initial line..."));
  443. /*
  444. * Run 'start_fish_server'. If it doesn't exist - no problem,
  445. * we'll talk directly to the shell.
  446. */
  447. if (fish_command
  448. (me, super, WAIT_REPLY, "%s",
  449. "#FISH\necho; start_fish_server 2>&1; echo '### 200'\n") != COMPLETE)
  450. ERRNOR (E_PROTO, -1);
  451. vfs_print_message ("%s", _("fish: Handshaking version..."));
  452. if (fish_command (me, super, WAIT_REPLY, "%s", "#VER 0.0.3\necho '### 000'\n") != COMPLETE)
  453. ERRNOR (E_PROTO, -1);
  454. /* Set up remote locale to C, otherwise dates cannot be recognized */
  455. if (fish_command
  456. (me, super, WAIT_REPLY, "%s",
  457. "LANG=C LC_ALL=C LC_TIME=C; export LANG LC_ALL LC_TIME;\n" "echo '### 200'\n") != COMPLETE)
  458. ERRNOR (E_PROTO, -1);
  459. vfs_print_message ("%s", _("fish: Getting host info..."));
  460. if (fish_info (me, super))
  461. SUP->scr_env = fish_set_env (SUP->host_flags);
  462. #if 0
  463. super->name =
  464. g_strconcat ("sh://", super->path_element->user, "@", super->path_element->host,
  465. PATH_SEP_STR, (char *) NULL);
  466. #else
  467. super->name = g_strdup (PATH_SEP_STR);
  468. #endif
  469. super->root = vfs_s_new_inode (me, super, fish_default_stat (me));
  470. return 0;
  471. }
  472. /* --------------------------------------------------------------------------------------------- */
  473. static int
  474. fish_open_archive (struct vfs_s_super *super,
  475. const vfs_path_t * vpath, const vfs_path_element_t * vpath_element)
  476. {
  477. (void) vpath;
  478. super->data = g_new0 (fish_super_data_t, 1);
  479. super->path_element = vfs_path_element_clone (vpath_element);
  480. if (strncmp (vpath_element->vfs_prefix, "rsh", 3) == 0)
  481. super->path_element->port = FISH_FLAG_RSH;
  482. SUP->scr_ls =
  483. fish_load_script_from_file (super->path_element->host, FISH_LS_FILE, FISH_LS_DEF_CONTENT);
  484. SUP->scr_exists =
  485. fish_load_script_from_file (super->path_element->host, FISH_EXISTS_FILE,
  486. FISH_EXISTS_DEF_CONTENT);
  487. SUP->scr_mkdir =
  488. fish_load_script_from_file (super->path_element->host, FISH_MKDIR_FILE,
  489. FISH_MKDIR_DEF_CONTENT);
  490. SUP->scr_unlink =
  491. fish_load_script_from_file (super->path_element->host, FISH_UNLINK_FILE,
  492. FISH_UNLINK_DEF_CONTENT);
  493. SUP->scr_chown =
  494. fish_load_script_from_file (super->path_element->host, FISH_CHOWN_FILE,
  495. FISH_CHOWN_DEF_CONTENT);
  496. SUP->scr_chmod =
  497. fish_load_script_from_file (super->path_element->host, FISH_CHMOD_FILE,
  498. FISH_CHMOD_DEF_CONTENT);
  499. SUP->scr_utime =
  500. fish_load_script_from_file (super->path_element->host, FISH_UTIME_FILE,
  501. FISH_UTIME_DEF_CONTENT);
  502. SUP->scr_rmdir =
  503. fish_load_script_from_file (super->path_element->host, FISH_RMDIR_FILE,
  504. FISH_RMDIR_DEF_CONTENT);
  505. SUP->scr_ln =
  506. fish_load_script_from_file (super->path_element->host, FISH_LN_FILE, FISH_LN_DEF_CONTENT);
  507. SUP->scr_mv =
  508. fish_load_script_from_file (super->path_element->host, FISH_MV_FILE, FISH_MV_DEF_CONTENT);
  509. SUP->scr_hardlink =
  510. fish_load_script_from_file (super->path_element->host, FISH_HARDLINK_FILE,
  511. FISH_HARDLINK_DEF_CONTENT);
  512. SUP->scr_get =
  513. fish_load_script_from_file (super->path_element->host, FISH_GET_FILE, FISH_GET_DEF_CONTENT);
  514. SUP->scr_send =
  515. fish_load_script_from_file (super->path_element->host, FISH_SEND_FILE,
  516. FISH_SEND_DEF_CONTENT);
  517. SUP->scr_append =
  518. fish_load_script_from_file (super->path_element->host, FISH_APPEND_FILE,
  519. FISH_APPEND_DEF_CONTENT);
  520. SUP->scr_info =
  521. fish_load_script_from_file (super->path_element->host, FISH_INFO_FILE,
  522. FISH_INFO_DEF_CONTENT);
  523. return fish_open_archive_int (vpath_element->class, super);
  524. }
  525. /* --------------------------------------------------------------------------------------------- */
  526. static int
  527. fish_archive_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *super,
  528. const vfs_path_t * vpath, void *cookie)
  529. {
  530. vfs_path_element_t *path_element;
  531. int result;
  532. (void) vpath;
  533. (void) cookie;
  534. path_element = vfs_path_element_clone (vpath_element);
  535. if (path_element->user == NULL)
  536. path_element->user = vfs_get_local_username ();
  537. result = ((strcmp (path_element->host, super->path_element->host) == 0)
  538. && (strcmp (path_element->user, super->path_element->user) == 0)
  539. && (path_element->port == super->path_element->port)) ? 1 : 0;
  540. vfs_path_element_free (path_element);
  541. return result;
  542. }
  543. /* --------------------------------------------------------------------------------------------- */
  544. static int
  545. fish_dir_load (struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
  546. {
  547. struct vfs_s_super *super = dir->super;
  548. char buffer[BUF_8K] = "\0";
  549. struct vfs_s_entry *ent = NULL;
  550. FILE *logfile;
  551. char *quoted_path;
  552. int reply_code;
  553. gchar *shell_commands;
  554. /*
  555. * Simple FISH debug interface :]
  556. */
  557. #if 0
  558. if (MEDATA->logfile == NULL)
  559. MEDATA->logfile = fopen ("/tmp/mc-FISH.sh", "w");
  560. #endif
  561. logfile = MEDATA->logfile;
  562. vfs_print_message (_("fish: Reading directory %s..."), remote_path);
  563. gettimeofday (&dir->timestamp, NULL);
  564. dir->timestamp.tv_sec += fish_directory_timeout;
  565. quoted_path = strutils_shell_escape (remote_path);
  566. shell_commands = g_strconcat (SUP->scr_env, "FISH_FILENAME=%s;\n", SUP->scr_ls, (char *) NULL);
  567. fish_command (me, super, NONE, shell_commands, quoted_path);
  568. g_free (shell_commands);
  569. g_free (quoted_path);
  570. ent = vfs_s_generate_entry (me, NULL, dir, 0);
  571. while (TRUE)
  572. {
  573. int res;
  574. res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP->sockr);
  575. if ((res == 0) || (res == EINTR))
  576. {
  577. vfs_s_free_entry (me, ent);
  578. me->verrno = ECONNRESET;
  579. goto error;
  580. }
  581. if (logfile != NULL)
  582. {
  583. fputs (buffer, logfile);
  584. fputs ("\n", logfile);
  585. fflush (logfile);
  586. }
  587. if (strncmp (buffer, "### ", 4) == 0)
  588. break;
  589. if (buffer[0] == '\0')
  590. {
  591. if (ent->name != NULL)
  592. {
  593. vfs_s_insert_entry (me, dir, ent);
  594. ent = vfs_s_generate_entry (me, NULL, dir, 0);
  595. }
  596. continue;
  597. }
  598. #define ST ent->ino->st
  599. switch (buffer[0])
  600. {
  601. case ':':
  602. {
  603. char *temp;
  604. char *data_start = buffer + 1;
  605. char *filename = data_start;
  606. char *filename_bound;
  607. filename_bound = filename + strlen (filename);
  608. if (strcmp (data_start, "\".\"") == 0 || strcmp (data_start, "\"..\"") == 0)
  609. break; /* We'll do "." and ".." ourselves */
  610. if (S_ISLNK (ST.st_mode))
  611. {
  612. char *linkname;
  613. char *linkname_bound;
  614. /* we expect: "escaped-name" -> "escaped-name"
  615. // -> cannot occur in filenames,
  616. // because it will be escaped to -\> */
  617. linkname_bound = filename_bound;
  618. if (*filename == '"')
  619. ++filename;
  620. linkname = strstr (filename, "\" -> \"");
  621. if (linkname == NULL)
  622. {
  623. /* broken client, or smth goes wrong */
  624. linkname = filename_bound;
  625. if (filename_bound > filename && *(filename_bound - 1) == '"')
  626. --filename_bound; /* skip trailing " */
  627. }
  628. else
  629. {
  630. filename_bound = linkname;
  631. linkname += 6; /* strlen ("\" -> \"") */
  632. if (*(linkname_bound - 1) == '"')
  633. --linkname_bound; /* skip trailing " */
  634. }
  635. ent->name = g_strndup (filename, filename_bound - filename);
  636. temp = ent->name;
  637. ent->name = strutils_shell_unescape (ent->name);
  638. g_free (temp);
  639. ent->ino->linkname = g_strndup (linkname, linkname_bound - linkname);
  640. temp = ent->ino->linkname;
  641. ent->ino->linkname = strutils_shell_unescape (ent->ino->linkname);
  642. g_free (temp);
  643. }
  644. else
  645. {
  646. /* we expect: "escaped-name" */
  647. if (filename_bound - filename > 2)
  648. {
  649. /*
  650. there is at least 2 "
  651. and we skip them
  652. */
  653. if (*filename == '"')
  654. ++filename;
  655. if (*(filename_bound - 1) == '"')
  656. --filename_bound;
  657. }
  658. ent->name = g_strndup (filename, filename_bound - filename);
  659. temp = ent->name;
  660. ent->name = strutils_shell_unescape (ent->name);
  661. g_free (temp);
  662. }
  663. break;
  664. }
  665. case 'S':
  666. ST.st_size = (off_t) g_ascii_strtoll (buffer + 1, NULL, 10);
  667. break;
  668. case 'P':
  669. {
  670. size_t skipped;
  671. vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode);
  672. break;
  673. }
  674. case 'R':
  675. {
  676. /*
  677. raw filemode:
  678. we expect: Roctal-filemode octal-filetype uid.gid
  679. */
  680. size_t skipped;
  681. vfs_parse_raw_filemode (buffer + 1, &skipped, &ST.st_mode);
  682. break;
  683. }
  684. case 'd':
  685. {
  686. vfs_split_text (buffer + 1);
  687. if (vfs_parse_filedate (0, &ST.st_ctime) == 0)
  688. break;
  689. ST.st_atime = ST.st_mtime = ST.st_ctime;
  690. #ifdef HAVE_STRUCT_STAT_ST_MTIM
  691. ST.st_atim.tv_nsec = ST.st_mtim.tv_nsec = ST.st_ctim.tv_nsec = 0;
  692. #endif
  693. }
  694. break;
  695. case 'D':
  696. {
  697. struct tm tim;
  698. /* cppcheck-suppress invalidscanf */
  699. if (sscanf (buffer + 1, "%d %d %d %d %d %d", &tim.tm_year, &tim.tm_mon,
  700. &tim.tm_mday, &tim.tm_hour, &tim.tm_min, &tim.tm_sec) != 6)
  701. break;
  702. ST.st_atime = ST.st_mtime = ST.st_ctime = mktime (&tim);
  703. #ifdef HAVE_STRUCT_STAT_ST_MTIM
  704. ST.st_atim.tv_nsec = ST.st_mtim.tv_nsec = ST.st_ctim.tv_nsec = 0;
  705. #endif
  706. }
  707. break;
  708. case 'E':
  709. {
  710. int maj, min;
  711. /* cppcheck-suppress invalidscanf */
  712. if (sscanf (buffer + 1, "%d,%d", &maj, &min) != 2)
  713. break;
  714. #ifdef HAVE_STRUCT_STAT_ST_RDEV
  715. ST.st_rdev = makedev (maj, min);
  716. #endif
  717. }
  718. default:
  719. break;
  720. }
  721. }
  722. vfs_s_free_entry (me, ent);
  723. reply_code = fish_decode_reply (buffer + 4, 0);
  724. if (reply_code == COMPLETE)
  725. {
  726. vfs_print_message (_("%s: done."), me->name);
  727. return 0;
  728. }
  729. me->verrno = reply_code == ERROR ? EACCES : E_REMOTE;
  730. error:
  731. vfs_print_message (_("%s: failure"), me->name);
  732. return -1;
  733. }
  734. /* --------------------------------------------------------------------------------------------- */
  735. static int
  736. fish_file_store (struct vfs_class *me, vfs_file_handler_t * fh, char *name, char *localname)
  737. {
  738. fish_fh_data_t *fish = (fish_fh_data_t *) fh->data;
  739. gchar *shell_commands = NULL;
  740. struct vfs_s_super *super = FH_SUPER;
  741. int code;
  742. off_t total = 0;
  743. char buffer[BUF_8K];
  744. struct stat s;
  745. int h;
  746. char *quoted_name;
  747. h = open (localname, O_RDONLY);
  748. if (h == -1)
  749. ERRNOR (EIO, -1);
  750. if (fstat (h, &s) < 0)
  751. {
  752. close (h);
  753. ERRNOR (EIO, -1);
  754. }
  755. /* First, try this as stor:
  756. *
  757. * ( head -c number ) | ( cat > file; cat >/dev/null )
  758. *
  759. * If 'head' is not present on the remote system, 'dd' will be used.
  760. * Unfortunately, we cannot trust most non-GNU 'head' implementations
  761. * even if '-c' options is supported. Therefore, we separate GNU head
  762. * (and other modern heads?) using '-q' and '-' . This causes another
  763. * implementations to fail (because of "incorrect options").
  764. *
  765. * Fallback is:
  766. *
  767. * rest=<number>
  768. * while [ $rest -gt 0 ]
  769. * do
  770. * cnt=`expr \( $rest + 255 \) / 256`
  771. * n=`dd bs=256 count=$cnt | tee -a <target_file> | wc -c`
  772. * rest=`expr $rest - $n`
  773. * done
  774. *
  775. * 'dd' was not designed for full filling of input buffers,
  776. * and does not report exact number of bytes (not blocks).
  777. * Therefore a more complex shell script is needed.
  778. *
  779. * On some systems non-GNU head writes "Usage:" error report to stdout
  780. * instead of stderr. It makes impossible the use of "head || dd"
  781. * algorithm for file appending case, therefore just "dd" is used for it.
  782. */
  783. quoted_name = strutils_shell_escape (name);
  784. vfs_print_message (_("fish: store %s: sending command..."), quoted_name);
  785. /* FIXME: File size is limited to ULONG_MAX */
  786. if (fish->append)
  787. {
  788. shell_commands =
  789. g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_FILESIZE=%" PRIuMAX ";\n",
  790. SUP->scr_append, (char *) NULL);
  791. code = fish_command (me, super, WAIT_REPLY, shell_commands, quoted_name,
  792. (uintmax_t) s.st_size);
  793. g_free (shell_commands);
  794. }
  795. else
  796. {
  797. shell_commands =
  798. g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_FILESIZE=%" PRIuMAX ";\n",
  799. SUP->scr_send, (char *) NULL);
  800. code = fish_command (me, super, WAIT_REPLY, shell_commands, quoted_name,
  801. (uintmax_t) s.st_size);
  802. g_free (shell_commands);
  803. }
  804. g_free (quoted_name);
  805. if (code != PRELIM)
  806. {
  807. close (h);
  808. ERRNOR (E_REMOTE, -1);
  809. }
  810. while (TRUE)
  811. {
  812. ssize_t n, t;
  813. while ((n = read (h, buffer, sizeof (buffer))) < 0)
  814. {
  815. if ((errno == EINTR) && tty_got_interrupt ())
  816. continue;
  817. vfs_print_message ("%s", _("fish: Local read failed, sending zeros"));
  818. close (h);
  819. h = open ("/dev/zero", O_RDONLY);
  820. }
  821. if (n == 0)
  822. break;
  823. t = write (SUP->sockw, buffer, n);
  824. if (t != n)
  825. {
  826. if (t == -1)
  827. me->verrno = errno;
  828. else
  829. me->verrno = EIO;
  830. goto error_return;
  831. }
  832. tty_disable_interrupt_key ();
  833. total += n;
  834. vfs_print_message ("%s: %" PRIuMAX "/%" PRIuMAX, _("fish: storing file"),
  835. (uintmax_t) total, (uintmax_t) s.st_size);
  836. }
  837. close (h);
  838. if (fish_get_reply (me, SUP->sockr, NULL, 0) != COMPLETE)
  839. ERRNOR (E_REMOTE, -1);
  840. return 0;
  841. error_return:
  842. close (h);
  843. fish_get_reply (me, SUP->sockr, NULL, 0);
  844. return -1;
  845. }
  846. /* --------------------------------------------------------------------------------------------- */
  847. static int
  848. fish_linear_start (struct vfs_class *me, vfs_file_handler_t * fh, off_t offset)
  849. {
  850. fish_fh_data_t *fish;
  851. gchar *shell_commands = NULL;
  852. struct vfs_s_super *super = FH_SUPER;
  853. char *name;
  854. char *quoted_name;
  855. if (fh->data == NULL)
  856. fh->data = g_new0 (fish_fh_data_t, 1);
  857. fish = (fish_fh_data_t *) fh->data;
  858. name = vfs_s_fullpath (me, fh->ino);
  859. if (name == NULL)
  860. return 0;
  861. quoted_name = strutils_shell_escape (name);
  862. g_free (name);
  863. fish->append = FALSE;
  864. /*
  865. * Check whether the remote file is readable by using 'dd' to copy
  866. * a single byte from the remote file to /dev/null. If 'dd' completes
  867. * with exit status of 0 use 'cat' to send the file contents to the
  868. * standard output (i.e. over the network).
  869. */
  870. shell_commands =
  871. g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_START_OFFSET=%" PRIuMAX ";\n",
  872. SUP->scr_get, (char *) NULL);
  873. offset = fish_command (me, super, WANT_STRING, shell_commands, quoted_name, (uintmax_t) offset);
  874. g_free (shell_commands);
  875. g_free (quoted_name);
  876. if (offset != PRELIM)
  877. ERRNOR (E_REMOTE, 0);
  878. fh->linear = LS_LINEAR_OPEN;
  879. fish->got = 0;
  880. errno = 0;
  881. #if SIZEOF_OFF_T == SIZEOF_LONG
  882. fish->total = (off_t) strtol (reply_str, NULL, 10);
  883. #else
  884. fish->total = (off_t) g_ascii_strtoll (reply_str, NULL, 10);
  885. #endif
  886. if (errno != 0)
  887. ERRNOR (E_REMOTE, 0);
  888. return 1;
  889. }
  890. /* --------------------------------------------------------------------------------------------- */
  891. static void
  892. fish_linear_abort (struct vfs_class *me, vfs_file_handler_t * fh)
  893. {
  894. fish_fh_data_t *fish = (fish_fh_data_t *) fh->data;
  895. struct vfs_s_super *super = FH_SUPER;
  896. char buffer[BUF_8K];
  897. ssize_t n;
  898. vfs_print_message ("%s", _("Aborting transfer..."));
  899. do
  900. {
  901. n = MIN ((off_t) sizeof (buffer), (fish->total - fish->got));
  902. if (n != 0)
  903. {
  904. n = read (SUP->sockr, buffer, n);
  905. if (n < 0)
  906. return;
  907. fish->got += n;
  908. }
  909. }
  910. while (n != 0);
  911. if (fish_get_reply (me, SUP->sockr, NULL, 0) != COMPLETE)
  912. vfs_print_message ("%s", _("Error reported after abort."));
  913. else
  914. vfs_print_message ("%s", _("Aborted transfer would be successful."));
  915. }
  916. /* --------------------------------------------------------------------------------------------- */
  917. static ssize_t
  918. fish_linear_read (struct vfs_class *me, vfs_file_handler_t * fh, void *buf, size_t len)
  919. {
  920. fish_fh_data_t *fish = (fish_fh_data_t *) fh->data;
  921. struct vfs_s_super *super = FH_SUPER;
  922. ssize_t n = 0;
  923. len = MIN ((size_t) (fish->total - fish->got), len);
  924. tty_disable_interrupt_key ();
  925. while (len != 0 && ((n = read (SUP->sockr, buf, len)) < 0))
  926. {
  927. if ((errno == EINTR) && !tty_got_interrupt ())
  928. continue;
  929. break;
  930. }
  931. tty_enable_interrupt_key ();
  932. if (n > 0)
  933. fish->got += n;
  934. else if (n < 0)
  935. fish_linear_abort (me, fh);
  936. else if (fish_get_reply (me, SUP->sockr, NULL, 0) != COMPLETE)
  937. ERRNOR (E_REMOTE, -1);
  938. ERRNOR (errno, n);
  939. }
  940. /* --------------------------------------------------------------------------------------------- */
  941. static void
  942. fish_linear_close (struct vfs_class *me, vfs_file_handler_t * fh)
  943. {
  944. fish_fh_data_t *fish = (fish_fh_data_t *) fh->data;
  945. if (fish->total != fish->got)
  946. fish_linear_abort (me, fh);
  947. }
  948. /* --------------------------------------------------------------------------------------------- */
  949. static int
  950. fish_ctl (void *fh, int ctlop, void *arg)
  951. {
  952. (void) arg;
  953. (void) fh;
  954. (void) ctlop;
  955. return 0;
  956. #if 0
  957. switch (ctlop)
  958. {
  959. case VFS_CTL_IS_NOTREADY:
  960. {
  961. int v;
  962. if (FH->linear == LS_NOT_LINEAR)
  963. vfs_die ("You may not do this");
  964. if (FH->linear == LS_LINEAR_CLOSED || FH->linear == LS_LINEAR_PREOPEN)
  965. return 0;
  966. v = vfs_s_select_on_two (FH_SUPER->u.fish.sockr, 0);
  967. return (((v < 0) && (errno == EINTR)) || v == 0) ? 1 : 0;
  968. }
  969. default:
  970. return 0;
  971. }
  972. #endif
  973. }
  974. /* --------------------------------------------------------------------------------------------- */
  975. static int
  976. G_GNUC_PRINTF (5, 6)
  977. fish_send_command (struct vfs_class *me, struct vfs_s_super *super, int flags, const char *scr,
  978. const char *vars, ...)
  979. {
  980. int r;
  981. GString *command;
  982. va_list ap;
  983. command = g_string_new (SUP->scr_env);
  984. va_start (ap, vars);
  985. g_string_append_vprintf (command, vars, ap);
  986. va_end (ap);
  987. g_string_append (command, scr);
  988. r = fish_command (me, super, WAIT_REPLY, "%s", command->str);
  989. vfs_stamp_create (&vfs_fish_ops, super);
  990. g_string_free (command, TRUE);
  991. if (r != COMPLETE)
  992. ERRNOR (E_REMOTE, -1);
  993. if ((flags & OPT_FLUSH) != 0)
  994. vfs_s_invalidate (me, super);
  995. return 0;
  996. }
  997. /* --------------------------------------------------------------------------------------------- */
  998. static int
  999. fish_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
  1000. {
  1001. const char *crpath1, *crpath2;
  1002. char *rpath1, *rpath2;
  1003. struct vfs_s_super *super, *super2;
  1004. const vfs_path_element_t *path_element;
  1005. int ret;
  1006. path_element = vfs_path_get_by_index (vpath1, -1);
  1007. crpath1 = vfs_s_get_path (vpath1, &super, 0);
  1008. if (crpath1 == NULL)
  1009. return -1;
  1010. crpath2 = vfs_s_get_path (vpath2, &super2, 0);
  1011. if (crpath2 == NULL)
  1012. return -1;
  1013. rpath1 = strutils_shell_escape (crpath1);
  1014. rpath2 = strutils_shell_escape (crpath2);
  1015. ret =
  1016. fish_send_command (path_element->class, super2, OPT_FLUSH, SUP->scr_mv,
  1017. "FISH_FILEFROM=%s FISH_FILETO=%s;\n", rpath1, rpath2);
  1018. g_free (rpath1);
  1019. g_free (rpath2);
  1020. return ret;
  1021. }
  1022. /* --------------------------------------------------------------------------------------------- */
  1023. static int
  1024. fish_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
  1025. {
  1026. const char *crpath1, *crpath2;
  1027. char *rpath1, *rpath2;
  1028. struct vfs_s_super *super, *super2;
  1029. const vfs_path_element_t *path_element;
  1030. int ret;
  1031. path_element = vfs_path_get_by_index (vpath1, -1);
  1032. crpath1 = vfs_s_get_path (vpath1, &super, 0);
  1033. if (crpath1 == NULL)
  1034. return -1;
  1035. crpath2 = vfs_s_get_path (vpath2, &super2, 0);
  1036. if (crpath2 == NULL)
  1037. return -1;
  1038. rpath1 = strutils_shell_escape (crpath1);
  1039. rpath2 = strutils_shell_escape (crpath2);
  1040. ret =
  1041. fish_send_command (path_element->class, super2, OPT_FLUSH, SUP->scr_hardlink,
  1042. "FISH_FILEFROM=%s FISH_FILETO=%s;\n", rpath1, rpath2);
  1043. g_free (rpath1);
  1044. g_free (rpath2);
  1045. return ret;
  1046. }
  1047. /* --------------------------------------------------------------------------------------------- */
  1048. static int
  1049. fish_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
  1050. {
  1051. char *qsetto;
  1052. const char *crpath;
  1053. char *rpath;
  1054. struct vfs_s_super *super;
  1055. const vfs_path_element_t *path_element;
  1056. int ret;
  1057. path_element = vfs_path_get_by_index (vpath2, -1);
  1058. crpath = vfs_s_get_path (vpath2, &super, 0);
  1059. if (crpath == NULL)
  1060. return -1;
  1061. rpath = strutils_shell_escape (crpath);
  1062. qsetto = strutils_shell_escape (vfs_path_get_by_index (vpath1, -1)->path);
  1063. ret =
  1064. fish_send_command (path_element->class, super, OPT_FLUSH, SUP->scr_ln,
  1065. "FISH_FILEFROM=%s FISH_FILETO=%s;\n", qsetto, rpath);
  1066. g_free (qsetto);
  1067. g_free (rpath);
  1068. return ret;
  1069. }
  1070. /* --------------------------------------------------------------------------------------------- */
  1071. static int
  1072. fish_stat (const vfs_path_t * vpath, struct stat *buf)
  1073. {
  1074. int ret;
  1075. ret = vfs_s_stat (vpath, buf);
  1076. fish_set_blksize (buf);
  1077. return ret;
  1078. }
  1079. /* --------------------------------------------------------------------------------------------- */
  1080. static int
  1081. fish_lstat (const vfs_path_t * vpath, struct stat *buf)
  1082. {
  1083. int ret;
  1084. ret = vfs_s_lstat (vpath, buf);
  1085. fish_set_blksize (buf);
  1086. return ret;
  1087. }
  1088. /* --------------------------------------------------------------------------------------------- */
  1089. static int
  1090. fish_fstat (void *vfs_info, struct stat *buf)
  1091. {
  1092. int ret;
  1093. ret = vfs_s_fstat (vfs_info, buf);
  1094. fish_set_blksize (buf);
  1095. return ret;
  1096. }
  1097. /* --------------------------------------------------------------------------------------------- */
  1098. static int
  1099. fish_chmod (const vfs_path_t * vpath, mode_t mode)
  1100. {
  1101. const char *crpath;
  1102. char *rpath;
  1103. struct vfs_s_super *super;
  1104. const vfs_path_element_t *path_element;
  1105. int ret;
  1106. path_element = vfs_path_get_by_index (vpath, -1);
  1107. crpath = vfs_s_get_path (vpath, &super, 0);
  1108. if (crpath == NULL)
  1109. return -1;
  1110. rpath = strutils_shell_escape (crpath);
  1111. ret =
  1112. fish_send_command (path_element->class, super, OPT_FLUSH, SUP->scr_chmod,
  1113. "FISH_FILENAME=%s FISH_FILEMODE=%4.4o;\n", rpath, (int) (mode & 07777));
  1114. g_free (rpath);
  1115. return ret;;
  1116. }
  1117. /* --------------------------------------------------------------------------------------------- */
  1118. static int
  1119. fish_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
  1120. {
  1121. char *sowner, *sgroup;
  1122. struct passwd *pw;
  1123. struct group *gr;
  1124. const char *crpath;
  1125. char *rpath;
  1126. struct vfs_s_super *super;
  1127. const vfs_path_element_t *path_element;
  1128. int ret;
  1129. pw = getpwuid (owner);
  1130. if (pw == NULL)
  1131. return 0;
  1132. gr = getgrgid (group);
  1133. if (gr == NULL)
  1134. return 0;
  1135. sowner = pw->pw_name;
  1136. sgroup = gr->gr_name;
  1137. path_element = vfs_path_get_by_index (vpath, -1);
  1138. crpath = vfs_s_get_path (vpath, &super, 0);
  1139. if (crpath == NULL)
  1140. return -1;
  1141. rpath = strutils_shell_escape (crpath);
  1142. /* FIXME: what should we report if chgrp succeeds but chown fails? */
  1143. ret =
  1144. fish_send_command (path_element->class, super, OPT_FLUSH, SUP->scr_chown,
  1145. "FISH_FILENAME=%s FISH_FILEOWNER=%s FISH_FILEGROUP=%s;\n", rpath, sowner,
  1146. sgroup);
  1147. g_free (rpath);
  1148. return ret;
  1149. }
  1150. /* --------------------------------------------------------------------------------------------- */
  1151. static void
  1152. fish_get_atime (mc_timesbuf_t * times, time_t * sec, long *nsec)
  1153. {
  1154. #ifdef HAVE_UTIMENSAT
  1155. *sec = (*times)[0].tv_sec;
  1156. *nsec = (*times)[0].tv_nsec;
  1157. #else
  1158. *sec = times->actime;
  1159. *nsec = 0;
  1160. #endif
  1161. }
  1162. /* --------------------------------------------------------------------------------------------- */
  1163. static void
  1164. fish_get_mtime (mc_timesbuf_t * times, time_t * sec, long *nsec)
  1165. {
  1166. #ifdef HAVE_UTIMENSAT
  1167. *sec = (*times)[1].tv_sec;
  1168. *nsec = (*times)[1].tv_nsec;
  1169. #else
  1170. *sec = times->modtime;
  1171. *nsec = 0;
  1172. #endif
  1173. }
  1174. /* --------------------------------------------------------------------------------------------- */
  1175. static int
  1176. fish_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
  1177. {
  1178. char utcatime[16], utcmtime[16];
  1179. char utcatime_w_nsec[30], utcmtime_w_nsec[30];
  1180. time_t atime, mtime;
  1181. long atime_nsec, mtime_nsec;
  1182. struct tm *gmt;
  1183. const char *crpath;
  1184. char *rpath;
  1185. struct vfs_s_super *super;
  1186. const vfs_path_element_t *path_element;
  1187. int ret;
  1188. path_element = vfs_path_get_by_index (vpath, -1);
  1189. crpath = vfs_s_get_path (vpath, &super, 0);
  1190. if (crpath == NULL)
  1191. return -1;
  1192. rpath = strutils_shell_escape (crpath);
  1193. fish_get_atime (times, &atime, &atime_nsec);
  1194. gmt = gmtime (&atime);
  1195. g_snprintf (utcatime, sizeof (utcatime), "%04d%02d%02d%02d%02d.%02d",
  1196. gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
  1197. gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
  1198. g_snprintf (utcatime_w_nsec, sizeof (utcatime_w_nsec), "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
  1199. gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
  1200. gmt->tm_hour, gmt->tm_min, gmt->tm_sec, atime_nsec);
  1201. fish_get_mtime (times, &mtime, &mtime_nsec);
  1202. gmt = gmtime (&mtime);
  1203. g_snprintf (utcmtime, sizeof (utcmtime), "%04d%02d%02d%02d%02d.%02d",
  1204. gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
  1205. gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
  1206. g_snprintf (utcmtime_w_nsec, sizeof (utcmtime_w_nsec), "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
  1207. gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
  1208. gmt->tm_hour, gmt->tm_min, gmt->tm_sec, mtime_nsec);
  1209. ret = fish_send_command (path_element->class, super, OPT_FLUSH, SUP->scr_utime,
  1210. "FISH_FILENAME=%s FISH_FILEATIME=%ld FISH_FILEMTIME=%ld "
  1211. "FISH_TOUCHATIME=%s FISH_TOUCHMTIME=%s FISH_TOUCHATIME_W_NSEC=\"%s\" "
  1212. "FISH_TOUCHMTIME_W_NSEC=\"%s\";\n", rpath, (long) atime, (long) mtime,
  1213. utcatime, utcmtime, utcatime_w_nsec, utcmtime_w_nsec);
  1214. g_free (rpath);
  1215. return ret;
  1216. }
  1217. /* --------------------------------------------------------------------------------------------- */
  1218. static int
  1219. fish_unlink (const vfs_path_t * vpath)
  1220. {
  1221. const char *crpath;
  1222. char *rpath;
  1223. struct vfs_s_super *super;
  1224. const vfs_path_element_t *path_element;
  1225. int ret;
  1226. path_element = vfs_path_get_by_index (vpath, -1);
  1227. crpath = vfs_s_get_path (vpath, &super, 0);
  1228. if (crpath == NULL)
  1229. return -1;
  1230. rpath = strutils_shell_escape (crpath);
  1231. ret =
  1232. fish_send_command (path_element->class, super, OPT_FLUSH, SUP->scr_unlink,
  1233. "FISH_FILENAME=%s;\n", rpath);
  1234. g_free (rpath);
  1235. return ret;
  1236. }
  1237. /* --------------------------------------------------------------------------------------------- */
  1238. static int
  1239. fish_exists (const vfs_path_t * vpath)
  1240. {
  1241. const char *crpath;
  1242. char *rpath;
  1243. struct vfs_s_super *super;
  1244. const vfs_path_element_t *path_element;
  1245. int ret;
  1246. path_element = vfs_path_get_by_index (vpath, -1);
  1247. crpath = vfs_s_get_path (vpath, &super, 0);
  1248. if (crpath == NULL)
  1249. return -1;
  1250. rpath = strutils_shell_escape (crpath);
  1251. ret =
  1252. fish_send_command (path_element->class, super, OPT_FLUSH, SUP->scr_exists,
  1253. "FISH_FILENAME=%s;\n", rpath);
  1254. g_free (rpath);
  1255. return (ret == 0 ? 1 : 0);
  1256. }
  1257. /* --------------------------------------------------------------------------------------------- */
  1258. static int
  1259. fish_mkdir (const vfs_path_t * vpath, mode_t mode)
  1260. {
  1261. const char *crpath;
  1262. char *rpath;
  1263. struct vfs_s_super *super;
  1264. const vfs_path_element_t *path_element;
  1265. int ret;
  1266. (void) mode;
  1267. path_element = vfs_path_get_by_index (vpath, -1);
  1268. crpath = vfs_s_get_path (vpath, &super, 0);
  1269. if (crpath == NULL)
  1270. return -1;
  1271. rpath = strutils_shell_escape (crpath);
  1272. ret =
  1273. fish_send_command (path_element->class, super, OPT_FLUSH, SUP->scr_mkdir,
  1274. "FISH_FILENAME=%s;\n", rpath);
  1275. g_free (rpath);
  1276. if (ret != 0)
  1277. return ret;
  1278. if (fish_exists (vpath) == 0)
  1279. {
  1280. path_element->class->verrno = EACCES;
  1281. return -1;
  1282. }
  1283. return 0;
  1284. }
  1285. /* --------------------------------------------------------------------------------------------- */
  1286. static int
  1287. fish_rmdir (const vfs_path_t * vpath)
  1288. {
  1289. const char *crpath;
  1290. char *rpath;
  1291. struct vfs_s_super *super;
  1292. const vfs_path_element_t *path_element;
  1293. int ret;
  1294. path_element = vfs_path_get_by_index (vpath, -1);
  1295. crpath = vfs_s_get_path (vpath, &super, 0);
  1296. if (crpath == NULL)
  1297. return -1;
  1298. rpath = strutils_shell_escape (crpath);
  1299. ret =
  1300. fish_send_command (path_element->class, super, OPT_FLUSH, SUP->scr_rmdir,
  1301. "FISH_FILENAME=%s;\n", rpath);
  1302. g_free (rpath);
  1303. return ret;
  1304. }
  1305. /* --------------------------------------------------------------------------------------------- */
  1306. static void
  1307. fish_fh_free_data (vfs_file_handler_t * fh)
  1308. {
  1309. if (fh != NULL)
  1310. MC_PTR_FREE (fh->data);
  1311. }
  1312. /* --------------------------------------------------------------------------------------------- */
  1313. static int
  1314. fish_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
  1315. {
  1316. fish_fh_data_t *fish;
  1317. (void) mode;
  1318. fh->data = g_new0 (fish_fh_data_t, 1);
  1319. fish = (fish_fh_data_t *) fh->data;
  1320. /* File will be written only, so no need to retrieve it */
  1321. if (((flags & O_WRONLY) == O_WRONLY) && ((flags & (O_RDONLY | O_RDWR)) == 0))
  1322. {
  1323. /* user pressed the button [ Append ] in the "Copy" dialog */
  1324. if ((flags & O_APPEND) != 0)
  1325. fish->append = TRUE;
  1326. if (fh->ino->localname == NULL)
  1327. {
  1328. vfs_path_t *vpath;
  1329. int tmp_handle;
  1330. tmp_handle = vfs_mkstemps (&vpath, me->name, fh->ino->ent->name);
  1331. if (tmp_handle == -1)
  1332. {
  1333. vfs_path_free (vpath);
  1334. goto fail;
  1335. }
  1336. fh->ino->localname = g_strdup (vfs_path_as_str (vpath));
  1337. vfs_path_free (vpath);
  1338. close (tmp_handle);
  1339. }
  1340. return 0;
  1341. }
  1342. if (fh->ino->localname == NULL && vfs_s_retrieve_file (me, fh->ino) == -1)
  1343. goto fail;
  1344. if (fh->ino->localname == NULL)
  1345. vfs_die ("retrieve_file failed to fill in localname");
  1346. return 0;
  1347. fail:
  1348. fish_fh_free_data (fh);
  1349. return -1;
  1350. }
  1351. /* --------------------------------------------------------------------------------------------- */
  1352. static void
  1353. fish_fill_names (struct vfs_class *me, fill_names_f func)
  1354. {
  1355. GList *iter;
  1356. for (iter = MEDATA->supers; iter != NULL; iter = g_list_next (iter))
  1357. {
  1358. const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
  1359. char *name;
  1360. char gbuf[10];
  1361. const char *flags = "";
  1362. switch (super->path_element->port)
  1363. {
  1364. case FISH_FLAG_RSH:
  1365. flags = ":r";
  1366. break;
  1367. case FISH_FLAG_COMPRESSED:
  1368. flags = ":C";
  1369. break;
  1370. default:
  1371. if (super->path_element->port > FISH_FLAG_RSH)
  1372. {
  1373. g_snprintf (gbuf, sizeof (gbuf), ":%d", super->path_element->port);
  1374. flags = gbuf;
  1375. }
  1376. break;
  1377. }
  1378. name =
  1379. g_strconcat (vfs_fish_ops.prefix, VFS_PATH_URL_DELIMITER,
  1380. super->path_element->user, "@", super->path_element->host, flags,
  1381. PATH_SEP_STR, super->path_element->path, (char *) NULL);
  1382. func (name);
  1383. g_free (name);
  1384. }
  1385. }
  1386. /* --------------------------------------------------------------------------------------------- */
  1387. static void *
  1388. fish_open (const vfs_path_t * vpath, int flags, mode_t mode)
  1389. {
  1390. /*
  1391. sorry, i've places hack here
  1392. cause fish don't able to open files with O_EXCL flag
  1393. */
  1394. flags &= ~O_EXCL;
  1395. return vfs_s_open (vpath, flags, mode);
  1396. }
  1397. /* --------------------------------------------------------------------------------------------- */
  1398. /*** public functions ****************************************************************************/
  1399. /* --------------------------------------------------------------------------------------------- */
  1400. void
  1401. init_fish (void)
  1402. {
  1403. static struct vfs_s_subclass fish_subclass;
  1404. tcp_init ();
  1405. fish_subclass.flags = VFS_S_REMOTE | VFS_S_USETMP;
  1406. fish_subclass.archive_same = fish_archive_same;
  1407. fish_subclass.open_archive = fish_open_archive;
  1408. fish_subclass.free_archive = fish_free_archive;
  1409. fish_subclass.fh_open = fish_fh_open;
  1410. fish_subclass.fh_free_data = fish_fh_free_data;
  1411. fish_subclass.dir_load = fish_dir_load;
  1412. fish_subclass.file_store = fish_file_store;
  1413. fish_subclass.linear_start = fish_linear_start;
  1414. fish_subclass.linear_read = fish_linear_read;
  1415. fish_subclass.linear_close = fish_linear_close;
  1416. vfs_s_init_class (&vfs_fish_ops, &fish_subclass);
  1417. vfs_fish_ops.name = "fish";
  1418. vfs_fish_ops.prefix = "sh";
  1419. vfs_fish_ops.fill_names = fish_fill_names;
  1420. vfs_fish_ops.stat = fish_stat;
  1421. vfs_fish_ops.lstat = fish_lstat;
  1422. vfs_fish_ops.fstat = fish_fstat;
  1423. vfs_fish_ops.chmod = fish_chmod;
  1424. vfs_fish_ops.chown = fish_chown;
  1425. vfs_fish_ops.utime = fish_utime;
  1426. vfs_fish_ops.open = fish_open;
  1427. vfs_fish_ops.symlink = fish_symlink;
  1428. vfs_fish_ops.link = fish_link;
  1429. vfs_fish_ops.unlink = fish_unlink;
  1430. vfs_fish_ops.rename = fish_rename;
  1431. vfs_fish_ops.mkdir = fish_mkdir;
  1432. vfs_fish_ops.rmdir = fish_rmdir;
  1433. vfs_fish_ops.ctl = fish_ctl;
  1434. vfs_register_class (&vfs_fish_ops);
  1435. }
  1436. /* --------------------------------------------------------------------------------------------- */