Zero struct stat tv_nsec (if supported) whenever st is filled manually
[midnight-commander.git] / src / vfs / fish / fish.c
blob12ca2f2728d17f1842c91ee0abc11a55bec66745
1 /*
2 Virtual File System: FISH implementation for transfering files over
3 shell connections.
5 Copyright (C) 1998-2017
6 Free Software Foundation, Inc.
8 Written by:
9 Pavel Machek, 1998
10 Michal Svec, 2000
11 Andrew Borodin <aborodin@vmail.ru>, 2010
12 Slava Zanko <slavazanko@gmail.com>, 2010, 2013
13 Ilia Maslakov <il.smind@gmail.com>, 2010
15 Derived from ftpfs.c.
17 This file is part of the Midnight Commander.
19 The Midnight Commander is free software: you can redistribute it
20 and/or modify it under the terms of the GNU General Public License as
21 published by the Free Software Foundation, either version 3 of the License,
22 or (at your option) any later version.
24 The Midnight Commander is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
29 You should have received a copy of the GNU General Public License
30 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 /**
34 * \file
35 * \brief Source: Virtual File System: FISH implementation for transfering files over
36 * shell connections
37 * \author Pavel Machek
38 * \author Michal Svec
39 * \date 1998, 2000
41 * Derived from ftpfs.c
42 * Read README.fish for protocol specification.
44 * Syntax of path is: \verbatim sh://user@host[:Cr]/path \endverbatim
45 * where C means you want compressed connection,
46 * and r means you want to use rsh
48 * Namespace: fish_vfs_ops exported.
51 /* Define this if your ssh can take -I option */
53 #include <config.h>
54 #include <errno.h>
55 #include <pwd.h>
56 #include <grp.h>
57 #include <sys/time.h> /* gettimeofday() */
58 #include <stdlib.h>
59 #include <string.h>
60 #include <inttypes.h> /* uintmax_t */
62 #include "lib/global.h"
63 #include "lib/tty/tty.h" /* enable/disable interrupt key */
64 #include "lib/strescape.h"
65 #include "lib/unixcompat.h"
66 #include "lib/fileloc.h"
67 #include "lib/util.h" /* my_exit() */
68 #include "lib/mcconfig.h"
70 #include "src/execute.h" /* pre_exec, post_exec */
72 #include "lib/vfs/vfs.h"
73 #include "lib/vfs/utilvfs.h"
74 #include "lib/vfs/netutil.h"
75 #include "lib/vfs/xdirentry.h"
76 #include "lib/vfs/gc.h" /* vfs_stamp_create */
78 #include "fish.h"
79 #include "fishdef.h"
81 /*** global variables ****************************************************************************/
83 int fish_directory_timeout = 900;
85 /*** file scope macro definitions ****************************************************************/
87 #define DO_RESOLVE_SYMLINK 1
88 #define DO_OPEN 2
89 #define DO_FREE_RESOURCE 4
91 #define FISH_FLAG_COMPRESSED 1
92 #define FISH_FLAG_RSH 2
94 #define OPT_FLUSH 1
95 #define OPT_IGNORE_ERROR 2
98 * Reply codes.
100 #define PRELIM 1 /* positive preliminary */
101 #define COMPLETE 2 /* positive completion */
102 #define CONTINUE 3 /* positive intermediate */
103 #define TRANSIENT 4 /* transient negative completion */
104 #define ERROR 5 /* permanent negative completion */
106 /* command wait_flag: */
107 #define NONE 0x00
108 #define WAIT_REPLY 0x01
109 #define WANT_STRING 0x02
111 /* environment flags */
112 #define FISH_HAVE_HEAD 1
113 #define FISH_HAVE_SED 2
114 #define FISH_HAVE_AWK 4
115 #define FISH_HAVE_PERL 8
116 #define FISH_HAVE_LSQ 16
117 #define FISH_HAVE_DATE_MDYT 32
118 #define FISH_HAVE_TAIL 64
120 #define SUP ((fish_super_data_t *) super->data)
122 /*** file scope type declarations ****************************************************************/
124 typedef struct
126 int sockr;
127 int sockw;
128 char *scr_ls;
129 char *scr_chmod;
130 char *scr_utime;
131 char *scr_exists;
132 char *scr_mkdir;
133 char *scr_unlink;
134 char *scr_chown;
135 char *scr_rmdir;
136 char *scr_ln;
137 char *scr_mv;
138 char *scr_hardlink;
139 char *scr_get;
140 char *scr_send;
141 char *scr_append;
142 char *scr_info;
143 int host_flags;
144 char *scr_env;
145 } fish_super_data_t;
147 typedef struct
149 off_t got;
150 off_t total;
151 gboolean append;
152 } fish_fh_data_t;
154 /*** file scope variables ************************************************************************/
156 static char reply_str[80];
158 static struct vfs_class vfs_fish_ops;
160 /* --------------------------------------------------------------------------------------------- */
161 /*** file scope functions ************************************************************************/
162 /* --------------------------------------------------------------------------------------------- */
164 static void
165 fish_set_blksize (struct stat *s)
167 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
168 /* redefine block size */
169 s->st_blksize = 64 * 1024; /* FIXME */
170 #endif
173 /* --------------------------------------------------------------------------------------------- */
175 static struct stat *
176 fish_default_stat (struct vfs_class *me)
178 struct stat *s;
180 s = vfs_s_default_stat (me, S_IFDIR | 0755);
181 fish_set_blksize (s);
182 vfs_adjust_stat (s);
184 return s;
187 /* --------------------------------------------------------------------------------------------- */
189 static char *
190 fish_load_script_from_file (const char *hostname, const char *script_name, const char *def_content)
192 char *scr_filename = NULL;
193 char *scr_content;
194 gsize scr_len = 0;
196 /* 1st: scan user directory */
197 scr_filename = g_build_path (PATH_SEP_STR, mc_config_get_data_path (), FISH_PREFIX, hostname,
198 script_name, (char *) NULL);
199 /* silent about user dir */
200 g_file_get_contents (scr_filename, &scr_content, &scr_len, NULL);
201 g_free (scr_filename);
202 /* 2nd: scan system dir */
203 if (scr_content == NULL)
205 scr_filename =
206 g_build_path (PATH_SEP_STR, LIBEXECDIR, FISH_PREFIX, script_name, (char *) NULL);
207 g_file_get_contents (scr_filename, &scr_content, &scr_len, NULL);
208 g_free (scr_filename);
211 if (scr_content != NULL)
212 return scr_content;
214 return g_strdup (def_content);
217 /* --------------------------------------------------------------------------------------------- */
219 static int
220 fish_decode_reply (char *s, gboolean was_garbage)
222 int code;
224 /* cppcheck-suppress invalidscanf */
225 if (sscanf (s, "%d", &code) == 0)
227 code = 500;
228 return 5;
230 if (code < 100)
231 return was_garbage ? ERROR : (code == 0 ? COMPLETE : PRELIM);
232 return code / 100;
235 /* --------------------------------------------------------------------------------------------- */
236 /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
238 static int
239 fish_get_reply (struct vfs_class *me, int sock, char *string_buf, int string_len)
241 char answer[BUF_1K];
242 gboolean was_garbage = FALSE;
244 while (TRUE)
246 if (!vfs_s_get_line (me, sock, answer, sizeof (answer), '\n'))
248 if (string_buf != NULL)
249 *string_buf = '\0';
250 return 4;
253 if (strncmp (answer, "### ", 4) == 0)
254 return fish_decode_reply (answer + 4, was_garbage ? 1 : 0);
256 was_garbage = TRUE;
257 if (string_buf != NULL)
258 g_strlcpy (string_buf, answer, string_len);
262 /* --------------------------------------------------------------------------------------------- */
264 static int
265 G_GNUC_PRINTF (4, 5)
266 fish_command (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *fmt, ...)
268 va_list ap;
269 char *str;
270 ssize_t status;
271 FILE *logfile = MEDATA->logfile;
273 va_start (ap, fmt);
274 str = g_strdup_vprintf (fmt, ap);
275 va_end (ap);
277 if (logfile != NULL)
279 size_t ret;
281 ret = fwrite (str, strlen (str), 1, logfile);
282 ret = fflush (logfile);
283 (void) ret;
286 tty_enable_interrupt_key ();
287 status = write (SUP->sockw, str, strlen (str));
288 g_free (str);
289 tty_disable_interrupt_key ();
291 if (status < 0)
292 return TRANSIENT;
294 if (wait_reply)
295 return fish_get_reply (me, SUP->sockr,
296 (wait_reply & WANT_STRING) ? reply_str :
297 NULL, sizeof (reply_str) - 1);
298 return COMPLETE;
301 /* --------------------------------------------------------------------------------------------- */
303 static void
304 fish_free_archive (struct vfs_class *me, struct vfs_s_super *super)
306 if ((SUP->sockw != -1) || (SUP->sockr != -1))
308 vfs_print_message (_("fish: Disconnecting from %s"), super->name ? super->name : "???");
309 fish_command (me, super, NONE, "%s", "#BYE\nexit\n");
310 close (SUP->sockw);
311 close (SUP->sockr);
312 SUP->sockw = SUP->sockr = -1;
314 g_free (SUP->scr_ls);
315 g_free (SUP->scr_exists);
316 g_free (SUP->scr_mkdir);
317 g_free (SUP->scr_unlink);
318 g_free (SUP->scr_chown);
319 g_free (SUP->scr_chmod);
320 g_free (SUP->scr_utime);
321 g_free (SUP->scr_rmdir);
322 g_free (SUP->scr_ln);
323 g_free (SUP->scr_mv);
324 g_free (SUP->scr_hardlink);
325 g_free (SUP->scr_get);
326 g_free (SUP->scr_send);
327 g_free (SUP->scr_append);
328 g_free (SUP->scr_info);
329 g_free (SUP->scr_env);
330 g_free (SUP);
331 super->data = NULL;
334 /* --------------------------------------------------------------------------------------------- */
336 static void
337 fish_pipeopen (struct vfs_s_super *super, const char *path, const char *argv[])
339 int fileset1[2], fileset2[2];
340 int res;
342 if ((pipe (fileset1) < 0) || (pipe (fileset2) < 0))
343 vfs_die ("Cannot pipe(): %m.");
345 res = fork ();
347 if (res != 0)
349 if (res < 0)
350 vfs_die ("Cannot fork(): %m.");
351 /* We are the parent */
352 close (fileset1[0]);
353 SUP->sockw = fileset1[1];
354 close (fileset2[1]);
355 SUP->sockr = fileset2[0];
357 else
359 res = dup2 (fileset1[0], STDIN_FILENO);
360 close (fileset1[0]);
361 close (fileset1[1]);
362 res = dup2 (fileset2[1], STDOUT_FILENO);
363 close (STDERR_FILENO);
364 /* stderr to /dev/null */
365 res = open ("/dev/null", O_WRONLY);
366 close (fileset2[0]);
367 close (fileset2[1]);
368 execvp (path, (char **) argv);
369 my_exit (3);
373 /* --------------------------------------------------------------------------------------------- */
375 static char *
376 fish_set_env (int flags)
378 GString *tmp;
380 tmp = g_string_sized_new (250);
381 g_string_assign (tmp, "");
383 if ((flags & FISH_HAVE_HEAD) != 0)
384 g_string_append (tmp, "FISH_HAVE_HEAD=1 export FISH_HAVE_HEAD; ");
386 if ((flags & FISH_HAVE_SED) != 0)
387 g_string_append (tmp, "FISH_HAVE_SED=1 export FISH_HAVE_SED; ");
389 if ((flags & FISH_HAVE_AWK) != 0)
390 g_string_append (tmp, "FISH_HAVE_AWK=1 export FISH_HAVE_AWK; ");
392 if ((flags & FISH_HAVE_PERL) != 0)
393 g_string_append (tmp, "FISH_HAVE_PERL=1 export FISH_HAVE_PERL; ");
395 if ((flags & FISH_HAVE_LSQ) != 0)
396 g_string_append (tmp, "FISH_HAVE_LSQ=1 export FISH_HAVE_LSQ; ");
398 if ((flags & FISH_HAVE_DATE_MDYT) != 0)
399 g_string_append (tmp, "FISH_HAVE_DATE_MDYT=1 export FISH_HAVE_DATE_MDYT; ");
401 if ((flags & FISH_HAVE_TAIL) != 0)
402 g_string_append (tmp, "FISH_HAVE_TAIL=1 export FISH_HAVE_TAIL; ");
404 return g_string_free (tmp, FALSE);
407 /* --------------------------------------------------------------------------------------------- */
409 static gboolean
410 fish_info (struct vfs_class *me, struct vfs_s_super *super)
412 if (fish_command (me, super, NONE, "%s", SUP->scr_info) == COMPLETE)
414 while (TRUE)
416 int res;
417 char buffer[BUF_8K];
419 res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP->sockr);
420 if ((res == 0) || (res == EINTR))
421 ERRNOR (ECONNRESET, FALSE);
422 if (strncmp (buffer, "### ", 4) == 0)
423 break;
424 SUP->host_flags = atol (buffer);
426 return TRUE;
428 ERRNOR (E_PROTO, FALSE);
431 /* --------------------------------------------------------------------------------------------- */
433 static void
434 fish_open_archive_pipeopen (struct vfs_s_super *super)
436 char gbuf[10];
437 const char *argv[10]; /* All of 10 is used now */
438 const char *xsh = (super->path_element->port == FISH_FLAG_RSH ? "rsh" : "ssh");
439 int i = 0;
441 argv[i++] = xsh;
442 if (super->path_element->port == FISH_FLAG_COMPRESSED)
443 argv[i++] = "-C";
445 if (super->path_element->port > FISH_FLAG_RSH)
447 argv[i++] = "-p";
448 g_snprintf (gbuf, sizeof (gbuf), "%d", super->path_element->port);
449 argv[i++] = gbuf;
453 * Add the user name to the ssh command line only if it was explicitly
454 * set in vfs URL. rsh/ssh will get current user by default
455 * plus we can set convenient overrides in ~/.ssh/config (explicit -l
456 * option breaks it for some)
459 if (super->path_element->user != NULL)
461 argv[i++] = "-l";
462 argv[i++] = super->path_element->user;
464 else
466 /* The rest of the code assumes it to be a valid username */
467 super->path_element->user = vfs_get_local_username ();
470 argv[i++] = super->path_element->host;
471 argv[i++] = "echo FISH:; /bin/sh";
472 argv[i++] = NULL;
474 fish_pipeopen (super, xsh, argv);
477 /* --------------------------------------------------------------------------------------------- */
479 static gboolean
480 fish_open_archive_talk (struct vfs_class *me, struct vfs_s_super *super)
482 char answer[2048];
484 printf ("\n%s\n", _("fish: Waiting for initial line..."));
486 if (vfs_s_get_line (me, SUP->sockr, answer, sizeof (answer), ':') == 0)
487 return FALSE;
489 if (strstr (answer, "assword") != NULL)
491 /* Currently, this does not work. ssh reads passwords from
492 /dev/tty, not from stdin :-(. */
494 printf ("\n%s\n", _("Sorry, we cannot do password authenticated connections for now."));
496 return FALSE;
497 #if 0
498 if (super->path_element->password == NULL)
500 char *p, *op;
502 p = g_strdup_printf (_("fish: Password is required for %s"), super->path_element->user);
503 op = vfs_get_password (p);
504 g_free (p);
505 if (op == NULL)
506 return FALSE;
507 super->path_element->password = op;
510 printf ("\n%s\n", _("fish: Sending password..."));
513 size_t str_len;
515 str_len = strlen (super->path_element->password);
516 if ((write (SUP.sockw, super->path_element->password, str_len) != (ssize_t) str_len)
517 || (write (SUP->sockw, "\n", 1) != 1))
518 return FALSE;
520 #endif
522 return TRUE;
525 /* --------------------------------------------------------------------------------------------- */
527 static int
528 fish_open_archive_int (struct vfs_class *me, struct vfs_s_super *super)
530 gboolean ftalk;
532 /* hide panels */
533 pre_exec ();
535 /* open pipe */
536 fish_open_archive_pipeopen (super);
538 /* Start talk with ssh-server (password prompt, etc ) */
539 ftalk = fish_open_archive_talk (me, super);
541 /* show panels */
542 post_exec ();
544 if (!ftalk)
545 ERRNOR (E_PROTO, -1);
547 vfs_print_message ("%s", _("fish: Sending initial line..."));
549 * Run 'start_fish_server'. If it doesn't exist - no problem,
550 * we'll talk directly to the shell.
553 if (fish_command
554 (me, super, WAIT_REPLY, "%s",
555 "#FISH\necho; start_fish_server 2>&1; echo '### 200'\n") != COMPLETE)
556 ERRNOR (E_PROTO, -1);
558 vfs_print_message ("%s", _("fish: Handshaking version..."));
559 if (fish_command (me, super, WAIT_REPLY, "%s", "#VER 0.0.3\necho '### 000'\n") != COMPLETE)
560 ERRNOR (E_PROTO, -1);
562 /* Set up remote locale to C, otherwise dates cannot be recognized */
563 if (fish_command
564 (me, super, WAIT_REPLY, "%s",
565 "LANG=C LC_ALL=C LC_TIME=C; export LANG LC_ALL LC_TIME;\n" "echo '### 200'\n") != COMPLETE)
566 ERRNOR (E_PROTO, -1);
568 vfs_print_message ("%s", _("fish: Getting host info..."));
569 if (fish_info (me, super))
570 SUP->scr_env = fish_set_env (SUP->host_flags);
572 #if 0
573 super->name =
574 g_strconcat ("sh://", super->path_element->user, "@", super->path_element->host,
575 PATH_SEP_STR, (char *) NULL);
576 #else
577 super->name = g_strdup (PATH_SEP_STR);
578 #endif
580 super->root = vfs_s_new_inode (me, super, fish_default_stat (me));
582 return 0;
585 /* --------------------------------------------------------------------------------------------- */
587 static int
588 fish_open_archive (struct vfs_s_super *super,
589 const vfs_path_t * vpath, const vfs_path_element_t * vpath_element)
591 (void) vpath;
593 super->data = g_new0 (fish_super_data_t, 1);
594 super->path_element = vfs_path_element_clone (vpath_element);
596 if (strncmp (vpath_element->vfs_prefix, "rsh", 3) == 0)
597 super->path_element->port = FISH_FLAG_RSH;
599 SUP->scr_ls =
600 fish_load_script_from_file (super->path_element->host, FISH_LS_FILE, FISH_LS_DEF_CONTENT);
601 SUP->scr_exists =
602 fish_load_script_from_file (super->path_element->host, FISH_EXISTS_FILE,
603 FISH_EXISTS_DEF_CONTENT);
604 SUP->scr_mkdir =
605 fish_load_script_from_file (super->path_element->host, FISH_MKDIR_FILE,
606 FISH_MKDIR_DEF_CONTENT);
607 SUP->scr_unlink =
608 fish_load_script_from_file (super->path_element->host, FISH_UNLINK_FILE,
609 FISH_UNLINK_DEF_CONTENT);
610 SUP->scr_chown =
611 fish_load_script_from_file (super->path_element->host, FISH_CHOWN_FILE,
612 FISH_CHOWN_DEF_CONTENT);
613 SUP->scr_chmod =
614 fish_load_script_from_file (super->path_element->host, FISH_CHMOD_FILE,
615 FISH_CHMOD_DEF_CONTENT);
616 SUP->scr_utime =
617 fish_load_script_from_file (super->path_element->host, FISH_UTIME_FILE,
618 FISH_UTIME_DEF_CONTENT);
619 SUP->scr_rmdir =
620 fish_load_script_from_file (super->path_element->host, FISH_RMDIR_FILE,
621 FISH_RMDIR_DEF_CONTENT);
622 SUP->scr_ln =
623 fish_load_script_from_file (super->path_element->host, FISH_LN_FILE, FISH_LN_DEF_CONTENT);
624 SUP->scr_mv =
625 fish_load_script_from_file (super->path_element->host, FISH_MV_FILE, FISH_MV_DEF_CONTENT);
626 SUP->scr_hardlink =
627 fish_load_script_from_file (super->path_element->host, FISH_HARDLINK_FILE,
628 FISH_HARDLINK_DEF_CONTENT);
629 SUP->scr_get =
630 fish_load_script_from_file (super->path_element->host, FISH_GET_FILE, FISH_GET_DEF_CONTENT);
631 SUP->scr_send =
632 fish_load_script_from_file (super->path_element->host, FISH_SEND_FILE,
633 FISH_SEND_DEF_CONTENT);
634 SUP->scr_append =
635 fish_load_script_from_file (super->path_element->host, FISH_APPEND_FILE,
636 FISH_APPEND_DEF_CONTENT);
637 SUP->scr_info =
638 fish_load_script_from_file (super->path_element->host, FISH_INFO_FILE,
639 FISH_INFO_DEF_CONTENT);
641 return fish_open_archive_int (vpath_element->class, super);
644 /* --------------------------------------------------------------------------------------------- */
646 static int
647 fish_archive_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *super,
648 const vfs_path_t * vpath, void *cookie)
650 vfs_path_element_t *path_element;
651 int result;
653 (void) vpath;
654 (void) cookie;
656 path_element = vfs_path_element_clone (vpath_element);
658 if (path_element->user == NULL)
659 path_element->user = vfs_get_local_username ();
661 result = ((strcmp (path_element->host, super->path_element->host) == 0)
662 && (strcmp (path_element->user, super->path_element->user) == 0)
663 && (path_element->port == super->path_element->port)) ? 1 : 0;
665 vfs_path_element_free (path_element);
667 return result;
670 /* --------------------------------------------------------------------------------------------- */
672 static int
673 fish_dir_load (struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
675 struct vfs_s_super *super = dir->super;
676 char buffer[BUF_8K] = "\0";
677 struct vfs_s_entry *ent = NULL;
678 FILE *logfile;
679 char *quoted_path;
680 int reply_code;
681 gchar *shell_commands;
684 * Simple FISH debug interface :]
686 #if 0
687 if (MEDATA->logfile == NULL)
688 MEDATA->logfile = fopen ("/tmp/mc-FISH.sh", "w");
689 #endif
690 logfile = MEDATA->logfile;
692 vfs_print_message (_("fish: Reading directory %s..."), remote_path);
694 gettimeofday (&dir->timestamp, NULL);
695 dir->timestamp.tv_sec += fish_directory_timeout;
696 quoted_path = strutils_shell_escape (remote_path);
697 shell_commands = g_strconcat (SUP->scr_env, "FISH_FILENAME=%s;\n", SUP->scr_ls, (char *) NULL);
698 fish_command (me, super, NONE, shell_commands, quoted_path);
699 g_free (shell_commands);
700 g_free (quoted_path);
701 ent = vfs_s_generate_entry (me, NULL, dir, 0);
703 while (TRUE)
705 int res;
707 res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP->sockr);
709 if ((res == 0) || (res == EINTR))
711 vfs_s_free_entry (me, ent);
712 me->verrno = ECONNRESET;
713 goto error;
715 if (logfile != NULL)
717 fputs (buffer, logfile);
718 fputs ("\n", logfile);
719 fflush (logfile);
721 if (strncmp (buffer, "### ", 4) == 0)
722 break;
723 if (buffer[0] == '\0')
725 if (ent->name != NULL)
727 vfs_s_insert_entry (me, dir, ent);
728 ent = vfs_s_generate_entry (me, NULL, dir, 0);
730 continue;
733 #define ST ent->ino->st
735 switch (buffer[0])
737 case ':':
739 char *temp;
740 char *data_start = buffer + 1;
741 char *filename = data_start;
742 char *filename_bound;
744 filename_bound = filename + strlen (filename);
746 if (strcmp (data_start, "\".\"") == 0 || strcmp (data_start, "\"..\"") == 0)
747 break; /* We'll do "." and ".." ourselves */
749 if (S_ISLNK (ST.st_mode))
751 char *linkname;
752 char *linkname_bound;
753 /* we expect: "escaped-name" -> "escaped-name"
754 // -> cannot occur in filenames,
755 // because it will be escaped to -\> */
758 linkname_bound = filename_bound;
760 if (*filename == '"')
761 ++filename;
763 linkname = strstr (filename, "\" -> \"");
764 if (linkname == NULL)
766 /* broken client, or smth goes wrong */
767 linkname = filename_bound;
768 if (filename_bound > filename && *(filename_bound - 1) == '"')
769 --filename_bound; /* skip trailing " */
771 else
773 filename_bound = linkname;
774 linkname += 6; /* strlen ("\" -> \"") */
775 if (*(linkname_bound - 1) == '"')
776 --linkname_bound; /* skip trailing " */
779 ent->name = g_strndup (filename, filename_bound - filename);
780 temp = ent->name;
781 ent->name = strutils_shell_unescape (ent->name);
782 g_free (temp);
784 ent->ino->linkname = g_strndup (linkname, linkname_bound - linkname);
785 temp = ent->ino->linkname;
786 ent->ino->linkname = strutils_shell_unescape (ent->ino->linkname);
787 g_free (temp);
789 else
791 /* we expect: "escaped-name" */
792 if (filename_bound - filename > 2)
795 there is at least 2 "
796 and we skip them
798 if (*filename == '"')
799 ++filename;
800 if (*(filename_bound - 1) == '"')
801 --filename_bound;
803 ent->name = g_strndup (filename, filename_bound - filename);
804 temp = ent->name;
805 ent->name = strutils_shell_unescape (ent->name);
806 g_free (temp);
808 break;
810 case 'S':
811 ST.st_size = (off_t) g_ascii_strtoll (buffer + 1, NULL, 10);
812 break;
813 case 'P':
815 size_t skipped;
817 vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode);
818 break;
820 case 'R':
823 raw filemode:
824 we expect: Roctal-filemode octal-filetype uid.gid
826 size_t skipped;
828 vfs_parse_raw_filemode (buffer + 1, &skipped, &ST.st_mode);
829 break;
831 case 'd':
833 vfs_split_text (buffer + 1);
834 if (vfs_parse_filedate (0, &ST.st_ctime) == 0)
835 break;
836 ST.st_atime = ST.st_mtime = ST.st_ctime;
837 #ifdef HAVE_STRUCT_STAT_ST_MTIM
838 ST.st_atim.tv_nsec = ST.st_mtim.tv_nsec = ST.st_ctim.tv_nsec = 0;
839 #endif
841 break;
842 case 'D':
844 struct tm tim;
846 /* cppcheck-suppress invalidscanf */
847 if (sscanf (buffer + 1, "%d %d %d %d %d %d", &tim.tm_year, &tim.tm_mon,
848 &tim.tm_mday, &tim.tm_hour, &tim.tm_min, &tim.tm_sec) != 6)
849 break;
850 ST.st_atime = ST.st_mtime = ST.st_ctime = mktime (&tim);
851 #ifdef HAVE_STRUCT_STAT_ST_MTIM
852 ST.st_atim.tv_nsec = ST.st_mtim.tv_nsec = ST.st_ctim.tv_nsec = 0;
853 #endif
855 break;
856 case 'E':
858 int maj, min;
860 /* cppcheck-suppress invalidscanf */
861 if (sscanf (buffer + 1, "%d,%d", &maj, &min) != 2)
862 break;
863 #ifdef HAVE_STRUCT_STAT_ST_RDEV
864 ST.st_rdev = makedev (maj, min);
865 #endif
867 default:
868 break;
872 vfs_s_free_entry (me, ent);
873 reply_code = fish_decode_reply (buffer + 4, 0);
874 if (reply_code == COMPLETE)
876 vfs_print_message (_("%s: done."), me->name);
877 return 0;
880 me->verrno = reply_code == ERROR ? EACCES : E_REMOTE;
882 error:
883 vfs_print_message (_("%s: failure"), me->name);
884 return -1;
887 /* --------------------------------------------------------------------------------------------- */
889 static int
890 fish_file_store (struct vfs_class *me, vfs_file_handler_t * fh, char *name, char *localname)
892 fish_fh_data_t *fish = (fish_fh_data_t *) fh->data;
893 gchar *shell_commands = NULL;
894 struct vfs_s_super *super = FH_SUPER;
895 int code;
896 off_t total = 0;
897 char buffer[BUF_8K];
898 struct stat s;
899 int h;
900 char *quoted_name;
902 h = open (localname, O_RDONLY);
903 if (h == -1)
904 ERRNOR (EIO, -1);
905 if (fstat (h, &s) < 0)
907 close (h);
908 ERRNOR (EIO, -1);
911 /* First, try this as stor:
913 * ( head -c number ) | ( cat > file; cat >/dev/null )
915 * If 'head' is not present on the remote system, 'dd' will be used.
916 * Unfortunately, we cannot trust most non-GNU 'head' implementations
917 * even if '-c' options is supported. Therefore, we separate GNU head
918 * (and other modern heads?) using '-q' and '-' . This causes another
919 * implementations to fail (because of "incorrect options").
921 * Fallback is:
923 * rest=<number>
924 * while [ $rest -gt 0 ]
925 * do
926 * cnt=`expr \( $rest + 255 \) / 256`
927 * n=`dd bs=256 count=$cnt | tee -a <target_file> | wc -c`
928 * rest=`expr $rest - $n`
929 * done
931 * 'dd' was not designed for full filling of input buffers,
932 * and does not report exact number of bytes (not blocks).
933 * Therefore a more complex shell script is needed.
935 * On some systems non-GNU head writes "Usage:" error report to stdout
936 * instead of stderr. It makes impossible the use of "head || dd"
937 * algorithm for file appending case, therefore just "dd" is used for it.
940 quoted_name = strutils_shell_escape (name);
941 vfs_print_message (_("fish: store %s: sending command..."), quoted_name);
943 /* FIXME: File size is limited to ULONG_MAX */
944 if (fish->append)
946 shell_commands =
947 g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_FILESIZE=%" PRIuMAX ";\n",
948 SUP->scr_append, (char *) NULL);
950 code = fish_command (me, super, WAIT_REPLY, shell_commands, quoted_name,
951 (uintmax_t) s.st_size);
952 g_free (shell_commands);
954 else
956 shell_commands =
957 g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_FILESIZE=%" PRIuMAX ";\n",
958 SUP->scr_send, (char *) NULL);
959 code = fish_command (me, super, WAIT_REPLY, shell_commands, quoted_name,
960 (uintmax_t) s.st_size);
961 g_free (shell_commands);
964 g_free (quoted_name);
966 if (code != PRELIM)
968 close (h);
969 ERRNOR (E_REMOTE, -1);
972 while (TRUE)
974 ssize_t n, t;
976 while ((n = read (h, buffer, sizeof (buffer))) < 0)
978 if ((errno == EINTR) && tty_got_interrupt ())
979 continue;
980 vfs_print_message ("%s", _("fish: Local read failed, sending zeros"));
981 close (h);
982 h = open ("/dev/zero", O_RDONLY);
985 if (n == 0)
986 break;
988 t = write (SUP->sockw, buffer, n);
989 if (t != n)
991 if (t == -1)
992 me->verrno = errno;
993 else
994 me->verrno = EIO;
995 goto error_return;
997 tty_disable_interrupt_key ();
998 total += n;
999 vfs_print_message ("%s: %" PRIuMAX "/%" PRIuMAX, _("fish: storing file"),
1000 (uintmax_t) total, (uintmax_t) s.st_size);
1002 close (h);
1004 if (fish_get_reply (me, SUP->sockr, NULL, 0) != COMPLETE)
1005 ERRNOR (E_REMOTE, -1);
1006 return 0;
1008 error_return:
1009 close (h);
1010 fish_get_reply (me, SUP->sockr, NULL, 0);
1011 return -1;
1014 /* --------------------------------------------------------------------------------------------- */
1016 static int
1017 fish_linear_start (struct vfs_class *me, vfs_file_handler_t * fh, off_t offset)
1019 fish_fh_data_t *fish;
1020 gchar *shell_commands = NULL;
1021 struct vfs_s_super *super = FH_SUPER;
1022 char *name;
1023 char *quoted_name;
1025 if (fh->data == NULL)
1026 fh->data = g_new0 (fish_fh_data_t, 1);
1028 fish = (fish_fh_data_t *) fh->data;
1030 name = vfs_s_fullpath (me, fh->ino);
1031 if (name == NULL)
1032 return 0;
1033 quoted_name = strutils_shell_escape (name);
1034 g_free (name);
1035 fish->append = FALSE;
1038 * Check whether the remote file is readable by using 'dd' to copy
1039 * a single byte from the remote file to /dev/null. If 'dd' completes
1040 * with exit status of 0 use 'cat' to send the file contents to the
1041 * standard output (i.e. over the network).
1044 shell_commands =
1045 g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_START_OFFSET=%" PRIuMAX ";\n",
1046 SUP->scr_get, (char *) NULL);
1047 offset = fish_command (me, super, WANT_STRING, shell_commands, quoted_name, (uintmax_t) offset);
1048 g_free (shell_commands);
1049 g_free (quoted_name);
1050 if (offset != PRELIM)
1051 ERRNOR (E_REMOTE, 0);
1052 fh->linear = LS_LINEAR_OPEN;
1053 fish->got = 0;
1054 errno = 0;
1055 #if SIZEOF_OFF_T == SIZEOF_LONG
1056 fish->total = (off_t) strtol (reply_str, NULL, 10);
1057 #else
1058 fish->total = (off_t) g_ascii_strtoll (reply_str, NULL, 10);
1059 #endif
1060 if (errno != 0)
1061 ERRNOR (E_REMOTE, 0);
1062 return 1;
1065 /* --------------------------------------------------------------------------------------------- */
1067 static void
1068 fish_linear_abort (struct vfs_class *me, vfs_file_handler_t * fh)
1070 fish_fh_data_t *fish = (fish_fh_data_t *) fh->data;
1071 struct vfs_s_super *super = FH_SUPER;
1072 char buffer[BUF_8K];
1073 ssize_t n;
1075 vfs_print_message ("%s", _("Aborting transfer..."));
1079 n = MIN ((off_t) sizeof (buffer), (fish->total - fish->got));
1080 if (n != 0)
1082 n = read (SUP->sockr, buffer, n);
1083 if (n < 0)
1084 return;
1085 fish->got += n;
1088 while (n != 0);
1090 if (fish_get_reply (me, SUP->sockr, NULL, 0) != COMPLETE)
1091 vfs_print_message ("%s", _("Error reported after abort."));
1092 else
1093 vfs_print_message ("%s", _("Aborted transfer would be successful."));
1096 /* --------------------------------------------------------------------------------------------- */
1098 static ssize_t
1099 fish_linear_read (struct vfs_class *me, vfs_file_handler_t * fh, void *buf, size_t len)
1101 fish_fh_data_t *fish = (fish_fh_data_t *) fh->data;
1102 struct vfs_s_super *super = FH_SUPER;
1103 ssize_t n = 0;
1105 len = MIN ((size_t) (fish->total - fish->got), len);
1106 tty_disable_interrupt_key ();
1107 while (len != 0 && ((n = read (SUP->sockr, buf, len)) < 0))
1109 if ((errno == EINTR) && !tty_got_interrupt ())
1110 continue;
1111 break;
1113 tty_enable_interrupt_key ();
1115 if (n > 0)
1116 fish->got += n;
1117 else if (n < 0)
1118 fish_linear_abort (me, fh);
1119 else if (fish_get_reply (me, SUP->sockr, NULL, 0) != COMPLETE)
1120 ERRNOR (E_REMOTE, -1);
1121 ERRNOR (errno, n);
1124 /* --------------------------------------------------------------------------------------------- */
1126 static void
1127 fish_linear_close (struct vfs_class *me, vfs_file_handler_t * fh)
1129 fish_fh_data_t *fish = (fish_fh_data_t *) fh->data;
1131 if (fish->total != fish->got)
1132 fish_linear_abort (me, fh);
1135 /* --------------------------------------------------------------------------------------------- */
1137 static int
1138 fish_ctl (void *fh, int ctlop, void *arg)
1140 (void) arg;
1141 (void) fh;
1142 (void) ctlop;
1144 return 0;
1146 #if 0
1147 switch (ctlop)
1149 case VFS_CTL_IS_NOTREADY:
1151 int v;
1153 if (FH->linear == 0)
1154 vfs_die ("You may not do this");
1155 if (FH->linear == LS_LINEAR_CLOSED || FH->linear == LS_LINEAR_PREOPEN)
1156 return 0;
1158 v = vfs_s_select_on_two (FH_SUPER->u.fish.sockr, 0);
1160 return (((v < 0) && (errno == EINTR)) || v == 0) ? 1 : 0;
1162 default:
1163 return 0;
1165 #endif
1168 /* --------------------------------------------------------------------------------------------- */
1170 static int
1171 fish_send_command (struct vfs_class *me, struct vfs_s_super *super, const char *cmd, int flags)
1173 int r;
1175 r = fish_command (me, super, WAIT_REPLY, "%s", cmd);
1176 vfs_stamp_create (&vfs_fish_ops, super);
1177 if (r != COMPLETE)
1178 ERRNOR (E_REMOTE, -1);
1179 if ((flags & OPT_FLUSH) != 0)
1180 vfs_s_invalidate (me, super);
1181 return 0;
1184 /* --------------------------------------------------------------------------------------------- */
1186 static int
1187 fish_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
1189 gchar *shell_commands = NULL;
1190 char buf[BUF_LARGE];
1191 const char *crpath1, *crpath2;
1192 char *rpath1, *rpath2;
1193 struct vfs_s_super *super, *super2;
1194 const vfs_path_element_t *path_element;
1196 path_element = vfs_path_get_by_index (vpath1, -1);
1198 crpath1 = vfs_s_get_path (vpath1, &super, 0);
1199 if (crpath1 == NULL)
1200 return -1;
1202 crpath2 = vfs_s_get_path (vpath2, &super2, 0);
1203 if (crpath2 == NULL)
1204 return -1;
1206 rpath1 = strutils_shell_escape (crpath1);
1207 rpath2 = strutils_shell_escape (crpath2);
1208 shell_commands = g_strconcat (SUP->scr_env, "FISH_FILEFROM=%s FISH_FILETO=%s;\n",
1209 SUP->scr_mv, (char *) NULL);
1210 g_snprintf (buf, sizeof (buf), shell_commands, rpath1, rpath2);
1211 g_free (shell_commands);
1212 g_free (rpath1);
1213 g_free (rpath2);
1214 return fish_send_command (path_element->class, super2, buf, OPT_FLUSH);
1217 /* --------------------------------------------------------------------------------------------- */
1219 static int
1220 fish_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
1222 gchar *shell_commands = NULL;
1223 char buf[BUF_LARGE];
1224 const char *crpath1, *crpath2;
1225 char *rpath1, *rpath2;
1226 struct vfs_s_super *super, *super2;
1227 const vfs_path_element_t *path_element;
1229 path_element = vfs_path_get_by_index (vpath1, -1);
1231 crpath1 = vfs_s_get_path (vpath1, &super, 0);
1232 if (crpath1 == NULL)
1233 return -1;
1235 crpath2 = vfs_s_get_path (vpath2, &super2, 0);
1236 if (crpath2 == NULL)
1237 return -1;
1239 rpath1 = strutils_shell_escape (crpath1);
1240 rpath2 = strutils_shell_escape (crpath2);
1241 shell_commands = g_strconcat (SUP->scr_env, "FISH_FILEFROM=%s FISH_FILETO=%s;\n",
1242 SUP->scr_hardlink, (char *) NULL);
1243 g_snprintf (buf, sizeof (buf), shell_commands, rpath1, rpath2);
1244 g_free (shell_commands);
1245 g_free (rpath1);
1246 g_free (rpath2);
1247 return fish_send_command (path_element->class, super2, buf, OPT_FLUSH);
1251 /* --------------------------------------------------------------------------------------------- */
1253 static int
1254 fish_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
1256 char *qsetto;
1257 gchar *shell_commands = NULL;
1258 char buf[BUF_LARGE];
1259 const char *crpath;
1260 char *rpath;
1261 struct vfs_s_super *super;
1262 const vfs_path_element_t *path_element;
1264 path_element = vfs_path_get_by_index (vpath2, -1);
1266 crpath = vfs_s_get_path (vpath2, &super, 0);
1267 if (crpath == NULL)
1268 return -1;
1270 rpath = strutils_shell_escape (crpath);
1271 qsetto = strutils_shell_escape (vfs_path_get_by_index (vpath1, -1)->path);
1273 shell_commands = g_strconcat (SUP->scr_env, "FISH_FILEFROM=%s FISH_FILETO=%s;\n",
1274 SUP->scr_ln, (char *) NULL);
1275 g_snprintf (buf, sizeof (buf), shell_commands, qsetto, rpath);
1276 g_free (shell_commands);
1277 g_free (qsetto);
1278 g_free (rpath);
1279 return fish_send_command (path_element->class, super, buf, OPT_FLUSH);
1282 /* --------------------------------------------------------------------------------------------- */
1284 static int
1285 fish_stat (const vfs_path_t * vpath, struct stat *buf)
1287 int ret;
1289 ret = vfs_s_stat (vpath, buf);
1290 fish_set_blksize (buf);
1291 return ret;
1294 /* --------------------------------------------------------------------------------------------- */
1296 static int
1297 fish_lstat (const vfs_path_t * vpath, struct stat *buf)
1299 int ret;
1301 ret = vfs_s_lstat (vpath, buf);
1302 fish_set_blksize (buf);
1303 return ret;
1306 /* --------------------------------------------------------------------------------------------- */
1308 static int
1309 fish_fstat (void *vfs_info, struct stat *buf)
1311 int ret;
1313 ret = vfs_s_fstat (vfs_info, buf);
1314 fish_set_blksize (buf);
1315 return ret;
1318 /* --------------------------------------------------------------------------------------------- */
1320 static int
1321 fish_chmod (const vfs_path_t * vpath, mode_t mode)
1323 gchar *shell_commands = NULL;
1324 char buf[BUF_LARGE];
1325 const char *crpath;
1326 char *rpath;
1327 struct vfs_s_super *super;
1328 const vfs_path_element_t *path_element;
1330 path_element = vfs_path_get_by_index (vpath, -1);
1332 crpath = vfs_s_get_path (vpath, &super, 0);
1333 if (crpath == NULL)
1334 return -1;
1335 rpath = strutils_shell_escape (crpath);
1337 shell_commands = g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_FILEMODE=%4.4o;\n",
1338 SUP->scr_chmod, (char *) NULL);
1339 g_snprintf (buf, sizeof (buf), shell_commands, rpath, (int) (mode & 07777));
1340 g_free (shell_commands);
1341 g_free (rpath);
1342 return fish_send_command (path_element->class, super, buf, OPT_FLUSH);
1345 /* --------------------------------------------------------------------------------------------- */
1347 static int
1348 fish_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
1350 char *sowner, *sgroup;
1351 struct passwd *pw;
1352 struct group *gr;
1354 pw = getpwuid (owner);
1355 if (pw == NULL)
1356 return 0;
1358 gr = getgrgid (group);
1359 if (gr == NULL)
1360 return 0;
1362 sowner = pw->pw_name;
1363 sgroup = gr->gr_name;
1366 gchar *shell_commands = NULL;
1367 char buf[BUF_LARGE];
1368 const char *crpath;
1369 char *rpath;
1370 struct vfs_s_super *super;
1371 const vfs_path_element_t *path_element;
1373 path_element = vfs_path_get_by_index (vpath, -1);
1375 crpath = vfs_s_get_path (vpath, &super, 0);
1376 if (crpath == NULL)
1377 return -1;
1378 rpath = strutils_shell_escape (crpath);
1380 shell_commands = g_strconcat (SUP->scr_env,
1381 "FISH_FILENAME=%s FISH_FILEOWNER=%s FISH_FILEGROUP=%s;\n",
1382 SUP->scr_chown, (char *) NULL);
1383 g_snprintf (buf, sizeof (buf), shell_commands, rpath, sowner, sgroup);
1384 g_free (shell_commands);
1385 fish_send_command (path_element->class, super, buf, OPT_FLUSH);
1386 /* FIXME: what should we report if chgrp succeeds but chown fails? */
1387 /* fish_send_command(me, super, buf, OPT_FLUSH); */
1388 g_free (rpath);
1389 return fish_send_command (path_element->class, super, buf, OPT_FLUSH);
1393 /* --------------------------------------------------------------------------------------------- */
1395 static void
1396 fish_get_atime (mc_timesbuf_t * times, time_t * sec, long *nsec)
1398 #ifdef HAVE_UTIMENSAT
1399 *sec = (*times)[0].tv_sec;
1400 *nsec = (*times)[0].tv_nsec;
1401 #else
1402 *sec = times->actime;
1403 *nsec = 0;
1404 #endif
1407 /* --------------------------------------------------------------------------------------------- */
1409 static void
1410 fish_get_mtime (mc_timesbuf_t * times, time_t * sec, long *nsec)
1412 #ifdef HAVE_UTIMENSAT
1413 *sec = (*times)[1].tv_sec;
1414 *nsec = (*times)[1].tv_nsec;
1415 #else
1416 *sec = times->modtime;
1417 *nsec = 0;
1418 #endif
1421 /* --------------------------------------------------------------------------------------------- */
1423 static int
1424 fish_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
1426 gchar *shell_commands = NULL;
1427 char utcatime[16], utcmtime[16];
1428 char utcatime_w_nsec[30], utcmtime_w_nsec[30];
1429 time_t atime, mtime;
1430 long atime_nsec, mtime_nsec;
1431 struct tm *gmt;
1432 char *cmd;
1433 const char *crpath;
1434 char *rpath;
1435 struct vfs_s_super *super;
1436 const vfs_path_element_t *path_element;
1437 int ret;
1439 path_element = vfs_path_get_by_index (vpath, -1);
1441 crpath = vfs_s_get_path (vpath, &super, 0);
1442 if (crpath == NULL)
1443 return -1;
1444 rpath = strutils_shell_escape (crpath);
1446 fish_get_atime (times, &atime, &atime_nsec);
1447 gmt = gmtime (&atime);
1448 g_snprintf (utcatime, sizeof (utcatime), "%04d%02d%02d%02d%02d.%02d",
1449 gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
1450 gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
1451 g_snprintf (utcatime_w_nsec, sizeof (utcatime_w_nsec), "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
1452 gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
1453 gmt->tm_hour, gmt->tm_min, gmt->tm_sec, atime_nsec);
1455 fish_get_mtime (times, &mtime, &mtime_nsec);
1456 gmt = gmtime (&mtime);
1457 g_snprintf (utcmtime, sizeof (utcmtime), "%04d%02d%02d%02d%02d.%02d",
1458 gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
1459 gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
1460 g_snprintf (utcmtime_w_nsec, sizeof (utcmtime_w_nsec), "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
1461 gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
1462 gmt->tm_hour, gmt->tm_min, gmt->tm_sec, mtime_nsec);
1464 shell_commands =
1465 g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_FILEATIME=%ld FISH_FILEMTIME=%ld ",
1466 "FISH_TOUCHATIME=%s FISH_TOUCHMTIME=%s ",
1467 "FISH_TOUCHATIME_W_NSEC=\"%s\" FISH_TOUCHMTIME_W_NSEC=\"%s\";\n",
1468 SUP->scr_utime, (char *) NULL);
1469 cmd =
1470 g_strdup_printf (shell_commands, rpath, (long) atime, (long) mtime, utcatime, utcmtime,
1471 utcatime_w_nsec, utcmtime_w_nsec);
1472 g_free (shell_commands);
1473 g_free (rpath);
1474 ret = fish_send_command (path_element->class, super, cmd, OPT_FLUSH);
1475 g_free (cmd);
1477 return ret;
1480 /* --------------------------------------------------------------------------------------------- */
1482 static int
1483 fish_unlink (const vfs_path_t * vpath)
1485 gchar *shell_commands = NULL;
1486 char buf[BUF_LARGE];
1487 const char *crpath;
1488 char *rpath;
1489 struct vfs_s_super *super;
1490 const vfs_path_element_t *path_element;
1492 path_element = vfs_path_get_by_index (vpath, -1);
1494 crpath = vfs_s_get_path (vpath, &super, 0);
1495 if (crpath == NULL)
1496 return -1;
1497 rpath = strutils_shell_escape (crpath);
1499 shell_commands =
1500 g_strconcat (SUP->scr_env, "FISH_FILENAME=%s;\n", SUP->scr_unlink, (char *) NULL);
1501 g_snprintf (buf, sizeof (buf), shell_commands, rpath);
1502 g_free (shell_commands);
1503 g_free (rpath);
1504 return fish_send_command (path_element->class, super, buf, OPT_FLUSH);
1507 /* --------------------------------------------------------------------------------------------- */
1509 static int
1510 fish_exists (const vfs_path_t * vpath)
1512 gchar *shell_commands = NULL;
1513 char buf[BUF_LARGE];
1514 const char *crpath;
1515 char *rpath;
1516 struct vfs_s_super *super;
1517 const vfs_path_element_t *path_element;
1519 path_element = vfs_path_get_by_index (vpath, -1);
1521 crpath = vfs_s_get_path (vpath, &super, 0);
1522 if (crpath == NULL)
1523 return -1;
1524 rpath = strutils_shell_escape (crpath);
1526 shell_commands =
1527 g_strconcat (SUP->scr_env, "FISH_FILENAME=%s;\n", SUP->scr_exists, (char *) NULL);
1528 g_snprintf (buf, sizeof (buf), shell_commands, rpath);
1529 g_free (shell_commands);
1530 g_free (rpath);
1532 return (fish_send_command (path_element->class, super, buf, OPT_FLUSH) == 0) ? 1 : 0;
1535 /* --------------------------------------------------------------------------------------------- */
1537 static int
1538 fish_mkdir (const vfs_path_t * vpath, mode_t mode)
1540 gchar *shell_commands = NULL;
1541 int ret_code;
1542 char buf[BUF_LARGE];
1543 const char *crpath;
1544 char *rpath;
1545 struct vfs_s_super *super;
1546 const vfs_path_element_t *path_element;
1548 (void) mode;
1550 path_element = vfs_path_get_by_index (vpath, -1);
1552 crpath = vfs_s_get_path (vpath, &super, 0);
1553 if (crpath == NULL)
1554 return -1;
1555 rpath = strutils_shell_escape (crpath);
1557 shell_commands =
1558 g_strconcat (SUP->scr_env, "FISH_FILENAME=%s;\n", SUP->scr_mkdir, (char *) NULL);
1559 g_snprintf (buf, sizeof (buf), shell_commands, rpath);
1560 g_free (shell_commands);
1562 g_free (rpath);
1563 ret_code = fish_send_command (path_element->class, super, buf, OPT_FLUSH);
1565 if (ret_code != 0)
1566 return ret_code;
1568 if (fish_exists (vpath) == 0)
1570 path_element->class->verrno = EACCES;
1571 return -1;
1573 return 0;
1576 /* --------------------------------------------------------------------------------------------- */
1578 static int
1579 fish_rmdir (const vfs_path_t * vpath)
1581 gchar *shell_commands = NULL;
1582 char buf[BUF_LARGE];
1583 const char *crpath;
1584 char *rpath;
1585 struct vfs_s_super *super;
1586 const vfs_path_element_t *path_element;
1588 path_element = vfs_path_get_by_index (vpath, -1);
1590 crpath = vfs_s_get_path (vpath, &super, 0);
1591 if (crpath == NULL)
1592 return -1;
1593 rpath = strutils_shell_escape (crpath);
1595 shell_commands =
1596 g_strconcat (SUP->scr_env, "FISH_FILENAME=%s;\n", SUP->scr_rmdir, (char *) NULL);
1597 g_snprintf (buf, sizeof (buf), shell_commands, rpath);
1598 g_free (shell_commands);
1599 g_free (rpath);
1600 return fish_send_command (path_element->class, super, buf, OPT_FLUSH);
1603 /* --------------------------------------------------------------------------------------------- */
1605 static void
1606 fish_fh_free_data (vfs_file_handler_t * fh)
1608 if (fh != NULL)
1609 MC_PTR_FREE (fh->data);
1612 /* --------------------------------------------------------------------------------------------- */
1614 static int
1615 fish_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
1617 fish_fh_data_t *fish;
1619 (void) mode;
1621 fh->data = g_new0 (fish_fh_data_t, 1);
1622 fish = (fish_fh_data_t *) fh->data;
1624 /* File will be written only, so no need to retrieve it */
1625 if (((flags & O_WRONLY) == O_WRONLY) && ((flags & (O_RDONLY | O_RDWR)) == 0))
1627 /* user pressed the button [ Append ] in the "Copy" dialog */
1628 if ((flags & O_APPEND) != 0)
1629 fish->append = TRUE;
1631 if (fh->ino->localname == NULL)
1633 vfs_path_t *vpath;
1634 int tmp_handle;
1636 tmp_handle = vfs_mkstemps (&vpath, me->name, fh->ino->ent->name);
1637 if (tmp_handle == -1)
1639 vfs_path_free (vpath);
1640 goto fail;
1642 fh->ino->localname = g_strdup (vfs_path_as_str (vpath));
1643 vfs_path_free (vpath);
1644 close (tmp_handle);
1646 return 0;
1648 if (fh->ino->localname == NULL && vfs_s_retrieve_file (me, fh->ino) == -1)
1649 goto fail;
1650 if (fh->ino->localname == NULL)
1651 vfs_die ("retrieve_file failed to fill in localname");
1652 return 0;
1654 fail:
1655 fish_fh_free_data (fh);
1656 return -1;
1659 /* --------------------------------------------------------------------------------------------- */
1661 static void
1662 fish_fill_names (struct vfs_class *me, fill_names_f func)
1664 GList *iter;
1666 for (iter = MEDATA->supers; iter != NULL; iter = g_list_next (iter))
1668 const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
1670 char *name;
1671 char gbuf[10];
1672 const char *flags = "";
1674 switch (super->path_element->port)
1676 case FISH_FLAG_RSH:
1677 flags = ":r";
1678 break;
1679 case FISH_FLAG_COMPRESSED:
1680 flags = ":C";
1681 break;
1682 default:
1683 if (super->path_element->port > FISH_FLAG_RSH)
1685 g_snprintf (gbuf, sizeof (gbuf), ":%d", super->path_element->port);
1686 flags = gbuf;
1688 break;
1691 name =
1692 g_strconcat (vfs_fish_ops.prefix, VFS_PATH_URL_DELIMITER,
1693 super->path_element->user, "@", super->path_element->host, flags,
1694 PATH_SEP_STR, super->path_element->path, (char *) NULL);
1695 func (name);
1696 g_free (name);
1700 /* --------------------------------------------------------------------------------------------- */
1702 static void *
1703 fish_open (const vfs_path_t * vpath, int flags, mode_t mode)
1706 sorry, i've places hack here
1707 cause fish don't able to open files with O_EXCL flag
1709 flags &= ~O_EXCL;
1710 return vfs_s_open (vpath, flags, mode);
1713 /* --------------------------------------------------------------------------------------------- */
1714 /*** public functions ****************************************************************************/
1715 /* --------------------------------------------------------------------------------------------- */
1717 void
1718 init_fish (void)
1720 static struct vfs_s_subclass fish_subclass;
1722 tcp_init ();
1724 fish_subclass.flags = VFS_S_REMOTE | VFS_S_USETMP;
1725 fish_subclass.archive_same = fish_archive_same;
1726 fish_subclass.open_archive = fish_open_archive;
1727 fish_subclass.free_archive = fish_free_archive;
1728 fish_subclass.fh_open = fish_fh_open;
1729 fish_subclass.fh_free_data = fish_fh_free_data;
1730 fish_subclass.dir_load = fish_dir_load;
1731 fish_subclass.file_store = fish_file_store;
1732 fish_subclass.linear_start = fish_linear_start;
1733 fish_subclass.linear_read = fish_linear_read;
1734 fish_subclass.linear_close = fish_linear_close;
1736 vfs_s_init_class (&vfs_fish_ops, &fish_subclass);
1737 vfs_fish_ops.name = "fish";
1738 vfs_fish_ops.prefix = "sh";
1739 vfs_fish_ops.fill_names = fish_fill_names;
1740 vfs_fish_ops.stat = fish_stat;
1741 vfs_fish_ops.lstat = fish_lstat;
1742 vfs_fish_ops.fstat = fish_fstat;
1743 vfs_fish_ops.chmod = fish_chmod;
1744 vfs_fish_ops.chown = fish_chown;
1745 vfs_fish_ops.utime = fish_utime;
1746 vfs_fish_ops.open = fish_open;
1747 vfs_fish_ops.symlink = fish_symlink;
1748 vfs_fish_ops.link = fish_link;
1749 vfs_fish_ops.unlink = fish_unlink;
1750 vfs_fish_ops.rename = fish_rename;
1751 vfs_fish_ops.mkdir = fish_mkdir;
1752 vfs_fish_ops.rmdir = fish_rmdir;
1753 vfs_fish_ops.ctl = fish_ctl;
1754 vfs_register_class (&vfs_fish_ops);
1757 /* --------------------------------------------------------------------------------------------- */