fish.c 52 KB

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