Roxen.git / server / plugins / protocols / ftp.pike

version» Context lines:

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.101 2004/06/04 08:29:30 _cvs_stephen Exp $ +  * $Id: ftp.pike,v 2.102 2004/06/06 22:04:33 _cvs_dirix Exp $    *    * Henrik Grubbström <grubba@roxen.com>    */      /*    * TODO:    *    * How much is supposed to be logged?    */   
Roxen.git/server/plugins/protocols/ftp.pike:641:    {    User user;    foreach(master_session->conf->user_databases(), UserDB user_db) {    if (user = user_db->find_user_from_uid(uid)) {    return user->name();    }    }    return (uid?((string)uid):"root");    }    -  string ls_l(string file, array st) +  string ls_l(string file, Stdio.Stat st)    {    DWRITE("ls_l(\"%s\")\n", file);    -  int mode = st[0] & 007777; +  int mode = st->mode & 007777;    array(string) perm = "----------"/"";    -  if (st[1] < 0) { +  if (st->size < 0) {    perm[0] = "d";    }       foreach(decode_mode, array(string|int) info) {    if ((mode & info[0]) == info[1]) {    perm[info[2]] = info[3];    }    }    -  mapping lt = localtime(st[3]); +  mapping lt = localtime(st->mtime);       // NOTE: SiteBuilder may set st[5] and st[6] to strings. -  string user = (string)st[5]; -  string group = (string)st[6]; +  string user = (string)st->uid; +  string group = (string)st->gid;    if (!(flags & LS_FLAG_n)) {    // Use symbolic names for uid and gid. -  if (!stringp(st[5])) { -  user = name_from_uid(st[5]); +  if (!stringp(st->uid)) { +  user = name_from_uid(st-uid);    }       // FIXME: Convert st[6] to symbolic group name.    }       string ts;    int now = time(1);    // Half a year:    // 365.25*24*60*60/2 = 15778800 -  if ((st[3] <= now - 15778800) || (st[3] > now)) { +  if ((st->mtime <= now - 15778800) || (st->mtime > now)) {    // Month Day Year    ts = sprintf("%s %02d %04d",    months[lt->mon], lt->mday, 1900+lt->year);    } else {    // Month Day Hour:minute    ts = sprintf("%s %02d %02d:%02d",    months[lt->mon], lt->mday, lt->hour, lt->min);    }       if (flags & LS_FLAG_G) {    // No group.    return sprintf("%s 1 %-10s %12d %s %s\n", perm*"", -  user, (st[1]<0? 512:st[1]), +  user, (st->type<0? 512:st-type),    ts, file);    } else {    return sprintf("%s 1 %-10s %-6s %12d %s %s\n", perm*"", -  user, group, (st[1]<0? 512:st[1]), +  user, group, (st->type<0? 512:st->type),    ts, file);    }    }   }      class LSFile   {    static inherit LS_L;       static string cwd;
Roxen.git/server/plugins/protocols/ftp.pike:715:    static object ftpsession;       static array(string) output_queue = ({});    static int output_pos;    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) +  Stdio.Stat file_stat(string long, RequestID|void session)    { -  array|object st = stat_cache[long]; +  Stdio.Stat st = stat_cache[long];    if (zero_type(st)) {    session = RequestID2(session || master_session);    session->method = "DIR";    long = replace(long, "//", "/"); -  st = session->conf->stat_file(long, session); +  st = session->conf->file_stat(long, session);    stat_cache[long] = st;    destruct(session);    }    return st;    }       // FIXME: Should convert output somewhere below.    static void output(string s)    {    if(stringp(s)) {
Roxen.git/server/plugins/protocols/ftp.pike:771:    {    dir = dir || cwd;       DWRITE("FTP: LSFile->list_files(%O, \"%s\"\n", files, dir);       if (!(flags & LS_FLAG_U)) {    if (flags & LS_FLAG_S) {    array(int) sizes = allocate(sizeof(files));    int i;    for (i=0; i < sizeof(files); i++) { -  array|object st = stat_file(combine_path(dir, files[i])); +  Stdio.Stat st = file_stat(combine_path(dir, files[i]));    if (st) { -  sizes[i] = st[1]; +  sizes[i] = st->type;    } else {    // Should not happen, but...    files -= ({ files[i] });    }    }    sort(sizes, files);    } else if (flags & LS_FLAG_t) {    array(int) times = allocate(sizeof(files));    int i;    for (i=0; i < sizeof(files); i++) { -  array|object st = stat_file(combine_path(dir, files[i])); +  Stdio.Stat st = file_stat(combine_path(dir, files[i]));    if (st) { -  times[i] = -st[-4]; // Note: Negative time. +  times[i] = -st->mtime; // Note: Negative time.    } else {    // Should not happen, but...    files -= ({ files[i] });    }    }    sort(times, files);    } else {    sort(files);    }    if (flags & LS_FLAG_r) {    files = reverse(files);    }    }       string res = "";    int total;    foreach(files, string short) {    string long = combine_path(dir, short); -  array|object st = stat_file(long); +  Stdio.Stat st = file_stat(long);    if (st) {    if (flags & LS_FLAG_Q) {    // Enclose in quotes.    // Space needs to be quoted to be compatible with -m    short = "\"" +    replace(short,    ({ "\n", "\r", "\\", "\"", "\'", " " }),    ({ "\\n", "\\r", "\\\\", "\\\"", "\\\'", "\\020" })) +    "\"";    }    if (flags & LS_FLAG_F) { -  if (st[1] < 0) { +  if (st->type < 0) {    // Directory    short += "/"; -  } else if (st[0] & 0111) { +  } else if (st->type & 0111) {    // Executable    short += "*";    }    }    int blocks = 1; -  if (st[1] >= 0) { -  blocks = (st[1] + 1023)/1024; // Blocks are 1KB. +  if (st->type >= 0) { +  blocks = (st->type + 1023)/1024; // Blocks are 1KB.    }    total += blocks;    if (flags & LS_FLAG_s) {    res += sprintf("%7d ", blocks);    }    if (flags & LS_FLAG_b) {    short = quote_non_print(short);    }    if (flags & LS_FLAG_l) {    res += ls_l(short, st);
Roxen.git/server/plugins/protocols/ftp.pike:904:    "find_dir_stat(\"%s\") => %O\n", long, dir);       // Put them in the stat cache.    foreach(indices(dir||({})), string f) {    stat_cache[combine_path(long, f)] = dir[f];    }       if ((flags & LS_FLAG_a) &&    (long != "/")) {    if (dir) { -  dir[".."] = stat_file(combine_path(long,"../")); +  dir[".."] = file_stat(combine_path(long,"../"));    } else { -  dir = ([ "..":stat_file(combine_path(long,"../")) ]); +  dir = ([ "..":file_stat(combine_path(long,"../")) ]);    }    }    string listing = "";    if (dir && sizeof(dir)) {    if (!(flags & LS_FLAG_A)) {    foreach(indices(dir), string f) {    if (sizeof(f) && (f[0] == '.')) {    m_delete(dir, f);    }    }
Roxen.git/server/plugins/protocols/ftp.pike:928:    foreach(indices(dir), string f) {    if ((< ".", ".." >)[f]) {    m_delete(dir, f);    }    }    }    if (flags & LS_FLAG_R) {    foreach(indices(dir), string f) {    if (!((<".","..">)[f])) {    array(mixed) st = dir[f]; -  if (st && (st[1] < 0)) { +  if (st && (st->type < 0)) {    if (short[-1] == '/') {    dir_stack->push(short + f);    } else {    dir_stack->push(short + "/" + f);    }    }    }    }    }    if (sizeof(dir)) {
Roxen.git/server/plugins/protocols/ftp.pike:1041:    conv = Locale.Charset.encoder("EBCDIC-US", "");    }       array(string) files = allocate(sizeof(argv));    int n_files;       foreach(argv, string short) {    RequestID session = RequestID2(master_session);    session->method = "LIST";    string long = fix_path(short); -  array|object st = stat_file(long, session); +  Stdio.Stat st = file_stat(long, session);    if (st) { -  if ((< -2, -3 >)[st[1]] && +  if ((< -2, -3 >)[st->type] &&    (!(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);    }
Roxen.git/server/plugins/protocols/ftp.pike:1808:       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, +  static private Stdio.Stat file_stat(string fname,    object|void session)    {    mapping file;       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, "//", "/"); -  file = conf->stat_file(fname, session); +  file = conf->file_stat(fname, session);    }    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;
Roxen.git/server/plugins/protocols/ftp.pike:1883:    send(550, ({ sprintf("'%s': %s: No such file or directory.",    cmd, f) }));    break;    }    session->conf->sent = file->len;    session->conf->log(file, session);    }       static private int open_file(string fname, object session, string cmd)    { -  object|array|mapping file; +  Stdio.Stat file = file_stat(fname, session);    -  file = stat_file(fname, session); -  +     // The caller is assumed to have made a new session object for us    // but not to set not_query in it..    session->not_query = fname;       if (objectp(file) || arrayp(file)) { -  array|object st = file; +  Stdio.Stat st = file;    file = 0; -  if (st && (st[1] < 0) && !((<"RMD", "XRMD", "CHMOD">)[cmd])) { +  if (st && (st->type < 0) && !((<"RMD", "XRMD", "CHMOD">)[cmd])) {    send(550, ({ sprintf("%s: not a plain file.", fname) }));    return 0;    }    mixed err;    if ((err = catch(file = conf->get_file(session)))) {    report_error("FTP: Error opening file \"%s\"\n"    "%s\n", fname, describe_backtrace(err));    send(550, ({ sprintf("%s: Error, can't open file.", fname) }));    return 0;    }
Roxen.git/server/plugins/protocols/ftp.pike:2329:    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);    mapping res = -  id->conf->stat_file(id->not_query, id); +  id->conf->file_stat(id->not_query, id);    destruct(id);    return res;    }, cwd, master_session);    if (sizeof(matches)) {    args[index] = matches;    }    }    }    if (stringp(args[index])) {    // No glob
Roxen.git/server/plugins/protocols/ftp.pike:2524:    }       string make_MLSD_fact(string f, mapping(string:array) dir, object session)    {    array st = dir[f];       mapping(string:string) facts = ([]);       // Construct the facts here.    -  facts["UNIX.mode"] = st[0]; +  facts["UNIX.mode"] = st->mode;    -  if (st[1] >= 0) { -  facts->size = (string)st[1]; +  if (st->type >= 0) { +  facts->size = (string)st->type;    facts->type = "File";    facts["media-type"] = session->conf->type_from_filename(f) ||    "application/octet-stream";    } else {    facts->type = ([ "..":"pdir", ".":"cdir" ])[f] || "dir";    }    -  facts->modify = make_MDTM(st[3]); +  facts->modify = make_MDTM(st->mtime);       facts->charset = "8bit";       // Construct and return the answer.       return(Array.map(indices(facts), lambda(string s, mapping f) {    return s + "=" + f[s];    }, facts) * ";" + " " + f);    }   
Roxen.git/server/plugins/protocols/ftp.pike:2809:    string home = auth_user->homedir();    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); +  Stdio.Stat st = conf->file_stat(home, session);    destruct(session);    -  if (st && (st[1] < 0)) { +  if (st && (st->type < 0)) {    cwd = home;    }    }    logged_in = 1;    send(230, ({ sprintf("User %s logged in.", user) }));    conf->log(([ "error":202 ]), master_session);    }       void ftp_CWD(string args)    {
Roxen.git/server/plugins/protocols/ftp.pike:2837:    string ncwd = fix_path(args);       if ((ncwd == "") || (ncwd[-1] != '/')) {    ncwd += "/";    }       object session = RequestID2(master_session);    session->method = "CWD";    session->not_query = ncwd;    -  array|object st = conf->stat_file(ncwd, session); +  Stdio.Stat st = conf->file_stat(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]]) { +  if (!(< -2, -3 >)[st-type]) {    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    array(string) files = conf->find_dir(cwd, session);       if (files) {    files = reverse(sort(Array.filter(files, lambda(string s) {    return(s[..5] == "README");    })));    foreach(files, string f) { -  array|object st = conf->stat_file(replace(cwd + f, "//", "/"), +  Stdio.Stat st = conf->file_stat(replace(cwd + f, "//", "/"),    session);    -  if (st && (st[1] >= 0)) { +  if (st && (st->type >= 0)) {    reply = ({ sprintf("Please read the file %s.", f),    sprintf("It was last modified %s - %d days ago.", -  ctime(st[3]) - "\n", -  (time(1) - st[3])/86400), +  ctime(st->mtime) - "\n", +  (time(1) - st->mtime)/86400),    "" }) + reply;    }    }    }    string message;    catch {    message = conf->try_get_file(cwd + ".message", session);    };    if (message) {    reply = (message/"\n")+({ "" })+reply;
Roxen.git/server/plugins/protocols/ftp.pike:3249:       static private string rename_from; // rename from       void ftp_RNFR(string args)    {    if (!expect_argument("RNFR", args)) {    return;    }    args = fix_path(args);    -  if (stat_file(args)) { +  if (file_stat(args)) {    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) }) );    }    }       void ftp_RNTO(string args)    {    if(!rename_from) {
Roxen.git/server/plugins/protocols/ftp.pike:3306:    }       void ftp_MLST(string args)    {    args = fix_path(args || ".");       RequestID session = RequestID2(master_session);       session->method = "DIR";    -  array|object st = stat_file(args, session); +  Stdio.Stat st = file_stat(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";    -  array|object st = stat_file(args, session); +  Stdio.Stat st = file_stat(args, session);    -  if (st && (st[1] < 0)) { +  if (st && (st->type < 0)) {    if (args[-1] != '/') {    args += "/";    }       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;
Roxen.git/server/plugins/protocols/ftp.pike:3383:       args = fix_path(args);       RequestID session = RequestID2(master_session);       session->data = 0;    session->misc->len = 0;    session->method = "DELETE";    session->not_query = args;    -  array|object st = stat_file(args, session); +  Stdio.Stat st = file_stat(args, session);       if (!st) {    send_error("RMD", args, session->file, session);    destruct(session);    return; -  } else if (st[1] != -2) { -  if (st[1] == -3) { +  } else if (st->type != -2) { +  if (st->type == -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;    }   
Roxen.git/server/plugins/protocols/ftp.pike:3479:    send(211, ({ "The following features are supported:" }) + a +    ({ "END" }));    }       void ftp_MDTM(string args)    {    if (!expect_argument("MDTM", args)) {    return;    }    args = fix_path(args); -  mapping|array|object st = stat_file(args); +  Stdio.Stat st = file_stat(args);       if (!arrayp(st) && !objectp(st)) {    send_error("MDTM", args, st, master_session);    } else { -  send(213, ({ make_MDTM(st[3]) })); +  send(213, ({ make_MDTM(st->mtime) }));    }    }       void ftp_SIZE(string args)    {    if (!expect_argument("SIZE", args)) {    return;    }    args = fix_path(args);    -  mapping|array|object st = stat_file(args); +  Stdio.Stat st = file_stat(args);       if (!arrayp(st) && !objectp(st)) {    send_error("SIZE", args, st, master_session);    return;    } -  int size = st[1]; +  int size = st->type;    if (size < 0) {    send_error("SIZE", args, ([ "error":405, ]), master_session);    // size = 512;    } else {    send(213, ({ (string)size }));    }    }       void ftp_STAT(string args)    {
Roxen.git/server/plugins/protocols/ftp.pike:3550:    user?sprintf("as %s", user):"anonymously",    (["A":"ASCII", "E":"EBCDIC", "I":"IMAGE", "L":"LOCAL"])    [mode],    "Non-Print",    "File",    "Stream"    )/"\n");    return;    }    string long = fix_path(args); -  mapping|array|object st = stat_file(long); +  Stdio.Stat st = file_stat(long);       if (!arrayp(st) && !objectp(st)) {    send_error("STAT", long, st, master_session);    } 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");    }