Roxen.git/server/plugins/protocols/ftp.pike:1:
// This is a roxen protocol module.
// Copyright © 1997 - 2001, Roxen IS.
/*
* FTP protocol mk 2
*
- * $Id: ftp.pike,v 2.92 2004/05/17 13:17:23 mani Exp $
+ * $Id: ftp.pike,v 2.93 2004/05/17 13:20:05 mani Exp $
*
* Henrik Grubbström <grubba@roxen.com>
*/
/*
* TODO:
*
* How much is supposed to be logged?
*/
Roxen.git/server/plugins/protocols/ftp.pike:165: Inside #if defined(FTP_REQUESTID_DEBUG)
{
#ifdef FTP_REQUESTID_DEBUG
report_debug("REQUESTID: Destroy request id #%d.\n", _num);
#endif
}
void create(object|void m_rid)
{
#ifdef FTP_REQUESTID_DEBUG
_num = ++__num[0];
- report_debug("REQUESTID: New request id #%d.\n", _num);
+ if (m_rid) {
+ report_debug("REQUESTID: New request id #%d (CHILD to #%d).\n",
+ _num, m_rid->_num);
+ } else {
+ report_debug("REQUESTID: New request id #%d (MASTER).\n", _num);
+ }
#else
DWRITE("REQUESTID: New request id.\n");
#endif
if (m_rid) {
this_program o = this;
foreach(indices(m_rid), string var) {
if (!(< "create", "connection", "configuration",
"__INIT", "clone_me", "end", "ready_to_receive",
"send", "scan_for_query", "send_result", "misc",
Roxen.git/server/plugins/protocols/ftp.pike:705:
static string output_mode = "A";
static mapping(string:array|object) stat_cache = ([]);
static object conv;
static array|object stat_file(string long, RequestID|void session)
{
array|object st = stat_cache[long];
if (zero_type(st)) {
- if (!session) {
- session = RequestID2(master_session);
+ session = RequestID2(session || master_session);
session->method = "DIR";
- }
+
long = replace(long, "//", "/");
st = session->conf->stat_file(long, session);
stat_cache[long] = st;
-
+ destruct(session);
}
return st;
}
// FIXME: Should convert output somewhere below.
static void output(string s)
{
if(stringp(s)) {
// ls is always ASCII-mode...
s = replace(s, "\n", "\r\n");
Roxen.git/server/plugins/protocols/ftp.pike:872:
}
RequestID session = RequestID2(master_session);
session->method = "DIR";
mixed err;
mapping(string:array) dir;
err = catch {
dir = session->conf->find_dir_stat(long, session);
};
+ destruct(session);
+
if (err) {
report_error("FTP: LSFile->list_next_directory(): "
"find_dir_stat(\"%s\") failed:\n"
"%s\n", long, describe_backtrace(err));
}
DWRITE("FTP: LSFile->list_next_directory(): "
"find_dir_stat(\"%s\") => %O\n", long, dir);
// Put them in the stat cache.
Roxen.git/server/plugins/protocols/ftp.pike:1039:
(!(flags & LS_FLAG_d))) {
// Directory
dir_stack->push(short);
} else {
files[n_files++] = short;
}
} else {
output(short + ": not found\n");
session->conf->log(([ "error":404 ]), session);
}
+ destruct(session);
}
DWRITE("FTP: LSFile: %d files, %d directories\n",
n_files, dir_stack->ptr);
if (n_files) {
if (n_files < sizeof(files)) {
files -= ({ 0 });
}
string s = list_files(files, cwd); // May modify dir_stack (-R)
output(s);
RequestID session = RequestID2(master_session);
session->not_query = Array.map(files, fix_path) * " ";
session->method = "LIST";
session->conf->sent = sizeof(s);
session->conf->log(([ "error":200, "len":sizeof(s) ]), session);
-
+ destruct(session);
}
if (dir_stack->ptr) {
name_directories = dir_stack->ptr &&
((dir_stack->ptr > 1) || n_files);
list_next_directory();
} else {
output(0);
}
}
Roxen.git/server/plugins/protocols/ftp.pike:1787:
fd = 0;
//BACKEND_CLOSE(fd);
}
curr_pipe = 0;
if (session && session->file) {
session->file->len = amount;
session->conf->log(session->file, session);
session->file = 0;
}
-
+ destruct(session);
send(226, ({ "Transfer complete." }));
}
static private mapping|array|object stat_file(string fname,
object|void session)
{
mapping file;
- if (!session) {
- session = RequestID2(master_session);
+ session = RequestID2(session || master_session);
session->method = "STAT";
- }
-
+
session->not_query = fname;
foreach(conf->first_modules(), function funp) {
if ((file = funp(session))) {
break;
}
}
if (!file) {
fname = replace(fname, "//", "/");
- return(conf->stat_file(fname, session));
+ file = conf->stat_file(fname, session);
}
- return(file);
+ destruct(session);
+ return file;
}
static private int expect_argument(string cmd, string args)
{
if ((< "", 0 >)[args]) {
send(504, ({ sprintf("Syntax: %s %s", cmd, cmd_help[cmd]) }));
return 0;
}
return 1;
}
Roxen.git/server/plugins/protocols/ftp.pike:1951:
send(150, ({ sprintf("Opening %s data connection for %s (%d bytes).",
modes[file->mode], file->full_path, file->len) }));
} else {
send(150, ({ sprintf("Opening %s mode data connection for %s",
modes[file->mode], file->full_path) }));
}
}
else
{
send(425, ({ "Can't build data connect: Connection refused." }));
+ destruct(session);
return;
}
switch(file->mode) {
case "A":
if (file->data) {
file->data = replace(file->data,
({ "\r\n", "\n", "\r" }),
({ "\r\n", "\r\n", "\r\n" }));
}
if(objectp(file->file) && file->file->set_nonblocking)
Roxen.git/server/plugins/protocols/ftp.pike:2074:
break;
case 501:
send(502, ({ sprintf("%s: Command not implemented.", args) }));
break;
default:
send(550, ({ sprintf("%s: Error opening file.", args) }));
break;
}
session->conf->sent = session->file->len;
session->conf->log(session->file, session);
+ destruct(session);
return;
}
master_session->file = session->file;
} else {
// Error message has already been sent.
if (fd) {
BACKEND_CLOSE(fd);
}
-
+ destruct(session);
}
}
static private void discard_data_connection() {
if(pasv_port && sizeof(pasv_accepted))
pasv_accepted = pasv_accepted[1..];
}
static private void connect_and_send(mapping file, object session)
{
Roxen.git/server/plugins/protocols/ftp.pike:2273:
}
foreach(sort(dir), string f) {
array(string) arr = my_combine_path_array(path, f);
string p = arr*"/";
if (!paths[p]) {
paths[p] = 1;
new_matches += ({ arr });
}
}
}
+ destruct(id);
}
matches = new_matches;
} else {
// No glob
// Just add the part. Modify matches in-place.
for(i=0; i<sizeof(matches); i++) {
matches[i] = my_combine_path_array(matches[i], part);
string path = matches[i]*"/";
if (paths[path]) {
matches[i] = 0;
Roxen.git/server/plugins/protocols/ftp.pike:2305:
for (i=0; i < sizeof(matches); i++) {
matches[i] *= "/";
}
// Filter out non-existing or forbiden files/directories
matches = Array.filter(matches,
lambda(string short, string cwd,
object m_id) {
object id = RequestID2(m_id);
id->method = "LIST";
id->not_query = combine_path(cwd, short);
- return(id->conf->stat_file(id->not_query,
- id));
+ mapping res =
+ id->conf->stat_file(id->not_query, id);
+ destruct(id);
+ return res;
}, cwd, master_session);
if (sizeof(matches)) {
args[index] = matches;
}
}
}
if (stringp(args[index])) {
// No glob
args[index] = ({ my_combine_path("", args[index]) });
}
Roxen.git/server/plugins/protocols/ftp.pike:2785:
if ((home == "") || (home[-1] != '/')) {
home += "/";
}
// Compatibility...
master_session->misc->home = home;
object session = RequestID2(master_session);
session->method = "STAT";
array(int)|object st = conf->stat_file(home, session);
+ destruct(session);
if (st && (st[1] < 0)) {
cwd = home;
}
}
logged_in = 1;
send(230, ({ sprintf("User %s logged in.", user) }));
conf->log(([ "error":202 ]), master_session);
}
Roxen.git/server/plugins/protocols/ftp.pike:2818:
session->method = "CWD";
session->not_query = ncwd;
array|object st = conf->stat_file(ncwd, session);
ncwd = session->not_query; // Makes internal redirects to work.
if (!st) {
send(550, ({ sprintf("%s: No such file or directory, or access denied.",
ncwd) }));
session->conf->sent = session->file && session->file->len;
session->conf->log(session->file || ([ "error":404 ]), session);
+ destruct(session);
return;
}
if (!(< -2, -3 >)[st[1]]) {
send(504, ({ sprintf("%s: Not a directory.", ncwd) }));
session->conf->log(([ "error":400 ]), session);
-
+ destruct(session);
return;
}
// CWD Successfull
cwd = ncwd;
array(string) reply = ({ sprintf("Current directory is now %s.", cwd) });
// Check for .messages etc
session->method = "GET"; // Important
Roxen.git/server/plugins/protocols/ftp.pike:2865:
message = conf->try_get_file(cwd + ".message", session);
};
if (message) {
reply = (message/"\n")+({ "" })+reply;
}
session->method = "CWD"; // Restore it again.
send(250, reply);
session->conf->sent = sizeof(reply * "\n");
session->conf->log(([ "error":200, "len":session->conf->sent ]), session);
+ destruct(session);
}
void ftp_XCWD(string args)
{
ftp_CWD(args);
}
void ftp_CDUP(string args)
{
ftp_CWD("../");
Roxen.git/server/plugins/protocols/ftp.pike:3150:
restart_point -= sizeof(session->file->data);
m_delete(session->file, "data");
}
}
if (restart_point) {
if (!(session->file->file && session->file->file->seek &&
(session->file->file->seek(restart_point) != -1))) {
restart_point = 0;
send(550, ({ "'RETR': Error restoring restart point." }));
discard_data_connection();
+ destruct(session);
return;
}
restart_point = 0;
}
}
connect_and_send(session->file, session);
}
- else
+ else {
discard_data_connection();
-
+ destruct(session);
}
-
+ }
void ftp_STOR(string args)
{
if (!expect_argument("STOR", args)) {
return;
}
args = fix_path(args);
connect_and_receive(args);
Roxen.git/server/plugins/protocols/ftp.pike:3227:
RequestID session = RequestID2(master_session);
session->method = "STAT";
if (stat_file(args, session)) {
send(350, ({ sprintf("%s ok, waiting for destination name.", args) }) );
rename_from = args;
} else {
send(550, ({ sprintf("%s: no such file or permission denied.",args) }) );
}
+ destruct(session);
}
void ftp_RNTO(string args)
{
if(!rename_from) {
send(503, ({ "RNFR needed before RNTO." }));
return;
}
if (!expect_argument("RNTO", args)) {
return;
Roxen.git/server/plugins/protocols/ftp.pike:3250:
RequestID session = RequestID2(master_session);
session->method = "MV";
session->misc->move_from = rename_from;
session->not_query = args;
if (open_file(args, session, "MOVE")) {
send(250, ({ sprintf("%s moved to %s.", rename_from, args) }));
session->conf->log(([ "error":200 ]), session);
}
rename_from = 0;
+ destruct(session);
}
void ftp_NLST(string args)
{
// ftp_MLST(args); return;
array(string) argv = glob_expand_command_line("/usr/bin/ls " + (args||""));
call_ls(argv);
Roxen.git/server/plugins/protocols/ftp.pike:3286:
array|object st = stat_file(args, session);
if (st) {
session->file = ([]);
session->file->full_path = args;
send_MLST_response(([ args:st ]), session);
} else {
send_error("MLST", args, session->file, session);
}
+ destruct(session);
}
void ftp_MLSD(string args)
{
args = fix_path(args || ".");
RequestID session = RequestID2(master_session);
session->method = "DIR";
Roxen.git/server/plugins/protocols/ftp.pike:3313:
session->file = ([]);
session->file->full_path = args;
send_MLSD_response(session->conf->find_dir_stat(args, session), session);
} else {
if (st) {
session->file->error = 405;
}
send_error("MLSD", args, session->file, session);
discard_data_connection();
}
+ destruct(session);
}
void ftp_DELE(string args)
{
if (!expect_argument("DELE", args)) {
return;
}
args = fix_path(args);
RequestID session = RequestID2(master_session);
session->data = 0;
session->misc->len = 0;
session->method = "DELETE";
if (open_file(args, session, "DELE")) {
send(250, ({ sprintf("%s deleted.", args) }));
session->conf->log(([ "error":200 ]), session);
- return;
+
}
-
+ destruct(session);
}
void ftp_RMD(string args)
{
if (!expect_argument("RMD", args)) {
return;
}
args = fix_path(args);
RequestID session = RequestID2(master_session);
session->data = 0;
session->misc->len = 0;
session->method = "DELETE";
array|object st = stat_file(args, session);
if (!st) {
send_error("RMD", args, session->file, session);
-
+ destruct(session);
return;
} else if (st[1] != -2) {
if (st[1] == -3) {
send(504, ({ sprintf("%s is a module mountpoint.", args) }));
session->conf->log(([ "error":405 ]), session);
} else {
send(504, ({ sprintf("%s is not a directory.", args) }));
session->conf->log(([ "error":405 ]), session);
}
-
+ destruct(session);
return;
}
if (open_file(args, session, "RMD")) {
send(250, ({ sprintf("%s deleted.", args) }));
session->conf->log(([ "error":200 ]), session);
- return;
+
}
-
+ destruct(session);
}
void ftp_XRMD(string args)
{
ftp_RMD(args);
}
void ftp_MKD(string args)
{
if (!expect_argument("MKD", args)) {
Roxen.git/server/plugins/protocols/ftp.pike:3395:
RequestID session = RequestID2(master_session);
session->method = "MKDIR";
session->data = 0;
session->misc->len = 0;
if (open_file(args, session, "MKD")) {
send(257, ({ sprintf("\"%s\" created.", args) }));
session->conf->log(([ "error":200 ]), session);
- return;
+
}
-
+ destruct(session);
}
void ftp_XMKD(string args)
{
ftp_MKD(args);
}
void ftp_SYST(string args)
{
send(215, ({ "UNIX Type: L8: ChiliMoon Internet Server"}));
Roxen.git/server/plugins/protocols/ftp.pike:3449:
if (!expect_argument("MDTM", args)) {
return;
}
args = fix_path(args);
RequestID session = RequestID2(master_session);
session->method = "STAT";
mapping|array|object st = stat_file(args, session);
if (!arrayp(st) && !objectp(st)) {
send_error("MDTM", args, st, session);
- return;
- }
+ } else {
send(213, ({ make_MDTM(st[3]) }));
}
-
+ destruct(session);
+ }
void ftp_SIZE(string args)
{
if (!expect_argument("SIZE", args)) {
return;
}
args = fix_path(args);
RequestID session = RequestID2(master_session);
session->method = "STAT";
mapping|array|object st = stat_file(args, session);
if (!arrayp(st) && !objectp(st)) {
send_error("SIZE", args, st, session);
-
+ destruct(session);
return;
}
int size = st[1];
if (size < 0) {
send_error("SIZE", args, ([ "error":405, ]), session);
- return;
+
// size = 512;
- }
+ } else {
send(213, ({ (string)size }));
}
-
+ destruct(session);
+ }
void ftp_STAT(string args)
{
// According to RFC 1123 4.1.3.3, this command can be sent during
// a file-transfer.
// RFC 959 4.1.3:
// The command may be sent during a file transfer (along with the
// Telnet IP and Synch signals--see the Section on FTP Commands)
// in which case the server will respond with the status of the
// operation in progress, [...]
Roxen.git/server/plugins/protocols/ftp.pike:3524:
)/"\n");
return;
}
string long = fix_path(args);
RequestID session = RequestID2(master_session);
session->method = "STAT";
mapping|array|object st = stat_file(long);
if (!arrayp(st) && !objectp(st)) {
send_error("STAT", long, st, session);
- return;
- }
-
+ } else {
string s = LS_L(master_session)->ls_l(args, st);
send(213, sprintf("status of \"%s\":\n"
"%s"
"End of Status", args, s)/"\n");
}
-
+ destruct(session);
+ }
void ftp_NOOP(string args)
{
send(200, ({ "Nothing done ok" }));
}
void ftp_HELP(string args)
{
if ((< "", 0 >)[args]) {
send(214, ({
Roxen.git/server/plugins/protocols/ftp.pike:3643:
RequestID session = RequestID2(master_session);
session->method = "CHMOD";
session->misc->mode = mode;
session->not_query = fname;
if (open_file(fname, session, "CHMOD")) {
send(250, ({ sprintf("Changed permissions of %s to 0%o.",
fname, mode) }));
session->conf->log(([ "error":200 ]), session);
}
+ destruct(session);
}
void ftp_SITE_UMASK(array(string) args)
{
if (sizeof(args) < 1) {
send(501, ({ sprintf("'SITE UMASK %s': incorrect arguments",
args*" ") }));
return;
}
Roxen.git/server/plugins/protocols/ftp.pike:3832:
destruct();
}
void destroy()
{
DWRITE("FTP2: destroy()\n");
logout();
port_obj->sessions--;
+ if (master_session) {
+ destruct(master_session);
}
-
+ }
void create(object fd, object c)
{
port_obj = c;
// FIXME: Only supports one configuration!
conf = port_obj->urls[port_obj->sorted_urls[0]]->conf;
// Support delayed loading.
if (!conf->inited) {