⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpserver.pm

📁 Wget很好的处理了http和ftp的下载,很值得学习的经典代码
💻 PM
📖 第 1 页 / 共 2 页
字号:
                print {$conn->{socket}} "426 Transfer aborted. Data connection closed.\r\n";                return;            }        }    }    unless (close ($sock) && close (FILE)) {        print {$conn->{socket}} "550 File retrieval error: $!.\r\n";        return;    }    print {$conn->{socket}} "226 File retrieval complete. Data connection has been closed.\r\n";}sub _SIZE_command{    my ($conn, $cmd, $path) = @_;        my $dir = $conn->{dir};    # Absolute path?    if (substr ($path, 0, 1) eq "/") {        $dir = "/";        $path =~ s,^/+,,;        $path = "." if $path eq "";    }    # Parse the first elements of path until we find the appropriate    # working directory.    my @elems = split /\//, $path;    my $filename = pop @elems;    foreach (@elems) {        if ($_ eq "" || $_ eq ".") {             next # Ignore these.        } elsif ($_ eq "..") {            # Go to parent directory.            unless ($dir eq "/") {                $dir = substr ($dir, 0, rindex ($dir, "/"));            }        } else {            unless (-d $conn->{rootdir} . $dir . $_) {                print {$conn->{socket}} "550 File or directory not found.\r\n";                return;            }            $dir .= $_;        }    }    unless (defined $filename && length $filename) {        print {$conn->{socket}} "550 File or directory not found.\r\n";	    return;    }    if ($filename eq "." || $filename eq "..") {        print {$conn->{socket}} "550 SIZE command is not supported on directories.\r\n";	    return;    }    my $fullname = $conn->{rootdir} . $dir . $filename;    unless (-f $fullname) {        print {$conn->{socket}} "550 SIZE command is only supported on plain files.\r\n";        return;    }    my $size = 0;    if ($conn->{type} eq 'A') {        # ASCII mode: we have to count the characters by hand.        unless (open (FILE, '<', $filename)) {            print {$conn->{socket}} "550 Cannot calculate size of $filename.\r\n";            return;        }        $size++ while (defined (getc(FILE)));        close FILE;    } else {        # BINARY mode: we can use stat        $size = (stat($filename))[7];    }    print {$conn->{socket}} "213 $size\r\n";}sub _SYST_command{    my ($conn, $cmd, $dummy) = @_;        print {$conn->{socket}} "215 UNIX Type: L8\r\n";}sub _TYPE_command{    my ($conn, $cmd, $type) = @_;        # See RFC 959 section 5.3.2.    if ($type =~ /^([AI])$/i) {        $conn->{type} = 'A';    } elsif ($type =~ /^([AI])\sN$/i) {        $conn->{type} = 'A';    } elsif ($type =~ /^L\s8$/i) {        $conn->{type} = 'L8';    } else {        print {$conn->{socket}} "504 This server does not support TYPE $type.\r\n";        return;    }    print {$conn->{socket}} "200 TYPE changed to $type.\r\n";}sub _USER_command{    my ($conn, $cmd, $username) = @_;    print STDERR "username: $username\n" if $log;    $conn->{username} = $username;    print STDERR "switching to WAIT4PWD state\n" if $log;    $conn->{state} = $_connection_states{WAIT4PWD};        if ($conn->{username} eq "anonymous") {        print {$conn->{socket}} "230 Anonymous user access granted.\r\n";    } else {        print {$conn->{socket}} "331 Password required.\r\n";    }}# HELPER ROUTINESsub __open_data_connection{    my $conn = shift;    my $sock;    if ($conn->{passive}) {        # Passive mode - wait for a connection from the client.        accept ($sock, $conn->{passive_socket}) or return undef;    } else {        # Active mode - connect back to the client.        "0" =~ /(0)/; # Perl 5.7 / IO::Socket::INET bug workaround.        $sock = IO::Socket::INET->new (LocalAddr => '127.0.0.1',                                       PeerAddr => $conn->{peeraddrstring},                                       PeerPort => $conn->{peerport},                                       Proto => 'tcp',                                       Type => SOCK_STREAM) or return undef;    }    return $sock;}sub __list_file{    my $sock = shift;    my $filename = shift;    # Get the status information.    my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,        $atime, $mtime, $ctime, $blksize, $blocks)      = lstat $filename;    # If the file has been removed since we created this    # handle, then $dev will be undefined. Return immediately.    return unless defined $dev;    # Generate printable user/group.    my $user = getpwuid ($uid) || "-";    my $group = getgrgid ($gid) || "-";    # Permissions from mode.    my $perms = $mode & 0777;    # Work out the mode using special "_" operator which causes Perl    # to use the result of the previous stat call.    $mode = (-f _ ? 'f' :             (-d _ ? 'd' :              (-l _ ? 'l' :               (-p _ ? 'p' :                (-S _ ? 's' :                 (-b _ ? 'b' :                  (-c _ ? 'c' : '?')))))));    # Generate printable date (this logic is taken from GNU fileutils:    # src/ls.c: print_long_format).    my $time = time;    my $fmt;    if ($time > $mtime + 6 * 30 * 24 * 60 * 60 || $time < $mtime - 60 * 60) {        $fmt = "%b %e  %Y";    } else {        $fmt = "%b %e %H:%M";    }    my $fmt_time = strftime $fmt, localtime ($mtime);    # Generate printable permissions.    my $fmt_perms = join "",      ($perms & 0400 ? 'r' : '-'),      ($perms & 0200 ? 'w' : '-'),      ($perms & 0100 ? 'x' : '-'),      ($perms & 040 ? 'r' : '-'),      ($perms & 020 ? 'w' : '-'),      ($perms & 010 ? 'x' : '-'),      ($perms & 04 ? 'r' : '-'),      ($perms & 02 ? 'w' : '-'),      ($perms & 01 ? 'x' : '-');    # Printable file type.    my $fmt_mode = $mode eq 'f' ? '-' : $mode;    # If it's a symbolic link, display the link.    my $link;    if ($mode eq 'l') {        $link = readlink $filename;        die "readlink: $!" unless defined $link;    }    my $fmt_link = defined $link ? " -> $link" : "";    # Display the file.    my $line = sprintf      ("%s%s%4d %-8s %-8s %8d %s %s%s\r\n",       $fmt_mode,       $fmt_perms,       $nlink,       $user,       $group,       $size,       $fmt_time,       $filename,       $fmt_link);    $sock->print ($line);}sub __get_file_list{    my $dir = shift;    my $wildcard = shift;    opendir (DIRHANDLE, $dir)        or die "Cannot open directory!!!";    my @allfiles = readdir DIRHANDLE;    my @filenames = ();        if ($wildcard) {        # Get rid of . and ..        @allfiles = grep !/^\.{1,2}$/, @allfiles;                # Convert wildcard to a regular expression.        $wildcard = __wildcard_to_regex ($wildcard);        @filenames = grep /$wildcard/, @allfiles;    } else {        @filenames = @allfiles;    }    closedir (DIRHANDLE);    return sort @filenames;}sub __wildcard_to_regex{    my $wildcard = shift;    $wildcard =~ s,([^?*a-zA-Z0-9]),\\$1,g; # Escape punctuation.    $wildcard =~ s,\*,.*,g; # Turn * into .*    $wildcard =~ s,\?,.,g;  # Turn ? into .    $wildcard = "^$wildcard\$"; # Bracket it.    return $wildcard;}############################################################################ FTPSERVER CLASS###########################################################################{    my %_attr_data = ( # DEFAULT        _localAddr  => 'localhost',        _localPort  => 8021,        _reuseAddr  => 1,        _rootDir    => Cwd::getcwd(),    );        sub _default_for    {        my ($self, $attr) = @_;        $_attr_data{$attr};    }    sub _standard_keys     {        keys %_attr_data;    }}sub new {    my ($caller, %args) = @_;    my $caller_is_obj = ref($caller);    my $class = $caller_is_obj || $caller;    my $self = bless {}, $class;    foreach my $attrname ($self->_standard_keys()) {        my ($argname) = ($attrname =~ /^_(.*)/);        if (exists $args{$argname}) {            $self->{$attrname} = $args{$argname};        } elsif ($caller_is_obj) {            $self->{$attrname} = $caller->{$attrname};        } else {            $self->{$attrname} = $self->_default_for($attrname);        }    }    return $self;}sub run {    my ($self, $synch_callback) = @_;    my $initialized = 0;    # turn buffering off on STDERR    select((select(STDERR), $|=1)[0]);    # initialize command table    my $command_table = {};    foreach (keys %_commands) {        my $subname = "_${_}_command";        $command_table->{$_} = \&$subname;    }    my $old_ils = $/;    $/ = "\r\n";    # create server socket    "0" =~ /(0)/; # Perl 5.7 / IO::Socket::INET bug workaround.    my $server_sock = IO::Socket::INET->new (LocalHost => $self->{_localAddr},                                             LocalPort => $self->{_localPort},                                             Listen => 1,                                             Reuse => $self->{_reuseAddr},                                             Proto => 'tcp',                                             Type => SOCK_STREAM) or die "bind: $!";    if (!$initialized) {        $synch_callback->();        $initialized = 1;    }    $SIG{CHLD} = sub { wait };    # the accept loop    while (my $client_addr = accept (my $socket, $server_sock))    {            # turn buffering off on $socket        select((select($socket), $|=1)[0]);                # find out who connected            my ($client_port, $client_ip) = sockaddr_in ($client_addr);        my $client_ipnum = inet_ntoa ($client_ip);        # print who connected        print STDERR "got a connection from: $client_ipnum\n" if $log;        # fork off a process to handle this connection.        my $pid = fork();        unless (defined $pid) {            warn "fork: $!";            sleep 5; # Back off in case system is overloaded.            next;        }        if ($pid == 0) { # Child process.            # install signals            $SIG{URG}  = sub {                 $GOT_SIGURG  = 1;             };            $SIG{PIPE} = sub {                print STDERR "Client closed connection abruptly.\n";                exit;            };            $SIG{ALRM} = sub {                print STDERR "Connection idle timeout expired. Closing server.\n";                exit;            };                        #$SIG{CHLD} = 'IGNORE';            print STDERR "in child\n" if $log;            my $conn = {                 'socket'       => $socket,                 'state'        => $_connection_states{NEWCONN},                'dir'          => '/',                'restart'      => 0,                'idle_timeout' => 60, # 1 minute timeout                'rootdir'      => $self->{_rootDir},            };                    print {$conn->{socket}} "220 GNU Wget Testing FTP Server ready.\r\n";            # command handling loop            for (;;) {                print STDERR "waiting for request\n" if $log;                last unless defined (my $req = <$socket>);                # Remove trailing CRLF.                $req =~ s/[\n\r]+$//;                print STDERR "received request $req\n" if $log;                # Get the command.                # See also RFC 2640 section 3.1.                unless ($req =~ m/^([A-Z]{3,4})\s?(.*)/i) {                    # badly formed command                    exit 0;                }                # The following strange 'eval' is necessary to work around a                # very odd bug in Perl 5.6.0. The following assignment to                # $cmd will fail in some cases unless you use $1 in some sort                # of an expression beforehand.                # - RWMJ 2002-07-05.                eval '$1 eq $1';                my ($cmd, $rest) = (uc $1, $2);                # Got a command which matches in the table?                unless (exists $command_table->{$cmd}) {                    print {$conn->{socket}} "500 Unrecognized command.\r\n";                    next;                }                # Command requires user to be authenticated?                unless ($_commands{$cmd} | $conn->{state}) {                    print {$conn->{socket}} "530 Not logged in.\r\n";                    next;                }                                # Handle the QUIT command specially.                if ($cmd eq "QUIT") {                    print {$conn->{socket}} "221 Goodbye. Service closing connection.\r\n";                    last;                }                # Run the command.                &{$command_table->{$cmd}} ($conn, $cmd, $rest);            }        } else { # Father            close $socket;        }    }     $/ = $old_ils;}1;# vim: et ts=4 sw=4

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -