fish.pl 10.8 KB
Newer Older
Waldo Bastian's avatar
Waldo Bastian committed
1
2
3
4
#!/usr/bin/perl
# This program 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, version 2 of the License
5
6
7
=pod
This file was transferred by kio_fish, a network client part of the
KDE project. You may safely delete it, it will be transferred again
8
when needed.
9
=cut
Waldo Bastian's avatar
Waldo Bastian committed
10
11

use Fcntl;
12

Jörg Walter's avatar
Jörg Walter committed
13
14
$|++;
#open(DEBUG,">/tmp/kio_fish.debug.$$.log");
Waldo Bastian's avatar
Waldo Bastian committed
15
16
17
# save code in initial directory if just transferred
if (defined $code) {
    unlink('.fishsrv.pl');
18
19
20
21
    sysopen(FH,'.fishsrv.pl',O_WRONLY|O_CREAT|O_EXCL);
    print FH $code;
    close(FH);
    chmod(0444,'.fishsrv.pl');
Waldo Bastian's avatar
Waldo Bastian committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# request new code if it changed (checksum mismatch)
# for automatic upgrades
} elsif ($ARGV[0] ne "{CHECKSUM}") {
    $|=1;
    print "### 100 transfer fish server\n";
    while(<STDIN>) {
        last if /^__END__/;
        $code.=$_;
    }
    exit(eval($code));
}

# we are up and running.
print "### 200\n";
use strict;
use POSIX qw(getcwd dup2 strftime);
$SIG{'CHLD'} = 'IGNORE';
$| = 1;
MAIN: while (<STDIN>) {
41
42
43
    chomp;
    chomp;
    next if !length($_) || substr($_,0,1) ne '#';
44
#print DEBUG "$_\n";
45
46
    s/^#//;
    /^VER / && do {
47
48
        # We do not advertise "append" capability anymore, as "write" is
        # as fast in perl mode and more reliable (overlapping writes)
Waldo Bastian's avatar
Waldo Bastian committed
49
        print "VER 0.0.3 copy lscount lslinks lsmime exec stat\n### 200\n";
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
        next;
    };
    /^PWD$/ && do {
        print getcwd(),"\n### 200\n";
        next;
    };
    /^SYMLINK\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $ofn = unquote($1);
        my $fn = unquote($2);
        print (symlink($ofn,$fn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^COPY\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $ofn = unquote($1);
        my $fn = unquote($2);
        my ($size) = (stat($ofn))[7];
        my $read = 1;
        if (-l $ofn) {
            my $dest = readlink($ofn);
            unlink($fn);
            symlink($dest,$fn) || ($read = 0);
        } else {
            sysopen(FH,$ofn,O_RDONLY) || do { print "### 500 $!\n"; next; };
            sysopen(OFH,$fn,O_WRONLY|O_CREAT|O_TRUNC) || do { close(FH); print "### 500 $!\n"; next; };
            local $/ = undef;
            my $buffer = '';
76
            while ($size > 32768 && ($read = sysread(FH,$buffer,32768)) > 0) {
77
78
79
80
81
82
                $size -= $read;
                if (syswrite(OFH,$buffer,$read) != $read) {
                    close(FH); close(OFH);
                    print "### 500 $!\n";
                    next MAIN;
                }
Jörg Walter's avatar
Jörg Walter committed
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
            }
            while ($size > 0 && ($read = sysread(FH,$buffer,$size)) > 0) {
                $size -= $read;
                if (syswrite(OFH,$buffer,$read) != $read) {
                    close(FH); close(OFH);
                    print "### 500 $!\n";
                    next MAIN;
                }
            }
            close(FH);
            close(OFH);
        }
        if ($read > 0) {
            print "### 200\n";
        } else {
            print "### 500 $!\n";
        }
        next;
    };
    /^LINK\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $ofn = unquote($1);
        my $fn = unquote($2);
        print (link($ofn,$fn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^RENAME\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $ofn = unquote($1);
        my $fn = unquote($2);
        print (rename($ofn,$fn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^CHGRP\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $fn = unquote($2);
        print (chown(-1,int($1),$fn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^CHOWN\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $fn = unquote($2);
        print (chown(int($1),-1,$fn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^CHMOD\s+([0-7]+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $fn = unquote($2);
        print (chmod(oct($1),$fn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^DELE\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $fn = unquote($1);
        print (unlink($fn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^RMD\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $dn = unquote($1);
        print (rmdir($dn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^MKD\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $dn = unquote($1);
142
143
144
145
146
147
        if (mkdir($dn,0777)) {
          print "### 200\n";
        } else {
          my $err = $!;
          print (chdir($dn)?"### 501 $err\n":"### 500 $err\n");
        }
148
149
150
151
152
153
154
155
        next;
    };
    /^CWD\s+((?:\\.|[^\\])*?)\s*$/ && do {
        my $dn = unquote($1);
        print (chdir($dn)?"### 200\n":"### 500 $!\n");
        next;
    };
    /^LIST\s+((?:\\.|[^\\])*?)\s*$/ && do {
Waldo Bastian's avatar
Waldo Bastian committed
156
157
158
159
160
        list($1, 1);
        next;
    };
    /^STAT\s+((?:\\.|[^\\])*?)\s*$/ && do {
        list($1, 0);
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
        next;
    };
    /^WRITE\s+(\d+)\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        write_loop($2,$3,O_WRONLY|O_CREAT,$1);
        next;
    };
    /^APPEND\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        write_loop($1,$2,O_WRONLY|O_APPEND);
        next;
    };
    /^STOR\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        write_loop($1,$2,O_WRONLY|O_CREAT|O_TRUNC);
        next;
    };
    /^RETR\s+((?:\\.|[^\\])*?)\s*$/ && do {
        read_loop($1);
        next;
    };
    /^READ\s+(\d+)\s+(\d+)\s+((?:\\.|[^\\])*?)\s*$/ && do {
        read_loop($3,$2,$1);
        next;
    };
183
    /^EXEC\s+((?:\\.|[^\\])*?)\s+((?:\\.|[^\\])*?)\s*$/ && do {
184
185
        my $tempfile = unquote($2);
        my $command = unquote($1);
186
        $command = $command . ";echo \"###RESULT: \$?\"";
187
188
189
190
        print("### 500 $!\n"), next
            if (!sysopen(FH,$tempfile,O_CREAT|O_EXCL|O_WRONLY,0600));
        my $pid = fork();
        print("### 500 $!\n"), next
191
            if (!defined $pid);
192
193
194
195
196
197
198
199
200
201
        if ($pid == 0) {
            open(STDOUT,'>>&FH');
            open(STDERR,'>>&FH');
            open(STDIN,'</dev/null'); # not sure here, ms windows anyone?
            exec('/bin/sh','-c',$command);
            print STDERR "Couldn't exec /bin/sh: $!\n";
            exit(255);
        }
        waitpid($pid,0);
        close(FH);
202
203
204
        print "### 200\n";
        next;
    };
Waldo Bastian's avatar
Waldo Bastian committed
205
206
207
}
exit(0);

Waldo Bastian's avatar
Waldo Bastian committed
208
209
210
211
212
213
214
215
216
217
218
219
sub list {
    my $dn = unquote($_[0]);
    my @entries;
    if (!-e $dn) {
        print "### 404 File does not exist\n";
        return;
    } elsif ($_[1] && -d _) {
        opendir(DIR,$dn) || do { print "### 500 $!\n"; return; };
        @entries = readdir(DIR);
        closedir(DIR);
    } else {
        ($dn, @entries) = $dn =~ m{(.*)/(.*)};
220
        $dn = '/' if (!length($dn));
Waldo Bastian's avatar
Waldo Bastian committed
221
222
223
224
225
    }
    print scalar(@entries),"\n### 100\n";
    my $cwd = getcwd();
    chdir($dn) || do { print "### 500 $!\n"; return; };
    foreach (@entries) {
Fabian Vogt's avatar
Fabian Vogt committed
226
        $_ = '.' if (!length($_));
Waldo Bastian's avatar
Waldo Bastian committed
227
228
229
230
231
232
233
234
235
236
237
238
239
240
        my $link = readlink;
        my ($mode,$uid,$gid,$size,$mtime) = (lstat)[2,4,5,7,9];
        print filetype($mode,$link,$uid,$gid);
        print "S$size\n";
        print strftime("D%Y %m %d %H %M %S\n",localtime($mtime));
        print ":$_\n";
        print "L$link\n" if defined $link;
        print mimetype($_);
        print "\n";
    }
    chdir($cwd);
    print "### 200\n";
}

Waldo Bastian's avatar
Waldo Bastian committed
241
sub read_loop {
242
243
244
    my $fn = unquote($_[0]);
    my ($size) = ($_[1]?int($_[1]):(stat($fn))[7]);
    my $error = '';
245
    print "### 501 Is directory\n" and return if -d $fn;
246
247
248
249
    sysopen(FH,$fn,O_RDONLY) || ($error = $!);
    if ($_[2]) {
        sysseek(FH,int($_[2]),0) || do { close(FH); $error ||= $!; };
    }
250
    print "### 500 $error\n" and return if $error;
251
    if (@_ < 2) {
252
        print "$size\n";
253
    }
254
    print "### 100\n";
255
256
    my $buffer = '';
    my $read = 1;
257
258
    while ($size > 32768 && ($read = sysread(FH,$buffer,32768)) > 0) {
#print DEBUG "$size left, $read read\n";
259
260
261
262
        $size -= $read;
        print $buffer;
    }
    while ($size > 0 && ($read = sysread(FH,$buffer,$size)) > 0) {
263
#print DEBUG "$size left, $read read\n";
264
265
266
267
268
269
270
271
272
273
274
275
276
277
        $size -= $read;
        print $buffer;
    }
    while ($size > 0) {
        print ' ';
        $size--;
    }
    $error ||= $! if $read <= 0;
    close(FH);
    if (!$error) {
        print "### 200\n";
    } else {
        print "### 500 $error\n";
    }
Waldo Bastian's avatar
Waldo Bastian committed
278
279
280
}

sub write_loop {
281
282
    my $size = int($_[0]);
    my $fn = unquote($_[1]);
283
#print DEBUG "write_loop called $size size, $fn fn, $_[2]\n";
284
285
    my $error = '';
    sysopen(FH,$fn,$_[2]) || do { print "### 400 $!\n"; return; };
286
    eval { flock(FH,2); };
287
288
289
290
291
292
293
    if ($_[3]) {
        sysseek(FH,int($_[3]),0) || do { close(FH);print "### 400 $!\n"; return; };
    }
    <STDIN>;
    print "### 100\n";
    my $buffer = '';
    my $read = 1;
294
295
    while ($size > 32768 && ($read = read(STDIN,$buffer,32768)) > 0) {
#print DEBUG "$size left, $read read\n";
296
297
298
299
        $size -= $read;
        $error ||= $! if (syswrite(FH,$buffer,$read) != $read);
    }
    while ($size > 0 && ($read = read(STDIN,$buffer,$size)) > 0) {
300
#print DEBUG "$size left, $read read\n";
301
302
303
304
305
306
307
308
309
        $size -= $read;
        $error ||= $! if (syswrite(FH,$buffer,$read) != $read);
    }
    close(FH);
    if (!$error) {
        print "### 200\n";
    } else {
        print "### 500 $error\n";
    }
Waldo Bastian's avatar
Waldo Bastian committed
310
311
312
313
314
}

sub unquote { $_ = shift; s/\\(.)/$1/g; return $_; }

sub filetype {
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
    my ($mode,$link,$uid,$gid) = @_;
    my $result = 'P';
    while (1) {
        -f _ && do { $result .= '-'; last; };
        -d _ && do { $result .= 'd'; last; };
        defined($link) && do { $result .= 'l'; last; };
        -c _ && do { $result .= 'c'; last; };
        -b _ && do { $result .= 'b'; last; };
        -S _ && do { $result .= 's'; last; };
        -p _ && do { $result .= 'p'; last; };
        $result .= '?'; last;
    }
    $result .= ($mode & 0400?'r':'-');
    $result .= ($mode & 0200?'w':'-');
    $result .= ($mode & 0100?($mode&04000?'s':'x'):($mode&04000?'S':'-'));
    $result .= ($mode & 0040?'r':'-');
    $result .= ($mode & 0020?'w':'-');
    $result .= ($mode & 0010?($mode&02000?'s':'x'):($mode&02000?'S':'-'));
    $result .= ($mode & 0004?'r':'-');
    $result .= ($mode & 0002?'w':'-');
    $result .= ($mode & 0001?($mode&01000?'t':'x'):($mode&01000?'T':'-'));
Waldo Bastian's avatar
Waldo Bastian committed
336

337
338
    $result .= ' ';
    $result .= (getpwuid($uid)||$uid);
339
    $result .= ':';
340
341
342
    $result .= (getgrgid($gid)||$gid);
    $result .= "\n";
    return $result;
Waldo Bastian's avatar
Waldo Bastian committed
343
344
345
}

sub mimetype {
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
    my $fn = shift;
    return "Minode/directory\n" if -d $fn;
    pipe(IN,OUT);
    my $pid = fork();
    return '' if (!defined $pid);
    if ($pid) {
        close(OUT);
        my $type = <IN>;
        close(IN);
        chomp $type;
        chomp $type;
        $type =~ s/[,; ].*//;
        return '' if ($type !~ m/\//);
        return "M$type\n"
    }
    close(IN);
    sysopen(NULL,'/dev/null',O_RDWR);
    dup2(fileno(NULL),fileno(STDIN));
    dup2(fileno(OUT),fileno(STDOUT));
    dup2(fileno(NULL),fileno(STDERR));
    exec('/usr/bin/file','-i','-b','-L',$fn);
    exit(0);
Waldo Bastian's avatar
Waldo Bastian committed
368
369
}
__END__