Diff for /embedaddon/lighttpd/src/mod_webdav.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2014/06/15 20:20:06 version 1.1.1.3, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "base.h"  #include "base.h"
 #include "log.h"  #include "log.h"
 #include "buffer.h"  #include "buffer.h"
 #include "response.h"  #include "response.h"
   #include "connections.h"
   
 #include "plugin.h"  #include "plugin.h"
   
Line 120  FREE_FUNC(mod_webdav_free) { Line 123  FREE_FUNC(mod_webdav_free) {
                 for (i = 0; i < srv->config_context->used; i++) {                  for (i = 0; i < srv->config_context->used; i++) {
                         plugin_config *s = p->config_storage[i];                          plugin_config *s = p->config_storage[i];
   
                        if (!s) continue;                        if (NULL == s) continue;
   
                         buffer_free(s->sqlite_db_name);                          buffer_free(s->sqlite_db_name);
 #ifdef USE_PROPPATCH  #ifdef USE_PROPPATCH
Line 182  SETDEFAULTS_FUNC(mod_webdav_set_defaults) { Line 185  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
         p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));          p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
   
         for (i = 0; i < srv->config_context->used; i++) {          for (i = 0; i < srv->config_context->used; i++) {
                   data_config const* config = (data_config const*)srv->config_context->data[i];
                 plugin_config *s;                  plugin_config *s;
   
                 s = calloc(1, sizeof(plugin_config));                  s = calloc(1, sizeof(plugin_config));
Line 194  SETDEFAULTS_FUNC(mod_webdav_set_defaults) { Line 198  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
   
                 p->config_storage[i] = s;                  p->config_storage[i] = s;
   
                if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {                if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
                         return HANDLER_ERROR;                          return HANDLER_ERROR;
                 }                  }
   
                if (!buffer_is_empty(s->sqlite_db_name)) {                if (!buffer_string_is_empty(s->sqlite_db_name)) {
 #ifdef USE_PROPPATCH  #ifdef USE_PROPPATCH
                         const char *next_stmt;                          const char *next_stmt;
                         char *err;                          char *err;
Line 211  SETDEFAULTS_FUNC(mod_webdav_set_defaults) { Line 215  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
                         }                          }
   
                         if (SQLITE_OK != sqlite3_exec(s->sql,                          if (SQLITE_OK != sqlite3_exec(s->sql,
                                        "CREATE TABLE properties ("                                        "CREATE TABLE IF NOT EXISTS properties ("
                                         "  resource TEXT NOT NULL,"                                          "  resource TEXT NOT NULL,"
                                         "  prop TEXT NOT NULL,"                                          "  prop TEXT NOT NULL,"
                                         "  ns TEXT NOT NULL,"                                          "  ns TEXT NOT NULL,"
Line 228  SETDEFAULTS_FUNC(mod_webdav_set_defaults) { Line 232  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
                                 sqlite3_free(err);                                  sqlite3_free(err);
                         }                          }
   
                           if (SQLITE_OK != sqlite3_exec(s->sql,
                                           "CREATE TABLE IF NOT EXISTS locks ("
                                           "  locktoken TEXT NOT NULL,"
                                           "  resource TEXT NOT NULL,"
                                           "  lockscope TEXT NOT NULL,"
                                           "  locktype TEXT NOT NULL,"
                                           "  owner TEXT NOT NULL,"
                                           "  depth INT NOT NULL,"
                                           "  timeout TIMESTAMP NOT NULL,"
                                           "  PRIMARY KEY(locktoken))",
                                           NULL, NULL, &err)) {
   
                                   if (0 != strcmp(err, "table locks already exists")) {
                                           log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
                                           sqlite3_free(err);
   
                                           return HANDLER_ERROR;
                                   }
                                   sqlite3_free(err);
                           }
   
                         if (SQLITE_OK != sqlite3_prepare(s->sql,                          if (SQLITE_OK != sqlite3_prepare(s->sql,
                                 CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),                                  CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
                                 &(s->stmt_select_prop), &next_stmt)) {                                  &(s->stmt_select_prop), &next_stmt)) {
Line 284  SETDEFAULTS_FUNC(mod_webdav_set_defaults) { Line 309  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
                         }                          }
   
                         if (SQLITE_OK != sqlite3_prepare(s->sql,                          if (SQLITE_OK != sqlite3_prepare(s->sql,
                                CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),                                CONST_STR_LEN("UPDATE OR REPLACE properties SET resource = ? WHERE resource = ?"),
                                 &(s->stmt_move_uri), &next_stmt)) {                                  &(s->stmt_move_uri), &next_stmt)) {
                                 /* prepare failed */                                  /* prepare failed */
                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));                                  log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
Line 294  SETDEFAULTS_FUNC(mod_webdav_set_defaults) { Line 319  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
   
                         /* LOCKS */                          /* LOCKS */
   
                         if (SQLITE_OK != sqlite3_exec(s->sql,  
                                         "CREATE TABLE locks ("  
                                         "  locktoken TEXT NOT NULL,"  
                                         "  resource TEXT NOT NULL,"  
                                         "  lockscope TEXT NOT NULL,"  
                                         "  locktype TEXT NOT NULL,"  
                                         "  owner TEXT NOT NULL,"  
                                         "  depth INT NOT NULL,"  
                                         "  timeout TIMESTAMP NOT NULL,"  
                                         "  PRIMARY KEY(locktoken))",  
                                         NULL, NULL, &err)) {  
   
                                 if (0 != strcmp(err, "table locks already exists")) {  
                                         log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);  
                                         sqlite3_free(err);  
   
                                         return HANDLER_ERROR;  
                                 }  
                                 sqlite3_free(err);  
                         }  
   
                         if (SQLITE_OK != sqlite3_prepare(s->sql,                          if (SQLITE_OK != sqlite3_prepare(s->sql,
                                 CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),                                  CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
                                 &(s->stmt_create_lock), &next_stmt)) {                                  &(s->stmt_create_lock), &next_stmt)) {
Line 334  SETDEFAULTS_FUNC(mod_webdav_set_defaults) { Line 338  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
                         }                          }
   
                         if (SQLITE_OK != sqlite3_prepare(s->sql,                          if (SQLITE_OK != sqlite3_prepare(s->sql,
                                CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),                                CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout-CURRENT_TIME FROM locks WHERE locktoken = ?"),
                                 &(s->stmt_read_lock), &next_stmt)) {                                  &(s->stmt_read_lock), &next_stmt)) {
                                 /* prepare failed */                                  /* prepare failed */
                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));                                  log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
Line 343  SETDEFAULTS_FUNC(mod_webdav_set_defaults) { Line 347  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
                         }                          }
   
                         if (SQLITE_OK != sqlite3_prepare(s->sql,                          if (SQLITE_OK != sqlite3_prepare(s->sql,
                                CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),                                CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout-CURRENT_TIME FROM locks WHERE resource = ?"),
                                 &(s->stmt_read_lock_by_uri), &next_stmt)) {                                  &(s->stmt_read_lock_by_uri), &next_stmt)) {
                                 /* prepare failed */                                  /* prepare failed */
                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));                                  log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
Line 446  URIHANDLER_FUNC(mod_webdav_uri_handler) { Line 450  URIHANDLER_FUNC(mod_webdav_uri_handler) {
   
         UNUSED(srv);          UNUSED(srv);
   
        if (con->uri.path->used == 0) return HANDLER_GO_ON;        if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
   
         mod_webdav_patch_connection(srv, con, p);          mod_webdav_patch_connection(srv, con, p);
   
Line 519  static int webdav_gen_response_status_tag(server *srv, Line 523  static int webdav_gen_response_status_tag(server *srv,
         } else {          } else {
                 buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));                  buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
         }          }
        buffer_append_long(b, status);        buffer_append_int(b, status);
         buffer_append_string_len(b, CONST_STR_LEN(" "));          buffer_append_string_len(b, CONST_STR_LEN(" "));
         buffer_append_string(b, get_http_status_name(status));          buffer_append_string(b, get_http_status_name(status));
   
Line 558  static int webdav_delete_file(server *srv, connection  Line 562  static int webdav_delete_file(server *srv, connection 
                         /* bind the values to the insert */                          /* bind the values to the insert */
   
                         sqlite3_bind_text(stmt, 1,                          sqlite3_bind_text(stmt, 1,
                                          dst->rel_path->ptr,                                CONST_BUF_LEN(dst->rel_path),
                                          dst->rel_path->used - 1,                                SQLITE_TRANSIENT);
                                          SQLITE_TRANSIENT); 
   
                         if (SQLITE_DONE != sqlite3_step(stmt)) {                          if (SQLITE_DONE != sqlite3_step(stmt)) {
                                 /* */                                  /* */
Line 590  static int webdav_delete_dir(server *srv, connection * Line 593  static int webdav_delete_dir(server *srv, connection *
                         int status = 0;                          int status = 0;
   
                         if ((de->d_name[0] == '.' && de->d_name[1] == '\0')  ||                          if ((de->d_name[0] == '.' && de->d_name[1] == '\0')  ||
                            (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {                          (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
                                 continue;                                  continue;
                                 /* ignore the parent dir */                                  /* ignore the parent dir */
                         }                          }
   
                        buffer_copy_string_buffer(d.path, dst->path);                        buffer_copy_buffer(d.path, dst->path);
                        BUFFER_APPEND_SLASH(d.path);                        buffer_append_slash(d.path);
                         buffer_append_string(d.path, de->d_name);                          buffer_append_string(d.path, de->d_name);
   
                        buffer_copy_string_buffer(d.rel_path, dst->rel_path);                        buffer_copy_buffer(d.rel_path, dst->rel_path);
                        BUFFER_APPEND_SLASH(d.rel_path);                        buffer_append_slash(d.rel_path);
                         buffer_append_string(d.rel_path, de->d_name);                          buffer_append_string(d.rel_path, de->d_name);
   
                         /* stat and unlink afterwards */                          /* stat and unlink afterwards */
Line 636  static int webdav_delete_dir(server *srv, connection * Line 639  static int webdav_delete_dir(server *srv, connection *
                                                 /* bind the values to the insert */                                                  /* bind the values to the insert */
   
                                                 sqlite3_bind_text(stmt, 1,                                                  sqlite3_bind_text(stmt, 1,
                                                                  d.rel_path->ptr,                                                        CONST_BUF_LEN(d.rel_path),
                                                                  d.rel_path->used - 1,                                                        SQLITE_TRANSIENT);
                                                                  SQLITE_TRANSIENT); 
   
                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {                                                  if (SQLITE_DONE != sqlite3_step(stmt)) {
                                                         /* */                                                          /* */
Line 659  static int webdav_delete_dir(server *srv, connection * Line 661  static int webdav_delete_dir(server *srv, connection *
         return have_multi_status;          return have_multi_status;
 }  }
   
   /* don't want to block when open()ing a fifo */
   #if defined(O_NONBLOCK)
   # define FIFO_NONBLOCK O_NONBLOCK
   #else
   # define FIFO_NONBLOCK 0
   #endif
   
   #ifndef O_BINARY
   #define O_BINARY 0
   #endif
   
 static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physical *src, physical *dst, int overwrite) {  static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physical *src, physical *dst, int overwrite) {
        stream s;        char *data;
        int status = 0, ofd;        ssize_t rd, wr, offset;
         int status = 0, ifd, ofd;
         UNUSED(srv);          UNUSED(srv);
         UNUSED(con);          UNUSED(con);
   
        if (stream_open(&s, src->path)) {        if (-1 == (ifd = open(src->path->ptr, O_RDONLY | O_BINARY | FIFO_NONBLOCK))) {
                 return 403;                  return 403;
         }          }
   
Line 686  static int webdav_copy_file(server *srv, connection *c Line 700  static int webdav_copy_file(server *srv, connection *c
                         status = 403;                          status = 403;
                         break;                          break;
                 }                  }
                stream_close(&s);                close(ifd);
                 return status;                  return status;
         }          }
   
        if (-1 == write(ofd, s.start, s.size)) {        data = malloc(131072);
                switch(errno) {        force_assert(data);
                case ENOSPC:
                        status = 507;        while (0 < (rd = read(ifd, data, 131072))) {
                 offset = 0;
                 do {
                         wr = write(ofd, data+offset, (size_t)(rd-offset));
                 } while (wr >= 0 ? (offset += wr) != rd : (errno == EINTR));
                 if (-1 == wr) {
                         status = (errno == ENOSPC) ? 507 : 403;
                         break;                          break;
                 default:  
                         status = 403;  
                         break;  
                 }                  }
   
         }          }
           if (0 != rd && 0 == status) status = 403;
   
        stream_close(&s);        free(data);
        close(ofd);        close(ifd);
         if (0 != close(ofd)) {
                 if (0 == status) status = (errno == ENOSPC) ? 507 : 403;
                 log_error_write(srv, __FILE__, __LINE__, "sbss",
                                 "close ", dst->path, "failed: ", strerror(errno));
         }
   
 #ifdef USE_PROPPATCH  #ifdef USE_PROPPATCH
         if (0 == status) {          if (0 == status) {
Line 714  static int webdav_copy_file(server *srv, connection *c Line 738  static int webdav_copy_file(server *srv, connection *c
   
                         /* bind the values to the insert */                          /* bind the values to the insert */
                         sqlite3_bind_text(stmt, 1,                          sqlite3_bind_text(stmt, 1,
                                          dst->rel_path->ptr,                                CONST_BUF_LEN(dst->rel_path),
                                          dst->rel_path->used - 1,                                SQLITE_TRANSIENT);
                                          SQLITE_TRANSIENT); 
   
                         sqlite3_bind_text(stmt, 2,                          sqlite3_bind_text(stmt, 2,
                                          src->rel_path->ptr,                                CONST_BUF_LEN(src->rel_path),
                                          src->rel_path->used - 1,                                SQLITE_TRANSIENT);
                                          SQLITE_TRANSIENT); 
   
                         if (SQLITE_DONE != sqlite3_step(stmt)) {                          if (SQLITE_DONE != sqlite3_step(stmt)) {
                                 /* */                                  /* */
Line 751  static int webdav_copy_dir(server *srv, connection *co Line 773  static int webdav_copy_dir(server *srv, connection *co
                 while (NULL != (de = readdir(srcdir))) {                  while (NULL != (de = readdir(srcdir))) {
                         struct stat st;                          struct stat st;
   
                        if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||                        if ((de->d_name[0] == '.' && de->d_name[1] == '\0')
                            (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {                                || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
                                 continue;                                  continue;
                         }                          }
   
                        buffer_copy_string_buffer(s.path, src->path);                        buffer_copy_buffer(s.path, src->path);
                        BUFFER_APPEND_SLASH(s.path);                        buffer_append_slash(s.path);
                         buffer_append_string(s.path, de->d_name);                          buffer_append_string(s.path, de->d_name);
   
                        buffer_copy_string_buffer(d.path, dst->path);                        buffer_copy_buffer(d.path, dst->path);
                        BUFFER_APPEND_SLASH(d.path);                        buffer_append_slash(d.path);
                         buffer_append_string(d.path, de->d_name);                          buffer_append_string(d.path, de->d_name);
   
                        buffer_copy_string_buffer(s.rel_path, src->rel_path);                        buffer_copy_buffer(s.rel_path, src->rel_path);
                        BUFFER_APPEND_SLASH(s.rel_path);                        buffer_append_slash(s.rel_path);
                         buffer_append_string(s.rel_path, de->d_name);                          buffer_append_string(s.rel_path, de->d_name);
   
                        buffer_copy_string_buffer(d.rel_path, dst->rel_path);                        buffer_copy_buffer(d.rel_path, dst->rel_path);
                        BUFFER_APPEND_SLASH(d.rel_path);                        buffer_append_slash(d.rel_path);
                         buffer_append_string(d.rel_path, de->d_name);                          buffer_append_string(d.rel_path, de->d_name);
   
                         if (-1 == stat(s.path->ptr, &st)) {                          if (-1 == stat(s.path->ptr, &st)) {
Line 793  static int webdav_copy_dir(server *srv, connection *co Line 815  static int webdav_copy_dir(server *srv, connection *co
   
                                                 /* bind the values to the insert */                                                  /* bind the values to the insert */
                                                 sqlite3_bind_text(stmt, 1,                                                  sqlite3_bind_text(stmt, 1,
                                                          dst->rel_path->ptr,                                                        CONST_BUF_LEN(dst->rel_path),
                                                          dst->rel_path->used - 1,                                                        SQLITE_TRANSIENT);
                                                          SQLITE_TRANSIENT); 
   
                                                 sqlite3_bind_text(stmt, 2,                                                  sqlite3_bind_text(stmt, 2,
                                                          src->rel_path->ptr,                                                        CONST_BUF_LEN(src->rel_path),
                                                          src->rel_path->used - 1,                                                        SQLITE_TRANSIENT);
                                                          SQLITE_TRANSIENT); 
   
                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {                                                  if (SQLITE_DONE != sqlite3_step(stmt)) {
                                                         /* */                                                          /* */
Line 827  static int webdav_copy_dir(server *srv, connection *co Line 847  static int webdav_copy_dir(server *srv, connection *co
         return status;          return status;
 }  }
   
   #ifdef USE_LOCKS
   static void webdav_activelock(buffer *b,
                   const buffer *locktoken, const char *lockscope, const char *locktype, int depth, int timeout) {
           buffer_append_string_len(b, CONST_STR_LEN("<D:activelock>\n"));
   
           buffer_append_string_len(b, CONST_STR_LEN("<D:lockscope>"));
           buffer_append_string_len(b, CONST_STR_LEN("<D:"));
           buffer_append_string(b, lockscope);
           buffer_append_string_len(b, CONST_STR_LEN("/>"));
           buffer_append_string_len(b, CONST_STR_LEN("</D:lockscope>\n"));
   
           buffer_append_string_len(b, CONST_STR_LEN("<D:locktype>"));
           buffer_append_string_len(b, CONST_STR_LEN("<D:"));
           buffer_append_string(b, locktype);
           buffer_append_string_len(b, CONST_STR_LEN("/>"));
           buffer_append_string_len(b, CONST_STR_LEN("</D:locktype>\n"));
   
           buffer_append_string_len(b, CONST_STR_LEN("<D:depth>"));
           buffer_append_string(b, depth == 0 ? "0" : "infinity");
           buffer_append_string_len(b, CONST_STR_LEN("</D:depth>\n"));
   
           buffer_append_string_len(b, CONST_STR_LEN("<D:timeout>"));
           buffer_append_string_len(b, CONST_STR_LEN("Second-"));
           buffer_append_int(b, timeout);
           buffer_append_string_len(b, CONST_STR_LEN("</D:timeout>\n"));
   
           buffer_append_string_len(b, CONST_STR_LEN("<D:owner>"));
           buffer_append_string_len(b, CONST_STR_LEN("</D:owner>\n"));
   
           buffer_append_string_len(b, CONST_STR_LEN("<D:locktoken>"));
           buffer_append_string_len(b, CONST_STR_LEN("<D:href>"));
           buffer_append_string_buffer(b, locktoken);
           buffer_append_string_len(b, CONST_STR_LEN("</D:href>"));
           buffer_append_string_len(b, CONST_STR_LEN("</D:locktoken>\n"));
   
           buffer_append_string_len(b, CONST_STR_LEN("</D:activelock>\n"));
   }
   
   static void webdav_get_live_property_lockdiscovery(server *srv, connection *con, plugin_data *p, physical *dst, buffer *b) {
   
           sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
           if (!stmt) { /*(should not happen)*/
                   buffer_append_string_len(b, CONST_STR_LEN("<D:lockdiscovery>\n</D:lockdiscovery>\n"));
                   return;
           }
           UNUSED(srv);
           UNUSED(con);
   
           /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
            *   FROM locks
            *  WHERE resource = ? */
   
           sqlite3_reset(stmt);
   
           sqlite3_bind_text(stmt, 1,
                   CONST_BUF_LEN(dst->rel_path),
                   SQLITE_TRANSIENT);
   
           buffer_append_string_len(b, CONST_STR_LEN("<D:lockdiscovery>\n"));
           while (SQLITE_ROW == sqlite3_step(stmt)) {
                   const char *lockscope = (const char *)sqlite3_column_text(stmt, 2);
                   const char *locktype  = (const char *)sqlite3_column_text(stmt, 3);
                   const int depth       =               sqlite3_column_int(stmt, 5);
                   const int timeout     =               sqlite3_column_int(stmt, 6);
                   buffer locktoken = { NULL, 0, 0 };
                   locktoken.ptr         =       (char *)sqlite3_column_text(stmt, 0);
                   locktoken.used        =               sqlite3_column_bytes(stmt, 0);
                   if (locktoken.used) ++locktoken.used;
                   locktoken.size = locktoken.used;
   
                   if (timeout > 0) {
                           webdav_activelock(b, &locktoken, lockscope, locktype, depth, timeout);
                   }
           }
           buffer_append_string_len(b, CONST_STR_LEN("</D:lockdiscovery>\n"));
   }
   #endif
   
 static int webdav_get_live_property(server *srv, connection *con, plugin_data *p, physical *dst, char *prop_name, buffer *b) {  static int webdav_get_live_property(server *srv, connection *con, plugin_data *p, physical *dst, char *prop_name, buffer *b) {
         stat_cache_entry *sce = NULL;          stat_cache_entry *sce = NULL;
         int found = 0;          int found = 0;
Line 841  static int webdav_get_live_property(server *srv, conne Line 939  static int webdav_get_live_property(server *srv, conne
                 if (0 == strcmp(prop_name, "resourcetype")) {                  if (0 == strcmp(prop_name, "resourcetype")) {
                         if (S_ISDIR(sce->st.st_mode)) {                          if (S_ISDIR(sce->st.st_mode)) {
                                 buffer_append_string_len(b, CONST_STR_LEN("<D:resourcetype><D:collection/></D:resourcetype>"));                                  buffer_append_string_len(b, CONST_STR_LEN("<D:resourcetype><D:collection/></D:resourcetype>"));
                                found = 1;                        } else {
                                 buffer_append_string_len(b, CONST_STR_LEN("<D:resourcetype/>"));
                         }                          }
                           found = 1;
                 } else if (0 == strcmp(prop_name, "getcontenttype")) {                  } else if (0 == strcmp(prop_name, "getcontenttype")) {
                         if (S_ISDIR(sce->st.st_mode)) {                          if (S_ISDIR(sce->st.st_mode)) {
                                 buffer_append_string_len(b, CONST_STR_LEN("<D:getcontenttype>httpd/unix-directory</D:getcontenttype>"));                                  buffer_append_string_len(b, CONST_STR_LEN("<D:getcontenttype>httpd/unix-directory</D:getcontenttype>"));
Line 851  static int webdav_get_live_property(server *srv, conne Line 951  static int webdav_get_live_property(server *srv, conne
                                 for (k = 0; k < con->conf.mimetypes->used; k++) {                                  for (k = 0; k < con->conf.mimetypes->used; k++) {
                                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];                                          data_string *ds = (data_string *)con->conf.mimetypes->data[k];
   
                                        if (ds->key->used == 0) continue;                                        if (buffer_is_empty(ds->key)) continue;
   
                                        if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {                                        if (buffer_is_equal_right_len(dst->path, ds->key, buffer_string_length(ds->key))) {
                                                 buffer_append_string_len(b,CONST_STR_LEN("<D:getcontenttype>"));                                                  buffer_append_string_len(b,CONST_STR_LEN("<D:getcontenttype>"));
                                                 buffer_append_string_buffer(b, ds->value);                                                  buffer_append_string_buffer(b, ds->value);
                                                 buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));                                                  buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));
Line 877  static int webdav_get_live_property(server *srv, conne Line 977  static int webdav_get_live_property(server *srv, conne
                         found = 1;                          found = 1;
                 } else if (0 == strcmp(prop_name, "getcontentlength")) {                  } else if (0 == strcmp(prop_name, "getcontentlength")) {
                         buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlength>"));                          buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlength>"));
                        buffer_append_off_t(b, sce->st.st_size);                        buffer_append_int(b, sce->st.st_size);
                         buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlength>"));                          buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlength>"));
                         found = 1;                          found = 1;
                 } else if (0 == strcmp(prop_name, "getcontentlanguage")) {                  } else if (0 == strcmp(prop_name, "getcontentlanguage")) {
Line 885  static int webdav_get_live_property(server *srv, conne Line 985  static int webdav_get_live_property(server *srv, conne
                         buffer_append_string_len(b, CONST_STR_LEN("en"));                          buffer_append_string_len(b, CONST_STR_LEN("en"));
                         buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlanguage>"));                          buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlanguage>"));
                         found = 1;                          found = 1;
                   } else if (0 == strcmp(prop_name, "getetag")) {
                           etag_create(con->physical.etag, &sce->st, con->etag_flags);
                           buffer_append_string_len(b, CONST_STR_LEN("<D:getetag>"));
                           buffer_append_string_buffer(b, con->physical.etag);
                           buffer_append_string_len(b, CONST_STR_LEN("</D:getetag>"));
                           buffer_reset(con->physical.etag);
                           found = 1;
                 #ifdef USE_LOCKS
                   } else if (0 == strcmp(prop_name, "lockdiscovery")) {
                           webdav_get_live_property_lockdiscovery(srv, con, p, dst, b);
                           found = 1;
                   } else if (0 == strcmp(prop_name, "supportedlock")) {
                           buffer_append_string_len(b,CONST_STR_LEN("<D:supportedlock>"));
                           buffer_append_string_len(b,CONST_STR_LEN("<D:lockentry>"));
                           buffer_append_string_len(b,CONST_STR_LEN("<D:lockscope><D:exclusive/></D:lockscope>"));
                           buffer_append_string_len(b,CONST_STR_LEN("<D:locktype><D:write/></D:locktype>"));
                           buffer_append_string_len(b,CONST_STR_LEN("</D:lockentry>"));
                           buffer_append_string_len(b, CONST_STR_LEN("</D:supportedlock>"));
                           found = 1;
                 #endif
                 }                  }
         }          }
   
Line 907  static int webdav_get_property(server *srv, connection Line 1027  static int webdav_get_property(server *srv, connection
                         /* bind the values to the insert */                          /* bind the values to the insert */
   
                         sqlite3_bind_text(stmt, 1,                          sqlite3_bind_text(stmt, 1,
                                          dst->rel_path->ptr,                                CONST_BUF_LEN(dst->rel_path),
                                          dst->rel_path->used - 1,                                SQLITE_TRANSIENT);
                                          SQLITE_TRANSIENT); 
                         sqlite3_bind_text(stmt, 2,                          sqlite3_bind_text(stmt, 2,
                                          prop_name,                                prop_name,
                                          strlen(prop_name),                                strlen(prop_name),
                                          SQLITE_TRANSIENT);                                SQLITE_TRANSIENT);
                         sqlite3_bind_text(stmt, 3,                          sqlite3_bind_text(stmt, 3,
                                          prop_ns,                                prop_ns,
                                          strlen(prop_ns),                                strlen(prop_ns),
                                          SQLITE_TRANSIENT);                                SQLITE_TRANSIENT);
   
                         /* it is the PK */                          /* it is the PK */
                         while (SQLITE_ROW == sqlite3_step(stmt)) {                          while (SQLITE_ROW == sqlite3_step(stmt)) {
Line 941  typedef struct { Line 1060  typedef struct {
   
 static webdav_property live_properties[] = {  static webdav_property live_properties[] = {
         { "DAV:", "creationdate" },          { "DAV:", "creationdate" },
        { "DAV:", "displayname" },        /*{ "DAV:", "displayname" },*//*(not implemented)*/
         { "DAV:", "getcontentlanguage" },          { "DAV:", "getcontentlanguage" },
         { "DAV:", "getcontentlength" },          { "DAV:", "getcontentlength" },
         { "DAV:", "getcontenttype" },          { "DAV:", "getcontenttype" },
         { "DAV:", "getetag" },          { "DAV:", "getetag" },
         { "DAV:", "getlastmodified" },          { "DAV:", "getlastmodified" },
         { "DAV:", "resourcetype" },          { "DAV:", "resourcetype" },
           /*{ "DAV:", "source" },*//*(not implemented)*/
         #ifdef USE_LOCKS
         { "DAV:", "lockdiscovery" },          { "DAV:", "lockdiscovery" },
         { "DAV:", "source" },  
         { "DAV:", "supportedlock" },          { "DAV:", "supportedlock" },
         #endif
   
         { NULL, NULL }          { NULL, NULL }
 };  };
Line 965  typedef struct { Line 1086  typedef struct {
 static int webdav_get_props(server *srv, connection *con, plugin_data *p, physical *dst, webdav_properties *props, buffer *b_200, buffer *b_404) {  static int webdav_get_props(server *srv, connection *con, plugin_data *p, physical *dst, webdav_properties *props, buffer *b_200, buffer *b_404) {
         size_t i;          size_t i;
   
        if (props) {        if (props && props->used) {
                 for (i = 0; i < props->used; i++) {                  for (i = 0; i < props->used; i++) {
                         webdav_property *prop;                          webdav_property *prop;
   
Line 1003  static int webdav_parse_chunkqueue(server *srv, connec Line 1124  static int webdav_parse_chunkqueue(server *srv, connec
         for (c = cq->first; cq->bytes_out != cq->bytes_in; c = cq->first) {          for (c = cq->first; cq->bytes_out != cq->bytes_in; c = cq->first) {
                 size_t weWant = cq->bytes_out - cq->bytes_in;                  size_t weWant = cq->bytes_out - cq->bytes_in;
                 size_t weHave;                  size_t weHave;
                   int mapped;
                   void *data;
   
                 switch(c->type) {                  switch(c->type) {
                 case FILE_CHUNK:                  case FILE_CHUNK:
Line 1011  static int webdav_parse_chunkqueue(server *srv, connec Line 1134  static int webdav_parse_chunkqueue(server *srv, connec
                         if (weHave > weWant) weHave = weWant;                          if (weHave > weWant) weHave = weWant;
   
                         /* xml chunks are always memory, mmap() is our friend */                          /* xml chunks are always memory, mmap() is our friend */
                        if (c->file.mmap.start == MAP_FAILED) {                        mapped = (c->file.mmap.start != MAP_FAILED);
                         if (mapped) {
                                 data = c->file.mmap.start + c->offset;
                         } else {
                                 if (-1 == c->file.fd &&  /* open the file if not already open */                                  if (-1 == c->file.fd &&  /* open the file if not already open */
                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {                                      -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));                                          log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
Line 1019  static int webdav_parse_chunkqueue(server *srv, connec Line 1145  static int webdav_parse_chunkqueue(server *srv, connec
                                         return -1;                                          return -1;
                                 }                                  }
   
                                if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {                                if (MAP_FAILED != (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_PRIVATE, c->file.fd, 0))) {
                                        log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",                                        /* chunk_reset() or chunk_free() will cleanup for us */
                                                        strerror(errno), c->file.name,  c->file.fd);                                        c->file.mmap.length = c->file.length;
                                        close(c->file.fd);                                        data = c->file.mmap.start + c->offset;
                                        c->file.fd = -1;                                        mapped = 1;
                                } else {
                                        return -1;                                        ssize_t rd;
                                         if (weHave > 65536) weHave = 65536;
                                         data = malloc(weHave);
                                         force_assert(data);
                                         if (-1 == lseek(c->file.fd, c->file.start + c->offset, SEEK_SET)
                                             || 0 > (rd = read(c->file.fd, data, weHave))) {
                                                 log_error_write(srv, __FILE__, __LINE__, "ssbd", "lseek/read failed: ",
                                                                 strerror(errno), c->file.name, c->file.fd);
                                                 free(data);
                                                 return -1;
                                         }
                                         weHave = (size_t)rd;
                                 }                                  }
   
                                 close(c->file.fd);  
                                 c->file.fd = -1;  
   
                                 c->file.mmap.length = c->file.length;  
   
                                 /* chunk_reset() or chunk_free() will cleanup for us */  
                         }                          }
   
                        if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {                        if (XML_ERR_OK != (err = xmlParseChunk(ctxt, data, weHave, 0))) {
                                 log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);                                  log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
                         }                          }
   
                        c->offset += weHave;                        chunkqueue_mark_written(cq, weHave);
                        cq->bytes_out += weHave; 
   
                           if (!mapped) free(data);
                         break;                          break;
                 case MEM_CHUNK:                  case MEM_CHUNK:
                         /* append to the buffer */                          /* append to the buffer */
                        weHave = c->mem->used - 1 - c->offset;                        weHave = buffer_string_length(c->mem) - c->offset;
   
                         if (weHave > weWant) weHave = weWant;                          if (weHave > weWant) weHave = weWant;
   
Line 1058  static int webdav_parse_chunkqueue(server *srv, connec Line 1188  static int webdav_parse_chunkqueue(server *srv, connec
                                 log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);                                  log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
                         }                          }
   
                        c->offset += weHave;                        chunkqueue_mark_written(cq, weHave);
                        cq->bytes_out += weHave; 
   
                         break;                          break;
                 case UNUSED_CHUNK:  
                         break;  
                 }                  }
                 chunkqueue_remove_finished_chunks(cq);  
         }          }
   
   
         switch ((err = xmlParseChunk(ctxt, 0, 0, 1))) {          switch ((err = xmlParseChunk(ctxt, 0, 0, 1))) {
         case XML_ERR_DOCUMENT_END:          case XML_ERR_DOCUMENT_END:
         case XML_ERR_OK:          case XML_ERR_OK:
Line 1096  static int webdav_parse_chunkqueue(server *srv, connec Line 1221  static int webdav_parse_chunkqueue(server *srv, connec
 static int webdav_lockdiscovery(server *srv, connection *con,  static int webdav_lockdiscovery(server *srv, connection *con,
                 buffer *locktoken, const char *lockscope, const char *locktype, int depth) {                  buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
   
        buffer *b;        buffer *b = buffer_init();
   
         response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));          response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
   
Line 1104  static int webdav_lockdiscovery(server *srv, connectio Line 1229  static int webdav_lockdiscovery(server *srv, connectio
                 CONST_STR_LEN("Content-Type"),                  CONST_STR_LEN("Content-Type"),
                 CONST_STR_LEN("text/xml; charset=\"utf-8\""));                  CONST_STR_LEN("text/xml; charset=\"utf-8\""));
   
         b = chunkqueue_get_append_buffer(con->write_queue);  
   
         buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));          buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
   
         buffer_append_string_len(b,CONST_STR_LEN("<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));          buffer_append_string_len(b,CONST_STR_LEN("<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
         buffer_append_string_len(b,CONST_STR_LEN("<D:lockdiscovery>\n"));          buffer_append_string_len(b,CONST_STR_LEN("<D:lockdiscovery>\n"));
        buffer_append_string_len(b,CONST_STR_LEN("<D:activelock>\n"));        webdav_activelock(b, locktoken, lockscope, locktype, depth, 600);
 
        buffer_append_string_len(b,CONST_STR_LEN("<D:lockscope>")); 
        buffer_append_string_len(b,CONST_STR_LEN("<D:")); 
        buffer_append_string(b, lockscope); 
        buffer_append_string_len(b, CONST_STR_LEN("/>")); 
        buffer_append_string_len(b,CONST_STR_LEN("</D:lockscope>\n")); 
 
        buffer_append_string_len(b,CONST_STR_LEN("<D:locktype>")); 
        buffer_append_string_len(b,CONST_STR_LEN("<D:")); 
        buffer_append_string(b, locktype); 
        buffer_append_string_len(b, CONST_STR_LEN("/>")); 
        buffer_append_string_len(b,CONST_STR_LEN("</D:locktype>\n")); 
 
        buffer_append_string_len(b,CONST_STR_LEN("<D:depth>")); 
        buffer_append_string(b, depth == 0 ? "0" : "infinity"); 
        buffer_append_string_len(b,CONST_STR_LEN("</D:depth>\n")); 
 
        buffer_append_string_len(b,CONST_STR_LEN("<D:timeout>")); 
        buffer_append_string_len(b, CONST_STR_LEN("Second-600")); 
        buffer_append_string_len(b,CONST_STR_LEN("</D:timeout>\n")); 
 
        buffer_append_string_len(b,CONST_STR_LEN("<D:owner>")); 
        buffer_append_string_len(b,CONST_STR_LEN("</D:owner>\n")); 
 
        buffer_append_string_len(b,CONST_STR_LEN("<D:locktoken>")); 
        buffer_append_string_len(b, CONST_STR_LEN("<D:href>")); 
        buffer_append_string_buffer(b, locktoken); 
        buffer_append_string_len(b, CONST_STR_LEN("</D:href>")); 
        buffer_append_string_len(b,CONST_STR_LEN("</D:locktoken>\n")); 
 
        buffer_append_string_len(b,CONST_STR_LEN("</D:activelock>\n")); 
         buffer_append_string_len(b,CONST_STR_LEN("</D:lockdiscovery>\n"));          buffer_append_string_len(b,CONST_STR_LEN("</D:lockdiscovery>\n"));
         buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));          buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
   
           chunkqueue_append_buffer(con->write_queue, b);
           buffer_free(b);
   
         return 0;          return 0;
 }  }
 #endif  #endif
Line 1191  static int webdav_has_lock(server *srv, connection *co Line 1286  static int webdav_has_lock(server *srv, connection *co
                 sqlite3_reset(stmt);                  sqlite3_reset(stmt);
   
                 sqlite3_bind_text(stmt, 1,                  sqlite3_bind_text(stmt, 1,
                          CONST_BUF_LEN(uri),                        CONST_BUF_LEN(uri),
                          SQLITE_TRANSIENT);                        SQLITE_TRANSIENT);
   
                 while (SQLITE_ROW == sqlite3_step(stmt)) {                  while (SQLITE_ROW == sqlite3_step(stmt)) {
                         has_lock = 0;                          has_lock = 0;
Line 1208  static int webdav_has_lock(server *srv, connection *co Line 1303  static int webdav_has_lock(server *srv, connection *co
         return has_lock;          return has_lock;
 }  }
   
URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
 SUBREQUEST_FUNC(mod_webdav_subrequest_handler_huge) {
         plugin_data *p = p_d;          plugin_data *p = p_d;
         buffer *b;          buffer *b;
         DIR *dir;          DIR *dir;
         data_string *ds;          data_string *ds;
        int depth = -1;        int depth = -1; /* (Depth: infinity) */
         struct stat st;          struct stat st;
         buffer *prop_200;          buffer *prop_200;
         buffer *prop_404;          buffer *prop_404;
Line 1224  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1320  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
   
         if (!p->conf.enabled) return HANDLER_GO_ON;          if (!p->conf.enabled) return HANDLER_GO_ON;
         /* physical path is setup */          /* physical path is setup */
        if (con->physical.path->used == 0) return HANDLER_GO_ON;        if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
   
         /* PROPFIND need them */          /* PROPFIND need them */
        if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Depth"))) {        if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Depth")) && 1 == buffer_string_length(ds->value)) {
                depth = strtol(ds->value->ptr, NULL, 10);                if ('0' == *ds->value->ptr) {
        }                        depth = 0;
                 } else if ('1' == *ds->value->ptr) {
                         depth = 1;
                 }
         } /* else treat as Depth: infinity */
   
         switch (con->request.http_method) {          switch (con->request.http_method) {
         case HTTP_METHOD_PROPFIND:          case HTTP_METHOD_PROPFIND:
Line 1249  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1349  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                         break;                          break;
                 }                  }
   
                   if (S_ISDIR(sce->st.st_mode) && con->physical.path->ptr[buffer_string_length(con->physical.path)-1] != '/') {
                           http_response_redirect_to_directory(srv, con);
                           return HANDLER_FINISHED;
                   }
   
 #ifdef USE_PROPPATCH  #ifdef USE_PROPPATCH
                 /* any special requests or just allprop ? */                  /* any special requests or just allprop ? */
                 if (con->request.content_length) {                  if (con->request.content_length) {
                         xmlDocPtr xml;                          xmlDocPtr xml;
   
                           if (con->state == CON_STATE_READ_POST) {
                                   handler_t r = connection_handle_read_post_state(srv, con);
                                   if (r != HANDLER_GO_ON) return r;
                           }
   
                         if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {                          if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
                                 xmlNode *rootnode = xmlDocGetRootElement(xml);                                  xmlNode *rootnode = xmlDocGetRootElement(xml);
   
Line 1275  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1384  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                                                 if (prop->type == XML_TEXT_NODE) continue; /* ignore WS */                                                                  if (prop->type == XML_TEXT_NODE) continue; /* ignore WS */
   
                                                                 if (prop->ns &&                                                                  if (prop->ns &&
                                                                    (0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&                                                                  (0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&
                                                                     (0 != xmlStrcmp(prop->ns->prefix, BAD_CAST ""))) {                                                                      (0 != xmlStrcmp(prop->ns->prefix, BAD_CAST ""))) {
                                                                         size_t i;                                                                          size_t i;
                                                                         log_error_write(srv, __FILE__, __LINE__, "ss",                                                                          log_error_write(srv, __FILE__, __LINE__, "ss",
Line 1319  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1428  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                                                 /* bind the values to the insert */                                                                  /* bind the values to the insert */
   
                                                                 sqlite3_bind_text(stmt, 1,                                                                  sqlite3_bind_text(stmt, 1,
                                                                                  con->uri.path->ptr,                                                                        CONST_BUF_LEN(con->uri.path),
                                                                                  con->uri.path->used - 1,                                                                        SQLITE_TRANSIENT);
                                                                                  SQLITE_TRANSIENT); 
   
                                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {                                                                  if (SQLITE_DONE != sqlite3_step(stmt)) {
                                                                 }                                                                  }
Line 1343  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1451  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
   
                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));                  response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
   
                b = chunkqueue_get_append_buffer(con->write_queue);                b = buffer_init();
   
                 buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));                  buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
   
Line 1354  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1462  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                 prop_200 = buffer_init();                  prop_200 = buffer_init();
                 prop_404 = buffer_init();                  prop_404 = buffer_init();
   
                switch(depth) {                {
                case 0:                        /* Depth: 0  or  Depth: 1 */
                        /* Depth: 0 */ 
                         webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);                          webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
   
                         buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));                          buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));
Line 1367  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1474  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                         buffer_append_string_encoded(b, CONST_BUF_LEN(con->uri.path), ENCODING_REL_URI);                          buffer_append_string_encoded(b, CONST_BUF_LEN(con->uri.path), ENCODING_REL_URI);
                         buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));                          buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
   
                        if (!buffer_is_empty(prop_200)) {                        if (!buffer_string_is_empty(prop_200)) {
                                 buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));                                  buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
                                 buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));                                  buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
   
Line 1379  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1486  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
   
                                 buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));                                  buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
                         }                          }
                        if (!buffer_is_empty(prop_404)) {                        if (!buffer_string_is_empty(prop_404)) {
                                 buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));                                  buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
                                 buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));                                  buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
   
Line 1393  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1500  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                         }                          }
   
                         buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));                          buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
                   }
   
                        break;                if (depth == 1) {
                case 1:
                         if (NULL != (dir = opendir(con->physical.path->ptr))) {                          if (NULL != (dir = opendir(con->physical.path->ptr))) {
                                 struct dirent *de;                                  struct dirent *de;
                                 physical d;                                  physical d;
Line 1405  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1513  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                 d.rel_path = buffer_init();                                  d.rel_path = buffer_init();
   
                                 while(NULL != (de = readdir(dir))) {                                  while(NULL != (de = readdir(dir))) {
                                        if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {                                        if (de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) {
                                                 continue;                                                  continue;
                                                /* ignore the parent dir */                                                /* ignore the parent and target dir */
                                         }                                          }
   
                                        buffer_copy_string_buffer(d.path, dst->path);                                        buffer_copy_buffer(d.path, dst->path);
                                        BUFFER_APPEND_SLASH(d.path);                                        buffer_append_slash(d.path);
   
                                        buffer_copy_string_buffer(d.rel_path, dst->rel_path);                                        buffer_copy_buffer(d.rel_path, dst->rel_path);
                                        BUFFER_APPEND_SLASH(d.rel_path);                                        buffer_append_slash(d.rel_path);
   
                                        if (de->d_name[0] == '.' && de->d_name[1] == '\0') {                                        buffer_append_string(d.path, de->d_name);
                                                /* don't append the . */                                        buffer_append_string(d.rel_path, de->d_name);
                                        } else { 
                                                buffer_append_string(d.path, de->d_name); 
                                                buffer_append_string(d.rel_path, de->d_name); 
                                        } 
   
                                         buffer_reset(prop_200);                                          buffer_reset(prop_200);
                                         buffer_reset(prop_404);                                          buffer_reset(prop_404);
Line 1434  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1538  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                         buffer_append_string_len(b,CONST_STR_LEN("://"));                                          buffer_append_string_len(b,CONST_STR_LEN("://"));
                                         buffer_append_string_buffer(b, con->uri.authority);                                          buffer_append_string_buffer(b, con->uri.authority);
                                         buffer_append_string_encoded(b, CONST_BUF_LEN(d.rel_path), ENCODING_REL_URI);                                          buffer_append_string_encoded(b, CONST_BUF_LEN(d.rel_path), ENCODING_REL_URI);
                                           if (0 == stat(d.path->ptr, &st) && S_ISDIR(st.st_mode)) {
                                                   /* Append a '/' on subdirectories */
                                                   buffer_append_string_len(b,CONST_STR_LEN("/"));
                                           }
                                         buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));                                          buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
   
                                        if (!buffer_is_empty(prop_200)) {                                        if (!buffer_string_is_empty(prop_200)) {
                                                 buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));                                                  buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
                                                 buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));                                                  buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
   
Line 1448  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1556  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
   
                                                 buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));                                                  buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
                                         }                                          }
                                        if (!buffer_is_empty(prop_404)) {                                        if (!buffer_string_is_empty(prop_404)) {
                                                 buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));                                                  buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
                                                 buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));                                                  buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
   
Line 1467  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1575  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                 buffer_free(d.path);                                  buffer_free(d.path);
                                 buffer_free(d.rel_path);                                  buffer_free(d.rel_path);
                         }                          }
                        break;
                 }                  }
   
                 if (req_props) {                  if (req_props) {
Line 1489  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1597  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                 if (p->conf.log_xml) {                  if (p->conf.log_xml) {
                         log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);                          log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
                 }                  }
   
                   chunkqueue_append_buffer(con->write_queue, b);
                   buffer_free(b);
   
                 con->file_finished = 1;                  con->file_finished = 1;
   
                 return HANDLER_FINISHED;                  return HANDLER_FINISHED;
Line 1551  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1663  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                  break;                                   break;
                         }                          }
                 } else if (S_ISDIR(st.st_mode)) {                  } else if (S_ISDIR(st.st_mode)) {
                        buffer *multi_status_resp = buffer_init();                        buffer *multi_status_resp;
   
                           if (con->physical.path->ptr[buffer_string_length(con->physical.path)-1] != '/') {
                                   http_response_redirect_to_directory(srv, con);
                                   return HANDLER_FINISHED;
                           }
   
                           multi_status_resp = buffer_init();
   
                         if (webdav_delete_dir(srv, con, p, &(con->physical), multi_status_resp)) {                          if (webdav_delete_dir(srv, con, p, &(con->physical), multi_status_resp)) {
                                 /* we got an error somewhere in between, build a 207 */                                  /* we got an error somewhere in between, build a 207 */
                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));                                  response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
   
                                b = chunkqueue_get_append_buffer(con->write_queue);                                b = buffer_init();
   
                                 buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));                                  buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
   
Line 1571  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1690  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                         log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);                                          log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
                                 }                                  }
   
                                   chunkqueue_append_buffer(con->write_queue, b);
                                   buffer_free(b);
   
                                 con->http_status = 207;                                  con->http_status = 207;
                                 con->file_finished = 1;                                  con->file_finished = 1;
                         } else {                          } else {
Line 1578  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1700  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
   
                                 if (-1 == rmdir(con->physical.path->ptr)) {                                  if (-1 == rmdir(con->physical.path->ptr)) {
                                         switch(errno) {                                          switch(errno) {
                                           case EPERM:
                                                   con->http_status = 403;
                                                   break;
                                         case ENOENT:                                          case ENOENT:
                                                 con->http_status = 404;                                                  con->http_status = 404;
                                                 break;                                                  break;
Line 1619  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1744  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                 }                  }
   
                 /* is a exclusive lock set on the source */                  /* is a exclusive lock set on the source */
                if (!webdav_has_lock(srv, con, p, con->uri.path)) {                /* (check for lock once before potentially reading large input) */
                 if (0 == cq->bytes_in && !webdav_has_lock(srv, con, p, con->uri.path)) {
                         con->http_status = 423;                          con->http_status = 423;
                         return HANDLER_FINISHED;                          return HANDLER_FINISHED;
                 }                  }
   
                   if (con->state == CON_STATE_READ_POST) {
                           handler_t r = connection_handle_read_post_state(srv, con);
                           if (r != HANDLER_GO_ON) return r;
                   }
   
                 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);  
   
                 /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support                  /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
                  * - most important Content-Range                   * - most important Content-Range
                  *                   *
Line 1708  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1836  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
   
                 for (c = cq->first; c; c = cq->first) {                  for (c = cq->first; c; c = cq->first) {
                         int r = 0;                          int r = 0;
                           int mapped;
                           void *data;
                           size_t dlen;
   
                         /* copy all chunks */                          /* copy all chunks */
                         switch(c->type) {                          switch(c->type) {
                         case FILE_CHUNK:                          case FILE_CHUNK:
   
                                if (c->file.mmap.start == MAP_FAILED) {                                mapped = (c->file.mmap.start != MAP_FAILED);
                                 dlen = c->file.length - c->offset;
                                 if (mapped) {
                                         data = c->file.mmap.start + c->offset;
                                 } else {
                                         if (-1 == c->file.fd &&  /* open the file if not already open */                                          if (-1 == c->file.fd &&  /* open the file if not already open */
                                             -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {                                              -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));                                                  log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
Line 1721  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1856  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                                 return HANDLER_ERROR;                                                  return HANDLER_ERROR;
                                         }                                          }
   
                                        if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {                                        if (MAP_FAILED != (c->file.mmap.start = mmap(NULL, c->file.length, PROT_READ, MAP_PRIVATE, c->file.fd, 0))) {
                                                log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",                                                /* chunk_reset() or chunk_free() will cleanup for us */
                                                                strerror(errno), c->file.name,  c->file.fd);                                                c->file.mmap.length = c->file.length;
                                                close(c->file.fd);                                                data = c->file.mmap.start + c->offset;
                                                c->file.fd = -1;                                                mapped = 1;
                                                close(fd);                                        } else {
                                                return HANDLER_ERROR;                                                ssize_t rd;
                                                 if (dlen > 65536) dlen = 65536;
                                                 data = malloc(dlen);
                                                 force_assert(data);
                                                 if (-1 == lseek(c->file.fd, c->file.start + c->offset, SEEK_SET)
                                                     || 0 > (rd = read(c->file.fd, data, dlen))) {
                                                         log_error_write(srv, __FILE__, __LINE__, "ssbd", "lseek/read failed: ",
                                                                         strerror(errno), c->file.name, c->file.fd);
                                                         free(data);
                                                         close(fd);
                                                         return HANDLER_ERROR;
                                                 }
                                                 dlen = (size_t)rd;
                                         }                                          }
   
                                         c->file.mmap.length = c->file.length;  
   
                                         close(c->file.fd);  
                                         c->file.fd = -1;  
   
                                         /* chunk_reset() or chunk_free() will cleanup for us */  
                                 }                                  }
   
                                if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {                                if ((r = write(fd, data, dlen)) < 0) {
                                         switch(errno) {                                          switch(errno) {
                                         case ENOSPC:                                          case ENOSPC:
                                                 con->http_status = 507;                                                  con->http_status = 507;
Line 1749  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1890  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                                 break;                                                  break;
                                         }                                          }
                                 }                                  }
   
                                   if (!mapped) free(data);
                                 break;                                  break;
                         case MEM_CHUNK:                          case MEM_CHUNK:
                                if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {                                if ((r = write(fd, c->mem->ptr + c->offset, buffer_string_length(c->mem) - c->offset)) < 0) {
                                         switch(errno) {                                          switch(errno) {
                                         case ENOSPC:                                          case ENOSPC:
                                                 con->http_status = 507;                                                  con->http_status = 507;
Line 1763  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1906  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                         }                                          }
                                 }                                  }
                                 break;                                  break;
                         case UNUSED_CHUNK:  
                                 break;  
                         }                          }
   
                         if (r > 0) {                          if (r > 0) {
                                c->offset += r;                                chunkqueue_mark_written(cq, r);
                                cq->bytes_out += r; 
                         } else {                          } else {
                                 break;                                  break;
                         }                          }
                         chunkqueue_remove_finished_chunks(cq);  
                 }                  }
                close(fd);                if (0 != close(fd)) {
                         log_error_write(srv, __FILE__, __LINE__, "sbss",
                                         "close ", con->physical.path, "failed: ", strerror(errno));
                         return HANDLER_ERROR;
                 }
   
                 return HANDLER_FINISHED;                  return HANDLER_FINISHED;
         }          }
Line 1806  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 1949  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                 }                  }
   
                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Overwrite"))) {                  if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Overwrite"))) {
                        if (ds->value->used != 2 ||                        if (buffer_string_length(ds->value) != 1 ||
                             (ds->value->ptr[0] != 'F' &&                              (ds->value->ptr[0] != 'F' &&
                              ds->value->ptr[0] != 'T') )  {                               ds->value->ptr[0] != 'T') )  {
                                 con->http_status = 400;                                  con->http_status = 400;
Line 1862  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2005  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                         return HANDLER_FINISHED;                          return HANDLER_FINISHED;
                 }                  }
   
                buffer_copy_string_buffer(p->tmp_buf, p->uri.path_raw);                buffer_copy_buffer(p->tmp_buf, p->uri.path_raw);
                 buffer_urldecode_path(p->tmp_buf);                  buffer_urldecode_path(p->tmp_buf);
                 buffer_path_simplify(p->uri.path, p->tmp_buf);                  buffer_path_simplify(p->uri.path, p->tmp_buf);
   
                 /* we now have a URI which is clean. transform it into a physical path */                  /* we now have a URI which is clean. transform it into a physical path */
                buffer_copy_string_buffer(p->physical.doc_root, con->physical.doc_root);                buffer_copy_buffer(p->physical.doc_root, con->physical.doc_root);
                buffer_copy_string_buffer(p->physical.rel_path, p->uri.path);                buffer_copy_buffer(p->physical.rel_path, p->uri.path);
   
                 if (con->conf.force_lowercase_filenames) {                  if (con->conf.force_lowercase_filenames) {
                         buffer_to_lower(p->physical.rel_path);                          buffer_to_lower(p->physical.rel_path);
                 }                  }
   
                buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);                /* Destination physical path
                BUFFER_APPEND_SLASH(p->physical.path);                 * src con->physical.path might have been remapped with mod_alias.
                buffer_copy_string_buffer(p->physical.basedir, p->physical.path);                 *   (but mod_alias does not modify con->physical.rel_path)
                  * Find matching prefix to support use of mod_alias to remap webdav root.
                  * Aliasing of paths underneath the webdav root might not work.
                  * Likewise, mod_rewrite URL rewriting might thwart this comparison.
                  * Use mod_redirect instead of mod_alias to remap paths *under* webdav root.
                  * Use mod_redirect instead of mod_rewrite on *any* parts of path to webdav.
                  * (Related, use mod_auth to protect webdav root, but avoid attempting to
                  *  use mod_auth on paths underneath webdav root, as Destination is not
                  *  validated with mod_auth)
                  *
                  * tl;dr: webdav paths and webdav properties are managed by mod_webdav,
                  *        so do not modify paths externally or else undefined behavior
                  *        or corruption may occur
                  */
                 {
                         /* find matching URI prefix
                          * check if remaining con->physical.rel_path matches suffix
                          *   of con->physical.basedir so that we can use it to
                          *   remap Destination physical path */
                         size_t i, remain;
                         sep = con->uri.path->ptr;
                         sep2 = p->uri.path->ptr;
                         for (i = 0; sep[i] && sep[i] == sep2[i]; ++i) ;
                         if (sep[i] == '\0' && (sep2[i] == '\0' || sep2[i] == '/' || (i > 0 && sep[i-1] == '/'))) {
                                 /* src and dst URI match or dst is nested inside src; invalid COPY or MOVE */
                                 con->http_status = 403;
                                 return HANDLER_FINISHED;
                         }
                         while (i != 0 && sep[--i] != '/') ; /* find matching directory path */
                         remain = buffer_string_length(con->uri.path) - i;
                         if (!con->conf.force_lowercase_filenames
                             ? buffer_is_equal_right_len(con->physical.path, con->physical.rel_path, remain)
                             :(buffer_string_length(con->physical.path) >= remain
                               && 0 == strncasecmp(con->physical.path->ptr+buffer_string_length(con->physical.path)-remain, con->physical.rel_path->ptr+i, remain))) {
                                 /* (at this point, p->physical.rel_path is identical to (or lowercased version of) p->uri.path) */
                                 buffer_copy_string_len(p->physical.path, con->physical.path->ptr, buffer_string_length(con->physical.path)-remain);
                                 buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr+i, buffer_string_length(p->physical.rel_path)-i);
   
                /* don't add a second / */                                buffer_copy_buffer(p->physical.basedir, con->physical.basedir);
                if (p->physical.rel_path->ptr[0] == '/') {                                buffer_append_slash(p->physical.basedir);
                        buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);                        } else {
                } else {                                /* unable to perform physical path remap here;
                        buffer_append_string_buffer(p->physical.path, p->physical.rel_path);                                 * assume doc_root/rel_path and no remapping */
                                 buffer_copy_buffer(p->physical.path, p->physical.doc_root);
                                 buffer_append_slash(p->physical.path);
                                 buffer_copy_buffer(p->physical.basedir, p->physical.path);
 
                                 /* don't add a second / */
                                 if (p->physical.rel_path->ptr[0] == '/') {
                                         buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, buffer_string_length(p->physical.rel_path) - 1);
                                 } else {
                                         buffer_append_string_buffer(p->physical.path, p->physical.rel_path);
                                 }
                         }
                 }                  }
   
                 /* let's see if the source is a directory                  /* let's see if the source is a directory
Line 1900  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2090  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                         }                          }
                 } else if (S_ISDIR(st.st_mode)) {                  } else if (S_ISDIR(st.st_mode)) {
                         int r;                          int r;
                           int created = 0;
                         /* src is a directory */                          /* src is a directory */
   
                           if (con->physical.path->ptr[buffer_string_length(con->physical.path)-1] != '/') {
                                   http_response_redirect_to_directory(srv, con);
                                   return HANDLER_FINISHED;
                           }
   
                         if (-1 == stat(p->physical.path->ptr, &st)) {                          if (-1 == stat(p->physical.path->ptr, &st)) {
                                 if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {                                  if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
                                         con->http_status = 403;                                          con->http_status = 403;
                                         return HANDLER_FINISHED;                                          return HANDLER_FINISHED;
                                 }                                  }
                                   created = 1;
                         } else if (!S_ISDIR(st.st_mode)) {                          } else if (!S_ISDIR(st.st_mode)) {
                                 if (overwrite == 0) {                                  if (overwrite == 0) {
                                         /* copying into a non-dir ? */                                          /* copying into a non-dir ? */
Line 1918  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2115  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                                 con->http_status = 403;                                                  con->http_status = 403;
                                                 return HANDLER_FINISHED;                                                  return HANDLER_FINISHED;
                                         }                                          }
                                           created = 1;
                                 }                                  }
                         }                          }
   
Line 1933  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2131  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
   
                                 rmdir(con->physical.path->ptr);                                  rmdir(con->physical.path->ptr);
                         }                          }
                        con->http_status = 201;                        con->http_status = created ? 201 : 204;
                         con->file_finished = 1;                          con->file_finished = 1;
                 } else {                  } else {
                         /* it is just a file, good */                          /* it is just a file, good */
                         int r;                          int r;
                           int destdir = 0;
   
                         /* does the client have a lock for this connection ? */                          /* does the client have a lock for this connection ? */
                         if (!webdav_has_lock(srv, con, p, p->uri.path)) {                          if (!webdav_has_lock(srv, con, p, p->uri.path)) {
Line 1950  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2149  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                 if (S_ISDIR(st.st_mode)) {                                  if (S_ISDIR(st.st_mode)) {
                                         /* file to dir/                                          /* file to dir/
                                          * append basename to physical path */                                           * append basename to physical path */
                                           destdir = 1;
   
                                         if (NULL != (sep = strrchr(con->physical.path->ptr, '/'))) {                                          if (NULL != (sep = strrchr(con->physical.path->ptr, '/'))) {
                                                 buffer_append_string(p->physical.path, sep);                                                  buffer_append_string(p->physical.path, sep);
Line 1959  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2159  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                         }                          }
   
                         if (-1 == r) {                          if (-1 == r) {
                                con->http_status = 201; /* we will create a new one */                                con->http_status = destdir ? 204 : 201; /* we will create a new one */
                                 con->file_finished = 1;                                  con->file_finished = 1;
   
                                 switch(errno) {                                  switch(errno) {
Line 1982  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2182  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
 #ifdef USE_PROPPATCH  #ifdef USE_PROPPATCH
                                         sqlite3_stmt *stmt;                                          sqlite3_stmt *stmt;
   
                                         stmt = p->conf.stmt_delete_uri;  
                                         if (stmt) {  
   
                                                 sqlite3_reset(stmt);  
   
                                                 /* bind the values to the insert */  
                                                 sqlite3_bind_text(stmt, 1,  
                                                                   con->uri.path->ptr,  
                                                                   con->uri.path->used - 1,  
                                                                   SQLITE_TRANSIENT);  
   
                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {  
                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move(delete old) failed:", sqlite3_errmsg(p->conf.sql));  
                                                 }  
                                         }  
   
                                         stmt = p->conf.stmt_move_uri;                                          stmt = p->conf.stmt_move_uri;
                                         if (stmt) {                                          if (stmt) {
   
Line 2005  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2189  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
   
                                                 /* bind the values to the insert */                                                  /* bind the values to the insert */
                                                 sqlite3_bind_text(stmt, 1,                                                  sqlite3_bind_text(stmt, 1,
                                                                  p->uri.path->ptr,                                                        CONST_BUF_LEN(p->uri.path),
                                                                  p->uri.path->used - 1,                                                        SQLITE_TRANSIENT);
                                                                  SQLITE_TRANSIENT); 
   
                                                 sqlite3_bind_text(stmt, 2,                                                  sqlite3_bind_text(stmt, 2,
                                                                  con->uri.path->ptr,                                                        CONST_BUF_LEN(con->uri.path),
                                                                  con->uri.path->used - 1,                                                        SQLITE_TRANSIENT);
                                                                  SQLITE_TRANSIENT); 
   
                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {                                                  if (SQLITE_DONE != sqlite3_step(stmt)) {
                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));                                                          log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
Line 2060  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2242  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                         }                          }
                 }                  }
   
                   if (S_ISDIR(st.st_mode) && con->physical.path->ptr[buffer_string_length(con->physical.path)-1] != '/') {
                           http_response_redirect_to_directory(srv, con);
                           return HANDLER_FINISHED;
                   }
   
 #ifdef USE_PROPPATCH  #ifdef USE_PROPPATCH
                 if (con->request.content_length) {                  if (con->request.content_length) {
                         xmlDocPtr xml;                          xmlDocPtr xml;
   
                           if (con->state == CON_STATE_READ_POST) {
                                   handler_t r = connection_handle_read_post_state(srv, con);
                                   if (r != HANDLER_GO_ON) return r;
                           }
   
                         if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {                          if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
                                 xmlNode *rootnode = xmlDocGetRootElement(xml);                                  xmlNode *rootnode = xmlDocGetRootElement(xml);
   
Line 2097  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2289  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                                         for (props = cmd->children; props; props = props->next) {                                                          for (props = cmd->children; props; props = props->next) {
                                                                 if (0 == xmlStrcmp(props->name, BAD_CAST "prop")) {                                                                  if (0 == xmlStrcmp(props->name, BAD_CAST "prop")) {
                                                                         xmlNode *prop;                                                                          xmlNode *prop;
                                                                           char *propval = NULL;
                                                                         int r;                                                                          int r;
   
                                                                         prop = props->children;                                                                          prop = props->children;
Line 2117  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2310  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                                                         /* bind the values to the insert */                                                                          /* bind the values to the insert */
   
                                                                         sqlite3_bind_text(stmt, 1,                                                                          sqlite3_bind_text(stmt, 1,
                                                                                          con->uri.path->ptr,                                                                                CONST_BUF_LEN(con->uri.path),
                                                                                          con->uri.path->used - 1,                                                                                SQLITE_TRANSIENT);
                                                                                          SQLITE_TRANSIENT); 
                                                                         sqlite3_bind_text(stmt, 2,                                                                          sqlite3_bind_text(stmt, 2,
                                                                                          (char *)prop->name,                                                                                (char *)prop->name,
                                                                                          strlen((char *)prop->name),                                                                                strlen((char *)prop->name),
                                                                                          SQLITE_TRANSIENT);                                                                                SQLITE_TRANSIENT);
                                                                         if (prop->ns) {                                                                          if (prop->ns) {
                                                                                 sqlite3_bind_text(stmt, 3,                                                                                  sqlite3_bind_text(stmt, 3,
                                                                                                  (char *)prop->ns->href,                                                                                        (char *)prop->ns->href,
                                                                                                  strlen((char *)prop->ns->href),                                                                                        strlen((char *)prop->ns->href),
                                                                                                  SQLITE_TRANSIENT);                                                                                        SQLITE_TRANSIENT);
                                                                         } else {                                                                          } else {
                                                                                 sqlite3_bind_text(stmt, 3,                                                                                  sqlite3_bind_text(stmt, 3,
                                                                                                  "",                                                                                        "",
                                                                                                  0,                                                                                        0,
                                                                                                  SQLITE_TRANSIENT);                                                                                        SQLITE_TRANSIENT);
                                                                         }                                                                          }
                                                                         if (stmt == p->conf.stmt_update_prop) {                                                                          if (stmt == p->conf.stmt_update_prop) {
                                                                                   propval = prop->children
                                                                                     ? (char *)xmlNodeListGetString(xml, prop->children, 0)
                                                                                     : NULL;
   
                                                                                 sqlite3_bind_text(stmt, 4,                                                                                  sqlite3_bind_text(stmt, 4,
                                                                                          (char *)xmlNodeGetContent(prop),                                                                                        propval ? propval : "",
                                                                                          strlen((char *)xmlNodeGetContent(prop)),                                                                                        propval ? strlen(propval) : 0,
                                                                                          SQLITE_TRANSIENT);                                                                                        SQLITE_TRANSIENT);
                                                                         }                                                                          }
   
                                                                         if (SQLITE_DONE != (r = sqlite3_step(stmt))) {                                                                          if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
                                                                                 log_error_write(srv, __FILE__, __LINE__, "ss",                                                                                  log_error_write(srv, __FILE__, __LINE__, "ss",
                                                                                                 "sql-set failed:", sqlite3_errmsg(p->conf.sql));                                                                                                  "sql-set failed:", sqlite3_errmsg(p->conf.sql));
                                                                         }                                                                          }
   
                                                                           if (propval) xmlFree(propval);
                                                                 }                                                                  }
                                                         }                                                          }
                                                         if (empty_ns) break;                                                          if (empty_ns) break;
Line 2172  URIHANDLER_FUNC(mod_webdav_subrequest_handler) { Line 2370  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
                                         }                                          }
                                         con->file_finished = 1;                                          con->file_finished = 1;
   
                                           xmlFreeDoc(xml);
                                         return HANDLER_FINISHED;                                          return HANDLER_FINISHED;
                                 }                                  }
   
Line 2220  propmatch_cleanup: Line 2419  propmatch_cleanup:
                 if (con->request.content_length) {                  if (con->request.content_length) {
                         xmlDocPtr xml;                          xmlDocPtr xml;
                         buffer *hdr_if = NULL;                          buffer *hdr_if = NULL;
                           int created = 0;
   
                           if (con->state == CON_STATE_READ_POST) {
                                   handler_t r = connection_handle_read_post_state(srv, con);
                                   if (r != HANDLER_GO_ON) return r;
                           }
   
                         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {                          if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
                                 hdr_if = ds->value;                                  hdr_if = ds->value;
                         }                          }
   
                        /* we don't support Depth: Infinity on locks */                        if (0 != stat(con->physical.path->ptr, &st)) {
                        if (hdr_if == NULL && depth == -1) {                                if (errno == ENOENT) {
                                con->http_status = 409; /* Conflict */                                        int fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_APPEND|O_BINARY|FIFO_NONBLOCK, WEBDAV_FILE_MODE);
                                         if (fd >= 0) {
                                                 close(fd);
                                                 created = 1;
                                         } else {
                                                 log_error_write(srv, __FILE__, __LINE__, "sBss",
                                                                 "create file", con->physical.path, ":", strerror(errno));
                                                 con->http_status = 403; /* Forbidden */
   
                                return HANDLER_FINISHED;                                                return HANDLER_FINISHED;
                                         }
                                 }
                         } else if (hdr_if == NULL && depth == -1) {
                                 /* we don't support Depth: Infinity on directories */
                                 if (S_ISDIR(st.st_mode)) {
                                         con->http_status = 409; /* Conflict */
 
                                         return HANDLER_FINISHED;
                                 }
                         }                          }
   
                         if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {                          if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
Line 2286  propmatch_cleanup: Line 2507  propmatch_cleanup:
                                                         sqlite3_reset(stmt);                                                          sqlite3_reset(stmt);
   
                                                         sqlite3_bind_text(stmt, 1,                                                          sqlite3_bind_text(stmt, 1,
                                                                          p->uri.path->ptr,                                                                CONST_BUF_LEN(p->uri.path),
                                                                          p->uri.path->used - 1,                                                                SQLITE_TRANSIENT);
                                                                          SQLITE_TRANSIENT); 
   
                                                         /* it is the PK */                                                          /* it is the PK */
                                                         while (SQLITE_ROW == sqlite3_step(stmt)) {                                                          while (SQLITE_ROW == sqlite3_step(stmt)) {
Line 2335  propmatch_cleanup: Line 2555  propmatch_cleanup:
                                                         sqlite3_reset(stmt);                                                          sqlite3_reset(stmt);
   
                                                         sqlite3_bind_text(stmt, 1,                                                          sqlite3_bind_text(stmt, 1,
                                                                          CONST_BUF_LEN(p->tmp_buf),                                                                        CONST_BUF_LEN(p->tmp_buf),
                                                                          SQLITE_TRANSIENT);                                                                        SQLITE_TRANSIENT);
   
                                                         sqlite3_bind_text(stmt, 2,                                                          sqlite3_bind_text(stmt, 2,
                                                                          CONST_BUF_LEN(con->uri.path),                                                                        CONST_BUF_LEN(con->uri.path),
                                                                          SQLITE_TRANSIENT);                                                                        SQLITE_TRANSIENT);
   
                                                         sqlite3_bind_text(stmt, 3,                                                          sqlite3_bind_text(stmt, 3,
                                                                          (const char *)lockscope,                                                                        (const char *)lockscope,
                                                                          xmlStrlen(lockscope),                                                                        xmlStrlen(lockscope),
                                                                          SQLITE_TRANSIENT);                                                                        SQLITE_TRANSIENT);
   
                                                         sqlite3_bind_text(stmt, 4,                                                          sqlite3_bind_text(stmt, 4,
                                                                          (const char *)locktype,                                                                        (const char *)locktype,
                                                                          xmlStrlen(locktype),                                                                        xmlStrlen(locktype),
                                                                          SQLITE_TRANSIENT);                                                                        SQLITE_TRANSIENT);
   
                                                         /* owner */                                                          /* owner */
                                                         sqlite3_bind_text(stmt, 5,                                                          sqlite3_bind_text(stmt, 5,
                                                                          "",                                                                        "",
                                                                          0,                                                                        0,
                                                                          SQLITE_TRANSIENT);                                                                        SQLITE_TRANSIENT);
   
                                                         /* depth */                                                          /* depth */
                                                         sqlite3_bind_int(stmt, 6,                                                          sqlite3_bind_int(stmt, 6,
                                                                         depth);                                                                        depth);
   
   
                                                         if (SQLITE_DONE != sqlite3_step(stmt)) {                                                          if (SQLITE_DONE != sqlite3_step(stmt)) {
Line 2371  propmatch_cleanup: Line 2591  propmatch_cleanup:
                                                         /* looks like we survived */                                                          /* looks like we survived */
                                                         webdav_lockdiscovery(srv, con, p->tmp_buf, (const char *)lockscope, (const char *)locktype, depth);                                                          webdav_lockdiscovery(srv, con, p->tmp_buf, (const char *)lockscope, (const char *)locktype, depth);
   
                                                        con->http_status = 201;                                                        con->http_status = created ? 201 : 200;
                                                         con->file_finished = 1;                                                          con->file_finished = 1;
                                                 }                                                  }
                                         }                                          }
Line 2390  propmatch_cleanup: Line 2610  propmatch_cleanup:
                                 sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;                                  sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
   
                                 /* remove the < > around the token */                                  /* remove the < > around the token */
                                if (locktoken->used < 6) {                                if (buffer_string_length(locktoken) < 5) {
                                         con->http_status = 400;                                          con->http_status = 400;
   
                                         return HANDLER_FINISHED;                                          return HANDLER_FINISHED;
                                 }                                  }
   
                                buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);                                buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, buffer_string_length(locktoken) - 4);
   
                                 sqlite3_reset(stmt);                                  sqlite3_reset(stmt);
   
                                 sqlite3_bind_text(stmt, 1,                                  sqlite3_bind_text(stmt, 1,
                                          CONST_BUF_LEN(p->tmp_buf),                                        CONST_BUF_LEN(p->tmp_buf),
                                          SQLITE_TRANSIENT);                                        SQLITE_TRANSIENT);
   
                                 if (SQLITE_DONE != sqlite3_step(stmt)) {                                  if (SQLITE_DONE != sqlite3_step(stmt)) {
                                         log_error_write(srv, __FILE__, __LINE__, "ss",                                          log_error_write(srv, __FILE__, __LINE__, "ss",
Line 2433  propmatch_cleanup: Line 2653  propmatch_cleanup:
                         sqlite3_stmt *stmt = p->conf.stmt_remove_lock;                          sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
   
                         /* remove the < > around the token */                          /* remove the < > around the token */
                        if (locktoken->used < 4) {                        if (buffer_string_length(locktoken) < 3) {
                                 con->http_status = 400;                                  con->http_status = 400;
   
                                 return HANDLER_FINISHED;                                  return HANDLER_FINISHED;
Line 2449  propmatch_cleanup: Line 2669  propmatch_cleanup:
                          * - 412                           * - 412
                          *  */                           *  */
   
                        buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);                        buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, buffer_string_length(locktoken) - 2);
   
                         sqlite3_reset(stmt);                          sqlite3_reset(stmt);
   
                         sqlite3_bind_text(stmt, 1,                          sqlite3_bind_text(stmt, 1,
                                  CONST_BUF_LEN(p->tmp_buf),                                CONST_BUF_LEN(p->tmp_buf),
                                  SQLITE_TRANSIENT);                                SQLITE_TRANSIENT);
   
                         sqlite3_bind_text(stmt, 2,  
                                   CONST_BUF_LEN(con->uri.path),  
                                   SQLITE_TRANSIENT);  
   
                         if (SQLITE_DONE != sqlite3_step(stmt)) {                          if (SQLITE_DONE != sqlite3_step(stmt)) {
                                 log_error_write(srv, __FILE__, __LINE__, "ss",                                  log_error_write(srv, __FILE__, __LINE__, "ss",
                                         "remove lock:", sqlite3_errmsg(p->conf.sql));                                          "remove lock:", sqlite3_errmsg(p->conf.sql));
Line 2492  propmatch_cleanup: Line 2708  propmatch_cleanup:
 }  }
   
   
   SUBREQUEST_FUNC(mod_webdav_subrequest_handler) {
           handler_t r;
           plugin_data *p = p_d;
           if (con->mode != p->id) return HANDLER_GO_ON;
   
           r = mod_webdav_subrequest_handler_huge(srv, con, p_d);
           if (con->http_status >= 400) con->mode = DIRECT;
           return r;
   }
   
   
   PHYSICALPATH_FUNC(mod_webdav_physical_handler) {
           plugin_data *p = p_d;
           if (!p->conf.enabled) return HANDLER_GO_ON;
   
           /* physical path is setup */
           if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
   
           UNUSED(srv);
   
           switch (con->request.http_method) {
           case HTTP_METHOD_PROPFIND:
           case HTTP_METHOD_PROPPATCH:
           case HTTP_METHOD_PUT:
           case HTTP_METHOD_COPY:
           case HTTP_METHOD_MOVE:
           case HTTP_METHOD_MKCOL:
           case HTTP_METHOD_DELETE:
           case HTTP_METHOD_LOCK:
           case HTTP_METHOD_UNLOCK:
                   con->conf.stream_request_body = 0;
                   con->mode = p->id;
                   break;
           default:
                   break;
           }
   
           return HANDLER_GO_ON;
   }
   
   
 /* this function is called at dlopen() time and inits the callbacks */  /* this function is called at dlopen() time and inits the callbacks */
   
 int mod_webdav_plugin_init(plugin *p);  int mod_webdav_plugin_init(plugin *p);
Line 2501  int mod_webdav_plugin_init(plugin *p) { Line 2758  int mod_webdav_plugin_init(plugin *p) {
   
         p->init        = mod_webdav_init;          p->init        = mod_webdav_init;
         p->handle_uri_clean  = mod_webdav_uri_handler;          p->handle_uri_clean  = mod_webdav_uri_handler;
        p->handle_physical   = mod_webdav_subrequest_handler;        p->handle_physical   = mod_webdav_physical_handler;
         p->handle_subrequest = mod_webdav_subrequest_handler;
         p->set_defaults  = mod_webdav_set_defaults;          p->set_defaults  = mod_webdav_set_defaults;
         p->cleanup     = mod_webdav_free;          p->cleanup     = mod_webdav_free;
   

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>