ftpd.c
来自「C实现的MUD,对大家基本入门网络游戏很有帮助!」· C语言 代码 · 共 1,581 行 · 第 1/3 页
C
1,581 行
mixed tmp;
if ( UTYPE == BINARY ) {
data_mode_name = "BINARY";
data_mode = STREAM_BINARY;
tmp = allocate_buffer( 0 );
} else {
data_mode_name = "ASCII";
data_mode = STREAM;
tmp = "";
}
if ( socket_info[ fd ][ DATA_FD ] ) {
socket_write( fd, "425 Can't open data connection.\n" );
return;
}
new_fd = socket_create( data_mode, "data_read_callback",
"data_close_callback" );
if ( new_fd < 0 ) {
socket_write( fd, "425 Can't create data socket.\n" );
return;
}
if ( ( ret = socket_connect( new_fd, sprintf("%s %d",
socket_info[ fd ][ DATA_ADDR ], socket_info[ fd ][ DATA_PORT ]),
"data_read_callback", "data_write_callback" ) ) < 0 ) {
TP( "Error: " + socket_info[ fd ][ DATA_ADDR ] + " " +
socket_info[ fd ][ DATA_PORT ] + "\n" );
TP( socket_error( ret ) + "\n" );
socket_write( fd, "425 Can't build data connection.\n" );
socket_close( new_fd );
return;
}
socket_info[ new_fd ] = ([
PATH : path,
PARENT_FD : fd,
DATA : tmp,
TYPE : DOWNLOAD,
APPEND : append
]);
socket_info[ fd ][ DATA_FD ] = new_fd;
socket_write( fd, sprintf("150 Opening %s mode data connection for %s.\n",
data_mode_name, path) );
} /* read_connection() */
void data_read_callback( int fd, mixed mess )
{
if ( socket_info[ fd ][ TYPE ] != DOWNLOAD )
return;
socket_info[ socket_info[ fd ][ PARENT_FD ]][ LAST_DATA ] = time();
if ( stringp( mess ) )
mess = replace_string( mess, "\r", "" );
socket_info[ fd ][ DATA ] += mess;
} /* data_read_callback() */
void data_close_callback( int fd )
{
int pos, size, res;
if ( socket_info[ fd ][ TYPE ] == DOWNLOAD ) {
if ( socket_info[ fd ][ APPEND ] != 1 )
catch( rm( socket_info[ fd ][ PATH ] ) );
else pos = file_size( socket_info[ fd ][ PATH ] );
do {
if (catch( res = write_buffer( UPATH, pos,
UDATA[pos..(pos+(BLOCK_SIZE-1))] ) ))
socket_write( socket_info[ fd ][ PARENT_FD ],
"452 Error writing file.\n");
if (res)
pos += BLOCK_SIZE;
} while (res);
size = stringp( UDATA ) ? strlen( UDATA ) : sizeof( UDATA );
#ifdef FILE_LOCKING
flock_wrapper( socket_info[ fd ][ PATH ], F_UNLOCK,
socket_info[ fd ][ PARENT_FD ]);
#endif
if ( socket_info[ fd ][ APPEND ] == -1)
socket_write( socket_info[ fd ][ PARENT_FD ],
sprintf("226 Transfer complete (unique file name:%s).\n",
socket_info[ fd ][ PATH ]) );
else
socket_write( socket_info[ fd ][ PARENT_FD ],
"226 Transfer complete.\n" );
}
/*
* only close data connections here
*/
if (!undefinedp( socket_info[fd][PARENT_FD] )) {
socket_close( fd );
map_delete( socket_info[ socket_info[ fd ][ PARENT_FD ] ],
DATA_FD );
}
} /* data_close_callback() */
protected void logout( int fd )
{
socket_info[ fd ][ LOGGED_IN ] = 0;
if ( UNAME ) {
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_CONNECT
log_file( LOG_FILE, sprintf("%s logged out from %s.\n", UNAME, USITE) );
#endif
}
} /* logout() */
/*
* parse user command
*/
protected void parse_comm( int fd, string str )
{
string *command, tmp, tmp2;
mixed *misc;
int port, i, s;
TP( "Parsing " + str + ".\n" );
command = explode( str, " " );
socket_info[ fd ][ LAST_DATA ] = time();
switch( lower_case( command[ 0 ] ) ) {
case "port": // specify data connection port
command = explode( implode( command[1..1000], " " ), "," );
if ( sizeof( command ) < 6 )
socket_write( fd, "550 Failed command.\n" );
else {
socket_info[ fd ][ DATA_ADDR ] = implode( command[ 0..3 ], "." );
sscanf( command[ 4 ], "%d", i );
port = i << 8;
i = atoi( command[5] );
port += i;
socket_info[ fd ][ DATA_PORT ] = port;
socket_write( fd, "200 PORT command successful.\n" );
}
break;
case "user": // specify user name
if ( socket_info[ fd ][ LOGGED_IN ] ) {
logout( fd );
UNAME = 0;
}
CHECK_CMD(1);
if ( !check_access( command[ 1 ] ) ) {
socket_write( fd, sprintf("530 User %s access denied.\n",
command[ 1 ]) );
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_NO_CONNECT
log_file( LOG_FILE, sprintf("%s denied access from %s.\n",
command[ 1 ], USITE) );
#endif
} else {
#ifdef ANONYMOUS_FTP
if ( command[ 1 ] == "anonymous" )
socket_write( fd,
"331 Guest login ok, send your complete E-mail address as password.\n" );
else
#endif
socket_write( fd, sprintf(
"331 Password required for %s.\n", command[ 1 ]) );
UNAME = command[ 1 ];
}
break;
case "pass": // specify password
if ( socket_info[fd][LOGGED_IN] || !socket_info[fd][USER_NAME] ) {
socket_write( fd, "503 Log in with USER first.\n" );
break;
}
if ( !check_password( socket_info[fd][ USER_NAME ],
implode( command[ 1..sizeof( command ) - 1 ], " " ) ) ) {
#ifdef ANONYMOUS_FTP
if (UNAME == "anonymous")
socket_write( fd,
"530 Login failed. Please send your complete E-mail address as password.\n" );
else
#endif
socket_write( fd, "530 Login incorrect.\n" );
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_NO_CONNECT
log_file( LOG_FILE, sprintf(
"%s failed/incorrect login from %s.\n", UNAME, USITE) );
#endif
UNAME = 0;
} else
#ifdef CHECK_SITE
if (!check_site( UNAME, fd )) {
/*
* Note: this particular response of 530 is not mentioned
* as a possible response to the PASS command in RFC959,
* because site checking is TMI specific.
*/
socket_write( fd, sprintf("530 User %s: Can't login from %s.\n",
UNAME, USITE) );
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_NO_CONNECT
log_file( LOG_FILE, sprintf("%s refused login from %s.\n",
UNAME, USITE) );
#endif
UNAME = 0;
lose_user( fd );
} else
#endif
{
socket_info[ fd ][ LOGGED_IN ] = 1;
#ifdef ANONYMOUS_FTP
if ( UNAME == "anonymous" )
UCWD = FTP_DIR;
else
#endif
UCWD = HOME_DIR( UNAME );
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_CONNECT
#ifdef ANONYMOUS_FTP
if (UNAME == "anonymous")
log_file( LOG_FILE, sprintf("%s (%s) connected from %s.\n",
UNAME, str[strlen(command[0]) + 1..<1], USITE) );
else
#endif
log_file( LOG_FILE, sprintf("%s connected from %s.\n",
UNAME, USITE) );
#endif
if ( !directory_exists( UCWD ) ) {
socket_write( fd, "230 No directory! Logging in with home="
#ifdef GUEST_WIZARD_FTP
PUB_DIR ".\n" );
socket_info[ fd ][ CWD ] = PUB_DIR;
#else
"/\n" );
socket_info[ fd ][ CWD ] = "/";
#endif
} else {
#ifdef LOGIN_MSG
tmp = read_file( LOGIN_MSG );
tmp = tmp[0..<2];
tmp = sprintf("230- %s\n",
replace_string( tmp, "\n", "\n230- " ) );
socket_write( fd, tmp );
#endif
#ifdef ANONYMOUS_FTP
if (UNAME == "anonymous")
socket_write( fd,
"230 Guest login ok, access restrictions apply.\n" );
else
#endif ANONYMOUS_FTP
socket_write( fd, sprintf(
"230 User %s logged in successfully.\n", UNAME) );
}
socket_info[ fd ][ TYPE ] = STRING;
}
break;
case "allo": // allocate storage (vacuously)
socket_write( fd, "202 ALLO command ignored.\n" );
break;
case "noop": // do nothing
socket_write( fd, "200 NOOP command successful.\n" );
break;
case "retr": // retrieve a file
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
if ((i = file_size(tmp)) == -2) {
socket_write( fd, sprintf("550 %s: Not a plain file.\n",
command[1]));
} else if (i == -1) {
socket_write( fd, sprintf(
"550 %s: No such file or directory(%s).\n", command[1], tmp));
} else if ( !check_valid_read( tmp, fd ) ) {
PERMISSION_DENIED550(command[ 1 ]);
} else {
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("%s retr %s (%s).\n",
UNAME, tmp, (UTYPE == BINARY ? "BINARY" : "ASCII") ) );
#endif
data_conn( fd, tmp, command[ 1 ], FILE );
}
break;
case "stou": // store a file with a unique name
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
i = file_size(tmp);
if (i >= 0 && check_valid_write( tmp, fd )) {
for (i = MAX_UNIQUE_TRIES; i; i--) {
if (file_size(sprintf("%s%d", tmp, i)) == -1)
break;
}
if (i) {
tmp = sprintf("%s%d", tmp, i);
#ifdef FILE_LOCKING
if (flock_wrapper(tmp, F_LOCK, fd)) { /* parent fd */
#endif
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("%s stou %s (%s).\n", UNAME,
tmp, (UTYPE == BINARY ? "BINARY" : "ASCII") ) );
#endif
read_connection( fd, tmp, -1 );
#ifdef FILE_LOCKING
} else {
PERMISSION_DENIED550(command[ 1 ]);
}
#endif
} else {
socket_write( fd, "452 Unique file name cannot be created.\n");
}
} else {
PERMISSION_DENIED553(command[ 1 ]);
}
break;
case "stor": // store a file
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
if ( file_size(tmp) != -2 && check_valid_write( tmp, fd ) ) {
#ifdef FILE_LOCKING
if (flock_wrapper(tmp, F_LOCK, fd)) { /* parent fd */
#endif
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("%s stor %s (%s).\n", UNAME,
tmp, (UTYPE == BINARY ? "BINARY" : "ASCII") ) );
#endif
read_connection( fd, tmp, 0 );
#ifdef FILE_LOCKING
} else {
PERMISSION_DENIED550(command[ 1 ]);
}
#endif
} else {
PERMISSION_DENIED553(command[ 1 ]);
}
break;
case "appe": // append to a file
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
if ( file_size(tmp) >= 0 && check_valid_write( tmp, fd ) ) {
#ifdef FILE_LOCKING
if (flock_wrapper(tmp, F_LOCK, fd)) { /* parent fd */
#endif
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("%s appe %s (%s).\n", UNAME,
tmp, (UTYPE == BINARY ? "BINARY" : "ASCII") ) );
#endif
read_connection( fd, tmp, 1 );
#ifdef FILE_LOCKING
} else {
PERMISSION_DENIED550(command[ 1 ]);
}
#endif
} else {
PERMISSION_DENIED553(command[ 1 ]);
}
break;
case "dele": // delete a file
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
if ((i = file_size(tmp)) == -2) {
socket_write( fd, sprintf("550 %s: Not a plain file.\n",
command[1]));
} else if (i == -1) {
socket_write( fd, sprintf(
"550 %s: No such file or directory.\n", command[1]));
} else if ( check_valid_write( tmp, fd ) ) {
#ifdef FILE_LOCKING
if (flock_wrapper(tmp, F_LOCK, fd)) { /* parent fd */
#endif
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_FILE
log_file( LOG_FILE, sprintf("%s dele %s.\n", UNAME, tmp) );
#endif
catch( i = rm(tmp) );
if (i)
socket_write( fd, "250 DELE command successful.\n" );
else
socket_write( fd, sprintf(
"550 Permission denied to %s.\n", command[ 1 ]) );
#ifdef FILE_LOCKING
flock_wrapper(tmp, F_UNLOCK, fd); /* parent fd */
} else {
PERMISSION_DENIED550(command[ 1 ]);
}
#endif
} else {
PERMISSION_DENIED553(command[ 1 ]);
}
break;
/* Supposed to return modified time in the format: YYYYMMDDHHMMSS */
case "mdtm": // show last modification time of file
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
if ( check_valid_read( tmp, fd ) ) {
if ((i = file_size(tmp)) == -2)
socket_write( fd, sprintf("550 %s: Not a plain file.\n",
command[1]));
else if (i == -1)
socket_write( fd, sprintf(
"550 %s: No such file or directory.\n", command[1]));
else {
misc = stat(tmp);
tmp2 = ctime(misc[1]);
tmp2 = sprintf("%s%02d%c%c%s%s%s",
tmp2[20..23], member_array(tmp2[4..6], MONTHS),
tmp2[8] == ' ' ? '0' : tmp2[8],
tmp2[11..12], tmp2[14..15], tmp2[17..18]);
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_CD_SIZE
log_file( LOG_FILE, sprintf("%s mdtm %s.\n", UNAME, tmp) );
#endif
socket_write( fd, sprintf("213 %s\n", tmp2) );
}
} else
PERMISSION_DENIED550(command[ 1 ]);
break;
case "size": // return size of file
CHECK_LOGIN();
CHECK_CMD(1);
tmp = get_path( fd, command[ 1 ] );
if ( check_valid_read( tmp, fd ) ) {
if ( directory_exists( tmp ) )
socket_write( fd, sprintf("550 %s: Not a plain file.\n",
command[ 1 ]) );
else
if ( !file_exists( tmp ) )
socket_write( fd, sprintf("550 %s does not exist.\n",
command[ 1 ]) );
else {
#ifdef LOG_TIME
log_file( LOG_FILE, FTP_TIME );
#endif
#ifdef LOG_CD_SIZE
log_file( LOG_FILE, sprintf("%s size %s.\n",
UNAME, tmp) );
#endif
socket_write( fd, sprintf("215 %d\n", file_size( tmp )) );
}
} else
PERMISSION_DENIED550(command[ 1 ]);
break;
case "nlst": // give name list of files in directory
CHECK_LOGIN();
/* Send name list */
if ((i = sizeof(command)) > 1 && command[1] == "-l") {
if (i == 2)
command[1] = ".";
else
command = ({ command[0] }) + command[2..s-1];
// and fall through to "list"
} else {
/* Used by commands like "dir", "mget", and "mput" */
if ( i > 1 )
tmp = get_path( fd, command[ 1 ] );
else
tmp = socket_info[ fd ][ CWD ];
if ( check_valid_read( tmp, fd ) ) {
tmp2 = ls( tmp, 1, fd );
if (tmp2 == "")
socket_write( fd, "550 No files found.\n" );
else
data_conn( fd, tmp2, "ls", STRING );
} else
PERMISSION_DENIED550(tmp);
break;
}
case "list": // give list files in a directory
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?