1998-09-13 14:40:43 +04:00
/* Virtual File System: FISH implementation for transfering files over
shell connections .
2007-09-25 19:33:35 +04:00
Copyright ( C ) 1998 , 1999 , 2000 , 2001 , 2002 , 2003 , 2004 , 2005 , 2006 ,
2007 Free Software Foundation , Inc .
1998-09-13 14:40:43 +04:00
Written by : 1998 Pavel Machek
2000-03-29 17:36:54 +04:00
Spaces fix : 2000 Michal Svec
1998-09-13 14:40:43 +04:00
Derived from ftpfs . c .
1998-09-27 23:27:58 +04:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU Library General Public License
as published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
1998-09-13 14:40:43 +04:00
This program 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
1998-09-27 23:27:58 +04:00
GNU Library General Public License for more details .
1998-09-13 14:40:43 +04:00
1998-09-27 23:27:58 +04:00
You should have received a copy of the GNU Library General Public
License along with this program ; if not , write to the Free Software
2005-05-27 07:35:10 +04:00
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA . */
1998-09-13 14:40:43 +04:00
/*
* Read README . fish for protocol specification .
*
* Syntax of path is : / # sh : user @ host [ : Cr ] / path
* where C means you want compressed connection ,
* and r means you want to use rsh
1998-10-13 02:07:53 +04:00
*
* Namespace : fish_vfs_ops exported .
1998-09-13 14:40:43 +04:00
*/
1998-11-21 22:36:01 +03:00
/* Define this if your ssh can take -I option */
2001-06-26 01:34:46 +04:00
# include <config.h>
2003-10-16 12:47:33 +04:00
# include <errno.h>
2001-06-26 01:34:46 +04:00
2005-02-19 19:36:38 +03:00
# include "../src/global.h"
# include "../src/tty.h" /* enable/disable interrupt key */
# include "../src/wtools.h" /* message() */
# include "../src/main.h" /* print_vfs_message */
1999-01-21 01:01:11 +03:00
# include "utilvfs.h"
1998-11-21 22:36:01 +03:00
# include "xdirentry.h"
1998-09-13 14:40:43 +04:00
# include "vfs.h"
2004-08-17 03:18:42 +04:00
# include "vfs-impl.h"
2003-11-13 11:03:03 +03:00
# include "gc.h" /* vfs_stamp_create */
1998-09-13 14:40:43 +04:00
# include "tcputil.h"
2005-01-28 02:32:13 +03:00
# include "../src/unixcompat.h"
2006-02-23 18:32:18 +03:00
# include "fish.h"
2009-01-24 12:44:46 +03:00
# include "../mhl/memory.h"
# include "../mhl/escape.h"
2003-10-11 03:38:03 +04:00
2006-02-23 18:32:18 +03:00
int fish_directory_timeout = 900 ;
2003-10-11 03:38:03 +04:00
# 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
1998-10-23 12:26:25 +04:00
1998-09-13 14:40:43 +04:00
/*
* 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
static char reply_str [ 80 ] ;
2003-10-11 03:38:03 +04:00
static struct vfs_class vfs_fish_ops ;
2001-10-20 07:41:31 +04:00
static int
2003-10-28 03:57:02 +03:00
fish_command ( struct vfs_class * me , struct vfs_s_super * super ,
int wait_reply , const char * fmt , . . . )
2006-02-03 17:45:44 +03:00
__attribute__ ( ( format ( __printf__ , 4 , 5 ) ) ) ;
2001-10-20 07:41:31 +04:00
2003-10-28 03:57:02 +03:00
static int fish_decode_reply ( char * s , int was_garbage )
1998-09-13 14:40:43 +04:00
{
1998-11-21 22:36:01 +03:00
int code ;
1998-09-13 14:40:43 +04:00
if ( ! sscanf ( s , " %d " , & code ) ) {
code = 500 ;
return 5 ;
}
if ( code < 100 ) return was_garbage ? ERROR : ( ! code ? COMPLETE : PRELIM ) ;
return code / 100 ;
}
/* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
2003-10-28 03:57:02 +03:00
static int fish_get_reply ( struct vfs_class * me , int sock , char * string_buf , int string_len )
1998-09-13 14:40:43 +04:00
{
char answer [ 1024 ] ;
int was_garbage = 0 ;
for ( ; ; ) {
1998-11-21 22:36:01 +03:00
if ( ! vfs_s_get_line ( me , sock , answer , sizeof ( answer ) , ' \n ' ) ) {
1998-09-13 14:40:43 +04:00
if ( string_buf )
* string_buf = 0 ;
return 4 ;
}
2004-09-01 22:39:48 +04:00
1998-09-13 14:40:43 +04:00
if ( strncmp ( answer , " ### " , 4 ) ) {
was_garbage = 1 ;
2004-09-01 22:39:48 +04:00
if ( string_buf )
g_strlcpy ( string_buf , answer , string_len ) ;
2003-10-28 03:57:02 +03:00
} else return fish_decode_reply ( answer + 4 , was_garbage ) ;
1998-09-13 14:40:43 +04:00
}
}
1998-11-21 22:36:01 +03:00
# define SUP super->u.fish
1998-09-13 14:40:43 +04:00
2001-10-20 07:41:31 +04:00
static int
2003-10-28 03:57:02 +03:00
fish_command ( struct vfs_class * me , struct vfs_s_super * super ,
int wait_reply , const char * fmt , . . . )
1998-09-13 14:40:43 +04:00
{
va_list ap ;
1998-10-30 20:45:43 +03:00
char * str ;
1999-01-11 03:48:23 +03:00
int status ;
1998-11-21 22:36:01 +03:00
FILE * logfile = MEDATA - > logfile ;
1998-10-30 20:45:43 +03:00
1998-09-13 14:40:43 +04:00
va_start ( ap , fmt ) ;
1998-11-21 22:36:01 +03:00
1998-10-30 20:45:43 +03:00
str = g_strdup_vprintf ( fmt , ap ) ;
1998-09-13 14:40:43 +04:00
va_end ( ap ) ;
1998-11-21 22:36:01 +03:00
2003-10-28 03:57:02 +03:00
if ( logfile ) {
fwrite ( str , strlen ( str ) , 1 , logfile ) ;
1998-09-13 14:40:43 +04:00
fflush ( logfile ) ;
}
2003-10-28 03:57:02 +03:00
enable_interrupt_key ( ) ;
1998-11-21 22:36:01 +03:00
2003-10-28 03:57:02 +03:00
status = write ( SUP . sockw , str , strlen ( str ) ) ;
1998-10-30 20:45:43 +03:00
g_free ( str ) ;
1998-11-21 22:36:01 +03:00
2003-10-28 03:57:02 +03:00
disable_interrupt_key ( ) ;
1998-11-21 22:36:01 +03:00
if ( status < 0 )
return TRANSIENT ;
2003-10-28 03:57:02 +03:00
1998-09-13 14:40:43 +04:00
if ( wait_reply )
2003-10-28 03:57:02 +03:00
return fish_get_reply ( me , SUP . sockr ,
( wait_reply & WANT_STRING ) ? reply_str :
NULL , sizeof ( reply_str ) - 1 ) ;
1998-09-13 14:40:43 +04:00
return COMPLETE ;
}
static void
2003-10-28 03:57:02 +03:00
fish_free_archive ( struct vfs_class * me , struct vfs_s_super * super )
1998-09-13 14:40:43 +04:00
{
2003-10-28 03:57:02 +03:00
if ( ( SUP . sockw ! = - 1 ) | | ( SUP . sockr ! = - 1 ) ) {
print_vfs_message ( _ ( " fish: Disconnecting from %s " ) ,
super - > name ? super - > name : " ??? " ) ;
fish_command ( me , super , NONE , " #BYE \n exit \n " ) ;
close ( SUP . sockw ) ;
close ( SUP . sockr ) ;
1998-11-21 22:36:01 +03:00
SUP . sockw = SUP . sockr = - 1 ;
1998-09-13 14:40:43 +04:00
}
2002-07-19 20:04:27 +04:00
g_free ( SUP . host ) ;
g_free ( SUP . user ) ;
g_free ( SUP . cwdir ) ;
g_free ( SUP . password ) ;
1998-09-13 14:40:43 +04:00
}
static void
2004-08-17 15:14:51 +04:00
fish_pipeopen ( struct vfs_s_super * super , const char * path , const char * argv [ ] )
1998-09-13 14:40:43 +04:00
{
int fileset1 [ 2 ] , fileset2 [ 2 ] ;
int res ;
1998-11-21 22:36:01 +03:00
if ( ( pipe ( fileset1 ) < 0 ) | | ( pipe ( fileset2 ) < 0 ) )
2002-12-08 04:12:18 +03:00
vfs_die ( " Cannot pipe(): %m. " ) ;
1998-09-13 14:40:43 +04:00
1998-09-27 23:27:58 +04:00
if ( ( res = fork ( ) ) ) {
2002-12-08 04:12:18 +03:00
if ( res < 0 ) vfs_die ( " Cannot fork(): %m. " ) ;
1998-09-13 14:40:43 +04:00
/* We are the parent */
close ( fileset1 [ 0 ] ) ;
1998-11-21 22:36:01 +03:00
SUP . sockw = fileset1 [ 1 ] ;
1998-09-13 14:40:43 +04:00
close ( fileset2 [ 1 ] ) ;
1998-11-21 22:36:01 +03:00
SUP . sockr = fileset2 [ 0 ] ;
1998-09-13 14:40:43 +04:00
} else {
close ( 0 ) ;
dup ( fileset1 [ 0 ] ) ;
close ( fileset1 [ 0 ] ) ; close ( fileset1 [ 1 ] ) ;
close ( 1 ) ; close ( 2 ) ;
dup ( fileset2 [ 1 ] ) ;
2001-05-23 00:24:53 +04:00
/* stderr to /dev/null */
open ( " /dev/null " , O_WRONLY ) ;
1998-09-13 14:40:43 +04:00
close ( fileset2 [ 0 ] ) ; close ( fileset2 [ 1 ] ) ;
2004-08-17 15:14:51 +04:00
execvp ( path , const_cast ( char * * , argv ) ) ;
2002-08-20 04:14:33 +04:00
_exit ( 3 ) ;
1998-09-13 14:40:43 +04:00
}
}
1998-11-21 22:36:01 +03:00
/* The returned directory should always contain a trailing slash */
2003-10-12 05:00:44 +04:00
static char * fish_getcwd ( struct vfs_class * me , struct vfs_s_super * super )
1998-11-21 22:36:01 +03:00
{
2003-10-28 03:57:02 +03:00
if ( fish_command ( me , super , WANT_STRING , " #PWD \n pwd; echo '### 200' \n " ) = = COMPLETE )
2004-09-24 19:08:21 +04:00
return g_strconcat ( reply_str , " / " , ( char * ) NULL ) ;
1998-11-21 22:36:01 +03:00
ERRNOR ( EIO , NULL ) ;
}
2003-10-28 03:57:02 +03:00
1998-11-21 22:36:01 +03:00
static int
2003-10-28 03:57:02 +03:00
fish_open_archive_int ( struct vfs_class * me , struct vfs_s_super * super )
1998-09-13 14:40:43 +04:00
{
2003-12-06 07:24:56 +03:00
{
2004-08-17 14:26:44 +04:00
const char * argv [ 10 ] ;
const char * xsh = ( SUP . flags = = FISH_FLAG_RSH ? " rsh " : " ssh " ) ;
2003-12-06 07:24:56 +03:00
int i = 0 ;
1998-09-13 14:40:43 +04:00
2003-12-06 07:24:56 +03:00
argv [ i + + ] = xsh ;
if ( SUP . flags = = FISH_FLAG_COMPRESSED )
argv [ i + + ] = " -C " ;
argv [ i + + ] = " -l " ;
argv [ i + + ] = SUP . user ;
argv [ i + + ] = SUP . host ;
argv [ i + + ] = " echo FISH:; /bin/sh " ;
argv [ i + + ] = NULL ;
fish_pipeopen ( super , xsh , argv ) ;
}
1998-09-13 14:40:43 +04:00
{
2003-10-28 03:57:02 +03:00
char answer [ 2048 ] ;
print_vfs_message ( _ ( " fish: Waiting for initial line... " ) ) ;
if ( ! vfs_s_get_line ( me , SUP . sockr , answer , sizeof ( answer ) , ' : ' ) )
1998-11-21 22:36:01 +03:00
ERRNOR ( E_PROTO , - 1 ) ;
2004-10-28 15:24:43 +04:00
print_vfs_message ( " %s " , answer ) ;
2003-10-28 03:57:02 +03:00
if ( strstr ( answer , " assword " ) ) {
1998-09-13 14:40:43 +04:00
2003-10-28 03:57:02 +03:00
/* Currently, this does not work. ssh reads passwords from
/ dev / tty , not from stdin : - ( . */
1998-09-13 14:40:43 +04:00
2003-10-28 03:57:02 +03:00
message ( 1 , MSG_ERROR ,
_
( " Sorry, we cannot do password authenticated connections for now. " ) ) ;
1998-11-21 22:36:01 +03:00
ERRNOR ( EPERM , - 1 ) ;
2003-10-28 03:57:02 +03:00
if ( ! SUP . password ) {
1998-11-21 22:36:01 +03:00
char * p , * op ;
2003-10-28 03:57:02 +03:00
p = g_strconcat ( _ ( " fish: Password required for " ) ,
2004-09-24 19:08:21 +04:00
SUP . user , " " , ( char * ) NULL ) ;
1998-09-13 14:40:43 +04:00
op = vfs_get_password ( p ) ;
1999-01-21 01:01:11 +03:00
g_free ( p ) ;
1998-09-13 14:40:43 +04:00
if ( op = = NULL )
1998-11-21 22:36:01 +03:00
ERRNOR ( EPERM , - 1 ) ;
2004-10-28 15:24:43 +04:00
SUP . password = op ;
1998-09-13 14:40:43 +04:00
}
2003-10-28 03:57:02 +03:00
print_vfs_message ( _ ( " fish: Sending password... " ) ) ;
write ( SUP . sockw , SUP . password , strlen ( SUP . password ) ) ;
write ( SUP . sockw , " \n " , 1 ) ;
1998-09-13 14:40:43 +04:00
}
}
2003-10-28 03:57:02 +03:00
print_vfs_message ( _ ( " fish: Sending initial line... " ) ) ;
2001-04-17 23:48:03 +04:00
/*
* Run ` start_fish_server ' . If it doesn ' t exist - no problem ,
* we ' ll talk directly to the shell .
*/
2003-10-28 03:57:02 +03:00
if ( fish_command
( me , super , WAIT_REPLY ,
2003-12-06 07:05:35 +03:00
" #FISH \n echo; start_fish_server 2>&1; echo '### 200' \n " ) ! =
2003-10-28 03:57:02 +03:00
COMPLETE )
ERRNOR ( E_PROTO , - 1 ) ;
print_vfs_message ( _ ( " fish: Handshaking version... " ) ) ;
if ( fish_command
( me , super , WAIT_REPLY ,
" #VER 0.0.0 \n echo '### 000' \n " ) ! = COMPLETE )
ERRNOR ( E_PROTO , - 1 ) ;
1998-09-13 14:40:43 +04:00
2002-07-14 20:27:15 +04:00
/* Set up remote locale to C, otherwise dates cannot be recognized */
2003-10-28 03:57:02 +03:00
if ( fish_command
( me , super , WAIT_REPLY ,
" LANG=C; LC_ALL=C; LC_TIME=C \n "
" export LANG; export LC_ALL; export LC_TIME \n " " echo '### 200' \n " )
! = COMPLETE )
ERRNOR ( E_PROTO , - 1 ) ;
print_vfs_message ( _ ( " fish: Setting up current directory... " ) ) ;
2002-07-19 20:36:32 +04:00
SUP . cwdir = fish_getcwd ( me , super ) ;
2003-10-28 03:57:02 +03:00
print_vfs_message ( _ ( " fish: Connected, home %s. " ) , SUP . cwdir ) ;
1998-11-21 22:36:01 +03:00
#if 0
2003-10-28 03:57:02 +03:00
super - > name =
2004-09-24 19:08:21 +04:00
g_strconcat ( " /#sh: " , SUP . user , " @ " , SUP . host , " / " , ( char * ) NULL ) ;
1998-11-21 22:36:01 +03:00
# endif
2003-10-28 03:57:02 +03:00
super - > name = g_strdup ( PATH_SEP_STR ) ;
1998-11-21 22:36:01 +03:00
2003-10-28 03:57:02 +03:00
super - > root =
vfs_s_new_inode ( me , super ,
vfs_s_default_stat ( me , S_IFDIR | 0755 ) ) ;
1998-11-21 22:36:01 +03:00
return 0 ;
1998-09-13 14:40:43 +04:00
}
1999-11-11 17:23:40 +03:00
static int
2003-10-28 05:10:33 +03:00
fish_open_archive ( struct vfs_class * me , struct vfs_s_super * super ,
const char * archive_name , char * op )
1998-09-13 14:40:43 +04:00
{
2000-04-10 16:00:43 +04:00
char * host , * user , * password , * p ;
1998-11-21 22:36:01 +03:00
int flags ;
2005-02-22 21:35:22 +03:00
( void ) archive_name ;
2003-10-28 05:10:33 +03:00
p = vfs_split_url ( strchr ( op , ' : ' ) + 1 , & host , & user , & flags ,
& password , 0 , URL_NOSLASH ) ;
2000-04-10 16:00:43 +04:00
2004-09-25 03:00:18 +04:00
g_free ( p ) ;
2000-04-10 16:00:43 +04:00
SUP . host = host ;
SUP . user = user ;
1998-11-21 22:36:01 +03:00
SUP . flags = flags ;
2003-10-28 05:10:33 +03:00
if ( ! strncmp ( op , " rsh: " , 4 ) )
1998-11-21 22:36:01 +03:00
SUP . flags | = FISH_FLAG_RSH ;
2002-07-19 20:36:32 +04:00
SUP . cwdir = NULL ;
1998-11-21 22:36:01 +03:00
if ( password )
2000-04-10 16:00:43 +04:00
SUP . password = password ;
2003-10-28 03:57:02 +03:00
return fish_open_archive_int ( me , super ) ;
1998-09-13 14:40:43 +04:00
}
1998-11-21 22:36:01 +03:00
static int
2003-10-28 05:10:33 +03:00
fish_archive_same ( struct vfs_class * me , struct vfs_s_super * super ,
const char * archive_name , char * op , void * cookie )
{
2000-04-10 16:00:43 +04:00
char * host , * user ;
1998-11-21 22:36:01 +03:00
int flags ;
2000-04-10 16:00:43 +04:00
2005-02-22 21:35:22 +03:00
( void ) me ;
( void ) archive_name ;
( void ) cookie ;
2003-10-28 05:10:33 +03:00
op = vfs_split_url ( strchr ( op , ' : ' ) + 1 , & host , & user , & flags , 0 , 0 ,
URL_NOSLASH ) ;
2000-04-10 16:00:43 +04:00
2004-09-25 03:00:18 +04:00
g_free ( op ) ;
2000-04-10 16:00:43 +04:00
2003-10-28 05:10:33 +03:00
flags = ( ( strcmp ( host , SUP . host ) = = 0 )
& & ( strcmp ( user , SUP . user ) = = 0 ) & & ( flags = = SUP . flags ) ) ;
2000-04-10 16:00:43 +04:00
g_free ( host ) ;
g_free ( user ) ;
return flags ;
1998-09-13 14:40:43 +04:00
}
1998-11-21 22:36:01 +03:00
static int
2003-10-28 03:57:02 +03:00
fish_dir_load ( struct vfs_class * me , struct vfs_s_inode * dir , char * remote_path )
1998-09-13 14:40:43 +04:00
{
2003-10-12 05:00:44 +04:00
struct vfs_s_super * super = dir - > super ;
1998-09-13 14:40:43 +04:00
char buffer [ 8192 ] ;
2003-10-12 05:00:44 +04:00
struct vfs_s_entry * ent = NULL ;
1998-11-21 22:36:01 +03:00
FILE * logfile ;
2002-11-01 19:55:02 +03:00
char * quoted_path ;
2007-11-02 17:50:41 +03:00
int reply_code ;
2009-01-07 21:17:04 +03:00
1998-11-21 22:36:01 +03:00
logfile = MEDATA - > logfile ;
1998-09-13 14:40:43 +04:00
1999-08-16 09:31:23 +04:00
print_vfs_message ( _ ( " fish: Reading directory %s... " ) , remote_path ) ;
1998-11-21 22:36:01 +03:00
2003-10-16 09:47:23 +04:00
gettimeofday ( & dir - > timestamp , NULL ) ;
2006-02-23 18:32:18 +03:00
dir - > timestamp . tv_sec + = fish_directory_timeout ;
2002-11-01 19:55:02 +03:00
quoted_path = name_quote ( remote_path , 0 ) ;
2003-10-28 03:57:02 +03:00
fish_command ( me , super , NONE ,
2009-01-23 23:00:30 +03:00
" #LIST \" /%s \" \n "
2009-01-23 01:26:57 +03:00
" if `perl -v > /dev/null 2>&1` ; then \n "
" perl -e \" \n "
" use strict; \n "
" use POSIX; \n "
" use Fcntl; \n "
" use POSIX ':fcntl_h'; #S_ISLNK was here until 5.6 \n "
" import Fcntl ':mode' unless defined &S_ISLNK; #and is now here \n "
2009-01-25 01:29:20 +03:00
" my \\ \ $dirname = \\ \" /%s \\ \" ; \n "
" if (opendir ( DIR, \\ \ $dirname )) { \n "
" while( (my \\ \ $filename = readdir(DIR))){ \n "
" my ( \\ \ $dev, \\ \ $ino, \\ \ $mode, \\ \ $nlink, \\ \ $uid, \\ \ $gid, \\ \ $rdev, \\ \ $size, \\ \ $atime, \\ \ $mtime, \\ \ $ctime, \\ \ $blksize, \\ \ $blocks) = lstat( \\ \" \\ \ $dirname/ \\ \ $filename \\ \" ); \n "
" my \\ \ $mloctime= scalar localtime \\ \ $mtime; \n "
" if (S_ISLNK( \\ \ $mode) ) { \n "
" my \\ \ $linkname = readlink ( \\ \" \\ \ $dirname/ \\ \ $filename \\ \" ); \n "
" printf( \\ \" P \\ \ $mode \\ \ $uid. \\ \ $gid \n S \\ \ $size \n d \\ \ $mloctime \n : \\ \\ \" \\ \ $filename \\ \\ \" -> \\ \\ \" \\ \ $linkname \\ \\ \" \n \n \\ \" ); \n "
2009-01-23 01:26:57 +03:00
" } else { \n "
2009-01-25 01:29:20 +03:00
" printf( \\ \" P \\ \ $mode \\ \ $uid. \\ \ $gid \n S \\ \ $size \n d \\ \ $mloctime \n : \\ \\ \" \\ \ $filename \\ \\ \" \n \n \\ \" ); \n "
2009-01-23 01:26:57 +03:00
" }} \n "
2009-01-25 01:29:20 +03:00
" printf( \\ \" ###200 \n \\ \" ); \n "
" closedir(DIR); \n "
" } else { \n "
" printf( \\ \" ###500 \n \\ \" ); \n "
" } \" \n "
2009-01-23 23:00:30 +03:00
" elif `ls -1 \" /%s \" >/dev/null 2>&1` ; then \n "
" if `ls -Q \" /%s \" >/dev/null 2>&1`; then \n "
2009-01-23 01:26:57 +03:00
" LSOPT= \" -Qlan \" ; \n "
" ADD=0; \n "
" else \n "
" LSOPT= \" -lan \" ; \n "
" ADD=1; \n "
" fi \n "
2009-01-23 23:00:30 +03:00
" ls $LSOPT \" /%s \" 2>/dev/null | grep '^[^cbt]' | ( \n "
2009-01-23 01:26:57 +03:00
" while read p l u g s m d y n; do \n "
" if [ $ADD = 0 ]; then \n "
" echo \" P$p $u.$g \n S$s \n d$m $d $y \n :$n \n \" \n "
" elif `sed --version >/dev/null 2>&1` ; then \n "
2009-01-24 12:44:46 +03:00
" file=`echo $n | sed -e 's#^ \\ (.* \\ ) -> \\ (.* \\ )# \1 \" -> \" \2 #'` \n "
2009-01-23 01:26:57 +03:00
" echo \" P$p $u $g \n S$s \n d$m $d $y \n : \" $file \" \n \" \n "
" else \n "
" echo \" P$p $u $g \n S$s \n d$m $d $y \n : \" $n \" \n \" \n "
" fi \n "
" done ) \n "
2009-01-23 23:00:30 +03:00
" ls $LSOPT \" /%s \" 2>/dev/null | grep '^[cb]' | ( \n "
2009-01-23 01:26:57 +03:00
" while read p l u g a i m d y n; do \n "
" if [ $ADD = 0 ]; then \n "
" echo \" P$p $u.$g \n E$a$i \n d$m $d $y \n :$n \n \" \n "
" elif `sed --version >/dev/null 2>&1` ; then \n "
2009-01-24 12:44:46 +03:00
" file=`echo $n | sed -e 's#^ \\ (.* \\ ) -> \\ (.* \\ )# \1 \" -> \" \2 #'` \n "
2009-01-23 01:26:57 +03:00
" echo \" P$p $u $g \n S$s \n d$m $d $y \n : \" $file \" \n \" \n "
" else \n "
" echo \" P$p $u $g \n S$s \n d$m $d $y \n : \" $n \" \n \" \n "
" fi \n "
" done) \n "
" echo '### 200' \n "
" else \n "
" echo '### 500' \n "
" fi \n " ,
2009-01-23 23:00:30 +03:00
remote_path , quoted_path , quoted_path , quoted_path , quoted_path , quoted_path ) ;
2002-11-01 19:55:02 +03:00
g_free ( quoted_path ) ;
2003-10-28 03:57:02 +03:00
ent = vfs_s_generate_entry ( me , NULL , dir , 0 ) ;
1998-11-21 22:36:01 +03:00
while ( 1 ) {
int res = vfs_s_get_line_interruptible ( me , buffer , sizeof ( buffer ) , SUP . sockr ) ;
if ( ( ! res ) | | ( res = = EINTR ) ) {
vfs_s_free_entry ( me , ent ) ;
me - > verrno = ECONNRESET ;
goto error ;
}
1999-11-11 17:23:40 +03:00
if ( logfile ) {
1998-09-13 14:40:43 +04:00
fputs ( buffer , logfile ) ;
fputs ( " \n " , logfile ) ;
fflush ( logfile ) ;
}
if ( ! strncmp ( buffer , " ### " , 4 ) )
break ;
1998-11-21 22:36:01 +03:00
if ( ( ! buffer [ 0 ] ) ) {
if ( ent - > name ) {
vfs_s_insert_entry ( me , dir , ent ) ;
2003-10-28 03:57:02 +03:00
ent = vfs_s_generate_entry ( me , NULL , dir , 0 ) ;
1998-09-13 14:40:43 +04:00
}
continue ;
}
1998-11-21 22:36:01 +03:00
# define ST ent->ino->st
1998-09-13 14:40:43 +04:00
switch ( buffer [ 0 ] ) {
1998-11-21 22:36:01 +03:00
case ' : ' : {
2009-01-06 17:29:39 +03:00
char * copy_buffer = buffer + 1 ;
char * filename = buffer + 1 ;
char * linkname = buffer + 1 ;
if ( ! strcmp ( buffer + 1 , " . " ) | | ! strcmp ( buffer + 1 , " .. " ) )
break ; /* We'll do . and .. ourself */
2009-01-07 21:17:04 +03:00
if ( S_ISLNK ( ST . st_mode ) ) {
2009-01-06 17:29:39 +03:00
while ( * copy_buffer ) {
if ( strncmp ( copy_buffer , " -> " , 4 ) = = 0 )
filename = copy_buffer ;
copy_buffer + + ;
}
int f_size = filename - linkname ;
2009-01-07 21:17:04 +03:00
ent - > name = malloc ( f_size + 1 ) ;
2009-01-06 17:29:39 +03:00
strncpy ( ent - > name , linkname , f_size ) ;
ent - > name [ f_size ] = ' \0 ' ;
2009-01-07 21:17:04 +03:00
ent - > ino - > linkname = strdup ( filename + 4 ) ;
2009-01-06 17:41:31 +03:00
} else {
ent - > name = g_strdup ( buffer + 1 ) ;
}
break ;
2009-01-06 17:29:39 +03:00
}
2004-08-30 22:36:58 +04:00
case ' S ' :
# ifdef HAVE_ATOLL
ST . st_size = ( off_t ) atoll ( buffer + 1 ) ;
# else
ST . st_size = ( off_t ) atof ( buffer + 1 ) ;
# endif
break ;
1998-09-13 14:40:43 +04:00
case ' P ' : {
2005-09-26 15:10:24 +04:00
size_t skipped ;
2009-01-06 17:29:39 +03:00
vfs_parse_filemode ( buffer + 1 , & skipped , & ST . st_mode ) ;
2005-09-26 15:10:24 +04:00
break ;
}
1998-09-13 14:40:43 +04:00
case ' d ' : {
1998-10-13 02:07:53 +04:00
vfs_split_text ( buffer + 1 ) ;
1998-11-21 22:36:01 +03:00
if ( ! vfs_parse_filedate ( 0 , & ST . st_ctime ) )
1998-09-13 14:40:43 +04:00
break ;
1998-11-21 22:36:01 +03:00
ST . st_atime = ST . st_mtime = ST . st_ctime ;
1998-09-13 14:40:43 +04:00
}
break ;
case ' D ' : {
struct tm tim ;
if ( sscanf ( buffer + 1 , " %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 ;
1998-11-21 22:36:01 +03:00
ST . st_atime = ST . st_mtime = ST . st_ctime = mktime ( & tim ) ;
1998-09-13 14:40:43 +04:00
}
break ;
case ' E ' : {
int maj , min ;
if ( sscanf ( buffer + 1 , " %d,%d " , & maj , & min ) ! = 2 )
break ;
2003-10-29 20:36:16 +03:00
# ifdef HAVE_STRUCT_STAT_ST_RDEV
2005-01-28 02:32:13 +03:00
ST . st_rdev = makedev ( maj , min ) ;
1998-09-13 14:40:43 +04:00
# endif
}
}
}
1998-11-21 22:36:01 +03:00
vfs_s_free_entry ( me , ent ) ;
2007-11-02 17:50:41 +03:00
reply_code = fish_decode_reply ( buffer + 4 , 0 ) ;
if ( reply_code = = COMPLETE ) {
2002-07-19 20:36:32 +04:00
g_free ( SUP . cwdir ) ;
SUP . cwdir = g_strdup ( remote_path ) ;
2002-07-19 08:29:37 +04:00
print_vfs_message ( _ ( " %s: done. " ) , me - > name ) ;
return 0 ;
2007-11-02 17:50:41 +03:00
} else if ( reply_code = = ERROR ) {
me - > verrno = EACCES ;
} else {
me - > verrno = E_REMOTE ;
2002-07-19 08:29:37 +04:00
}
1998-11-21 22:36:01 +03:00
error :
2002-07-19 08:29:37 +04:00
print_vfs_message ( _ ( " %s: failure " ) , me - > name ) ;
2007-11-02 17:50:41 +03:00
return - 1 ;
1998-09-13 14:40:43 +04:00
}
static int
2003-10-28 03:57:02 +03:00
fish_file_store ( struct vfs_class * me , struct vfs_s_fh * fh , char * name , char * localname )
1998-09-13 14:40:43 +04:00
{
2003-10-12 05:00:44 +04:00
struct vfs_s_super * super = FH_SUPER ;
1998-11-21 22:36:01 +03:00
int n , total ;
1998-09-13 14:40:43 +04:00
char buffer [ 8192 ] ;
struct stat s ;
int was_error = 0 ;
1998-11-21 22:36:01 +03:00
int h ;
2002-11-01 19:55:02 +03:00
char * quoted_name ;
1998-09-13 14:40:43 +04:00
2002-11-01 19:55:02 +03:00
h = open ( localname , O_RDONLY ) ;
1998-09-13 14:40:43 +04:00
2002-11-01 19:55:02 +03:00
if ( h = = - 1 )
1998-11-21 22:36:01 +03:00
ERRNOR ( EIO , - 1 ) ;
2002-11-01 19:55:02 +03:00
if ( fstat ( h , & s ) < 0 ) {
close ( h ) ;
ERRNOR ( EIO , - 1 ) ;
}
2006-03-30 18:39:33 +04:00
/* 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 .
2006-03-31 18:29:37 +04:00
*
* 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 .
2006-03-30 18:39:33 +04:00
*/
1998-09-13 14:40:43 +04:00
2009-01-23 23:00:30 +03:00
name = mhl_shell_escape_dup ( name ) ;
1999-08-16 09:31:23 +04:00
print_vfs_message ( _ ( " fish: store %s: sending command... " ) , name ) ;
2009-01-23 23:00:30 +03:00
quoted_name = mhl_shell_escape_dup ( name_quote ( name , 0 ) ) ;
2003-05-08 10:04:04 +04:00
/* FIXME: File size is limited to ULONG_MAX */
2002-07-26 05:33:40 +04:00
if ( ! fh - > u . fish . append )
2003-10-28 03:57:02 +03:00
n = fish_command ( me , super , WAIT_REPLY ,
2009-01-23 23:00:30 +03:00
" #STOR %lu \" /%s \" \n "
2000-03-29 17:36:54 +04:00
" echo '### 001' \n "
2009-01-23 23:00:30 +03:00
" file= \" /%s \" \n "
2006-03-30 18:39:33 +04:00
" res=`exec 3>&1 \n "
2000-03-29 17:36:54 +04:00
" ( \n "
2006-03-30 18:39:33 +04:00
" head -c %lu -q - || echo DD >&3 \n "
2000-03-29 17:36:54 +04:00
" ) 2>/dev/null | ( \n "
2006-11-09 20:59:39 +03:00
" cat > \" $file \" \n "
2000-03-29 17:36:54 +04:00
" cat > /dev/null \n "
2006-03-30 18:39:33 +04:00
" )`; [ \" $res \" = DD ] && { \n "
2006-11-09 20:59:39 +03:00
" > \" $file \" \n "
2006-03-30 18:39:33 +04:00
" rest=%lu \n "
" while [ $rest -gt 0 ] \n "
" do \n "
" cnt=`expr \\ ( $rest + 255 \\ ) / 256` \n "
2006-11-09 20:59:39 +03:00
" n=`dd bs=256 count=$cnt | tee -a \" $file \" | wc -c` \n "
2006-03-30 18:39:33 +04:00
" rest=`expr $rest - $n` \n "
" done \n "
" }; echo '### 200' \n " ,
2006-03-31 18:29:37 +04:00
( unsigned long ) s . st_size , name ,
2006-11-09 20:59:39 +03:00
quoted_name , ( unsigned long ) s . st_size ,
( unsigned long ) s . st_size ) ;
2002-07-26 05:33:40 +04:00
else
2003-10-28 03:57:02 +03:00
n = fish_command ( me , super , WAIT_REPLY ,
2009-01-23 23:00:30 +03:00
" #STOR %lu \" /%s \" \n "
2002-07-26 05:33:40 +04:00
" echo '### 001' \n "
2006-03-31 18:29:37 +04:00
" { \n "
2009-01-23 23:00:30 +03:00
" file= \" /%s \" \n "
2006-03-30 18:39:33 +04:00
" rest=%lu \n "
" while [ $rest -gt 0 ] \n "
" do \n "
" cnt=`expr \\ ( $rest + 255 \\ ) / 256` \n "
2006-11-09 20:59:39 +03:00
" n=`dd bs=256 count=$cnt | tee -a \" $file \" | wc -c` \n "
2006-03-30 18:39:33 +04:00
" rest=`expr $rest - $n` \n "
" done \n "
" }; echo '### 200' \n " ,
2002-07-26 05:33:40 +04:00
( unsigned long ) s . st_size , name ,
2006-11-09 20:59:39 +03:00
quoted_name , ( unsigned long ) s . st_size ) ;
2002-07-26 05:33:40 +04:00
2002-11-01 19:55:02 +03:00
g_free ( quoted_name ) ;
if ( n ! = PRELIM ) {
close ( h ) ;
1998-11-21 22:36:01 +03:00
ERRNOR ( E_REMOTE , - 1 ) ;
2002-11-01 19:55:02 +03:00
}
1998-09-13 14:40:43 +04:00
total = 0 ;
while ( 1 ) {
2004-11-29 15:45:42 +03:00
int t ;
1998-11-21 22:36:01 +03:00
while ( ( n = read ( h , buffer , sizeof ( buffer ) ) ) < 0 ) {
2004-09-09 17:26:02 +04:00
if ( ( errno = = EINTR ) & & got_interrupt ( ) )
1998-09-13 14:40:43 +04:00
continue ;
1999-08-16 09:31:23 +04:00
print_vfs_message ( _ ( " fish: Local read failed, sending zeros " ) ) ;
1998-11-21 22:36:01 +03:00
close ( h ) ;
h = open ( " /dev/zero " , O_RDONLY ) ;
1998-09-13 14:40:43 +04:00
}
if ( n = = 0 )
break ;
2004-11-29 15:45:42 +03:00
if ( ( t = write ( SUP . sockw , buffer , n ) ) ! = n ) {
if ( t = = - 1 ) {
2004-11-29 23:15:22 +03:00
me - > verrno = errno ;
2004-11-29 15:45:42 +03:00
} else {
me - > verrno = EIO ;
}
1998-09-13 14:40:43 +04:00
goto error_return ;
}
1998-11-21 22:36:01 +03:00
disable_interrupt_key ( ) ;
1998-09-13 14:40:43 +04:00
total + = n ;
2001-10-20 11:04:31 +04:00
print_vfs_message ( _ ( " fish: storing %s %d (%lu) " ) ,
was_error ? _ ( " zeros " ) : _ ( " file " ) , total ,
( unsigned long ) s . st_size ) ;
1998-09-13 14:40:43 +04:00
}
2002-11-01 19:55:02 +03:00
close ( h ) ;
2009-01-23 23:00:30 +03:00
mhl_mem_free ( quoted_name ) ;
2003-10-28 03:57:02 +03:00
if ( ( fish_get_reply ( me , SUP . sockr , NULL , 0 ) ! = COMPLETE ) | | was_error )
2000-02-23 10:43:14 +03:00
ERRNOR ( E_REMOTE , - 1 ) ;
1998-09-13 14:40:43 +04:00
return 0 ;
1998-11-21 22:36:01 +03:00
error_return :
close ( h ) ;
2003-10-28 03:57:02 +03:00
fish_get_reply ( me , SUP . sockr , NULL , 0 ) ;
2009-01-23 23:00:30 +03:00
mhl_mem_free ( quoted_name ) ;
1998-11-21 22:36:01 +03:00
return - 1 ;
1998-09-13 14:40:43 +04:00
}
2004-10-07 01:20:17 +04:00
static int
fish_linear_start ( struct vfs_class * me , struct vfs_s_fh * fh , off_t offset )
1998-09-21 13:52:07 +04:00
{
1998-11-21 22:36:01 +03:00
char * name ;
2002-11-01 19:55:02 +03:00
char * quoted_name ;
1998-10-13 02:07:53 +04:00
if ( offset )
1998-11-21 22:36:01 +03:00
ERRNOR ( E_NOTSUPP , 0 ) ;
name = vfs_s_fullpath ( me , fh - > ino ) ;
if ( ! name )
return 0 ;
2002-11-01 19:55:02 +03:00
quoted_name = name_quote ( name , 0 ) ;
g_free ( name ) ;
2009-01-24 12:44:46 +03:00
name = mhl_shell_escape_dup ( quoted_name ) ;
2002-07-26 05:33:40 +04:00
fh - > u . fish . append = 0 ;
2007-10-26 17:46:42 +04:00
/*
* 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 ) .
*/
2003-10-28 03:57:02 +03:00
offset = fish_command ( me , FH_SUPER , WANT_STRING ,
2009-01-23 23:00:30 +03:00
" #RETR \" /%s \" \n "
" if dd if= \" /%s \" of=/dev/null bs=1 count=1 2>/dev/null ; \n "
2007-10-26 17:46:42 +04:00
" then \n "
2009-01-23 23:00:30 +03:00
" ls -ln \" /%s \" 2>/dev/null | ( \n "
2005-10-19 15:34:56 +04:00
" read p l u g s r \n "
" echo \" $s \" \n "
2000-03-29 17:36:54 +04:00
" ) \n "
" echo '### 100' \n "
2009-01-23 23:00:30 +03:00
" cat \" /%s \" \n "
2007-10-26 17:46:42 +04:00
" echo '### 200' \n "
" else \n "
" echo '### 500' \n "
" fi \n " ,
name , name , name , name ) ;
2000-04-05 17:08:42 +04:00
g_free ( name ) ;
if ( offset ! = PRELIM ) ERRNOR ( E_REMOTE , 0 ) ;
1998-11-21 22:36:01 +03:00
fh - > linear = LS_LINEAR_OPEN ;
fh - > u . fish . got = 0 ;
2007-10-11 16:32:42 +04:00
errno = 0 ;
# if SIZEOF_OFF_T == SIZEOF_LONG
fh - > u . fish . total = strtol ( reply_str , NULL , 10 ) ;
2007-04-26 19:10:02 +04:00
# else
2007-10-11 16:32:42 +04:00
fh - > u . fish . total = strtoll ( reply_str , NULL , 10 ) ;
2007-04-26 19:10:02 +04:00
# endif
2007-10-11 16:32:42 +04:00
if ( errno ! = 0 )
1998-11-21 22:36:01 +03:00
ERRNOR ( E_REMOTE , 0 ) ;
1998-09-21 13:52:07 +04:00
return 1 ;
}
1998-09-13 14:40:43 +04:00
static void
2003-10-28 03:57:02 +03:00
fish_linear_abort ( struct vfs_class * me , struct vfs_s_fh * fh )
1998-09-13 14:40:43 +04:00
{
2003-10-12 05:00:44 +04:00
struct vfs_s_super * super = FH_SUPER ;
1998-09-21 13:52:07 +04:00
char buffer [ 8192 ] ;
1998-09-13 14:40:43 +04:00
int n ;
1999-08-16 09:31:23 +04:00
print_vfs_message ( _ ( " Aborting transfer... " ) ) ;
1998-09-13 14:40:43 +04:00
do {
1999-01-21 01:01:11 +03:00
n = MIN ( 8192 , fh - > u . fish . total - fh - > u . fish . got ) ;
2004-12-28 15:25:24 +03:00
if ( n ) {
1998-11-21 22:36:01 +03:00
if ( ( n = read ( SUP . sockr , buffer , n ) ) < 0 )
1998-09-13 14:40:43 +04:00
return ;
2004-12-28 15:25:24 +03:00
fh - > u . fish . got + = n ;
}
1998-09-13 14:40:43 +04:00
} while ( n ) ;
2003-10-28 03:57:02 +03:00
if ( fish_get_reply ( me , SUP . sockr , NULL , 0 ) ! = COMPLETE )
1999-08-16 09:31:23 +04:00
print_vfs_message ( _ ( " Error reported after abort. " ) ) ;
1998-09-13 14:40:43 +04:00
else
1999-08-18 02:42:14 +04:00
print_vfs_message ( _ ( " Aborted transfer would be successful. " ) ) ;
1998-09-13 14:40:43 +04:00
}
1998-09-21 13:52:07 +04:00
static int
2003-10-28 03:57:02 +03:00
fish_linear_read ( struct vfs_class * me , struct vfs_s_fh * fh , void * buf , int len )
1998-09-13 14:40:43 +04:00
{
2003-10-12 05:00:44 +04:00
struct vfs_s_super * super = FH_SUPER ;
1998-09-21 13:52:07 +04:00
int n = 0 ;
1999-01-21 01:01:11 +03:00
len = MIN ( fh - > u . fish . total - fh - > u . fish . got , len ) ;
1998-11-21 22:36:01 +03:00
disable_interrupt_key ( ) ;
while ( len & & ( ( n = read ( SUP . sockr , buf , len ) ) < 0 ) ) {
1998-09-21 13:52:07 +04:00
if ( ( errno = = EINTR ) & & ! got_interrupt ( ) )
continue ;
break ;
}
1998-11-21 22:36:01 +03:00
enable_interrupt_key ( ) ;
1998-09-13 14:40:43 +04:00
1998-11-21 22:36:01 +03:00
if ( n > 0 ) fh - > u . fish . got + = n ;
2003-10-28 03:57:02 +03:00
if ( n < 0 ) fish_linear_abort ( me , fh ) ;
if ( ( ! n ) & & ( ( fish_get_reply ( me , SUP . sockr , NULL , 0 ) ! = COMPLETE ) ) )
1998-11-21 22:36:01 +03:00
ERRNOR ( E_REMOTE , - 1 ) ;
1998-09-21 13:52:07 +04:00
ERRNOR ( errno , n ) ;
1998-09-13 14:40:43 +04:00
}
1998-09-27 23:27:58 +04:00
static void
2003-10-28 03:57:02 +03:00
fish_linear_close ( struct vfs_class * me , struct vfs_s_fh * fh )
1998-09-13 14:40:43 +04:00
{
1998-11-21 22:36:01 +03:00
if ( fh - > u . fish . total ! = fh - > u . fish . got )
2003-10-28 03:57:02 +03:00
fish_linear_abort ( me , fh ) ;
1998-09-13 14:40:43 +04:00
}
1998-10-13 02:07:53 +04:00
static int
2003-10-16 20:12:19 +04:00
fish_ctl ( void * fh , int ctlop , void * arg )
1998-09-13 14:40:43 +04:00
{
2005-02-22 21:35:22 +03:00
( void ) arg ;
1998-11-21 22:36:01 +03:00
return 0 ;
2005-06-08 04:31:25 +04:00
#if 0
1998-09-13 14:40:43 +04:00
switch ( ctlop ) {
2003-10-16 20:12:19 +04:00
case VFS_CTL_IS_NOTREADY :
1998-09-21 13:52:07 +04:00
{
1998-10-13 02:07:53 +04:00
int v ;
1998-11-21 22:36:01 +03:00
if ( ! FH - > linear )
1998-10-13 02:07:53 +04:00
vfs_die ( " You may not do this " ) ;
2006-01-25 17:04:27 +03:00
if ( FH - > linear = = LS_LINEAR_CLOSED | | FH - > linear = = LS_LINEAR_PREOPEN )
1998-10-13 02:07:53 +04:00
return 0 ;
1998-11-21 22:36:01 +03:00
v = vfs_s_select_on_two ( FH_SUPER - > u . fish . sockr , 0 ) ;
1998-09-21 13:52:07 +04:00
if ( ( ( v < 0 ) & & ( errno = = EINTR ) ) | | v = = 0 )
return 1 ;
return 0 ;
1998-09-13 14:40:43 +04:00
}
1998-09-21 13:52:07 +04:00
default :
return 0 ;
1998-09-13 14:40:43 +04:00
}
2005-06-08 04:31:25 +04:00
# endif
1998-09-13 14:40:43 +04:00
}
static int
2004-08-17 02:15:28 +04:00
fish_send_command ( struct vfs_class * me , struct vfs_s_super * super , const char * cmd , int flags )
1998-09-13 14:40:43 +04:00
{
int r ;
2003-12-06 07:05:35 +03:00
r = fish_command ( me , super , WAIT_REPLY , " %s " , cmd ) ;
2003-11-27 00:10:42 +03:00
vfs_stamp_create ( & vfs_fish_ops , super ) ;
1998-11-21 22:36:01 +03:00
if ( r ! = COMPLETE ) ERRNOR ( E_REMOTE , - 1 ) ;
if ( flags & OPT_FLUSH )
vfs_s_invalidate ( me , super ) ;
1998-09-13 14:40:43 +04:00
return 0 ;
}
# define PREFIX \
1999-01-21 01:01:11 +03:00
char buf [ BUF_LARGE ] ; \
2005-09-05 04:52:56 +04:00
const char * crpath ; \
2004-11-29 15:45:42 +03:00
char * rpath , * mpath = g_strdup ( path ) ; \
2003-10-12 05:00:44 +04:00
struct vfs_s_super * super ; \
2005-09-05 04:52:56 +04:00
if ( ! ( crpath = vfs_s_get_path_mangle ( me , mpath , & super , 0 ) ) ) { \
2004-11-29 15:45:42 +03:00
g_free ( mpath ) ; \
2002-11-01 19:55:02 +03:00
return - 1 ; \
2004-11-29 15:45:42 +03:00
} \
2009-01-23 23:00:30 +03:00
rpath = mhl_shell_escape_dup ( name_quote ( crpath , 0 ) ) ; \
2004-11-29 15:45:42 +03:00
g_free ( mpath ) ;
1998-09-13 14:40:43 +04:00
# define POSTFIX(flags) \
2002-11-01 19:55:02 +03:00
g_free ( rpath ) ; \
2003-10-28 03:57:02 +03:00
return fish_send_command ( me , super , buf , flags ) ;
1998-09-13 14:40:43 +04:00
1998-10-13 02:07:53 +04:00
static int
2004-08-17 01:36:39 +04:00
fish_chmod ( struct vfs_class * me , const char * path , int mode )
1998-09-13 14:40:43 +04:00
{
PREFIX
2009-01-23 23:00:30 +03:00
g_snprintf ( buf , sizeof ( buf ) , " #CHMOD %4.4o \" /%s \" \n "
2001-05-27 10:46:34 +04:00
" chmod %4.4o \" /%s \" 2>/dev/null \n "
" echo '### 000' \n " ,
1998-11-21 22:36:01 +03:00
mode & 07777 , rpath ,
mode & 07777 , rpath ) ;
1998-09-13 14:40:43 +04:00
POSTFIX ( OPT_FLUSH ) ;
}
2007-10-29 16:31:44 +03:00
# define FISH_OP(name, string) \
2004-08-17 02:15:28 +04:00
static int fish_ # # name ( struct vfs_class * me , const char * path1 , const char * path2 ) \
1998-09-13 14:40:43 +04:00
{ \
1999-01-21 01:01:11 +03:00
char buf [ BUF_LARGE ] ; \
2005-09-05 04:52:56 +04:00
const char * crpath1 , * crpath2 ; \
2004-08-17 02:15:28 +04:00
char * rpath1 , * rpath2 , * mpath1 , * mpath2 ; \
2003-10-12 05:00:44 +04:00
struct vfs_s_super * super1 , * super2 ; \
2005-09-05 04:52:56 +04:00
if ( ! ( crpath1 = vfs_s_get_path_mangle ( me , mpath1 = g_strdup ( path1 ) , & super1 , 0 ) ) ) { \
2004-11-29 15:45:42 +03:00
g_free ( mpath1 ) ; \
1998-09-13 14:40:43 +04:00
return - 1 ; \
2004-11-29 15:45:42 +03:00
} \
2005-09-05 04:52:56 +04:00
if ( ! ( crpath2 = vfs_s_get_path_mangle ( me , mpath2 = g_strdup ( path2 ) , & super2 , 0 ) ) ) { \
2004-11-29 15:45:42 +03:00
g_free ( mpath1 ) ; \
g_free ( mpath2 ) ; \
1998-09-13 14:40:43 +04:00
return - 1 ; \
2004-11-29 15:45:42 +03:00
} \
2005-09-05 04:52:56 +04:00
rpath1 = name_quote ( crpath1 , 0 ) ; \
2004-11-29 15:45:42 +03:00
g_free ( mpath1 ) ; \
2005-09-05 04:52:56 +04:00
rpath2 = name_quote ( crpath2 , 0 ) ; \
2004-11-29 15:45:42 +03:00
g_free ( mpath2 ) ; \
2002-11-01 19:55:02 +03:00
g_snprintf ( buf , sizeof ( buf ) , string " \n " , rpath1 , rpath2 , rpath1 , rpath2 ) ; \
g_free ( rpath1 ) ; \
g_free ( rpath2 ) ; \
2003-10-28 03:57:02 +03:00
return fish_send_command ( me , super2 , buf , OPT_FLUSH ) ; \
1998-09-13 14:40:43 +04:00
}
2009-01-23 23:00:30 +03:00
FISH_OP ( rename , " #RENAME \" /%s \" \" /%s \" \n "
" mv \" /%s \" \" /%s \" 2>/dev/null \n "
2007-10-29 16:31:44 +03:00
" echo '### 000' " )
2009-01-23 23:00:30 +03:00
FISH_OP ( link , " #LINK \" /%s \" \" /%s \" \n "
" ln \" /%s \" \" /%s \" 2>/dev/null \n "
2007-10-29 16:31:44 +03:00
" echo '### 000' " )
1998-11-21 22:36:01 +03:00
2004-08-17 02:15:28 +04:00
static int fish_symlink ( struct vfs_class * me , const char * setto , const char * path )
1998-11-21 22:36:01 +03:00
{
2004-08-17 02:15:28 +04:00
char * qsetto ;
1998-11-21 22:36:01 +03:00
PREFIX
2004-08-17 02:15:28 +04:00
qsetto = name_quote ( setto , 0 ) ;
2000-03-29 17:36:54 +04:00
g_snprintf ( buf , sizeof ( buf ) ,
2009-01-23 23:00:30 +03:00
" #SYMLINK \" %s \" \" /%s \" \n "
" ln -s \" %s \" \" /%s \" 2>/dev/null \n "
2000-03-29 17:36:54 +04:00
" echo '### 000' \n " ,
2004-08-17 02:15:28 +04:00
qsetto , rpath , qsetto , rpath ) ;
g_free ( qsetto ) ;
1998-11-21 22:36:01 +03:00
POSTFIX ( OPT_FLUSH ) ;
}
1998-09-13 14:40:43 +04:00
1998-10-13 02:07:53 +04:00
static int
2004-08-17 01:36:39 +04:00
fish_chown ( struct vfs_class * me , const char * path , int owner , int group )
1998-09-13 14:40:43 +04:00
{
char * sowner , * sgroup ;
2001-07-09 20:15:33 +04:00
struct passwd * pw ;
struct group * gr ;
if ( ( pw = getpwuid ( owner ) ) = = NULL )
return 0 ;
if ( ( gr = getgrgid ( group ) ) = = NULL )
return 0 ;
sowner = pw - > pw_name ;
sgroup = gr - > gr_name ;
2004-11-29 15:45:42 +03:00
{
PREFIX
g_snprintf ( buf , sizeof ( buf ) ,
2009-01-23 23:00:30 +03:00
" #CHOWN /%s \" /%s \" \n "
" chown %s \" /%s \" 2>/dev/null \n "
2000-03-29 17:36:54 +04:00
" echo '### 000' \n " ,
1998-11-21 22:36:01 +03:00
sowner , rpath ,
sowner , rpath ) ;
2004-11-29 15:45:42 +03:00
fish_send_command ( me , super , buf , OPT_FLUSH ) ;
/* FIXME: what should we report if chgrp succeeds but chown fails? */
g_snprintf ( buf , sizeof ( buf ) ,
2009-01-23 23:00:30 +03:00
" #CHGRP /%s \" /%s \" \n "
" chgrp %s \" /%s \" 2>/dev/null \n "
2000-03-29 17:36:54 +04:00
" echo '### 000' \n " ,
1998-11-21 22:36:01 +03:00
sgroup , rpath ,
sgroup , rpath ) ;
2004-11-29 15:45:42 +03:00
/* fish_send_command(me, super, buf, OPT_FLUSH); */
POSTFIX ( OPT_FLUSH )
}
1998-09-13 14:40:43 +04:00
}
2004-08-17 02:15:28 +04:00
static int fish_unlink ( struct vfs_class * me , const char * path )
1998-09-13 14:40:43 +04:00
{
PREFIX
2000-03-29 17:36:54 +04:00
g_snprintf ( buf , sizeof ( buf ) ,
2009-01-23 23:00:30 +03:00
" #DELE \" /%s \" \n "
" rm -f \" /%s \" 2>/dev/null \n "
2000-03-29 17:36:54 +04:00
" echo '### 000' \n " ,
rpath , rpath ) ;
1998-09-13 14:40:43 +04:00
POSTFIX ( OPT_FLUSH ) ;
}
2004-08-17 02:15:28 +04:00
static int fish_mkdir ( struct vfs_class * me , const char * path , mode_t mode )
1998-09-13 14:40:43 +04:00
{
PREFIX
2005-02-22 21:38:58 +03:00
( void ) mode ;
2000-03-29 17:36:54 +04:00
g_snprintf ( buf , sizeof ( buf ) ,
2009-01-23 23:00:30 +03:00
" #MKD \" /%s \" \n "
" mkdir \" /%s \" 2>/dev/null \n "
2000-03-29 17:36:54 +04:00
" echo '### 000' \n " ,
rpath , rpath ) ;
1998-09-13 14:40:43 +04:00
POSTFIX ( OPT_FLUSH ) ;
}
2004-08-17 02:15:28 +04:00
static int fish_rmdir ( struct vfs_class * me , const char * path )
1998-09-13 14:40:43 +04:00
{
PREFIX
2000-03-29 17:36:54 +04:00
g_snprintf ( buf , sizeof ( buf ) ,
2009-01-23 23:00:30 +03:00
" #RMD \" /%s \" \n "
" rmdir \" /%s \" 2>/dev/null \n "
2000-03-29 17:36:54 +04:00
" echo '### 000' \n " ,
rpath , rpath ) ;
1998-09-13 14:40:43 +04:00
POSTFIX ( OPT_FLUSH ) ;
}
2003-10-29 04:35:36 +03:00
static int
fish_fh_open ( struct vfs_class * me , struct vfs_s_fh * fh , int flags ,
int mode )
1998-11-21 22:36:01 +03:00
{
2005-02-22 21:35:22 +03:00
( void ) mode ;
2002-07-26 05:33:40 +04:00
fh - > u . fish . append = 0 ;
2002-05-21 14:50:55 +04:00
/* File will be written only, so no need to retrieve it */
2003-10-29 04:35:36 +03:00
if ( ( ( flags & O_WRONLY ) = = O_WRONLY ) & & ! ( flags & ( O_RDONLY | O_RDWR ) ) ) {
2002-07-26 05:33:40 +04:00
fh - > u . fish . append = flags & O_APPEND ;
2003-10-29 04:35:36 +03:00
if ( ! fh - > ino - > localname ) {
int tmp_handle =
vfs_mkstemps ( & fh - > ino - > localname , me - > name ,
fh - > ino - > ent - > name ) ;
2002-05-22 17:31:15 +04:00
if ( tmp_handle = = - 1 )
return - 1 ;
close ( tmp_handle ) ;
}
2002-05-21 14:50:55 +04:00
return 0 ;
}
1998-11-21 22:36:01 +03:00
if ( ! fh - > ino - > localname )
2003-10-29 04:35:36 +03:00
if ( vfs_s_retrieve_file ( me , fh - > ino ) = = - 1 )
1998-11-21 22:36:01 +03:00
return - 1 ;
if ( ! fh - > ino - > localname )
2003-10-29 04:35:36 +03:00
vfs_die ( " retrieve_file failed to fill in localname " ) ;
1998-11-21 22:36:01 +03:00
return 0 ;
}
2002-07-19 09:29:31 +04:00
static void
2004-08-16 20:34:11 +04:00
fish_fill_names ( struct vfs_class * me , fill_names_f func )
2002-07-19 09:29:31 +04:00
{
2003-10-16 20:40:11 +04:00
struct vfs_s_super * super = MEDATA - > supers ;
2004-08-17 15:14:51 +04:00
const char * flags ;
2002-07-19 09:29:31 +04:00
char * name ;
while ( super ) {
switch ( SUP . flags & ( FISH_FLAG_RSH | FISH_FLAG_COMPRESSED ) ) {
case FISH_FLAG_RSH :
flags = " :r " ;
break ;
case FISH_FLAG_COMPRESSED :
flags = " :C " ;
break ;
case FISH_FLAG_RSH | FISH_FLAG_COMPRESSED :
flags = " " ;
break ;
2002-07-19 19:11:20 +04:00
default :
flags = " " ;
break ;
2002-07-19 09:29:31 +04:00
}
name = g_strconcat ( " /#sh: " , SUP . user , " @ " , SUP . host , flags ,
2004-09-24 19:08:21 +04:00
" / " , SUP . cwdir , ( char * ) NULL ) ;
2002-07-19 09:29:31 +04:00
( * func ) ( name ) ;
g_free ( name ) ;
super = super - > next ;
}
}
2003-10-11 03:38:03 +04:00
void
init_fish ( void )
{
2003-10-16 20:40:11 +04:00
static struct vfs_s_subclass fish_subclass ;
2003-10-28 10:09:39 +03:00
fish_subclass . flags = VFS_S_REMOTE ;
2003-10-28 03:57:02 +03:00
fish_subclass . archive_same = fish_archive_same ;
fish_subclass . open_archive = fish_open_archive ;
fish_subclass . free_archive = fish_free_archive ;
2003-10-16 20:40:11 +04:00
fish_subclass . fh_open = fish_fh_open ;
2003-10-28 03:57:02 +03:00
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 ;
2003-10-16 20:40:11 +04:00
2003-10-28 10:09:39 +03:00
vfs_s_init_class ( & vfs_fish_ops , & fish_subclass ) ;
2003-10-11 03:38:03 +04:00
vfs_fish_ops . name = " fish " ;
vfs_fish_ops . prefix = " sh: " ;
vfs_fish_ops . fill_names = fish_fill_names ;
vfs_fish_ops . chmod = fish_chmod ;
vfs_fish_ops . chown = fish_chown ;
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 ;
vfs_register_class ( & vfs_fish_ops ) ;
}