File indexing completed on 2024-05-05 04:59:31

0001 #!/usr/bin/perl
0002 # SPDX-License-Identifier: GPL-2.0-only
0003 =pod
0004 This file was transferred by kio_fish, a network client part of the
0005 KDE project. You may safely delete it, it will be transferred again
0006 when needed.
0007 =cut
0008 
0009 use Fcntl;
0010 
0011 $|++;
0012 #open(DEBUG,">/tmp/kio_fish.debug.$$.log");
0013 # save code in initial directory if just transferred
0014 if (defined $code) {
0015     unlink('.fishsrv.pl');
0016     sysopen(FH,'.fishsrv.pl',O_WRONLY|O_CREAT|O_EXCL);
0017     print FH $code;
0018     close(FH);
0019     chmod(0444,'.fishsrv.pl');
0020 # request new code if it changed (checksum mismatch)
0021 # for automatic upgrades
0022 } elsif ($ARGV[0] ne "{CHECKSUM}") {
0023     $|=1;
0024     print "### 100 transfer fish server\n";
0025     while(<STDIN>) {
0026         last if /^__END__/;
0027         $code.=$_;
0028     }
0029     exit(eval($code));
0030 }
0031 
0032 # we are up and running.
0033 print "### 200\n";
0034 use strict;
0035 use POSIX qw(getcwd dup2 strftime);
0036 $SIG{'CHLD'} = 'IGNORE';
0037 $| = 1;
0038 MAIN: while (<STDIN>) {
0039     chomp;
0040     chomp;
0041     next if !length($_) || substr($_,0,1) ne '#';
0042 #print DEBUG "$_\n";
0043     s/^#//;
0044     /^VER / && do {
0045         # We do not advertise "append" capability anymore, as "write" is
0046         # as fast in perl mode and more reliable (overlapping writes)
0047         print "VER 0.0.3 copy lscount lslinks lsmime exec stat\n### 200\n";
0048         next;
0049     };
0050     /^PWD$/ && do {
0051         print getcwd(),"\n### 200\n";
0052         next;
0053     };
0054     /^SYMLINK\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0055         my $ofn = unquote($1);
0056         my $fn = unquote($2);
0057         print (symlink($ofn,$fn)?"### 200\n":"### 500 $!\n");
0058         next;
0059     };
0060     /^COPY\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0061         my $ofn = unquote($1);
0062         my $fn = unquote($2);
0063         my ($size) = (stat($ofn))[7];
0064         my $read = 1;
0065         if (-l $ofn) {
0066             my $dest = readlink($ofn);
0067             unlink($fn);
0068             symlink($dest,$fn) || ($read = 0);
0069         } else {
0070             sysopen(FH,$ofn,O_RDONLY) || do { print "### 500 $!\n"; next; };
0071             sysopen(OFH,$fn,O_WRONLY|O_CREAT|O_TRUNC) || do { close(FH); print "### 500 $!\n"; next; };
0072             local $/ = undef;
0073             my $buffer = '';
0074             while ($size > 32768 && ($read = sysread(FH,$buffer,32768)) > 0) {
0075                 $size -= $read;
0076                 if (syswrite(OFH,$buffer,$read) != $read) {
0077                     close(FH); close(OFH);
0078                     print "### 500 $!\n";
0079                     next MAIN;
0080                 }
0081 
0082             }
0083             while ($size > 0 && ($read = sysread(FH,$buffer,$size)) > 0) {
0084                 $size -= $read;
0085                 if (syswrite(OFH,$buffer,$read) != $read) {
0086                     close(FH); close(OFH);
0087                     print "### 500 $!\n";
0088                     next MAIN;
0089                 }
0090             }
0091             close(FH);
0092             close(OFH);
0093         }
0094         if ($read > 0) {
0095             print "### 200\n";
0096         } else {
0097             print "### 500 $!\n";
0098         }
0099         next;
0100     };
0101     /^LINK\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0102         my $ofn = unquote($1);
0103         my $fn = unquote($2);
0104         print (link($ofn,$fn)?"### 200\n":"### 500 $!\n");
0105         next;
0106     };
0107     /^RENAME\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0108         my $ofn = unquote($1);
0109         my $fn = unquote($2);
0110         print (rename($ofn,$fn)?"### 200\n":"### 500 $!\n");
0111         next;
0112     };
0113     /^CHGRP\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0114         my $fn = unquote($2);
0115         print (chown(-1,int($1),$fn)?"### 200\n":"### 500 $!\n");
0116         next;
0117     };
0118     /^CHOWN\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0119         my $fn = unquote($2);
0120         print (chown(int($1),-1,$fn)?"### 200\n":"### 500 $!\n");
0121         next;
0122     };
0123     /^CHMOD\s+([0-7]+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0124         my $fn = unquote($2);
0125         print (chmod(oct($1),$fn)?"### 200\n":"### 500 $!\n");
0126         next;
0127     };
0128     /^DELE\s+((?:\\.|[^\\])*?)\s*$/ && do {
0129         my $fn = unquote($1);
0130         print (unlink($fn)?"### 200\n":"### 500 $!\n");
0131         next;
0132     };
0133     /^RMD\s+((?:\\.|[^\\])*?)\s*$/ && do {
0134         my $dn = unquote($1);
0135         print (rmdir($dn)?"### 200\n":"### 500 $!\n");
0136         next;
0137     };
0138     /^MKD\s+((?:\\.|[^\\])*?)\s*$/ && do {
0139         my $dn = unquote($1);
0140         if (mkdir($dn,0777)) {
0141           print "### 200\n";
0142         } else {
0143           my $err = $!;
0144           print (chdir($dn)?"### 501 $err\n":"### 500 $err\n");
0145         }
0146         next;
0147     };
0148     /^CWD\s+((?:\\.|[^\\])*?)\s*$/ && do {
0149         my $dn = unquote($1);
0150         print (chdir($dn)?"### 200\n":"### 500 $!\n");
0151         next;
0152     };
0153     /^LIST\s+((?:\\.|[^\\])*?)\s*$/ && do {
0154         list($1, 1);
0155         next;
0156     };
0157     /^STAT\s+((?:\\.|[^\\])*?)\s*$/ && do {
0158         list($1, 0);
0159         next;
0160     };
0161     /^WRITE\s+(\d+)\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0162         write_loop($2,$3,O_WRONLY|O_CREAT,$1);
0163         next;
0164     };
0165     /^APPEND\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0166         write_loop($1,$2,O_WRONLY|O_APPEND);
0167         next;
0168     };
0169     /^STOR\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0170         write_loop($1,$2,O_WRONLY|O_CREAT|O_TRUNC);
0171         next;
0172     };
0173     /^RETR\s+((?:\\.|[^\\])*?)\s*$/ && do {
0174         read_loop($1);
0175         next;
0176     };
0177     /^READ\s+(\d+)\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0178         read_loop($3,$2,$1);
0179         next;
0180     };
0181     /^EXEC\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
0182         my $tempfile = unquote($2);
0183         my $command = unquote($1);
0184         $command = $command . ";echo \"###RESULT: \$?\"";
0185         print("### 500 $!\n"), next
0186             if (!sysopen(FH,$tempfile,O_CREAT|O_EXCL|O_WRONLY,0600));
0187         my $pid = fork();
0188         print("### 500 $!\n"), next
0189             if (!defined $pid);
0190         if ($pid == 0) {
0191             open(STDOUT,'>>&FH');
0192             open(STDERR,'>>&FH');
0193             open(STDIN,'</dev/null'); # not sure here, ms windows anyone?
0194             exec('/bin/sh','-c',$command);
0195             print STDERR "Couldn't exec /bin/sh: $!\n";
0196             exit(255);
0197         }
0198         waitpid($pid,0);
0199         close(FH);
0200         print "### 200\n";
0201         next;
0202     };
0203 }
0204 exit(0);
0205 
0206 sub list {
0207     my $dn = unquote($_[0]);
0208     my @entries;
0209     if (!-e $dn) {
0210         print "### 404 File does not exist\n";
0211         return;
0212     } elsif ($_[1] && -d _) {
0213         opendir(DIR,$dn) || do { print "### 500 $!\n"; return; };
0214         @entries = readdir(DIR);
0215         closedir(DIR);
0216     } else {
0217         ($dn, @entries) = $dn =~ m{(.*)/(.*)};
0218         $dn = '/' if (!length($dn));
0219     }
0220     print scalar(@entries),"\n### 100\n";
0221     my $cwd = getcwd();
0222     chdir($dn) || do { print "### 500 $!\n"; return; };
0223     foreach (@entries) {
0224         $_ = '.' if (!length($_));
0225         my $link = readlink;
0226         my ($mode,$uid,$gid,$size,$mtime) = (lstat)[2,4,5,7,9];
0227         print filetype($mode,$link,$uid,$gid);
0228         print "S$size\n";
0229         print strftime("D%Y %m %d %H %M %S\n",localtime($mtime));
0230         print ":$_\n";
0231         print "L$link\n" if defined $link;
0232         print mimetype($_);
0233         print "\n";
0234     }
0235     chdir($cwd);
0236     print "### 200\n";
0237 }
0238 
0239 sub read_loop {
0240     my $fn = unquote($_[0]);
0241     my ($size) = ($_[1]?int($_[1]):(stat($fn))[7]);
0242     my $error = '';
0243     print "### 501 Is directory\n" and return if -d $fn;
0244     sysopen(FH,$fn,O_RDONLY) || ($error = $!);
0245     if ($_[2]) {
0246         sysseek(FH,int($_[2]),0) || do { close(FH); $error ||= $!; };
0247     }
0248     print "### 500 $error\n" and return if $error;
0249     if (@_ < 2) {
0250         print "$size\n";
0251     }
0252     print "### 100\n";
0253     my $buffer = '';
0254     my $read = 1;
0255     while ($size > 32768 && ($read = sysread(FH,$buffer,32768)) > 0) {
0256 #print DEBUG "$size left, $read read\n";
0257         $size -= $read;
0258         print $buffer;
0259     }
0260     while ($size > 0 && ($read = sysread(FH,$buffer,$size)) > 0) {
0261 #print DEBUG "$size left, $read read\n";
0262         $size -= $read;
0263         print $buffer;
0264     }
0265     while ($size > 0) {
0266         print ' ';
0267         $size--;
0268     }
0269     $error ||= $! if $read <= 0;
0270     close(FH);
0271     if (!$error) {
0272         print "### 200\n";
0273     } else {
0274         print "### 500 $error\n";
0275     }
0276 }
0277 
0278 sub write_loop {
0279     my $size = int($_[0]);
0280     my $fn = unquote($_[1]);
0281 #print DEBUG "write_loop called $size size, $fn fn, $_[2]\n";
0282     my $error = '';
0283     sysopen(FH,$fn,$_[2]) || do { print "### 400 $!\n"; return; };
0284     eval { flock(FH,2); };
0285     if ($_[3]) {
0286         sysseek(FH,int($_[3]),0) || do { close(FH);print "### 400 $!\n"; return; };
0287     }
0288     <STDIN>;
0289     print "### 100\n";
0290     my $buffer = '';
0291     my $read = 1;
0292     while ($size > 32768 && ($read = read(STDIN,$buffer,32768)) > 0) {
0293 #print DEBUG "$size left, $read read\n";
0294         $size -= $read;
0295         $error ||= $! if (syswrite(FH,$buffer,$read) != $read);
0296     }
0297     while ($size > 0 && ($read = read(STDIN,$buffer,$size)) > 0) {
0298 #print DEBUG "$size left, $read read\n";
0299         $size -= $read;
0300         $error ||= $! if (syswrite(FH,$buffer,$read) != $read);
0301     }
0302     close(FH);
0303     if (!$error) {
0304         print "### 200\n";
0305     } else {
0306         print "### 500 $error\n";
0307     }
0308 }
0309 
0310 sub unquote { $_ = shift; s/\\(.)/$1/g; return $_; }
0311 
0312 sub filetype {
0313     my ($mode,$link,$uid,$gid) = @_;
0314     my $result = 'P';
0315     while (1) {
0316         -f _ && do { $result .= '-'; last; };
0317         -d _ && do { $result .= 'd'; last; };
0318         defined($link) && do { $result .= 'l'; last; };
0319         -c _ && do { $result .= 'c'; last; };
0320         -b _ && do { $result .= 'b'; last; };
0321         -S _ && do { $result .= 's'; last; };
0322         -p _ && do { $result .= 'p'; last; };
0323         $result .= '?'; last;
0324     }
0325     $result .= ($mode & 0400?'r':'-');
0326     $result .= ($mode & 0200?'w':'-');
0327     $result .= ($mode & 0100?($mode&04000?'s':'x'):($mode&04000?'S':'-'));
0328     $result .= ($mode & 0040?'r':'-');
0329     $result .= ($mode & 0020?'w':'-');
0330     $result .= ($mode & 0010?($mode&02000?'s':'x'):($mode&02000?'S':'-'));
0331     $result .= ($mode & 0004?'r':'-');
0332     $result .= ($mode & 0002?'w':'-');
0333     $result .= ($mode & 0001?($mode&01000?'t':'x'):($mode&01000?'T':'-'));
0334 
0335     $result .= ' ';
0336     $result .= (getpwuid($uid)||$uid);
0337     $result .= ':';
0338     $result .= (getgrgid($gid)||$gid);
0339     $result .= "\n";
0340     return $result;
0341 }
0342 
0343 sub mimetype {
0344     my $fn = shift;
0345     return "Minode/directory\n" if -d $fn;
0346     pipe(IN,OUT);
0347     my $pid = fork();
0348     return '' if (!defined $pid);
0349     if ($pid) {
0350         close(OUT);
0351         my $type = <IN>;
0352         close(IN);
0353         chomp $type;
0354         chomp $type;
0355         $type =~ s/[,; ].*//;
0356         return '' if ($type !~ m/\//);
0357         return "M$type\n"
0358     }
0359     close(IN);
0360     sysopen(NULL,'/dev/null',O_RDWR);
0361     dup2(fileno(NULL),fileno(STDIN));
0362     dup2(fileno(OUT),fileno(STDOUT));
0363     dup2(fileno(NULL),fileno(STDERR));
0364     exec('/usr/bin/file','-i','-b','-L',$fn);
0365     exit(0);
0366 }
0367 __END__