Roxen.git / server / modules / filesystems / filesystem.pike

version» Context lines:

Roxen.git/server/modules/filesystems/filesystem.pike:1:   // This is a roxen module. Copyright © 1996 - 2001, Roxen IS.      // This is a virtual "file-system".   // It will be located somewhere in the name-space of the server.   // Also inherited by some of the other filesystems.      inherit "module";   inherit "socket";    - constant cvs_version= "$Id: filesystem.pike,v 1.129 2004/05/08 14:57:03 grubba Exp $"; + constant cvs_version= "$Id: filesystem.pike,v 1.130 2004/05/09 17:59:37 grubba Exp $";   constant thread_safe=1;      #include <module.h>   #include <roxen.h>   #include <stat.h>   #include <request_trace.h>         //<locale-token project="mod_filesystem">LOCALE</locale-token>   #define LOCALE(X,Y) _DEF_LOCALE("mod_filesystem",X,Y)
Roxen.git/server/modules/filesystems/filesystem.pike:414:    dir = Array.filter(dir, dir_filter_function, id);       if (!id->misc->internal_get)    foreach (internal_files, string globstr)    dir -= glob (globstr, dir);       return dir;   }      void recursive_rm(string real_dir, string virt_dir, -  RequestID id) +  int(0..1) check_status_needed, RequestID id)   { -  TRACE_ENTER(sprintf("Deleting all files in directory %O...", real_dir), -  this_object()); +  SIMPLE_TRACE_ENTER(this, "Deleting all files in directory %O...", real_dir);    foreach(get_dir(real_dir) || ({}), string fname) {    string real_fname = combine_path(real_dir, fname);    string virt_fname = virt_dir + "/" + fname; -  +     Stat stat = file_stat(real_fname); -  TRACE_ENTER(sprintf("Deleting file %O.", real_fname), -  this_object()); +     if (!stat) {    id->set_status_for_path(virt_fname, 404);    TRACE_LEAVE("File not found.");    continue;    } -  +  SIMPLE_TRACE_ENTER(this, "Deleting %s %O.", +  stat->isdir?"directory":"file", real_fname); +  int(0..1)|mapping sub_status; +  if (check_status_needed && +  mappingp(sub_status = write_access(virt_fname, 1, id))) { +  id->set_status_for_path(virt_fname, sub_status->error); +  TRACE_LEAVE("Write access denied."); +  continue; +  }    if (stat->isdir) { -  recursive_rm(real_fname, virt_fname, id); +  recursive_rm(real_fname, virt_fname, sub_status, id);    }       /* Clear the stat-cache for this file */    if (stat_cache) {    cache_set("stat_cache", real_fname, 0);    }       if (!rm(real_fname)) {   #if constant(System.EEXIST)    if (errno() != System.EEXIST)
Roxen.git/server/modules/filesystems/filesystem.pike:638:    write_access(combine_path(coll, ".."), 0, id);    if (ret) return ret;       mkdirs++;    object privs;    SETUID_TRACE("Creating directory/collection", 0);       if (query("no_symlinks") && (contains_symlinks(path, coll))) {    privs = 0;    errors++; -  report_error(LOCALE(46,"Creation of %s failed. Permission denied.\n"), +  report_error(LOCALE(46,"Creation of %O failed. Permission denied.\n"),    coll);    TRACE_LEAVE(sprintf("%s: Contains symlinks. Permission denied",    id->method));    return http_low_answer(403, "<h2>Permission denied.</h2>");    }       werror("mkdir(%O)\n", norm_f);       int code = mkdir(norm_f);    int err_code = errno();    privs = 0;       TRACE_ENTER(sprintf("%s: Accepted", id->method), 0);       if (code) {    chmod(norm_f, 0777 & ~(id->misc->umask || 022));    TRACE_LEAVE(sprintf("%s: Success", id->method));    TRACE_LEAVE(sprintf("%s: Success", id->method)); -  if (id->method == "MKCOL") { +     return Roxen.http_low_answer(201, "Created");    } -  return Roxen.http_string_answer("Ok"); -  } +        TRACE_LEAVE(sprintf("%s: Failed", id->method));    id->misc->error_code = 507;    if (err_code ==   #if constant(system.ENOENT)    system.ENOENT   #elif constant(System.ENOENT)    System.ENOENT   #else    2
Roxen.git/server/modules/filesystems/filesystem.pike:868:    return Roxen.http_auth_required("foo",    sprintf("<h1>Permission to '%s' denied</h1>",    id->method));    }    mkdirs++;    SETUID_TRACE("Creating directory/collection", 0);       if (query("no_symlinks") && (contains_symlinks(path, oldf))) {    privs = 0;    errors++; -  report_error(LOCALE(46,"Creation of %s failed. Permission denied.\n"), +  report_error(LOCALE(46,"Creation of %O failed. Permission denied.\n"),    oldf);    TRACE_LEAVE(sprintf("%s: Contains symlinks. Permission denied",    id->method));    return http_low_answer(403, "<h2>Permission denied.</h2>");    }       code = mkdir(f);    int err_code = errno();    privs = 0;   
Roxen.git/server/modules/filesystems/filesystem.pike:943:    TRACE_LEAVE("PUT: Locked");    return ret;    }       puts++;       QUOTA_WERR("Checking quota.\n");    if (id->misc->quota_obj && (id->misc->len > 0) &&    !id->misc->quota_obj->check_quota(URI, id->misc->len)) {    errors++; -  report_warning(LOCALE(47,"Creation of %s failed. Out of quota.\n"),f); +  report_warning(LOCALE(47,"Creation of %O failed. Out of quota.\n"),f);    TRACE_LEAVE("PUT: Out of quota.");    return http_low_answer(413, "<h2>Out of disk quota.</h2>",    "413 Out of disk quota");    }    -  -  SETUID_TRACE("Saving file", 0); -  +     if (query("no_symlinks") && (contains_symlinks(path, oldf))) { -  privs = 0; +     errors++; -  report_error(LOCALE(46,"Creation of %s failed. Permission denied.\n"),f); +  report_error(LOCALE(46,"Creation of %O failed. Permission denied.\n"),f);    TRACE_LEAVE("PUT: Contains symlinks. Permission denied");    return http_low_answer(403, "<h2>Permission denied.</h2>");    }    -  +  SETUID_TRACE("Saving file", 0); +     rm(f);    mkdirhier(f);       if (id->misc->quota_obj) {    QUOTA_WERR("Checking if the file already existed.");    if (size > 0) {    QUOTA_WERR("Deallocating " + size + "bytes.");    id->misc->quota_obj->deallocate(URI, size);    }    }
Roxen.git/server/modules/filesystems/filesystem.pike:1347:    (String.trim_whites(id->request_headers->depth||"infinity") !=    "infinity")) {    // RFC 2518 8.6.2:    // The DELETE method on a collection MUST act as if a "Depth: infinity"    // header was used on it.    TRACE_LEAVE(sprintf("DELETE: Bad depth header: %O.",    id->request_headers->depth));    return http_low_answer(400, "<h2>Unsupported depth.</h2>");    }    -  // FIXME: write_access(). -  +     if (size < 0) { -  +  mapping|int(0..1) res; +  if (mappingp(res = write_access(combine_path(oldf, "../"), 1, id)) || +  (res && mappingp(res = write_access(oldf, 1, id)))) { +  SIMPLE_TRACE_LEAVE("DELETE: Recursive write access denied."); +  id->set_status_for_path(query_location()+oldf, res->error); +  return 0; +  }    report_notice(LOCALE(64,"DELETING the directory %s.\n"), f);       accesses++;       SETUID_TRACE("Deleting directory", 0);       int start_ms_size = id->multi_status_size(); -  recursive_rm(f, query_location() + oldf, id); +  recursive_rm(f, query_location() + oldf, res, id);       if (!rm(f)) {    if (id->multi_status_size() > start_ms_size) {   #if constant(system.EEXIST)    if (errno() != system.EEXIST)   #endif    {    id->set_status_for_path(query_location() + oldf, 403);    }    } else {    TRACE_LEAVE("DELETE: Failed to delete directory.");    return http_low_answer(403, "<h2>Failed to delete directory.</h2>");    }    }       if (id->multi_status_size() > start_ms_size) {    TRACE_LEAVE("DELETE: Partial failure.");    return ([]);    }    } else { -  +  mapping|int(0..1) res; +  if ((res = write_access(combine_path(oldf, "../"), 0, id)) || +  (res = write_access(oldf, 0, id))) { +  SIMPLE_TRACE_LEAVE("DELETE: Write access denied."); +  id->set_status_for_path(query_location()+oldf, res->error); +  return 0; +  } +     report_notice(LOCALE(49,"DELETING the file %s.\n"),f);       accesses++;    -  SETUID_TRACE("Deleting file", 0); -  +     /* Clear the stat-cache for this file */    if (stat_cache) {    cache_set("stat_cache", f, 0);    }    -  +  SETUID_TRACE("Deleting file", 0); +     if(!rm(f))    {    privs = 0;    id->misc->error_code = 405;    TRACE_LEAVE("DELETE: Failed");    return 0;    }    privs = 0;    deletes++;   
Roxen.git/server/modules/filesystems/filesystem.pike:1415:       default:    id->misc->error_code = 501;    TRACE_LEAVE("Not supported");    return 0;    }    TRACE_LEAVE("Not reached");    return 0;   }    - mapping copy_file(string path, string dest, int(-1..1) behavior, RequestID id) + mapping copy_file(string source, string dest, int(-1..1) behavior, +  RequestID id)   { -  SIMPLE_TRACE_ENTER(this, "COPY: Copy %O to %O.", path, dest); -  Stat source_st = stat_file(path, id); +  SIMPLE_TRACE_ENTER(this, "COPY: Copy %O to %O.", source, dest); +  Stat source_st = stat_file(source, id);    if (!source_st) {    TRACE_LEAVE("COPY: Source doesn't exist.");    return Roxen.http_low_answer(404, "File not found.");    } -  Stat dest_st = stat_file(path, id); -  if (dest_st) { -  if ((source_st->isreg != dest_st->isreg) || -  (source_st->isdir != dest_st->isdir)) { -  TRACE_LEAVE("COPY: Resource types for source and destination differ."); -  return Roxen.http_low_answer(412, "Destination and source are different resource types."); +  if (!query("put")) { +  TRACE_LEAVE("COPY: Put not allowed."); +  return Roxen.http_low_answer(405, "Not allowed.");    } -  if (source_st->isdir) { -  TRACE_LEAVE("Already done (both are directories)."); -  return Roxen.http_low_answer(204, "Destination already existed."); +  if(query("check_auth") && (!id->conf->authenticate( id ) ) ) { +  TRACE_LEAVE("COPY: Authentication required."); +  return +  Roxen.http_auth_required("foo", +  sprintf("<h1>Permission to 'COPY' denied</h1>", +  id->method));    } -  if (lower_case(id->request_headers->overwrite||"F") == "t") { +  mapping|int(0..1) res = write_access(combine_path(dest, "../"), 0, id); +  if (mappingp(res)) return res; +  string dest_path = path + dest; +  catch { dest_path = decode_path(dest_path); }; +  if (query("no_symlinks") && (contains_symlinks(path, dest_path))) { +  errors++; +  report_error(LOCALE(46,"Copy to %O failed. Permission denied.\n"), +  dest); +  TRACE_LEAVE("COPY: Contains symlinks. Permission denied"); +  return http_low_answer(403, "<h2>Permission denied.</h2>"); +  } +  Stat dest_st = stat_file(dest, id); +  if (dest_st) { +  if (id->request_headers->overwrite) { +  // Obey the overwrite header. +  if (lower_case(id->request_headers->overwrite) != "t") {    TRACE_LEAVE("COPY: Destination already exists.");    return Roxen.http_low_answer(412, "Destination already exists.");    }    if (!query("delete")) {    TRACE_LEAVE("COPY: Deletion not allowed.");    return Roxen.http_low_answer(405, "Not allowed.");    } -  +  object privs; +  SETUID_TRACE("Deleting destination", 0); +  if (dest_st->isdir) { +  recursive_rm(dest_path, mountpoint + dest, 1, id); +  if (source_st->isdir) { +  privs = 0; +  SIMPLE_TRACE_LEAVE("COPY: Cleared directory %O", dest_path); +  SIMPLE_TRACE_LEAVE("Copy done."); +  return Roxen.http_status(204);    } -  if (!query("put")) { -  TRACE_LEAVE("COPY: Put not allowed."); -  return Roxen.http_low_answer(405, "Not allowed."); +  if (!rm(dest_path)) { +  privs = 0; +  SIMPLE_TRACE_LEAVE("COPY: Delete failed."); + #if constant(system.EEXIST) +  if (errno() != system.EEXIST) + #endif +  { +  id->set_status_for_path(mountpoint + dest, 403);    } -  if(query("check_auth") && (!id->conf->authenticate( id ) ) ) { -  TRACE_LEAVE("COPY: Authentication required."); -  return Roxen.http_auth_required("foo", -  sprintf("<h1>Permission to 'COPY' denied</h1>", -  id->method)); +  } else { +  SIMPLE_TRACE_LEAVE("COPY: Delete ok.");    } -  string dest_path = path + dest; -  catch { dest_path = decode_path(dest_path); }; +  } else if (source_st->isdir) { +  if (!rm(dest_path)) { +  SIMPLE_TRACE_LEAVE("COPY: File deletion failed."); +  privs = 0; + #if constant(system.EEXIST) +  if (errno() != system.EEXIST) + #endif +  { +  id->set_status_for_path(mountpoint + dest, 403); +  } +  } else { +  SIMPLE_TRACE_LEAVE("COPY: File deletion ok."); +  } +  } else { +  SIMPLE_TRACE_LEAVE("COPY: No need to perform deletion."); +  } +  privs = 0; +  } else if ((source_st->isreg != dest_st->isreg) || +  (source_st->isdir != dest_st->isdir)) { +  TRACE_LEAVE("COPY: Resource types for source and destination differ."); +  return Roxen.http_low_answer(412, "Destination and source are different resource types."); +  } else if (source_st->isdir) { +  TRACE_LEAVE("Already done (both are directories)."); +  return Roxen.http_low_answer(204, "Destination already existed."); +  } +  }    if (source_st->isdir) {    mkdirs++;    object privs;    SETUID_TRACE("Creating directory/collection", 0);    -  if (query("no_symlinks") && (contains_symlinks(path, dest))) { -  privs = 0; -  errors++; -  report_error(LOCALE(46,"Creation of %s failed. Permission denied.\n"), -  dest); -  TRACE_LEAVE("COPY: Contains symlinks. Permission denied"); -  return http_low_answer(403, "<h2>Permission denied.</h2>"); -  } -  +     int code = mkdir(dest_path);    int err_code = errno();    privs = 0;    TRACE_ENTER("COPY: Accepted", this_object());       if (code) {    chmod(dest_path, 0777 & ~(id->misc->umask || 022));    TRACE_LEAVE("COPY: Success");    TRACE_LEAVE("Success"); -  return http_low_answer(201, "Created"); +  return http_low_answer(dest_st?204:201, "Created");    } else {    TRACE_LEAVE("COPY: Failed");    TRACE_LEAVE("Failure");    if (err_code ==   #if constant(system.ENOENT)    system.ENOENT   #elif constant(System.ENOENT)    System.ENOENT   #else    2   #endif    ) {    return http_low_answer(409, "Missing intermediate.");    } else {    return http_low_answer(507, "Failed.");    }    }    } else { -  TRACE_LEAVE("COPY: is file. Not supported yet."); -  return Roxen.http_status(Protocols.HTTP.HTTP_NOT_IMPL); +  if (res = write_access(dest, 0, id)) { +  SIMPLE_TRACE_LEAVE("COPY: Write access to file %O denied.", dest); +  return res;    } -  +  string source_path = path + source; +  catch { source_path = decode_path(source_path); }; +  if (query("no_symlinks") && (contains_symlinks(path, source_path))) { +  errors++; +  report_error(LOCALE(46,"Copy to %O failed. Permission denied.\n"), +  dest); +  TRACE_LEAVE("COPY: Contains symlinks. Permission denied"); +  return http_low_answer(403, "<h2>Permission denied.</h2>");    } -  +  puts++;    -  +  QUOTA_WERR("Checking quota.\n"); +  if (id->misc->quota_obj && (id->misc->len > 0) && +  !id->misc->quota_obj->check_quota(mountpoint + dest, +  source_st->size)) { +  errors++; +  report_warning(LOCALE(47,"Creation of %O failed. Out of quota.\n"), +  dest_path); +  TRACE_LEAVE("PUT: Out of quota."); +  return http_low_answer(413, "<h2>Out of disk quota.</h2>", +  "413 Out of disk quota"); +  } +  object source_file = open(source_path, "r"); +  if (!source_file) { +  TRACE_LEAVE("Failed to open source file."); +  return Roxen.http_status(404); +  } +  object privs; +  SIMPLE_TRACE_ENTER(this, "COPY: Copying file."); +  object dest_file = open(dest_path, "cwt"); +  privs = 0; +  if (!dest_file) { +  TRACE_LEAVE("Failed to open destination file."); +  TRACE_LEAVE("Copy failed."); +  return Roxen.http_status(403); +  } +  int len = source_st->size; +  while (len > 0) { +  string buf = source_file->read((len > 4096)?4096:len); +  if (buf && sizeof(buf)) { +  int sub_len; +  len -= (sub_len = sizeof(buf)); +  while (sub_len > 0) { +  int written = dest_file->write(buf); +  if ((sub_len -= written) > 0) { +  if (!written) { +  SIMPLE_TRACE_LEAVE("Write failed with errno %d", +  dest_file->errno()); +  dest_file->close(); +  source_file->close(); +  SIMPLE_TRACE_LEAVE("Insufficient storage."); +  return Roxen.http_status(Protocols.HTTP.DAV_STORAGE_FULL); +  } +  buf = buf[written..]; +  } +  } +  } else { +  break; +  } +  } +  if (len > 0) { +  SIMPLE_TRACE_LEAVE("Read failed with %d bytes left.", len); +  } else { +  SIMPLE_TRACE_LEAVE("Copy complete."); +  } +  dest_file->close(); +  source_file->close(); +  TRACE_LEAVE("Copy ok."); +  return Roxen.http_status(dest_st?Protocols.HTTP.HTTP_NO_CONTENT: +  Protocols.HTTP.HTTP_CREATED); +  } + } +    string query_name()   {    if (sizeof(path) > 20) {    return sprintf((string)LOCALE(63,"%s from %s...%s"),    mountpoint, path[..7], path[sizeof(path)-8..]);    }    return sprintf((string)LOCALE(50,"%s from %s"), mountpoint, path);   }