diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:22:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:22:03 +0000 |
commit | ffccd5b2b05243e7976db80f90f453dccfae9886 (patch) | |
tree | 39a43152d27f7390d8f7a6fb276fa6887f87c6e8 /src/vfs/fish | |
parent | Initial commit. (diff) | |
download | mc-upstream/3%4.8.30.tar.xz mc-upstream/3%4.8.30.zip |
Adding upstream version 3:4.8.30.upstream/3%4.8.30
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/vfs/fish')
-rw-r--r-- | src/vfs/fish/Makefile.am | 13 | ||||
-rw-r--r-- | src/vfs/fish/Makefile.in | 857 | ||||
-rw-r--r-- | src/vfs/fish/fish.c | 1805 | ||||
-rw-r--r-- | src/vfs/fish/fish.h | 28 | ||||
-rw-r--r-- | src/vfs/fish/fishdef.h | 236 | ||||
-rw-r--r-- | src/vfs/fish/helpers/Makefile.am | 10 | ||||
-rw-r--r-- | src/vfs/fish/helpers/Makefile.in | 642 | ||||
-rw-r--r-- | src/vfs/fish/helpers/README.fish | 217 | ||||
-rw-r--r-- | src/vfs/fish/helpers/append | 16 | ||||
-rw-r--r-- | src/vfs/fish/helpers/chmod | 6 | ||||
-rw-r--r-- | src/vfs/fish/helpers/chown | 6 | ||||
-rw-r--r-- | src/vfs/fish/helpers/fexists | 3 | ||||
-rw-r--r-- | src/vfs/fish/helpers/get | 105 | ||||
-rw-r--r-- | src/vfs/fish/helpers/hardlink | 8 | ||||
-rw-r--r-- | src/vfs/fish/helpers/info | 44 | ||||
-rw-r--r-- | src/vfs/fish/helpers/ln | 8 | ||||
-rw-r--r-- | src/vfs/fish/helpers/ls | 170 | ||||
-rw-r--r-- | src/vfs/fish/helpers/mkdir | 6 | ||||
-rw-r--r-- | src/vfs/fish/helpers/mv | 6 | ||||
-rw-r--r-- | src/vfs/fish/helpers/rmdir | 6 | ||||
-rw-r--r-- | src/vfs/fish/helpers/send | 17 | ||||
-rw-r--r-- | src/vfs/fish/helpers/unlink | 6 | ||||
-rw-r--r-- | src/vfs/fish/helpers/utime | 13 |
23 files changed, 4228 insertions, 0 deletions
diff --git a/src/vfs/fish/Makefile.am b/src/vfs/fish/Makefile.am new file mode 100644 index 0000000..4f3ca87 --- /dev/null +++ b/src/vfs/fish/Makefile.am @@ -0,0 +1,13 @@ +SUBDIRS = helpers +DIST_SUBDIRS = helpers + +AM_CPPFLAGS = \ + -DLIBEXECDIR=\""$(libexecdir)/@PACKAGE@/"\" \ + $(GLIB_CFLAGS) \ + -I$(top_srcdir) + +noinst_LTLIBRARIES = libvfs-fish.la + +libvfs_fish_la_SOURCES = \ + fish.c fish.h \ + fishdef.h diff --git a/src/vfs/fish/Makefile.in b/src/vfs/fish/Makefile.in new file mode 100644 index 0000000..cd952a8 --- /dev/null +++ b/src/vfs/fish/Makefile.in @@ -0,0 +1,857 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/vfs/fish +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/m4.include/gnulib/mode_t.m4 \ + $(top_srcdir)/m4.include/gnulib/stat-size.m4 \ + $(top_srcdir)/m4.include/gnulib/fstypename.m4 \ + $(top_srcdir)/m4.include/gnulib/fsusage.m4 \ + $(top_srcdir)/m4.include/gnulib/mountlist.m4 \ + $(top_srcdir)/m4.include/gnulib/windows-stat-inodes.m4 \ + $(top_srcdir)/m4.include/gnulib/sys_types_h.m4 \ + $(top_srcdir)/m4.include/ax_path_lib_pcre.m4 \ + $(top_srcdir)/m4.include/ax_check_pcre2.m4 \ + $(top_srcdir)/m4.include/dx_doxygen.m4 \ + $(top_srcdir)/m4.include/ax_require_defined.m4 \ + $(top_srcdir)/m4.include/ax_check_compile_flag.m4 \ + $(top_srcdir)/m4.include/ax_append_flag.m4 \ + $(top_srcdir)/m4.include/ax_append_compile_flags.m4 \ + $(top_srcdir)/m4.include/mc-cflags.m4 \ + $(top_srcdir)/m4.include/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/m4.include/mc-check-search-type.m4 \ + $(top_srcdir)/m4.include/mc-get-fs-info.m4 \ + $(top_srcdir)/m4.include/mc-with-x.m4 \ + $(top_srcdir)/m4.include/mc-use-termcap.m4 \ + $(top_srcdir)/m4.include/mc-with-screen.m4 \ + $(top_srcdir)/m4.include/mc-with-screen-ncurses.m4 \ + $(top_srcdir)/m4.include/mc-with-screen-slang.m4 \ + $(top_srcdir)/m4.include/mc-with-internal-edit.m4 \ + $(top_srcdir)/m4.include/mc-subshell.m4 \ + $(top_srcdir)/m4.include/mc-background.m4 \ + $(top_srcdir)/m4.include/mc-ext2fs-attr.m4 \ + $(top_srcdir)/m4.include/mc-glib.m4 \ + $(top_srcdir)/m4.include/mc-vfs.m4 \ + $(top_srcdir)/m4.include/vfs/rpc.m4 \ + $(top_srcdir)/m4.include/vfs/socket.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-extfs.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-sfs.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-ftp.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-sftp.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-fish.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-undelfs.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-tarfs.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-cpiofs.m4 \ + $(top_srcdir)/m4.include/mc-version.m4 \ + $(top_srcdir)/m4.include/mc-tests.m4 \ + $(top_srcdir)/m4.include/mc-i18n.m4 \ + $(top_srcdir)/m4.include/mc-assert.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libvfs_fish_la_LIBADD = +am_libvfs_fish_la_OBJECTS = fish.lo +libvfs_fish_la_OBJECTS = $(am_libvfs_fish_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/fish.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libvfs_fish_la_SOURCES) +DIST_SOURCES = $(libvfs_fish_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +COM_ERR_CFLAGS = @COM_ERR_CFLAGS@ +COM_ERR_LIBS = @COM_ERR_LIBS@ +CP1251 = @CP1251@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOC_LINGUAS = @DOC_LINGUAS@ +DOXYGEN_PAPER_SIZE = @DOXYGEN_PAPER_SIZE@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DX_CONFIG = @DX_CONFIG@ +DX_DOCDIR = @DX_DOCDIR@ +DX_DOT = @DX_DOT@ +DX_DOXYGEN = @DX_DOXYGEN@ +DX_DVIPS = @DX_DVIPS@ +DX_EGREP = @DX_EGREP@ +DX_ENV = @DX_ENV@ +DX_FLAG_chi = @DX_FLAG_chi@ +DX_FLAG_chm = @DX_FLAG_chm@ +DX_FLAG_doc = @DX_FLAG_doc@ +DX_FLAG_dot = @DX_FLAG_dot@ +DX_FLAG_html = @DX_FLAG_html@ +DX_FLAG_man = @DX_FLAG_man@ +DX_FLAG_pdf = @DX_FLAG_pdf@ +DX_FLAG_ps = @DX_FLAG_ps@ +DX_FLAG_rtf = @DX_FLAG_rtf@ +DX_FLAG_xml = @DX_FLAG_xml@ +DX_HHC = @DX_HHC@ +DX_LATEX = @DX_LATEX@ +DX_MAKEINDEX = @DX_MAKEINDEX@ +DX_PDFLATEX = @DX_PDFLATEX@ +DX_PERL = @DX_PERL@ +DX_PROJECT = @DX_PROJECT@ +E2P_CFLAGS = @E2P_CFLAGS@ +E2P_LIBS = @E2P_LIBS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +EXT2FS_CFLAGS = @EXT2FS_CFLAGS@ +EXT2FS_LIBS = @EXT2FS_LIBS@ +EXTHELPERSDIR = @EXTHELPERSDIR@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GMODULE_CFLAGS = @GMODULE_CFLAGS@ +GMODULE_LIBS = @GMODULE_LIBS@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +HAVE_FILECMD = @HAVE_FILECMD@ +HAVE_ZIPINFO = @HAVE_ZIPINFO@ +HAVE_nroff = @HAVE_nroff@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMC_RELEASE = @LIBMC_RELEASE@ +LIBMC_VERSION = @LIBMC_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSSH_CFLAGS = @LIBSSH_CFLAGS@ +LIBSSH_LIBS = @LIBSSH_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANDOC = @MANDOC@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAN_DATE = @MAN_DATE@ +MAN_FLAGS = @MAN_FLAGS@ +MAN_VERSION = @MAN_VERSION@ +MCLIBS = @MCLIBS@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCRE_CFLAGS = @PCRE_CFLAGS@ +PCRE_LIBS = @PCRE_LIBS@ +PERL = @PERL@ +PERL_FOR_BUILD = @PERL_FOR_BUILD@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +RANLIB = @RANLIB@ +RUBY = @RUBY@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SLANG_CFLAGS = @SLANG_CFLAGS@ +SLANG_LIBS = @SLANG_LIBS@ +STRIP = @STRIP@ +TESTS_LDFLAGS = @TESTS_LDFLAGS@ +UNZIP = @UNZIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +X11_WWW = @X11_WWW@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +ZIP = @ZIP@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = helpers +DIST_SUBDIRS = helpers +AM_CPPFLAGS = \ + -DLIBEXECDIR=\""$(libexecdir)/@PACKAGE@/"\" \ + $(GLIB_CFLAGS) \ + -I$(top_srcdir) + +noinst_LTLIBRARIES = libvfs-fish.la +libvfs_fish_la_SOURCES = \ + fish.c fish.h \ + fishdef.h + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/vfs/fish/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/vfs/fish/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libvfs-fish.la: $(libvfs_fish_la_OBJECTS) $(libvfs_fish_la_DEPENDENCIES) $(EXTRA_libvfs_fish_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libvfs_fish_la_OBJECTS) $(libvfs_fish_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fish.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/fish.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/fish.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-generic clean-libtool \ + clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/vfs/fish/fish.c b/src/vfs/fish/fish.c new file mode 100644 index 0000000..ec71a41 --- /dev/null +++ b/src/vfs/fish/fish.c @@ -0,0 +1,1805 @@ +/* + Virtual File System: FISH implementation for transferring files over + shell connections. + + Copyright (C) 1998-2023 + Free Software Foundation, Inc. + + Written by: + Pavel Machek, 1998 + Michal Svec, 2000 + Andrew Borodin <aborodin@vmail.ru>, 2010-2022 + Slava Zanko <slavazanko@gmail.com>, 2010, 2013 + Ilia Maslakov <il.smind@gmail.com>, 2010 + + Derived from ftpfs.c. + + This file is part of the Midnight Commander. + + The Midnight Commander is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * \brief Source: Virtual File System: FISH implementation for transferring files over + * shell connections + * \author Pavel Machek + * \author Michal Svec + * \date 1998, 2000 + * + * Derived from ftpfs.c + * Read README.fish for protocol specification. + * + * Syntax of path is: \verbatim sh://user@host[:Cr]/path \endverbatim + * where C means you want compressed connection, + * and r means you want to use rsh + * + * Namespace: fish_vfs_ops exported. + */ + +/* Define this if your ssh can take -I option */ + +#include <config.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> /* uintmax_t */ + +#include "lib/global.h" +#include "lib/tty/tty.h" /* enable/disable interrupt key */ +#include "lib/strescape.h" +#include "lib/unixcompat.h" +#include "lib/fileloc.h" +#include "lib/util.h" /* my_exit() */ +#include "lib/mcconfig.h" + +#include "src/execute.h" /* pre_exec, post_exec */ + +#include "lib/vfs/vfs.h" +#include "lib/vfs/utilvfs.h" +#include "lib/vfs/netutil.h" +#include "lib/vfs/xdirentry.h" +#include "lib/vfs/gc.h" /* vfs_stamp_create */ + +#include "fish.h" +#include "fishdef.h" + +/*** global variables ****************************************************************************/ + +int fish_directory_timeout = 900; + +/*** file scope macro definitions ****************************************************************/ + +#define DO_RESOLVE_SYMLINK 1 +#define DO_OPEN 2 +#define DO_FREE_RESOURCE 4 + +#define FISH_FLAG_COMPRESSED 1 +#define FISH_FLAG_RSH 2 + +#define OPT_FLUSH 1 +#define OPT_IGNORE_ERROR 2 + +/* + * Reply codes. + */ +#define PRELIM 1 /* positive preliminary */ +#define COMPLETE 2 /* positive completion */ +#define CONTINUE 3 /* positive intermediate */ +#define TRANSIENT 4 /* transient negative completion */ +#define ERROR 5 /* permanent negative completion */ + +/* command wait_flag: */ +#define NONE 0x00 +#define WAIT_REPLY 0x01 +#define WANT_STRING 0x02 + +/* environment flags */ +#define FISH_HAVE_HEAD 1 +#define FISH_HAVE_SED 2 +#define FISH_HAVE_AWK 4 +#define FISH_HAVE_PERL 8 +#define FISH_HAVE_LSQ 16 +#define FISH_HAVE_DATE_MDYT 32 +#define FISH_HAVE_TAIL 64 + +#define FISH_SUPER(super) ((fish_super_t *) (super)) +#define FISH_FILE_HANDLER(fh) ((fish_file_handler_t *) fh) + +/*** file scope type declarations ****************************************************************/ + +typedef struct +{ + struct vfs_s_super base; /* base class */ + + int sockr; + int sockw; + char *scr_ls; + char *scr_chmod; + char *scr_utime; + char *scr_exists; + char *scr_mkdir; + char *scr_unlink; + char *scr_chown; + char *scr_rmdir; + char *scr_ln; + char *scr_mv; + char *scr_hardlink; + char *scr_get; + char *scr_send; + char *scr_append; + char *scr_info; + int host_flags; + GString *scr_env; +} fish_super_t; + +typedef struct +{ + vfs_file_handler_t base; /* base class */ + + off_t got; + off_t total; + gboolean append; +} fish_file_handler_t; + +/*** forward declarations (file scope functions) *************************************************/ + +/*** file scope variables ************************************************************************/ + +static char reply_str[80]; + +static struct vfs_s_subclass fish_subclass; +static struct vfs_class *vfs_fish_ops = VFS_CLASS (&fish_subclass); + +/* --------------------------------------------------------------------------------------------- */ +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_set_blksize (struct stat *s) +{ +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + /* redefine block size */ + s->st_blksize = 64 * 1024; /* FIXME */ +#endif +} + +/* --------------------------------------------------------------------------------------------- */ + +static struct stat * +fish_default_stat (struct vfs_class *me) +{ + struct stat *s; + + s = vfs_s_default_stat (me, S_IFDIR | 0755); + fish_set_blksize (s); + vfs_adjust_stat (s); + + return s; +} + +/* --------------------------------------------------------------------------------------------- */ + +static char * +fish_load_script_from_file (const char *hostname, const char *script_name, const char *def_content) +{ + char *scr_filename = NULL; + char *scr_content; + gsize scr_len = 0; + + /* 1st: scan user directory */ + scr_filename = g_build_path (PATH_SEP_STR, mc_config_get_data_path (), FISH_PREFIX, hostname, + script_name, (char *) NULL); + /* silent about user dir */ + g_file_get_contents (scr_filename, &scr_content, &scr_len, NULL); + g_free (scr_filename); + /* 2nd: scan system dir */ + if (scr_content == NULL) + { + scr_filename = + g_build_path (PATH_SEP_STR, LIBEXECDIR, FISH_PREFIX, script_name, (char *) NULL); + g_file_get_contents (scr_filename, &scr_content, &scr_len, NULL); + g_free (scr_filename); + } + + if (scr_content != NULL) + return scr_content; + + return g_strdup (def_content); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_decode_reply (char *s, gboolean was_garbage) +{ + int code; + + /* cppcheck-suppress invalidscanf */ + if (sscanf (s, "%d", &code) == 0) + { + code = 500; + return 5; + } + if (code < 100) + return was_garbage ? ERROR : (code == 0 ? COMPLETE : PRELIM); + return code / 100; +} + +/* --------------------------------------------------------------------------------------------- */ +/* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */ + +static int +fish_get_reply (struct vfs_class *me, int sock, char *string_buf, int string_len) +{ + char answer[BUF_1K]; + gboolean was_garbage = FALSE; + + while (TRUE) + { + if (!vfs_s_get_line (me, sock, answer, sizeof (answer), '\n')) + { + if (string_buf != NULL) + *string_buf = '\0'; + return 4; + } + + if (strncmp (answer, "### ", 4) == 0) + return fish_decode_reply (answer + 4, was_garbage ? 1 : 0); + + was_garbage = TRUE; + if (string_buf != NULL) + g_strlcpy (string_buf, answer, string_len); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_command (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *cmd, + size_t cmd_len) +{ + ssize_t status; + FILE *logfile = me->logfile; + + if (cmd_len == (size_t) (-1)) + cmd_len = strlen (cmd); + + if (logfile != NULL) + { + size_t ret; + + ret = fwrite (cmd, cmd_len, 1, logfile); + ret = fflush (logfile); + (void) ret; + } + + tty_enable_interrupt_key (); + status = write (FISH_SUPER (super)->sockw, cmd, cmd_len); + tty_disable_interrupt_key (); + + if (status < 0) + return TRANSIENT; + + if (wait_reply) + return fish_get_reply (me, FISH_SUPER (super)->sockr, + (wait_reply & WANT_STRING) != 0 ? reply_str : + NULL, sizeof (reply_str) - 1); + return COMPLETE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +G_GNUC_PRINTF (5, 0) +fish_command_va (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *scr, + const char *vars, va_list ap) +{ + int r; + GString *command; + + command = mc_g_string_dup (FISH_SUPER (super)->scr_env); + g_string_append_vprintf (command, vars, ap); + g_string_append (command, scr); + r = fish_command (me, super, wait_reply, command->str, command->len); + g_string_free (command, TRUE); + + return r; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +G_GNUC_PRINTF (5, 6) +fish_command_v (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *scr, + const char *vars, ...) +{ + int r; + va_list ap; + + va_start (ap, vars); + r = fish_command_va (me, super, wait_reply, scr, vars, ap); + va_end (ap); + + return r; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +G_GNUC_PRINTF (5, 6) +fish_send_command (struct vfs_class *me, struct vfs_s_super *super, int flags, const char *scr, + const char *vars, ...) +{ + int r; + va_list ap; + + va_start (ap, vars); + r = fish_command_va (me, super, WAIT_REPLY, scr, vars, ap); + va_end (ap); + vfs_stamp_create (vfs_fish_ops, super); + + if (r != COMPLETE) + ERRNOR (E_REMOTE, -1); + if ((flags & OPT_FLUSH) != 0) + vfs_s_invalidate (me, super); + + return 0; +} + +/* --------------------------------------------------------------------------------------------- */ + +static struct vfs_s_super * +fish_new_archive (struct vfs_class *me) +{ + fish_super_t *arch; + + arch = g_new0 (fish_super_t, 1); + arch->base.me = me; + + return VFS_SUPER (arch); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_free_archive (struct vfs_class *me, struct vfs_s_super *super) +{ + fish_super_t *fish_super = FISH_SUPER (super); + + if ((fish_super->sockw != -1) || (fish_super->sockr != -1)) + vfs_print_message (_("fish: Disconnecting from %s"), super->name ? super->name : "???"); + + if (fish_super->sockw != -1) + { + fish_command (me, super, NONE, "#BYE\nexit\n", -1); + close (fish_super->sockw); + fish_super->sockw = -1; + } + + if (fish_super->sockr != -1) + { + close (fish_super->sockr); + fish_super->sockr = -1; + } + + g_free (fish_super->scr_ls); + g_free (fish_super->scr_exists); + g_free (fish_super->scr_mkdir); + g_free (fish_super->scr_unlink); + g_free (fish_super->scr_chown); + g_free (fish_super->scr_chmod); + g_free (fish_super->scr_utime); + g_free (fish_super->scr_rmdir); + g_free (fish_super->scr_ln); + g_free (fish_super->scr_mv); + g_free (fish_super->scr_hardlink); + g_free (fish_super->scr_get); + g_free (fish_super->scr_send); + g_free (fish_super->scr_append); + g_free (fish_super->scr_info); + g_string_free (fish_super->scr_env, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_pipeopen (struct vfs_s_super *super, const char *path, const char *argv[]) +{ + int fileset1[2], fileset2[2]; + int res; + + if ((pipe (fileset1) < 0) || (pipe (fileset2) < 0)) + vfs_die ("Cannot pipe(): %m."); + + res = fork (); + + if (res != 0) + { + if (res < 0) + vfs_die ("Cannot fork(): %m."); + /* We are the parent */ + close (fileset1[0]); + FISH_SUPER (super)->sockw = fileset1[1]; + close (fileset2[1]); + FISH_SUPER (super)->sockr = fileset2[0]; + } + else + { + res = dup2 (fileset1[0], STDIN_FILENO); + close (fileset1[0]); + close (fileset1[1]); + res = dup2 (fileset2[1], STDOUT_FILENO); + close (STDERR_FILENO); + /* stderr to /dev/null */ + res = open ("/dev/null", O_WRONLY); + close (fileset2[0]); + close (fileset2[1]); + execvp (path, (char **) argv); + my_exit (3); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +static GString * +fish_set_env (int flags) +{ + GString *ret; + + ret = g_string_sized_new (256); + + if ((flags & FISH_HAVE_HEAD) != 0) + g_string_append (ret, "FISH_HAVE_HEAD=1 export FISH_HAVE_HEAD; "); + + if ((flags & FISH_HAVE_SED) != 0) + g_string_append (ret, "FISH_HAVE_SED=1 export FISH_HAVE_SED; "); + + if ((flags & FISH_HAVE_AWK) != 0) + g_string_append (ret, "FISH_HAVE_AWK=1 export FISH_HAVE_AWK; "); + + if ((flags & FISH_HAVE_PERL) != 0) + g_string_append (ret, "FISH_HAVE_PERL=1 export FISH_HAVE_PERL; "); + + if ((flags & FISH_HAVE_LSQ) != 0) + g_string_append (ret, "FISH_HAVE_LSQ=1 export FISH_HAVE_LSQ; "); + + if ((flags & FISH_HAVE_DATE_MDYT) != 0) + g_string_append (ret, "FISH_HAVE_DATE_MDYT=1 export FISH_HAVE_DATE_MDYT; "); + + if ((flags & FISH_HAVE_TAIL) != 0) + g_string_append (ret, "FISH_HAVE_TAIL=1 export FISH_HAVE_TAIL; "); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +fish_info (struct vfs_class *me, struct vfs_s_super *super) +{ + fish_super_t *fish_super = FISH_SUPER (super); + + if (fish_command (me, super, NONE, fish_super->scr_info, -1) == COMPLETE) + { + while (TRUE) + { + int res; + char buffer[BUF_8K] = ""; + + res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), fish_super->sockr); + if ((res == 0) || (res == EINTR)) + ERRNOR (ECONNRESET, FALSE); + if (strncmp (buffer, "### ", 4) == 0) + break; + fish_super->host_flags = atol (buffer); + } + return TRUE; + } + ERRNOR (E_PROTO, FALSE); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_open_archive_pipeopen (struct vfs_s_super *super) +{ + char gbuf[10]; + const char *argv[10]; /* All of 10 is used now */ + const char *xsh = (super->path_element->port == FISH_FLAG_RSH ? "rsh" : "ssh"); + int i = 0; + + argv[i++] = xsh; + if (super->path_element->port == FISH_FLAG_COMPRESSED) + argv[i++] = "-C"; + + if (super->path_element->port > FISH_FLAG_RSH) + { + argv[i++] = "-p"; + g_snprintf (gbuf, sizeof (gbuf), "%d", super->path_element->port); + argv[i++] = gbuf; + } + + /* + * Add the user name to the ssh command line only if it was explicitly + * set in vfs URL. rsh/ssh will get current user by default + * plus we can set convenient overrides in ~/.ssh/config (explicit -l + * option breaks it for some) + */ + + if (super->path_element->user != NULL) + { + argv[i++] = "-l"; + argv[i++] = super->path_element->user; + } + else + { + /* The rest of the code assumes it to be a valid username */ + super->path_element->user = vfs_get_local_username (); + } + + argv[i++] = super->path_element->host; + argv[i++] = "echo FISH:; /bin/sh"; + argv[i++] = NULL; + + fish_pipeopen (super, xsh, argv); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +fish_open_archive_talk (struct vfs_class *me, struct vfs_s_super *super) +{ + fish_super_t *fish_super = FISH_SUPER (super); + char answer[2048]; + + printf ("\n%s\n", _("fish: Waiting for initial line...")); + + if (vfs_s_get_line (me, fish_super->sockr, answer, sizeof (answer), ':') == 0) + return FALSE; + + if (strstr (answer, "assword") != NULL) + { + /* Currently, this does not work. ssh reads passwords from + /dev/tty, not from stdin :-(. */ + + printf ("\n%s\n", _("Sorry, we cannot do password authenticated connections for now.")); + + return FALSE; +#if 0 + if (super->path_element->password == NULL) + { + char *p, *op; + + p = g_strdup_printf (_("fish: Password is required for %s"), super->path_element->user); + op = vfs_get_password (p); + g_free (p); + if (op == NULL) + return FALSE; + super->path_element->password = op; + } + + printf ("\n%s\n", _("fish: Sending password...")); + + { + size_t str_len; + + str_len = strlen (super->path_element->password); + if ((write (fish_super.sockw, super->path_element->password, str_len) != + (ssize_t) str_len) || (write (fish_super->sockw, "\n", 1) != 1)) + return FALSE; + } +#endif + } + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_open_archive_int (struct vfs_class *me, struct vfs_s_super *super) +{ + gboolean ftalk; + + /* hide panels */ + pre_exec (); + + /* open pipe */ + fish_open_archive_pipeopen (super); + + /* Start talk with ssh-server (password prompt, etc ) */ + ftalk = fish_open_archive_talk (me, super); + + /* show panels */ + post_exec (); + + if (!ftalk) + ERRNOR (E_PROTO, -1); + + vfs_print_message ("%s", _("fish: Sending initial line...")); + /* + * Run 'start_fish_server'. If it doesn't exist - no problem, + * we'll talk directly to the shell. + */ + + if (fish_command + (me, super, WAIT_REPLY, "#FISH\necho; start_fish_server 2>&1; echo '### 200'\n", + -1) != COMPLETE) + ERRNOR (E_PROTO, -1); + + vfs_print_message ("%s", _("fish: Handshaking version...")); + if (fish_command (me, super, WAIT_REPLY, "#VER 0.0.3\necho '### 000'\n", -1) != COMPLETE) + ERRNOR (E_PROTO, -1); + + /* Set up remote locale to C, otherwise dates cannot be recognized */ + if (fish_command + (me, super, WAIT_REPLY, + "LANG=C LC_ALL=C LC_TIME=C; export LANG LC_ALL LC_TIME;\n" "echo '### 200'\n", + -1) != COMPLETE) + ERRNOR (E_PROTO, -1); + + vfs_print_message ("%s", _("fish: Getting host info...")); + if (fish_info (me, super)) + FISH_SUPER (super)->scr_env = fish_set_env (FISH_SUPER (super)->host_flags); + +#if 0 + super->name = + g_strconcat ("sh://", super->path_element->user, "@", super->path_element->host, + PATH_SEP_STR, (char *) NULL); +#else + super->name = g_strdup (PATH_SEP_STR); +#endif + + super->root = vfs_s_new_inode (me, super, fish_default_stat (me)); + + return 0; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_open_archive (struct vfs_s_super *super, + const vfs_path_t * vpath, const vfs_path_element_t * vpath_element) +{ + fish_super_t *fish_super = FISH_SUPER (super); + + (void) vpath; + + super->path_element = vfs_path_element_clone (vpath_element); + + if (strncmp (vpath_element->vfs_prefix, "rsh", 3) == 0) + super->path_element->port = FISH_FLAG_RSH; + + fish_super->scr_ls = + fish_load_script_from_file (super->path_element->host, FISH_LS_FILE, FISH_LS_DEF_CONTENT); + fish_super->scr_exists = + fish_load_script_from_file (super->path_element->host, FISH_EXISTS_FILE, + FISH_EXISTS_DEF_CONTENT); + fish_super->scr_mkdir = + fish_load_script_from_file (super->path_element->host, FISH_MKDIR_FILE, + FISH_MKDIR_DEF_CONTENT); + fish_super->scr_unlink = + fish_load_script_from_file (super->path_element->host, FISH_UNLINK_FILE, + FISH_UNLINK_DEF_CONTENT); + fish_super->scr_chown = + fish_load_script_from_file (super->path_element->host, FISH_CHOWN_FILE, + FISH_CHOWN_DEF_CONTENT); + fish_super->scr_chmod = + fish_load_script_from_file (super->path_element->host, FISH_CHMOD_FILE, + FISH_CHMOD_DEF_CONTENT); + fish_super->scr_utime = + fish_load_script_from_file (super->path_element->host, FISH_UTIME_FILE, + FISH_UTIME_DEF_CONTENT); + fish_super->scr_rmdir = + fish_load_script_from_file (super->path_element->host, FISH_RMDIR_FILE, + FISH_RMDIR_DEF_CONTENT); + fish_super->scr_ln = + fish_load_script_from_file (super->path_element->host, FISH_LN_FILE, FISH_LN_DEF_CONTENT); + fish_super->scr_mv = + fish_load_script_from_file (super->path_element->host, FISH_MV_FILE, FISH_MV_DEF_CONTENT); + fish_super->scr_hardlink = + fish_load_script_from_file (super->path_element->host, FISH_HARDLINK_FILE, + FISH_HARDLINK_DEF_CONTENT); + fish_super->scr_get = + fish_load_script_from_file (super->path_element->host, FISH_GET_FILE, FISH_GET_DEF_CONTENT); + fish_super->scr_send = + fish_load_script_from_file (super->path_element->host, FISH_SEND_FILE, + FISH_SEND_DEF_CONTENT); + fish_super->scr_append = + fish_load_script_from_file (super->path_element->host, FISH_APPEND_FILE, + FISH_APPEND_DEF_CONTENT); + fish_super->scr_info = + fish_load_script_from_file (super->path_element->host, FISH_INFO_FILE, + FISH_INFO_DEF_CONTENT); + + return fish_open_archive_int (vpath_element->class, super); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_archive_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *super, + const vfs_path_t * vpath, void *cookie) +{ + vfs_path_element_t *path_element; + int result; + + (void) vpath; + (void) cookie; + + path_element = vfs_path_element_clone (vpath_element); + + if (path_element->user == NULL) + path_element->user = vfs_get_local_username (); + + result = ((strcmp (path_element->host, super->path_element->host) == 0) + && (strcmp (path_element->user, super->path_element->user) == 0) + && (path_element->port == super->path_element->port)) ? 1 : 0; + + vfs_path_element_free (path_element); + + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_parse_ls (char *buffer, struct vfs_s_entry *ent) +{ +#define ST ent->ino->st + + buffer++; + + switch (buffer[-1]) + { + case ':': + { + char *filename; + char *filename_bound; + char *temp; + + filename = buffer; + + if (strcmp (filename, "\".\"") == 0 || strcmp (filename, "\"..\"") == 0) + break; /* We'll do "." and ".." ourselves */ + + filename_bound = filename + strlen (filename); + + if (S_ISLNK (ST.st_mode)) + { + char *linkname; + char *linkname_bound; + /* we expect: "escaped-name" -> "escaped-name" + // -> cannot occur in filenames, + // because it will be escaped to -\> */ + + + linkname_bound = filename_bound; + + if (*filename == '"') + ++filename; + + linkname = strstr (filename, "\" -> \""); + if (linkname == NULL) + { + /* broken client, or smth goes wrong */ + linkname = filename_bound; + if (filename_bound > filename && *(filename_bound - 1) == '"') + --filename_bound; /* skip trailing " */ + } + else + { + filename_bound = linkname; + linkname += 6; /* strlen ("\" -> \"") */ + if (*(linkname_bound - 1) == '"') + --linkname_bound; /* skip trailing " */ + } + + ent->name = g_strndup (filename, filename_bound - filename); + temp = ent->name; + ent->name = strutils_shell_unescape (ent->name); + g_free (temp); + + ent->ino->linkname = g_strndup (linkname, linkname_bound - linkname); + temp = ent->ino->linkname; + ent->ino->linkname = strutils_shell_unescape (ent->ino->linkname); + g_free (temp); + } + else + { + /* we expect: "escaped-name" */ + if (filename_bound - filename > 2) + { + /* + there is at least 2 " + and we skip them + */ + if (*filename == '"') + ++filename; + if (*(filename_bound - 1) == '"') + --filename_bound; + } + + ent->name = g_strndup (filename, filename_bound - filename); + temp = ent->name; + ent->name = strutils_shell_unescape (ent->name); + g_free (temp); + } + break; + } + + case 'S': + ST.st_size = (off_t) g_ascii_strtoll (buffer, NULL, 10); + break; + + case 'P': + { + size_t skipped; + + vfs_parse_filemode (buffer, &skipped, &ST.st_mode); + break; + } + + case 'R': + { + /* + raw filemode: + we expect: Roctal-filemode octal-filetype uid.gid + */ + size_t skipped; + + vfs_parse_raw_filemode (buffer, &skipped, &ST.st_mode); + break; + } + + case 'd': + vfs_split_text (buffer); + if (vfs_parse_filedate (0, &ST.st_ctime) == 0) + break; + ST.st_atime = ST.st_mtime = ST.st_ctime; +#ifdef HAVE_STRUCT_STAT_ST_MTIM + ST.st_atim.tv_nsec = ST.st_mtim.tv_nsec = ST.st_ctim.tv_nsec = 0; +#endif + break; + + case 'D': + { + struct tm tim; + + memset (&tim, 0, sizeof (tim)); + /* cppcheck-suppress invalidscanf */ + if (sscanf (buffer, "%d %d %d %d %d %d", &tim.tm_year, &tim.tm_mon, + &tim.tm_mday, &tim.tm_hour, &tim.tm_min, &tim.tm_sec) != 6) + break; + ST.st_atime = ST.st_mtime = ST.st_ctime = mktime (&tim); +#ifdef HAVE_STRUCT_STAT_ST_MTIM + ST.st_atim.tv_nsec = ST.st_mtim.tv_nsec = ST.st_ctim.tv_nsec = 0; +#endif + } + break; + + case 'E': + { + int maj, min; + + /* cppcheck-suppress invalidscanf */ + if (sscanf (buffer, "%d,%d", &maj, &min) != 2) + break; +#ifdef HAVE_STRUCT_STAT_ST_RDEV + ST.st_rdev = makedev (maj, min); +#endif + } + break; + + default: + break; + } + +#undef ST +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_dir_load (struct vfs_class *me, struct vfs_s_inode *dir, const char *remote_path) +{ + struct vfs_s_super *super = dir->super; + char buffer[BUF_8K] = "\0"; + struct vfs_s_entry *ent = NULL; + char *quoted_path; + int reply_code; + + /* + * Simple FISH debug interface :] + */ +#if 0 + if (me->logfile == NULL) + me->logfile = fopen ("/tmp/mc-FISH.sh", "w"); +#endif + + vfs_print_message (_("fish: Reading directory %s..."), remote_path); + + dir->timestamp = g_get_monotonic_time () + fish_directory_timeout * G_USEC_PER_SEC; + + quoted_path = strutils_shell_escape (remote_path); + (void) fish_command_v (me, super, NONE, FISH_SUPER (super)->scr_ls, "FISH_FILENAME=%s;\n", + quoted_path); + g_free (quoted_path); + + ent = vfs_s_generate_entry (me, NULL, dir, 0); + + while (TRUE) + { + int res; + + res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), FISH_SUPER (super)->sockr); + + if ((res == 0) || (res == EINTR)) + { + vfs_s_free_entry (me, ent); + me->verrno = ECONNRESET; + goto error; + } + if (me->logfile != NULL) + { + fputs (buffer, me->logfile); + fputs ("\n", me->logfile); + fflush (me->logfile); + } + if (strncmp (buffer, "### ", 4) == 0) + break; + + if (buffer[0] != '\0') + fish_parse_ls (buffer, ent); + else if (ent->name != NULL) + { + vfs_s_insert_entry (me, dir, ent); + ent = vfs_s_generate_entry (me, NULL, dir, 0); + } + } + + vfs_s_free_entry (me, ent); + reply_code = fish_decode_reply (buffer + 4, 0); + if (reply_code == COMPLETE) + { + vfs_print_message (_("%s: done."), me->name); + return 0; + } + + me->verrno = reply_code == ERROR ? EACCES : E_REMOTE; + + error: + vfs_print_message (_("%s: failure"), me->name); + return -1; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_file_store (struct vfs_class *me, vfs_file_handler_t * fh, char *name, char *localname) +{ + fish_file_handler_t *fish = FISH_FILE_HANDLER (fh); + struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh); + fish_super_t *fish_super = FISH_SUPER (super); + int code; + off_t total = 0; + char buffer[BUF_8K]; + struct stat s; + int h; + char *quoted_name; + + h = open (localname, O_RDONLY); + if (h == -1) + ERRNOR (EIO, -1); + if (fstat (h, &s) < 0) + { + close (h); + ERRNOR (EIO, -1); + } + + /* First, try this as stor: + * + * ( head -c number ) | ( cat > file; cat >/dev/null ) + * + * If 'head' is not present on the remote system, 'dd' will be used. + * Unfortunately, we cannot trust most non-GNU 'head' implementations + * even if '-c' options is supported. Therefore, we separate GNU head + * (and other modern heads?) using '-q' and '-' . This causes another + * implementations to fail (because of "incorrect options"). + * + * Fallback is: + * + * rest=<number> + * while [ $rest -gt 0 ] + * do + * cnt=`expr \( $rest + 255 \) / 256` + * n=`dd bs=256 count=$cnt | tee -a <target_file> | wc -c` + * rest=`expr $rest - $n` + * done + * + * 'dd' was not designed for full filling of input buffers, + * and does not report exact number of bytes (not blocks). + * Therefore a more complex shell script is needed. + * + * On some systems non-GNU head writes "Usage:" error report to stdout + * instead of stderr. It makes impossible the use of "head || dd" + * algorithm for file appending case, therefore just "dd" is used for it. + */ + + quoted_name = strutils_shell_escape (name); + vfs_print_message (_("fish: store %s: sending command..."), quoted_name); + + /* FIXME: File size is limited to ULONG_MAX */ + code = + fish_command_v (me, super, WAIT_REPLY, + fish->append ? fish_super->scr_append : fish_super->scr_send, + "FISH_FILENAME=%s FISH_FILESIZE=%" PRIuMAX ";\n", quoted_name, + (uintmax_t) s.st_size); + g_free (quoted_name); + + if (code != PRELIM) + { + close (h); + ERRNOR (E_REMOTE, -1); + } + + while (TRUE) + { + ssize_t n, t; + + while ((n = read (h, buffer, sizeof (buffer))) < 0) + { + if ((errno == EINTR) && tty_got_interrupt ()) + continue; + vfs_print_message ("%s", _("fish: Local read failed, sending zeros")); + close (h); + h = open ("/dev/zero", O_RDONLY); + } + + if (n == 0) + break; + + t = write (fish_super->sockw, buffer, n); + if (t != n) + { + if (t == -1) + me->verrno = errno; + else + me->verrno = EIO; + goto error_return; + } + tty_disable_interrupt_key (); + total += n; + vfs_print_message ("%s: %" PRIuMAX "/%" PRIuMAX, _("fish: storing file"), + (uintmax_t) total, (uintmax_t) s.st_size); + } + close (h); + + if (fish_get_reply (me, fish_super->sockr, NULL, 0) != COMPLETE) + ERRNOR (E_REMOTE, -1); + return 0; + + error_return: + close (h); + fish_get_reply (me, fish_super->sockr, NULL, 0); + return -1; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_linear_start (struct vfs_class *me, vfs_file_handler_t * fh, off_t offset) +{ + fish_file_handler_t *fish = FISH_FILE_HANDLER (fh); + struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh); + char *name; + char *quoted_name; + + name = vfs_s_fullpath (me, fh->ino); + if (name == NULL) + return 0; + quoted_name = strutils_shell_escape (name); + g_free (name); + fish->append = FALSE; + + /* + * Check whether the remote file is readable by using 'dd' to copy + * a single byte from the remote file to /dev/null. If 'dd' completes + * with exit status of 0 use 'cat' to send the file contents to the + * standard output (i.e. over the network). + */ + + offset = + fish_command_v (me, super, WANT_STRING, FISH_SUPER (super)->scr_get, + "FISH_FILENAME=%s FISH_START_OFFSET=%" PRIuMAX ";\n", quoted_name, + (uintmax_t) offset); + g_free (quoted_name); + + if (offset != PRELIM) + ERRNOR (E_REMOTE, 0); + fh->linear = LS_LINEAR_OPEN; + fish->got = 0; + errno = 0; +#if SIZEOF_OFF_T == SIZEOF_LONG + fish->total = (off_t) strtol (reply_str, NULL, 10); +#else + fish->total = (off_t) g_ascii_strtoll (reply_str, NULL, 10); +#endif + if (errno != 0) + ERRNOR (E_REMOTE, 0); + return 1; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_linear_abort (struct vfs_class *me, vfs_file_handler_t * fh) +{ + fish_file_handler_t *fish = FISH_FILE_HANDLER (fh); + struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh); + char buffer[BUF_8K]; + ssize_t n; + + vfs_print_message ("%s", _("Aborting transfer...")); + + do + { + n = MIN ((off_t) sizeof (buffer), (fish->total - fish->got)); + if (n != 0) + { + n = read (FISH_SUPER (super)->sockr, buffer, n); + if (n < 0) + return; + fish->got += n; + } + } + while (n != 0); + + if (fish_get_reply (me, FISH_SUPER (super)->sockr, NULL, 0) != COMPLETE) + vfs_print_message ("%s", _("Error reported after abort.")); + else + vfs_print_message ("%s", _("Aborted transfer would be successful.")); +} + +/* --------------------------------------------------------------------------------------------- */ + +static ssize_t +fish_linear_read (struct vfs_class *me, vfs_file_handler_t * fh, void *buf, size_t len) +{ + fish_file_handler_t *fish = FISH_FILE_HANDLER (fh); + struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh); + ssize_t n = 0; + + len = MIN ((size_t) (fish->total - fish->got), len); + tty_disable_interrupt_key (); + while (len != 0 && ((n = read (FISH_SUPER (super)->sockr, buf, len)) < 0)) + { + if ((errno == EINTR) && !tty_got_interrupt ()) + continue; + break; + } + tty_enable_interrupt_key (); + + if (n > 0) + fish->got += n; + else if (n < 0) + fish_linear_abort (me, fh); + else if (fish_get_reply (me, FISH_SUPER (super)->sockr, NULL, 0) != COMPLETE) + ERRNOR (E_REMOTE, -1); + ERRNOR (errno, n); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_linear_close (struct vfs_class *me, vfs_file_handler_t * fh) +{ + fish_file_handler_t *fish = FISH_FILE_HANDLER (fh); + + if (fish->total != fish->got) + fish_linear_abort (me, fh); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_ctl (void *fh, int ctlop, void *arg) +{ + (void) arg; + (void) fh; + (void) ctlop; + + return 0; + +#if 0 + switch (ctlop) + { + case VFS_CTL_IS_NOTREADY: + { + vfs_file_handler_t *file = VFS_FILE_HANDLER (fh); + int v; + + if (file->linear == LS_NOT_LINEAR) + vfs_die ("You may not do this"); + if (file->linear == LS_LINEAR_CLOSED || file->linear == LS_LINEAR_PREOPEN) + return 0; + + v = vfs_s_select_on_two (VFS_FILE_HANDLER_SUPER (fh)->u.fish.sockr, 0); + + return (((v < 0) && (errno == EINTR)) || v == 0) ? 1 : 0; + } + default: + return 0; + } +#endif +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2) +{ + const char *crpath1, *crpath2; + char *rpath1, *rpath2; + struct vfs_s_super *super, *super2; + struct vfs_class *me; + int ret; + + crpath1 = vfs_s_get_path (vpath1, &super, 0); + if (crpath1 == NULL) + return -1; + + crpath2 = vfs_s_get_path (vpath2, &super2, 0); + if (crpath2 == NULL) + return -1; + + rpath1 = strutils_shell_escape (crpath1); + rpath2 = strutils_shell_escape (crpath2); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath1)); + + ret = + fish_send_command (me, super2, OPT_FLUSH, FISH_SUPER (super)->scr_mv, + "FISH_FILEFROM=%s FISH_FILETO=%s;\n", rpath1, rpath2); + + g_free (rpath1); + g_free (rpath2); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2) +{ + const char *crpath1, *crpath2; + char *rpath1, *rpath2; + struct vfs_s_super *super, *super2; + struct vfs_class *me; + int ret; + + crpath1 = vfs_s_get_path (vpath1, &super, 0); + if (crpath1 == NULL) + return -1; + + crpath2 = vfs_s_get_path (vpath2, &super2, 0); + if (crpath2 == NULL) + return -1; + + rpath1 = strutils_shell_escape (crpath1); + rpath2 = strutils_shell_escape (crpath2); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath1)); + + ret = + fish_send_command (me, super2, OPT_FLUSH, FISH_SUPER (super)->scr_hardlink, + "FISH_FILEFROM=%s FISH_FILETO=%s;\n", rpath1, rpath2); + + g_free (rpath1); + g_free (rpath2); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2) +{ + char *qsetto; + const char *crpath; + char *rpath; + struct vfs_s_super *super; + struct vfs_class *me; + int ret; + + crpath = vfs_s_get_path (vpath2, &super, 0); + if (crpath == NULL) + return -1; + + rpath = strutils_shell_escape (crpath); + qsetto = strutils_shell_escape (vfs_path_get_last_path_str (vpath1)); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath2)); + + ret = + fish_send_command (me, super, OPT_FLUSH, FISH_SUPER (super)->scr_ln, + "FISH_FILEFROM=%s FISH_FILETO=%s;\n", qsetto, rpath); + + g_free (qsetto); + g_free (rpath); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_stat (const vfs_path_t * vpath, struct stat *buf) +{ + int ret; + + ret = vfs_s_stat (vpath, buf); + fish_set_blksize (buf); + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_lstat (const vfs_path_t * vpath, struct stat *buf) +{ + int ret; + + ret = vfs_s_lstat (vpath, buf); + fish_set_blksize (buf); + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_fstat (void *vfs_info, struct stat *buf) +{ + int ret; + + ret = vfs_s_fstat (vfs_info, buf); + fish_set_blksize (buf); + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_chmod (const vfs_path_t * vpath, mode_t mode) +{ + const char *crpath; + char *rpath; + struct vfs_s_super *super; + struct vfs_class *me; + int ret; + + crpath = vfs_s_get_path (vpath, &super, 0); + if (crpath == NULL) + return -1; + + rpath = strutils_shell_escape (crpath); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); + + ret = + fish_send_command (me, super, OPT_FLUSH, FISH_SUPER (super)->scr_chmod, + "FISH_FILENAME=%s FISH_FILEMODE=%4.4o;\n", rpath, + (unsigned int) (mode & 07777)); + + g_free (rpath); + + return ret;; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_chown (const vfs_path_t * vpath, uid_t owner, gid_t group) +{ + char *sowner, *sgroup; + struct passwd *pw; + struct group *gr; + const char *crpath; + char *rpath; + struct vfs_s_super *super; + struct vfs_class *me; + int ret; + + pw = getpwuid (owner); + if (pw == NULL) + return 0; + + gr = getgrgid (group); + if (gr == NULL) + return 0; + + sowner = pw->pw_name; + sgroup = gr->gr_name; + + crpath = vfs_s_get_path (vpath, &super, 0); + if (crpath == NULL) + return -1; + + rpath = strutils_shell_escape (crpath); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); + + /* FIXME: what should we report if chgrp succeeds but chown fails? */ + ret = + fish_send_command (me, super, OPT_FLUSH, FISH_SUPER (super)->scr_chown, + "FISH_FILENAME=%s FISH_FILEOWNER=%s FISH_FILEGROUP=%s;\n", rpath, sowner, + sgroup); + + g_free (rpath); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_get_atime (mc_timesbuf_t * times, time_t * sec, long *nsec) +{ +#ifdef HAVE_UTIMENSAT + *sec = (*times)[0].tv_sec; + *nsec = (*times)[0].tv_nsec; +#else + *sec = times->actime; + *nsec = 0; +#endif +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_get_mtime (mc_timesbuf_t * times, time_t * sec, long *nsec) +{ +#ifdef HAVE_UTIMENSAT + *sec = (*times)[1].tv_sec; + *nsec = (*times)[1].tv_nsec; +#else + *sec = times->modtime; + *nsec = 0; +#endif +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_utime (const vfs_path_t * vpath, mc_timesbuf_t * times) +{ + char utcatime[16], utcmtime[16]; + char utcatime_w_nsec[30], utcmtime_w_nsec[30]; + time_t atime, mtime; + long atime_nsec, mtime_nsec; + struct tm *gmt; + const char *crpath; + char *rpath; + struct vfs_s_super *super; + struct vfs_class *me; + int ret; + + crpath = vfs_s_get_path (vpath, &super, 0); + if (crpath == NULL) + return -1; + + rpath = strutils_shell_escape (crpath); + + fish_get_atime (times, &atime, &atime_nsec); + gmt = gmtime (&atime); + g_snprintf (utcatime, sizeof (utcatime), "%04d%02d%02d%02d%02d.%02d", + gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, + gmt->tm_hour, gmt->tm_min, gmt->tm_sec); + g_snprintf (utcatime_w_nsec, sizeof (utcatime_w_nsec), "%04d-%02d-%02d %02d:%02d:%02d.%09ld", + gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, + gmt->tm_hour, gmt->tm_min, gmt->tm_sec, atime_nsec); + + fish_get_mtime (times, &mtime, &mtime_nsec); + gmt = gmtime (&mtime); + g_snprintf (utcmtime, sizeof (utcmtime), "%04d%02d%02d%02d%02d.%02d", + gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, + gmt->tm_hour, gmt->tm_min, gmt->tm_sec); + g_snprintf (utcmtime_w_nsec, sizeof (utcmtime_w_nsec), "%04d-%02d-%02d %02d:%02d:%02d.%09ld", + gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, + gmt->tm_hour, gmt->tm_min, gmt->tm_sec, mtime_nsec); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); + + ret = fish_send_command (me, super, OPT_FLUSH, FISH_SUPER (super)->scr_utime, + "FISH_FILENAME=%s FISH_FILEATIME=%ld FISH_FILEMTIME=%ld " + "FISH_TOUCHATIME=%s FISH_TOUCHMTIME=%s FISH_TOUCHATIME_W_NSEC=\"%s\" " + "FISH_TOUCHMTIME_W_NSEC=\"%s\";\n", rpath, (long) atime, (long) mtime, + utcatime, utcmtime, utcatime_w_nsec, utcmtime_w_nsec); + + g_free (rpath); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_unlink (const vfs_path_t * vpath) +{ + const char *crpath; + char *rpath; + struct vfs_s_super *super; + struct vfs_class *me; + int ret; + + crpath = vfs_s_get_path (vpath, &super, 0); + if (crpath == NULL) + return -1; + + rpath = strutils_shell_escape (crpath); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); + + ret = + fish_send_command (me, super, OPT_FLUSH, FISH_SUPER (super)->scr_unlink, + "FISH_FILENAME=%s;\n", rpath); + + g_free (rpath); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_exists (const vfs_path_t * vpath) +{ + const char *crpath; + char *rpath; + struct vfs_s_super *super; + struct vfs_class *me; + int ret; + + crpath = vfs_s_get_path (vpath, &super, 0); + if (crpath == NULL) + return -1; + + rpath = strutils_shell_escape (crpath); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); + + ret = + fish_send_command (me, super, OPT_FLUSH, FISH_SUPER (super)->scr_exists, + "FISH_FILENAME=%s;\n", rpath); + + g_free (rpath); + + return (ret == 0 ? 1 : 0); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_mkdir (const vfs_path_t * vpath, mode_t mode) +{ + const char *crpath; + char *rpath; + struct vfs_s_super *super; + struct vfs_class *me; + int ret; + + (void) mode; + + crpath = vfs_s_get_path (vpath, &super, 0); + if (crpath == NULL) + return -1; + + rpath = strutils_shell_escape (crpath); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); + + ret = + fish_send_command (me, super, OPT_FLUSH, FISH_SUPER (super)->scr_mkdir, + "FISH_FILENAME=%s;\n", rpath); + g_free (rpath); + + if (ret != 0) + return ret; + + if (fish_exists (vpath) == 0) + { + me->verrno = EACCES; + return -1; + } + return 0; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_rmdir (const vfs_path_t * vpath) +{ + const char *crpath; + char *rpath; + struct vfs_s_super *super; + struct vfs_class *me; + int ret; + + crpath = vfs_s_get_path (vpath, &super, 0); + if (crpath == NULL) + return -1; + + rpath = strutils_shell_escape (crpath); + + me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); + + ret = + fish_send_command (me, super, OPT_FLUSH, FISH_SUPER (super)->scr_rmdir, + "FISH_FILENAME=%s;\n", rpath); + + g_free (rpath); + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ + +static vfs_file_handler_t * +fish_fh_new (struct vfs_s_inode *ino, gboolean changed) +{ + fish_file_handler_t *fh; + + fh = g_new0 (fish_file_handler_t, 1); + vfs_s_init_fh (VFS_FILE_HANDLER (fh), ino, changed); + + return VFS_FILE_HANDLER (fh); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +fish_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode) +{ + fish_file_handler_t *fish = FISH_FILE_HANDLER (fh); + + (void) mode; + + /* File will be written only, so no need to retrieve it */ + if (((flags & O_WRONLY) == O_WRONLY) && ((flags & (O_RDONLY | O_RDWR)) == 0)) + { + /* user pressed the button [ Append ] in the "Copy" dialog */ + if ((flags & O_APPEND) != 0) + fish->append = TRUE; + + if (fh->ino->localname == NULL) + { + vfs_path_t *vpath = NULL; + int tmp_handle; + + tmp_handle = vfs_mkstemps (&vpath, me->name, fh->ino->ent->name); + if (tmp_handle == -1) + return (-1); + + fh->ino->localname = vfs_path_free (vpath, FALSE); + close (tmp_handle); + } + return 0; + } + + if (fh->ino->localname == NULL && vfs_s_retrieve_file (me, fh->ino) == -1) + return (-1); + + if (fh->ino->localname == NULL) + vfs_die ("retrieve_file failed to fill in localname"); + return 0; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +fish_fill_names (struct vfs_class *me, fill_names_f func) +{ + GList *iter; + + for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter)) + { + const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data; + + char *name; + char gbuf[10]; + const char *flags = ""; + + switch (super->path_element->port) + { + case FISH_FLAG_RSH: + flags = ":r"; + break; + case FISH_FLAG_COMPRESSED: + flags = ":C"; + break; + default: + if (super->path_element->port > FISH_FLAG_RSH) + { + g_snprintf (gbuf, sizeof (gbuf), ":%d", super->path_element->port); + flags = gbuf; + } + break; + } + + name = + g_strconcat (vfs_fish_ops->prefix, VFS_PATH_URL_DELIMITER, + super->path_element->user, "@", super->path_element->host, flags, + PATH_SEP_STR, super->path_element->path, (char *) NULL); + func (name); + g_free (name); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +static void * +fish_open (const vfs_path_t * vpath, int flags, mode_t mode) +{ + /* + sorry, i've places hack here + cause fish don't able to open files with O_EXCL flag + */ + flags &= ~O_EXCL; + return vfs_s_open (vpath, flags, mode); +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +void +vfs_init_fish (void) +{ + tcp_init (); + + vfs_init_subclass (&fish_subclass, "fish", VFSF_REMOTE | VFSF_USETMP, "sh"); + vfs_fish_ops->fill_names = fish_fill_names; + vfs_fish_ops->stat = fish_stat; + vfs_fish_ops->lstat = fish_lstat; + vfs_fish_ops->fstat = fish_fstat; + vfs_fish_ops->chmod = fish_chmod; + vfs_fish_ops->chown = fish_chown; + vfs_fish_ops->utime = fish_utime; + vfs_fish_ops->open = fish_open; + vfs_fish_ops->symlink = fish_symlink; + vfs_fish_ops->link = fish_link; + vfs_fish_ops->unlink = fish_unlink; + vfs_fish_ops->rename = fish_rename; + vfs_fish_ops->mkdir = fish_mkdir; + vfs_fish_ops->rmdir = fish_rmdir; + vfs_fish_ops->ctl = fish_ctl; + fish_subclass.archive_same = fish_archive_same; + fish_subclass.new_archive = fish_new_archive; + fish_subclass.open_archive = fish_open_archive; + fish_subclass.free_archive = fish_free_archive; + fish_subclass.fh_new = fish_fh_new; + fish_subclass.fh_open = fish_fh_open; + fish_subclass.dir_load = fish_dir_load; + fish_subclass.file_store = fish_file_store; + fish_subclass.linear_start = fish_linear_start; + fish_subclass.linear_read = fish_linear_read; + fish_subclass.linear_close = fish_linear_close; + vfs_register_class (vfs_fish_ops); +} + +/* --------------------------------------------------------------------------------------------- */ diff --git a/src/vfs/fish/fish.h b/src/vfs/fish/fish.h new file mode 100644 index 0000000..3c1fa06 --- /dev/null +++ b/src/vfs/fish/fish.h @@ -0,0 +1,28 @@ + +/** + * \file + * \brief Header: Virtual File System: FISH implementation for transferring files over + * shell connections + */ + + +#ifndef MC__VFS_FISH_H +#define MC__VFS_FISH_H + +/*** typedefs(not structures) and defined constants **********************************************/ + +/*** enums ***************************************************************************************/ + +/*** structures declarations (and typedefs of structures)*****************************************/ + +/*** global variables defined in .c file *********************************************************/ + +extern int fish_directory_timeout; + +/*** declarations of public functions ************************************************************/ + +void vfs_init_fish (void); + +/*** inline functions ****************************************************************************/ + +#endif diff --git a/src/vfs/fish/fishdef.h b/src/vfs/fish/fishdef.h new file mode 100644 index 0000000..129d2b9 --- /dev/null +++ b/src/vfs/fish/fishdef.h @@ -0,0 +1,236 @@ + +/** + * \file + * \brief Header: FISH script defaults + */ + +#ifndef MC__FISH_DEF_H +#define MC__FISH_DEF_H + +/*** typedefs(not structures) and defined constants **********************************************/ + +/* default 'ls' script */ +#define FISH_LS_DEF_CONTENT "" \ +"#LIST /${FISH_FILENAME}\n" \ +"export LC_TIME=C\n" \ +"ls -Qlan \"/${FISH_FILENAME}\" 2>/dev/null | grep '^[^cbt]' | (\n" \ +"while read p l u g s m d y n; do\n" \ +" echo \"P$p $u.$g\"\n" \ +" echo \"S$s\"\n" \ +" echo \"d$m $d $y\"\n" \ +" echo \":$n\"\n" \ +" echo\n" \ +"done\n" \ +")\n" \ +"ls -Qlan \"/${FISH_FILENAME}\" 2>/dev/null | grep '^[cb]' | (\n" \ +"while read p l u g a i m d y n; do\n" \ +" echo \"P$p $u.$g\"\n" \ +" echo \"E$a$i\"\n" \ +" echo \"d$m $d $y\"\n" \ +" echo \":$n\"\n" \ +" echo\n" \ +"done\n" \ +")\n" \ +"echo \"### 200\"\n" + +/* default file exists script */ +#define FISH_EXISTS_DEF_CONTENT "" \ +"#ISEXISTS $FISH_FILENAME\n" \ +"ls -l \"/${FISH_FILENAME}\" >/dev/null 2>/dev/null\n" \ +"echo '### '$?\n" + +/* default 'mkdir' script */ +#define FISH_MKDIR_DEF_CONTENT "" \ +"#MKD $FISH_FILENAME\n" \ +"if mkdir \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + +/* default 'unlink' script */ +#define FISH_UNLINK_DEF_CONTENT "" \ +"#DELE $FISH_FILENAME\n" \ +"if rm -f \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" +/* default 'chown' script */ +#define FISH_CHOWN_DEF_CONTENT "" \ +"#CHOWN $FISH_FILEOWNER:$FISH_FILEGROUP $FISH_FILENAME\n" \ +"if chown ${FISH_FILEOWNER}:${FISH_FILEGROUP} \"/${FISH_FILENAME}\"; then\n"\ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + +/* default 'chmod' script */ +#define FISH_CHMOD_DEF_CONTENT "" \ +"#CHMOD $FISH_FILEMODE $FISH_FILENAME\n" \ +"if chmod ${FISH_FILEMODE} \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + +/* default 'utime' script */ +#define FISH_UTIME_DEF_CONTENT "" \ +"#UTIME \"$FISH_TOUCHATIME_W_NSEC\" \"$FISH_TOUCHMTIME_W_NSEC\" $FISH_FILENAME\n" \ +"if TZ=UTC touch -h -m -d \"$FISH_TOUCHMTIME_W_NSEC\" \"/${FISH_FILENAME}\" 2>/dev/null && \\\n" \ +" TZ=UTC touch -h -a -d \"$FISH_TOUCHATIME_W_NSEC\" \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"elif TZ=UTC touch -h -m -t $FISH_TOUCHMTIME \"/${FISH_FILENAME}\" 2>/dev/null && \\\n" \ +" TZ=UTC touch -h -a -t $FISH_TOUCHATIME \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"elif [ -n \"$FISH_HAVE_PERL\" ] && \\\n" \ +" perl -e 'utime '$FISH_FILEATIME','$FISH_FILEMTIME',@ARGV;' \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + + +/* default 'rmdir' script */ +#define FISH_RMDIR_DEF_CONTENT "" \ +"#RMD $FISH_FILENAME\n" \ +"if rmdir \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + +/* default 'ln -s' symlink script */ +#define FISH_LN_DEF_CONTENT "" \ +"#SYMLINK $FISH_FILEFROM $FISH_FILETO\n" \ +"if ln -s \"/${FISH_FILEFROM}\" \"/${FISH_FILETO}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + +/* default 'mv' script */ +#define FISH_MV_DEF_CONTENT "" \ +"#RENAME $FISH_FILEFROM $FISH_FILETO\n" \ +"if mv \"/${FISH_FILEFROM}\" \"/${FISH_FILETO}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + +/* default 'ln' hardlink script */ +#define FISH_HARDLINK_DEF_CONTENT "" \ +"#LINK $FISH_FILEFROM $FISH_FILETO\n" \ +"if ln \"/${FISH_FILEFROM}\" \"/${FISH_FILETO}\" 2>/dev/null; then\n" \ +" echo \"### 000\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + +/* default 'retr' script */ +#define FISH_GET_DEF_CONTENT "" \ +"export LC_TIME=C\n" \ +"#RETR $FISH_FILENAME\n" \ +"if dd if=\"/${FISH_FILENAME}\" of=/dev/null bs=1 count=1 2>/dev/null ; then\n" \ +" ls -ln \"/${FISH_FILENAME}\" 2>/dev/null | (\n" \ +" read p l u g s r\n" \ +" echo $s\n" \ +" )\n" \ +" echo \"### 100\"\n" \ +" cat \"/${FISH_FILENAME}\"\n" \ +" echo \"### 200\"\n" \ +"else\n" \ +" echo \"### 500\"\n" \ +"fi\n" + +/* default 'stor' script */ +#define FISH_SEND_DEF_CONTENT "" \ +"FILENAME=\"/${FISH_FILENAME}\"\n" \ +"FILESIZE=${FISH_FILESIZE}\n" \ +"#STOR $FILESIZE $FILENAME\n" \ +"echo \"### 001\"\n" \ +"{\n" \ +" while [ $FILESIZE -gt 0 ]; do\n" \ +" cnt=`expr \\( $FILESIZE + 255 \\) / 256`\n" \ +" n=`dd bs=256 count=$cnt | tee -a \"${FILENAME}\" | wc -c`\n" \ +" FILESIZE=`expr $FILESIZE - $n`\n" \ +" done\n" \ +"}; echo \"### 200\"\n" + +/* default 'appe' script */ +#define FISH_APPEND_DEF_CONTENT "" \ +"FILENAME=\"/${FISH_FILENAME}\"\n" \ +"FILESIZE=${FISH_FILESIZE}\n" \ +"#APPE $FILESIZE $FILENAME\n" \ +"echo \"### 001\"\n" \ +"res=`exec 3>&1\n" \ +"(\n" \ +" head -c $FILESIZE -q - || echo DD >&3\n" \ +") 2>/dev/null | (\n" \ +" cat > \"${FILENAME}\"\n" \ +" cat > /dev/null\n" \ +")`; [ \"$res\" = DD ] && {\n" \ +" > \"${FILENAME}\"\n" \ +" while [ $FILESIZE -gt 0 ]\n" \ +" do\n" \ +" cnt=`expr \\( $FILESIZE + 255 \\) / 256`\n" \ +" n=`dd bs=256 count=$cnt | tee -a \"${FILENAME}\" | wc -c`\n" \ +" FILESIZE=`expr $FILESIZE - $n`\n" \ +" done\n" \ +"}; echo \"### 200\"\n" + +/* default 'info' script */ +#define FISH_INFO_DEF_CONTENT "" \ +"export LC_TIME=C\n" \ +"#FISH_HAVE_HEAD 1\n" \ +"#FISH_HAVE_SED 2\n" \ +"#FISH_HAVE_AWK 4\n" \ +"#FISH_HAVE_PERL 8\n" \ +"#FISH_HAVE_LSQ 16\n" \ +"#FISH_HAVE_DATE_MDYT 32\n" \ +"#FISH_HAVE_TAIL 64\n" \ +"res=0\n" \ +"if `echo yes| head -c 1 > /dev/null 2>&1` ; then\n" \ +" res=`expr $res + 1`\n" \ +"fi\n" \ +"if `sed --version >/dev/null 2>&1` ; then\n" \ +" res=`expr $res + 2`\n" \ +"fi\n" \ +"if `awk --version > /dev/null 2>&1` ; then\n" \ +" res=`expr $res + 4`\n" \ +"fi\n" \ +"if `perl -v > /dev/null 2>&1` ; then\n" \ +" res=`expr $res + 8`\n" \ +"fi\n" \ +"if `ls -Q / >/dev/null 2>&1` ; then\n" \ +" res=`expr $res + 16`\n" \ +"fi\n" \ +"dat=`ls -lan / 2>/dev/null | head -n 3 | tail -n 1 | (\n" \ +" while read p l u g s rec; do\n" \ +" if [ -n \"$g\" ]; then\n" \ +" if [ -n \"$l\" ]; then\n" \ +" echo \"$rec\"\n" \ +" fi\n" \ +" fi\n" \ +" done\n" \ +") | cut -c1 2>/dev/null`\n" \ +"r=`echo \"0123456789\"| grep \"$dat\"`\n" \ +"if [ -z \"$r\" ]; then\n" \ +" res=`expr $res + 32`\n" \ +"fi\n" \ +"if `echo yes| tail -c +1 - > /dev/null 2>&1` ; then\n" \ +" res=`expr $res + 64`\n" \ +"fi\n" \ +"echo $res\n" \ +"echo \"### 200\"\n" + +/*** enums ***************************************************************************************/ + +/*** structures declarations (and typedefs of structures)*****************************************/ + +/*** global variables defined in .c file *********************************************************/ + +/*** declarations of public functions ************************************************************/ + +/*** inline functions ****************************************************************************/ +#endif diff --git a/src/vfs/fish/helpers/Makefile.am b/src/vfs/fish/helpers/Makefile.am new file mode 100644 index 0000000..e3ba15d --- /dev/null +++ b/src/vfs/fish/helpers/Makefile.am @@ -0,0 +1,10 @@ +fishdir = $(libexecdir)/@PACKAGE@/fish + +# Files to install and distribute other than fish scripts +FISH_MISC = README.fish + +# Install and distribute FISH helper scripts w/o shebang & executable bit as data +fish_DATA = $(FISH_MISC) ls mkdir fexists unlink chown chmod rmdir ln mv hardlink get send append info utime +fishconfdir = $(sysconfdir)/@PACKAGE@ + +EXTRA_DIST = $(fish_DATA) diff --git a/src/vfs/fish/helpers/Makefile.in b/src/vfs/fish/helpers/Makefile.in new file mode 100644 index 0000000..c17efbb --- /dev/null +++ b/src/vfs/fish/helpers/Makefile.in @@ -0,0 +1,642 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/vfs/fish/helpers +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/m4.include/gnulib/mode_t.m4 \ + $(top_srcdir)/m4.include/gnulib/stat-size.m4 \ + $(top_srcdir)/m4.include/gnulib/fstypename.m4 \ + $(top_srcdir)/m4.include/gnulib/fsusage.m4 \ + $(top_srcdir)/m4.include/gnulib/mountlist.m4 \ + $(top_srcdir)/m4.include/gnulib/windows-stat-inodes.m4 \ + $(top_srcdir)/m4.include/gnulib/sys_types_h.m4 \ + $(top_srcdir)/m4.include/ax_path_lib_pcre.m4 \ + $(top_srcdir)/m4.include/ax_check_pcre2.m4 \ + $(top_srcdir)/m4.include/dx_doxygen.m4 \ + $(top_srcdir)/m4.include/ax_require_defined.m4 \ + $(top_srcdir)/m4.include/ax_check_compile_flag.m4 \ + $(top_srcdir)/m4.include/ax_append_flag.m4 \ + $(top_srcdir)/m4.include/ax_append_compile_flags.m4 \ + $(top_srcdir)/m4.include/mc-cflags.m4 \ + $(top_srcdir)/m4.include/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/m4.include/mc-check-search-type.m4 \ + $(top_srcdir)/m4.include/mc-get-fs-info.m4 \ + $(top_srcdir)/m4.include/mc-with-x.m4 \ + $(top_srcdir)/m4.include/mc-use-termcap.m4 \ + $(top_srcdir)/m4.include/mc-with-screen.m4 \ + $(top_srcdir)/m4.include/mc-with-screen-ncurses.m4 \ + $(top_srcdir)/m4.include/mc-with-screen-slang.m4 \ + $(top_srcdir)/m4.include/mc-with-internal-edit.m4 \ + $(top_srcdir)/m4.include/mc-subshell.m4 \ + $(top_srcdir)/m4.include/mc-background.m4 \ + $(top_srcdir)/m4.include/mc-ext2fs-attr.m4 \ + $(top_srcdir)/m4.include/mc-glib.m4 \ + $(top_srcdir)/m4.include/mc-vfs.m4 \ + $(top_srcdir)/m4.include/vfs/rpc.m4 \ + $(top_srcdir)/m4.include/vfs/socket.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-extfs.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-sfs.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-ftp.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-sftp.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-fish.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-undelfs.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-tarfs.m4 \ + $(top_srcdir)/m4.include/vfs/mc-vfs-cpiofs.m4 \ + $(top_srcdir)/m4.include/mc-version.m4 \ + $(top_srcdir)/m4.include/mc-tests.m4 \ + $(top_srcdir)/m4.include/mc-i18n.m4 \ + $(top_srcdir)/m4.include/mc-assert.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(fishdir)" +DATA = $(fish_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +COM_ERR_CFLAGS = @COM_ERR_CFLAGS@ +COM_ERR_LIBS = @COM_ERR_LIBS@ +CP1251 = @CP1251@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOC_LINGUAS = @DOC_LINGUAS@ +DOXYGEN_PAPER_SIZE = @DOXYGEN_PAPER_SIZE@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DX_CONFIG = @DX_CONFIG@ +DX_DOCDIR = @DX_DOCDIR@ +DX_DOT = @DX_DOT@ +DX_DOXYGEN = @DX_DOXYGEN@ +DX_DVIPS = @DX_DVIPS@ +DX_EGREP = @DX_EGREP@ +DX_ENV = @DX_ENV@ +DX_FLAG_chi = @DX_FLAG_chi@ +DX_FLAG_chm = @DX_FLAG_chm@ +DX_FLAG_doc = @DX_FLAG_doc@ +DX_FLAG_dot = @DX_FLAG_dot@ +DX_FLAG_html = @DX_FLAG_html@ +DX_FLAG_man = @DX_FLAG_man@ +DX_FLAG_pdf = @DX_FLAG_pdf@ +DX_FLAG_ps = @DX_FLAG_ps@ +DX_FLAG_rtf = @DX_FLAG_rtf@ +DX_FLAG_xml = @DX_FLAG_xml@ +DX_HHC = @DX_HHC@ +DX_LATEX = @DX_LATEX@ +DX_MAKEINDEX = @DX_MAKEINDEX@ +DX_PDFLATEX = @DX_PDFLATEX@ +DX_PERL = @DX_PERL@ +DX_PROJECT = @DX_PROJECT@ +E2P_CFLAGS = @E2P_CFLAGS@ +E2P_LIBS = @E2P_LIBS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +EXT2FS_CFLAGS = @EXT2FS_CFLAGS@ +EXT2FS_LIBS = @EXT2FS_LIBS@ +EXTHELPERSDIR = @EXTHELPERSDIR@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GMODULE_CFLAGS = @GMODULE_CFLAGS@ +GMODULE_LIBS = @GMODULE_LIBS@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +HAVE_FILECMD = @HAVE_FILECMD@ +HAVE_ZIPINFO = @HAVE_ZIPINFO@ +HAVE_nroff = @HAVE_nroff@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMC_RELEASE = @LIBMC_RELEASE@ +LIBMC_VERSION = @LIBMC_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSSH_CFLAGS = @LIBSSH_CFLAGS@ +LIBSSH_LIBS = @LIBSSH_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANDOC = @MANDOC@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAN_DATE = @MAN_DATE@ +MAN_FLAGS = @MAN_FLAGS@ +MAN_VERSION = @MAN_VERSION@ +MCLIBS = @MCLIBS@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCRE_CFLAGS = @PCRE_CFLAGS@ +PCRE_LIBS = @PCRE_LIBS@ +PERL = @PERL@ +PERL_FOR_BUILD = @PERL_FOR_BUILD@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +RANLIB = @RANLIB@ +RUBY = @RUBY@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SLANG_CFLAGS = @SLANG_CFLAGS@ +SLANG_LIBS = @SLANG_LIBS@ +STRIP = @STRIP@ +TESTS_LDFLAGS = @TESTS_LDFLAGS@ +UNZIP = @UNZIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +X11_WWW = @X11_WWW@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +ZIP = @ZIP@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +fishdir = $(libexecdir)/@PACKAGE@/fish + +# Files to install and distribute other than fish scripts +FISH_MISC = README.fish + +# Install and distribute FISH helper scripts w/o shebang & executable bit as data +fish_DATA = $(FISH_MISC) ls mkdir fexists unlink chown chmod rmdir ln mv hardlink get send append info utime +fishconfdir = $(sysconfdir)/@PACKAGE@ +EXTRA_DIST = $(fish_DATA) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/vfs/fish/helpers/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/vfs/fish/helpers/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-fishDATA: $(fish_DATA) + @$(NORMAL_INSTALL) + @list='$(fish_DATA)'; test -n "$(fishdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(fishdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(fishdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(fishdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(fishdir)" || exit $$?; \ + done + +uninstall-fishDATA: + @$(NORMAL_UNINSTALL) + @list='$(fish_DATA)'; test -n "$(fishdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(fishdir)'; $(am__uninstall_files_from_dir) +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(fishdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-fishDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-fishDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-fishDATA \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags-am uninstall uninstall-am uninstall-fishDATA + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/vfs/fish/helpers/README.fish b/src/vfs/fish/helpers/README.fish new file mode 100644 index 0000000..ac319c8 --- /dev/null +++ b/src/vfs/fish/helpers/README.fish @@ -0,0 +1,217 @@ + + FIles transferred over SHell protocol (V 0.0.3) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This protocol was designed for transferring files over a remote shell +connection (rsh and compatibles). It can be as well used for transfers over +rsh, and there may be other uses. + +Client sends requests of following form: + +#FISH_COMMAND +equivalent shell commands, +which may be multiline + +Only fish commands are defined here, shell equivalents are for your +information only and will probably vary from implementation to +implementation. Fish commands always have priority: server is +expected to execute fish command if it understands it. If it does not, +however, it can try the luck and execute shell command. + +Since version 4.7.3, the scripts that FISH sends to host machines after +a command is transmitted are no longer hardwired in the Midnight +Commander source code. + +First, mc looks for system-wide set of scripts, then it checks whether +current user has host-specific overrides in his per-user mc +configuration directory. User-defined overrides take priority over +sytem-wide scripts if they exist. The order in which the directories are +traversed is as follows: + + /usr/libexec/mc/fish + ~/.local/share/mc/fish/<hostname>/ + +Server's reply is multiline, but always ends with + +### 000<optional text> + +line. ### is prefix to mark this line, 000 is return code. Return +codes are superset to those used in ftp. + +There are few new exit codes defined: + +000 don't know; if there were no previous lines, this marks COMPLETE +success, if they were, it marks failure. + +001 don't know; if there were no previous lines, this marks +PRELIMinary success, if they were, it marks failure + + Connecting + ~~~~~~~~~~ +Client uses "echo FISH:;/bin/sh" as command executed on remote +machine. This should make it possible for server to distinguish FISH +connections from normal rsh/ssh. + + Commands + ~~~~~~~~ +#FISH +echo; start_fish_server; echo '### 200' + +This command is sent at the beginning. It marks that client wishes to +talk via FISH protocol. #VER command must follow. If server +understands FISH protocol, it has option to put FISH server somewhere +on system path and name it start_fish_server. + +#VER 0.0.2 <feature1> <feature2> <...> +echo '### 000' + +This command is the second one. It sends client version and extensions +to the server. Server should reply with protocol version to be used, +and list of extensions accepted. + +VER 0.0.0 <feature2> +### 200 + +#PWD +pwd; echo '### 200' + +Server should reply with current directory (in form /abc/def/ghi) +followed by line indicating success. + +#LIST /directory +ls -lLa $1 | grep '^[^cbt]' | ( while read p x u g s m d y n; do echo "P$p $u.$g +S$s +d$m $d $y +:$n +"; done ) +ls -lLa $1 | grep '^[cb]' | ( while read p x u g a i m d y n; do echo "P$p $u.$g +E$a$i +dD$m $d $y +:$n +"; done ) +echo '### 200' + +This allows client to list directory or get status information about +single file. Output is in following form (any line except :<filename> +may be omitted): + +P<unix permissions> <owner>.<group> +S<size> +d<3-letters month name> <day> <year or HH:MM> +D<year> <month> <day> <hour> <minute> <second>[.1234] +E<major-of-device>,<minor> +:<filename> +L<filename symlink points to> +<blank line to separate items> + +Unix permissions are of form X--------- where X is type of +file. Currently, '-' means regular file, 'd' means directory, 'c', 'b' +means character and block device, 'l' means symbolic link, 'p' means +FIFO and 's' means socket. + +'d' has three fields: month (one of strings Jan Feb Mar Apr May Jun +Jul Aug Sep Oct Nov Dec), day of month, and third is either single +number indicating year, or HH:MM field (assume current year in such +case). As you've probably noticed, this is pretty broken; it is for +compatibility with ls listing. + +#RETR /some/name +ls -l /some/name | ( read a b c d x e; echo $x ); echo '### 100'; cat /some/name; echo '### 200' + +Server sends line with filesize on it, followed by line with ### 100 +indicating partial success, then it sends binary data (exactly +filesize bytes) and follows them with (with no preceding newline) ### +200. + +Note that there's no way to abort running RETR command - except +closing the connection. + +#STOR <size> /file/name +> /file/name; echo '### 001'; ( dd bs=4096 count=<size/4096>; dd bs=<size%4096> count=1 ) 2>/dev/null | ( cat > %s; cat > /dev/null ); echo '### 200' + +This command is for storing /file/name, which is exactly size bytes +big. You probably think I went crazy. Well, I did not: that strange +cat > /dev/null has purpose to discard any extra data which was not +written to disk (due to for example out of space condition). + +[Why? Imagine uploading file with "rm -rf /" line in it.] + +#CWD /somewhere +cd /somewhere; echo '### 000' + +It is specified here, but I'm not sure how wise idea is to use this +one: it breaks stateless-ness of the protocol. + +Following commands should be rather self-explanatory: + +#CHMOD 1234 file +chmod 1234 file; echo '### 000' + +#DELE /some/path +rm -f /some/path; echo '### 000' + +#MKD /some/path +mkdir /some/path; echo '### 000' + +#RMD /some/path +rmdir /some/path; echo '### 000' + +#RENAME /path/a /path/b +mv /path/a /path/b; echo '### 000' + +#LINK /path/a /path/b +ln /path/a /path/b; echo '### 000' + +#SYMLINK /path/a /path/b +ln -s /path/a /path/b; echo '### 000' + +#CHOWN user /file/name +chown user /file/name; echo '### 000' + +#CHGRP group /file/name +chgrp group /file/name; echo '### 000' + +#INFO +...collect info about host into $result ... +echo $result +echo '### 200' + +#READ <offset> <size> /path/and/filename +cat /path/and/filename | ( dd bs=4096 count=<offset/4096> > /dev/null; +dd bs=<offset%4096> count=1 > /dev/null; +dd bs=4096 count=<offset/4096>; +dd bs=<offset%4096> count=1; ) + +Returns ### 200 on successful exit, ### 291 on successful exit when +reading ended at eof, ### 292 on successful exit when reading did not +end at eof. + +#WRITE <offset> <size> /path/and/filename + +Hmm, shall we define these ones if we know our client is not going to +use them? + +you can use follow parameters: +FISH_FILESIZE +FISH_FILENAME +FISH_FILEMODE +FISH_FILEOWNER +FISH_FILEGROUPE +FISH_FILEFROM +FISH_FILETO + +NB: +'FISH_FILESIZE' used if we operate with single file name in 'unlink', 'rmdir', 'chmod', etc... +'FISH_FILEFROM','FISH_FILETO' used if we operate with two files in 'ln', 'hardlink', 'mv' etc... +'FISH_FILEOWNER', 'FISH_FILEGROUPE' is a new user/group in chown + +also flags: +FISH_HAVE_HEAD +FISH_HAVE_SED +FISH_HAVE_AWK +FISH_HAVE_PERL +FISH_HAVE_LSQ +FISH_HAVE_DATE_MDYT + +That's all, folks! + pavel@ucw.cz diff --git a/src/vfs/fish/helpers/append b/src/vfs/fish/helpers/append new file mode 100644 index 0000000..81ded44 --- /dev/null +++ b/src/vfs/fish/helpers/append @@ -0,0 +1,16 @@ +#APPE $FISH_FILESIZE $FISH_FILENAME +FILENAME="/${FISH_FILENAME}" +echo "### 001" +{ + bss=4096 + bsl=4095 + if [ $FISH_FILESIZE -lt $bss ]; then + bss=1; + bsl=0; + fi + while [ $FISH_FILESIZE -gt 0 ]; do + cnt=`expr \\( $FISH_FILESIZE + $bsl \\) / $bss` + n=`dd bs=$bss count=$cnt | tee -a "${FILENAME}" | wc -c` + FISH_FILESIZE=`expr $FISH_FILESIZE - $n` + done +}; echo "### 200" diff --git a/src/vfs/fish/helpers/chmod b/src/vfs/fish/helpers/chmod new file mode 100644 index 0000000..a5a88b4 --- /dev/null +++ b/src/vfs/fish/helpers/chmod @@ -0,0 +1,6 @@ +#CHMOD $FISH_FILEMODE $FISH_FILENAME +if chmod ${FISH_FILEMODE} "/${FISH_FILENAME}" 2>/dev/null; then + echo "### 000" +else + echo "### 500" +fi diff --git a/src/vfs/fish/helpers/chown b/src/vfs/fish/helpers/chown new file mode 100644 index 0000000..469fdc1 --- /dev/null +++ b/src/vfs/fish/helpers/chown @@ -0,0 +1,6 @@ +#CHOWN $FISH_FILEOWNER:$FISH_FILEGROUP $FISH_FILENAME +if chown ${FISH_FILEOWNER}:${FISH_FILEGROUP} "/${FISH_FILENAME}" ; then + echo "### 000" +else + echo "### 500" +fi diff --git a/src/vfs/fish/helpers/fexists b/src/vfs/fish/helpers/fexists new file mode 100644 index 0000000..cf03b15 --- /dev/null +++ b/src/vfs/fish/helpers/fexists @@ -0,0 +1,3 @@ +#ISEXISTS $FISH_FILENAME +ls -l "/${FISH_FILENAME}" >/dev/null 2>/dev/null +echo '### '$? diff --git a/src/vfs/fish/helpers/get b/src/vfs/fish/helpers/get new file mode 100644 index 0000000..762267a --- /dev/null +++ b/src/vfs/fish/helpers/get @@ -0,0 +1,105 @@ +#RETR $FISH_FILENAME $FISH_START_OFFSET +LC_TIME=C +export LC_TIME +fish_get_perl () +{ +FILENAME=$1 +OFFSET=$2 +perl -e ' +use strict; +use POSIX; +use Fcntl; +my $filename = $ARGV[0]; +my $pos = $ARGV[1]; +my $content; +my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat("$filename"); +my $n; +if (open IFILE,$filename) { + if ($size<$pos) { + printf("0\n"); + } else { + $size-=$pos; + printf("$size\n"); + } + printf("### 100\n"); + seek (IFILE, $pos, 0); + while ($n = read(IFILE,$content,$blksize)!= 0) { + print $content; + } + close IFILE; + printf("### 200\n"); +} else { + printf("### 500\n"); +} +exit 0 +' "${FILENAME}" $OFFSET +} + +fish_get_tail () +{ +FILENAME=$1 +OFFSET=$2 +LC_TIME=C +export LC_TIME +if dd if="${FILENAME}" of=/dev/null bs=1 count=1 2>/dev/null ; then + file_size=`ls -ln "${FILENAME}" 2>/dev/null | ( + read p l u g s r + echo $s + )` + if [ $OFFSET -gt 0 ]; then + file_size=`expr $file_size - $OFFSET` + OFFSET=`expr $OFFSET + 1` + fi + if [ $file_size -gt 0 ]; then + echo $file_size + else + echo 0 + fi + echo "### 100" + if [ $OFFSET -gt 0 ]; then + tail -c +${OFFSET} "${FILENAME}" + else + cat "${FILENAME}" + fi + echo "### 200" +else + echo "### 500" +fi +} + +fish_get_dd () +{ +FILENAME=$1 +OFFSET=$2 +LC_TIME=C +export LC_TIME +if dd if="${FILENAME}" of=/dev/null bs=1 count=1 2>/dev/null ; then + file_size=`ls -ln "${FILENAME}" 2>/dev/null | ( + read p l u g s r + echo $s + )` + file_size=`expr $file_size - $OFFSET` + if [ $file_size -gt 0 ]; then + echo $file_size + else + echo 0 + fi + echo "### 100" + if [ $OFFSET -gt 0 ]; then + dd skip=$OFFSET ibs=1 if="${FILENAME}" 2>/dev/null + else + cat "${FILENAME}" + fi + echo "### 200" +else + echo "### 500" +fi +} + +if [ -n "${FISH_HAVE_PERL}" ]; then + fish_get_perl "/${FISH_FILENAME}" ${FISH_START_OFFSET} +elif [ -n "${FISH_HAVE_TAIL}" ]; then + fish_get_tail "/${FISH_FILENAME}" ${FISH_START_OFFSET} +else + fish_get_dd "/${FISH_FILENAME}" ${FISH_START_OFFSET} +fi diff --git a/src/vfs/fish/helpers/hardlink b/src/vfs/fish/helpers/hardlink new file mode 100644 index 0000000..4f36b3f --- /dev/null +++ b/src/vfs/fish/helpers/hardlink @@ -0,0 +1,8 @@ +#LINK $FISH_FILEFROM $FISH_FILETO +FILEFROM="/${FISH_FILEFROM}" +FILETO="/${FISH_FILETO}" +if ln "${FILEFROM}" "${FILETO}" 2>/dev/null; then + echo "### 000" +else + echo "### 500" +fi diff --git a/src/vfs/fish/helpers/info b/src/vfs/fish/helpers/info new file mode 100644 index 0000000..b85b0a7 --- /dev/null +++ b/src/vfs/fish/helpers/info @@ -0,0 +1,44 @@ +LC_TIME=C +export LC_TIME +#FISH_HAVE_HEAD 1 +#FISH_HAVE_SED 2 +#FISH_HAVE_AWK 4 +#FISH_HAVE_PERL 8 +#FISH_HAVE_LSQ 16 +#FISH_HAVE_DATE_MDYT 32 +#FISH_HAVE_TAIL 64 +res=0 +if `echo yes| head -c 1 > /dev/null 2>&1` ; then + res=`expr $res + 1` +fi +if `echo 1 | sed 's/1/2/' >/dev/null 2>&1` ; then + res=`expr $res + 2` +fi +if `echo 1| awk '{print}' > /dev/null 2>&1` ; then + res=`expr $res + 4` +fi +if `perl -v > /dev/null 2>&1` ; then + res=`expr $res + 8` +fi +if `ls -Q / >/dev/null 2>&1` ; then + res=`expr $res + 16` +fi +dat=`ls -lan / 2>/dev/null | head -n 3 | ( + while read p l u g s rec; do + if [ -n "$g" ]; then + if [ -n "$l" ]; then + echo "$rec" + fi + fi + done +)` +dat=`echo $dat | cut -c1 2>/dev/null` +r=`echo "0123456789"| grep "$dat"` +if [ -z "$r" ]; then + res=`expr $res + 32` +fi +if `echo yes| tail -c +1 - > /dev/null 2>&1` ; then + res=`expr $res + 64` +fi +echo $res +echo "### 200" diff --git a/src/vfs/fish/helpers/ln b/src/vfs/fish/helpers/ln new file mode 100644 index 0000000..a8445d8 --- /dev/null +++ b/src/vfs/fish/helpers/ln @@ -0,0 +1,8 @@ +#SYMLINK $FISH_FILEFROM $FISH_FILETO +FILEFROM="${FISH_FILEFROM}" +FILETO="/${FISH_FILETO}" +if ln -s "${FILEFROM}" "${FILETO}" 2>/dev/null; then + echo "### 000" +else + echo "### 500" +fi diff --git a/src/vfs/fish/helpers/ls b/src/vfs/fish/helpers/ls new file mode 100644 index 0000000..7165b51 --- /dev/null +++ b/src/vfs/fish/helpers/ls @@ -0,0 +1,170 @@ +#LIST /${FISH_DIR} +LC_TIME=C +export LC_TIME +perl_res="1" +fish_list_lsq () +{ +FISH_DIR="$1" +ls -Qlan "${FISH_DIR}" 2>/dev/null | grep '^[^cbt]' | ( +while read p l u g s m d y n; do + echo "P$p $u.$g" + echo "S$s" + echo "d$m $d $y" + echo ":$n" + echo +done +) + +ls -Qlan "${FISH_DIR}" 2>/dev/null | grep '^[cb]' | ( +while read p l u g a i m d y n; do + echo "P$p $u.$g" + echo "E$a$i" + echo "d$m $d $y" + echo ":$n" + echo +done +) +echo '### 200' +} + +fish_list_sed () +{ +FISH_DIR="$1" +ls -lan "${FISH_DIR}" 2>/dev/null | grep '^[^cbt]' | ( +while read p l u g s rec; do + if [ -n "$g" ]; then + if [ -n "$FISH_HAVE_DATE_MDYT" ]; then + filename=`echo "$rec"| sed 's/[^[:space:]]\+ \+[^[:space:]]\+ \+[^[:space:]]\+ //'` + filedate=`echo "$rec"| sed 's/\([^[:space:]]\+ \+[^[:space:]]\+ \+[^[:space:]]\+\) .*/\1/'` + else + filename=`echo "$rec"| sed 's/[^[:space:]]\+ \+[^[:space:]]\+ //'` + filedate=`echo "$rec"| sed 's/\([^[:space:]]\+ \+[^[:space:]]\+\) .*/\1/'` + fi + pfile=\"`echo "$filename" | sed -e 's#^\(.*\) -> \(.*\)#\1" -> "\2#'`\" + echo "P$p $u.$g" + echo "S$s" + if [ -n "$FISH_HAVE_DATE_MDYT" ]; then + echo "d$filedate" + else + echo "D$filedate" + fi + echo ":$pfile" + echo + fi +done +) +ls -lan "${FISH_DIR}" 2>/dev/null | grep '^[cb]' | ( +while read p l u g a i rec; do + if [ -n "$g" ]; then + if [ -n "$FISH_HAVE_DATE_MDYT" ]; then + filename=`echo "$rec"| sed 's/[^[:space:]]\+ \+[^[:space:]]\+ \+[^[:space:]]\+ //'` + filedate=`echo "$rec"| sed 's/\([^[:space:]]\+ \+[^[:space:]]\+ \+[^[:space:]]\+\) .*/\1/'` + else + filename=`echo "$rec"| sed 's/[^[:space:]]\+ \+[^[:space:]]\+ //'` + filedate=`echo "$rec"| sed 's/\([^[:space:]]\+ \+[^[:space:]]\+\) .*/\1/'` + fi + pfile=\"`echo "$filename" | sed -e 's#^\(.*\) -> \(.*\)#\1" -> "\2#'`\" + echo "P$p $u.$g" + echo "E$a$i" + if [ -n "$FISH_HAVE_DATE_MDYT" ]; then + echo "d$filedate" + else + echo "D$filedate" + fi + echo ":$pfile" + echo + fi +done +) +echo '### 200' +} + +fish_list_poor_ls () +{ +FISH_DIR="$1" +ls -lan "${FISH_DIR}" 2>/dev/null | grep '^[^cbt]' | ( +while read p l u g s m d y n n2 n3; do + if [ -n "$g" ]; then + if [ "$m" = "0" ]; then + s=$d; m=$y; d=$n; y=$n2; n=$n3 + else + n=$n" "$n2" "$n3 + fi + echo "P$p $u $g" + echo "S$s" + echo "d$m $d $y" + echo ":"$n + echo + fi +done +) +ls -lan "${FISH_DIR}" 2>/dev/null | grep '^[cb]' | ( +while read p l u g a i m d y n n2 n3; do + if [ -n "$g" ]; then + if [ "$a" = "0" ]; then + a=$m; i=$d; m=$y; d=$n; y=$n2; n=$n3 + else + n=$n" "$n2" "$n3 + fi + echo "P$p $u $g" + echo "E$a$i" + echo "d$m $d $y" + echo ":"$n + echo + fi +done +) +echo '### 200' +} + +fish_list_perl () +{ +FISH_DIR=$1 +perl -e ' +use strict; +use POSIX; +use Fcntl; +use POSIX ":fcntl_h"; #S_ISLNK was here until 5.6 +import Fcntl ":mode" unless defined &S_ISLNK; #and is now here +my $dirname = $ARGV[0]; +if (opendir (DIR, $dirname)) { +while((my $filename = readdir (DIR))){ + my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat("$dirname/$filename"); + my $mloctime= strftime("%m-%d-%Y %H:%M", localtime $mtime); + my $strutils_shell_escape_regex = s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'\''"\ \\])/\\$1/g; + my $e_filename = $filename; + $e_filename =~ $strutils_shell_escape_regex; + if (S_ISLNK ($mode)) { + my $linkname = readlink ("$dirname/$filename"); + $linkname =~ $strutils_shell_escape_regex; + printf("R%o %o $uid.$gid\nS$size\nd$mloctime\n:\"%s\" -> \"%s\"\n\n", S_IMODE($mode), S_IFMT($mode), $e_filename, $linkname); + } elsif (S_ISCHR ($mode) || S_ISBLK ($mode)) { + my $minor = $rdev % 256; + my $major = int( $rdev / 256 ); + printf("R%o %o $uid.$gid\nE$major,$minor\nd$mloctime\n:\"%s\"\n\n", S_IMODE($mode), S_IFMT($mode), $e_filename); + } else { + printf("R%o %o $uid.$gid\nS$size\nd$mloctime\n:\"%s\"\n\n", S_IMODE($mode), S_IFMT($mode), $e_filename); + } +} + printf("### 200\n"); + closedir(DIR); +} else { + printf("### 500\n"); +} +exit 0 +' "/${FISH_DIR}" +perl_res=$? +} + +if [ -n "${FISH_HAVE_PERL}" ]; then + fish_list_perl "/${FISH_FILENAME}" +fi +if [ "${perl_res}" != "0" ]; then + if [ -n "${FISH_HAVE_LSQ}" ]; then + fish_list_lsq "/${FISH_FILENAME}" + elif [ -n "${FISH_HAVE_SED}" ]; then + fish_list_sed "/${FISH_FILENAME}" + else + fish_list_poor_ls "/${FISH_FILENAME}" + fi +fi diff --git a/src/vfs/fish/helpers/mkdir b/src/vfs/fish/helpers/mkdir new file mode 100644 index 0000000..b32e995 --- /dev/null +++ b/src/vfs/fish/helpers/mkdir @@ -0,0 +1,6 @@ +#MKD $FISH_FILENAME +if mkdir "/$FISH_FILENAME" 2>/dev/null; then + echo "### 000" +else + echo "### 500" +fi diff --git a/src/vfs/fish/helpers/mv b/src/vfs/fish/helpers/mv new file mode 100644 index 0000000..c8cf70c --- /dev/null +++ b/src/vfs/fish/helpers/mv @@ -0,0 +1,6 @@ +#RENAME $FISH_FILEFROM $FISH_FILETO +if mv "/${FISH_FILEFROM}" "/${FISH_FILETO}" 2>/dev/null; then + echo "### 000" +else + echo "### 500" +fi diff --git a/src/vfs/fish/helpers/rmdir b/src/vfs/fish/helpers/rmdir new file mode 100644 index 0000000..0f99bf6 --- /dev/null +++ b/src/vfs/fish/helpers/rmdir @@ -0,0 +1,6 @@ +#RMD $FISH_FILENAME +if rmdir "/${FISH_FILENAME}" 2>/dev/null; then + echo "### 000" +else + echo "### 500" +fi diff --git a/src/vfs/fish/helpers/send b/src/vfs/fish/helpers/send new file mode 100644 index 0000000..80dd22b --- /dev/null +++ b/src/vfs/fish/helpers/send @@ -0,0 +1,17 @@ +#STOR $FISH_FILESIZE $FISH_FILENAME +FILENAME="/${FISH_FILENAME}" +echo "### 001" +{ + > "${FILENAME}" + bss=4096 + bsl=4095 + if [ $FISH_FILESIZE -lt $bss ]; then + bss=1; + bsl=0; + fi + while [ $FISH_FILESIZE -gt 0 ]; do + cnt=`expr \\( $FISH_FILESIZE + $bsl \\) / $bss` + n=`dd bs=$bss count=$cnt | tee -a "${FILENAME}" | wc -c` + FISH_FILESIZE=`expr $FISH_FILESIZE - $n` + done +}; echo "### 200" diff --git a/src/vfs/fish/helpers/unlink b/src/vfs/fish/helpers/unlink new file mode 100644 index 0000000..79b9ad0 --- /dev/null +++ b/src/vfs/fish/helpers/unlink @@ -0,0 +1,6 @@ +#DELE $FISH_FILENAME +if rm -f "/${FISH_FILENAME}" 2>/dev/null; then + echo "### 000" +else + echo "### 500" +fi diff --git a/src/vfs/fish/helpers/utime b/src/vfs/fish/helpers/utime new file mode 100644 index 0000000..94395b4 --- /dev/null +++ b/src/vfs/fish/helpers/utime @@ -0,0 +1,13 @@ +#UTIME "$FISH_TOUCHATIME_W_NSEC" "$FISH_TOUCHMTIME_W_NSEC" "$FISH_FILENAME" +if TZ=UTC touch -h -m -d "$FISH_TOUCHMTIME_W_NSEC" "/${FISH_FILENAME}" 2>/dev/null && \ + TZ=UTC touch -h -a -d "$FISH_TOUCHATIME_W_NSEC" "/${FISH_FILENAME}" 2>/dev/null; then + echo "### 000" +elif TZ=UTC touch -h -m -t $FISH_TOUCHMTIME "/${FISH_FILENAME}" 2>/dev/null && \ + TZ=UTC touch -h -a -t $FISH_TOUCHATIME "/${FISH_FILENAME}" 2>/dev/null; then + echo "### 000" +elif [ -n "$FISH_HAVE_PERL" ] && + perl -e 'utime '$FISH_FILEATIME','$FISH_FILEMTIME',@ARGV;' "/${FISH_FILENAME}" 2>/dev/null; then + echo "### 000" +else + echo "### 500" +fi |