Example #1
0
/* Remove possible quotes, and also the -gzip at the end
 * Remove "-gzip" at the end (cf. https://github.comowncloud/client/issues/1195)
 * The caller must take ownership of the resulting string.
 */
char *csync_normalize_etag(const char *etag)
{
    int len = 0;
    char *buf = NULL;
    if (!etag)
        return NULL;

    len = strlen(etag);
    /* strip "XXXX-gzip" */
    if(len >= 7 && etag[0] == '"' && c_streq(etag + len - 6, "-gzip\"")) {
        etag++;
        len -= 7;
    }
    /* strip leading -gzip */
    if(len >= 5 && c_streq(etag + len - 5, "-gzip")) {
        len -= 5;
    }
    /* strip normal quotes */
    if (etag[0] == '"' && etag[len-1] == '"') {
        etag++;
        len -= 2;
    }

    buf = c_malloc( len+1 );
    strncpy( buf, etag, len );
    buf[len] = '\0';
    return buf;
}
Example #2
0
END_TEST

START_TEST (check_c_streq_null)
{
  fail_if(c_streq(NULL, "test"), NULL);
  fail_if(c_streq("test", NULL), NULL);
  fail_if(c_streq(NULL, NULL), NULL);
}
Example #3
0
static void install_content_reader( ne_request *req, void *userdata, const ne_status *status )
{
    const char *enc = NULL;
    struct transfer_context *writeCtx = userdata;

    (void) status;
    if( !writeCtx ) {
        DEBUG_WEBDAV("Error: install_content_reader called without valid write context!");
        return;
    }

    enc = ne_get_response_header( req, "Content-Encoding" );
    if( status && status->code != 200 ) {
      DEBUG_WEBDAV("Content encoding ist <%s> with status %d", enc ? enc : "empty",
                   status ? status->code : -1 );
    }

    if( enc && c_streq( enc, "gzip" )) {
        writeCtx->decompress = ne_decompress_reader( req, ne_accept_2xx,
                                                     compress_reader,     /* reader callback */
                                                     (void*) writeCtx );  /* userdata        */
    } else {
        ne_add_response_body_reader( req, ne_accept_2xx,
                                     uncompress_reader,
                                     (void*) writeCtx );
        writeCtx->decompress = NULL;
    }
}
Example #4
0
csync_file_stat_t *csync_statedb_get_stat_by_file_id( sqlite3 *db,
                                                     const char *file_id ) {
   csync_file_stat_t *st = NULL;
   c_strlist_t *result = NULL;
   char *stmt = NULL;
   size_t len = 0;

   if (!file_id) {
       return 0;
   }
   if (c_streq(file_id, "")) {
       return 0;
   }
   stmt = sqlite3_mprintf("SELECT * FROM metadata WHERE fileid='%q'",
                          file_id);

   if (stmt == NULL) {
     return NULL;
   }

   result = csync_statedb_query(db, stmt);
   sqlite3_free(stmt);
   if (result == NULL) {
     return NULL;
   }

   if (result->count <= 6) {
     c_strlist_destroy(result);
     return NULL;
   }

   /* phash, pathlen, path, inode, uid, gid, mode, modtime */
   len = strlen(result->vector[2]);
   st = c_malloc(sizeof(csync_file_stat_t) + len + 1);
   if (st == NULL) {
     c_strlist_destroy(result);
     return NULL;
   }
   /* clear the whole structure */
   ZERO_STRUCTP(st);

   st->phash    = atoll(result->vector[0]);
   st->pathlen  = atoi(result->vector[1]);
   memcpy(st->path, (len ? result->vector[2] : ""), len + 1);
   st->inode    = atoll(result->vector[3]);
   st->uid      = atoi(result->vector[4]);
   st->gid      = atoi(result->vector[5]);
   st->mode     = atoi(result->vector[6]);
   st->modtime  = strtoul(result->vector[7], NULL, 10);
   st->type     = atoi(result->vector[8]);
   if( result->vector[9] )
     st->etag = c_strdup(result->vector[9]);

   csync_vio_set_file_id(st->file_id, file_id);

   c_strlist_destroy(result);

   return st;
 }
void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t *dst, const char* src ) {

    csync_vio_set_file_id( dst->file_id, src );
    if( c_streq( dst->file_id, "" )) {
        return;
    }
    dst->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID;
}
Example #6
0
static int owncloud_set_property(const char *key, void *data) {
#define READ_STRING_PROPERTY(P) \
    if (c_streq(key, #P)) { \
        SAFE_FREE(dav_session.P); \
        dav_session.P = c_strdup((const char*)data); \
        return 0; \
    }
#undef READ_STRING_PROPERTY

    if (c_streq(key, "file_progress_callback")) {
        _file_progress_cb = *(csync_file_progress_callback*)(data);
        return 0;
    }

    return -1;
}
Example #7
0
/* Return true if the two path have the same extension. false otherwise. */
static bool _csync_sameextension(const char *p1, const char *p2) {
    /* Find pointer to the extensions */
    const char *e1 = strrchr(p1, '.');
    const char *e2 = strrchr(p2, '.');

    /* If the found extension contains a '/', it is because the . was in the folder name
     *            => no extensions */
    if (e1 && strchr(e1, '/')) e1 = NULL;
    if (e2 && strchr(e2, '/')) e2 = NULL;

    /* If none have extension, it is the same extension */
    if (!e1 && !e2)
        return true;

    /* c_streq takes care of the rest */
    return c_streq(e1, e2);
}
static
#endif
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
    size_t i = 0;

    // We never want duplicates, so check whether the string is already
    // in the list first.
    if (*inList) {
        for (i = 0; i < (*inList)->count; ++i) {
            char *pattern = (*inList)->vector[i];
            if (c_streq(pattern, string)) {
                return 1;
            }
        }
    }
    return c_strlist_add_grow(inList, string);
}
Example #9
0
static int _csync_check_db_integrity(sqlite3 *db) {
    c_strlist_t *result = NULL;
    int rc = -1;

    result = csync_statedb_query(db, "PRAGMA quick_check;");
    if (result != NULL) {
        /* There is  a result */
        if (result->count > 0) {
            if (c_streq(result->vector[0], "ok")) {
                rc = 0;
            }
        }
        c_strlist_destroy(result);
    }

    return rc;

}
Example #10
0
csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx,
        const char *file_id ) {
    csync_file_stat_t *st = NULL;
    int rc = 0;

    if (!file_id) {
        return 0;
    }
    if (c_streq(file_id, "")) {
        return 0;
    }

    if( !ctx || ctx->db_is_empty ) {
        return NULL;
    }

    if( ctx->statedb.by_fileid_stmt == NULL ) {
        const char *query = "SELECT * FROM metadata WHERE fileid=?1";

        SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL));
        ctx->statedb.lastReturnValue = rc;
        if( rc != SQLITE_OK ) {
            CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for file id query.");
            return NULL;
        }
    }

    /* bind the query value */
    sqlite3_bind_text(ctx->statedb.by_fileid_stmt, 1, file_id, -1, SQLITE_STATIC);

    rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_fileid_stmt);
    ctx->statedb.lastReturnValue = rc;
    if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc);
    }
    // clear the resources used by the statement.
    sqlite3_reset(ctx->statedb.by_fileid_stmt);

    return st;
}
Example #11
0
static int _csync_check_db_integrity(sqlite3 *db) {
    c_strlist_t *result = NULL;
    int rc = -1;

    result = csync_statedb_query(db, "PRAGMA quick_check;");
    if (result != NULL) {
        /* There is  a result */
        if (result->count > 0) {
            if (c_streq(result->vector[0], "ok")) {
                rc = 0;
            }
        }
        c_strlist_destroy(result);
    }

    if( sqlite3_threadsafe() == 0 ) {
        CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "* WARNING: SQLite module is not threadsafe!");
        rc = -1;
    }

    return rc;
}
Example #12
0
static int _csync_statedb_check(const char *statedb) {
  int fd = -1;
  char buf[BUF_SIZE] = {0};
  sqlite3 *db = NULL;

  /* check db version */
  fd = open(statedb, O_RDONLY);
  if (fd >= 0) {
    if (read(fd, (void *) buf, (size_t) BUF_SIZE - 1) >= 0) {
      buf[BUF_SIZE - 1] = '\0';
      close(fd);
      if (c_streq(buf, "SQLite format 3")) {
        if (sqlite3_open(statedb, &db ) == SQLITE_OK) {
          /* everything is fine */
          sqlite3_close(db);
          return 0;
        } else {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "database corrupted, removing!");
          unlink(statedb);
        }
        sqlite3_close(db);
      } else {
        CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "sqlite version mismatch");
        unlink(statedb);
      }
    }
  }

  /* create database */
  if (sqlite3_open(statedb, &db) == SQLITE_OK) {
    sqlite3_close(db);
    return 0;
  }
  sqlite3_close(db);

  return -1;
}
Example #13
0
/* Configure the proxy depending on the variables */
static int configureProxy( ne_session *session )
{
    int port = 8080;
    int re = -1;

    if( ! session ) return -1;
    if( ! dav_session.proxy_type ) return 0; /* Go by NoProxy per default */

    if( dav_session.proxy_port > 0 ) {
        port = dav_session.proxy_port;
    }

    if( c_streq(dav_session.proxy_type, "NoProxy" )) {
        DEBUG_WEBDAV("No proxy configured.");
        re = 0;
    } else if( c_streq(dav_session.proxy_type, "DefaultProxy") ||
               c_streq(dav_session.proxy_type, "HttpProxy")    ||
               c_streq(dav_session.proxy_type, "HttpCachingProxy") ||
               c_streq(dav_session.proxy_type, "Socks5Proxy")) {

        if( dav_session.proxy_host ) {
            DEBUG_WEBDAV("%s at %s:%d", dav_session.proxy_type, dav_session.proxy_host, port );
            if (c_streq(dav_session.proxy_type, "Socks5Proxy")) {
                ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, dav_session.proxy_host, port,
                                       dav_session.proxy_user, dav_session.proxy_pwd);
            } else {
                ne_session_proxy(session, dav_session.proxy_host, port );
            }
            re = 2;
        } else {
            DEBUG_WEBDAV("%s requested but no proxy host defined.", dav_session.proxy_type );
	    /* we used to try ne_system_session_proxy here, but we should rather err out
	       to behave exactly like the caller. */
        }
    } else {
        DEBUG_WEBDAV( "Unsupported Proxy: %s", dav_session.proxy_type );
    }

    return re;
}
Example #14
0
/*
 * We merge replicas at the file level. The merged replica contains the
 * superset of files that are on the local machine and server copies of
 * the replica. In the case where the same file is in both the local
 * and server copy, the file that was modified most recently is used.
 * This means that new files are not deleted, and updated versions of
 * existing files are not overwritten.
 *
 * When a file is updated, the merge algorithm compares the destination
 * file with the the source file. If the destination file is newer
 * (timestamp is newer), it is not overwritten. If both files, on the
 * source and the destination, have been changed, the newer file wins.
 */
static int _csync_merge_algorithm_visitor(void *obj, void *data) {
    csync_file_stat_t *cur = NULL;
    csync_file_stat_t *other = NULL;
    csync_file_stat_t *tmp = NULL;
    uint64_t h = 0;
    int len = 0;

    CSYNC *ctx = NULL;
    c_rbtree_t *tree = NULL;
    c_rbnode_t *node = NULL;

    cur = (csync_file_stat_t *) obj;
    ctx = (CSYNC *) data;

    /* we need the opposite tree! */
    switch (ctx->current) {
    case LOCAL_REPLICA:
        tree = ctx->remote.tree;
        break;
    case REMOTE_REPLICA:
        tree = ctx->local.tree;
        break;
    default:
        break;
    }

    node = c_rbtree_find(tree, &cur->phash);

    if (!node) {
        /* Check the renamed path as well. */
        char *renamed_path = csync_rename_adjust_path(ctx, cur->path);
        if (!c_streq(renamed_path, cur->path)) {
            len = strlen( renamed_path );
            h = c_jhash64((uint8_t *) renamed_path, len, 0);
            node = c_rbtree_find(tree, &h);
        }
        SAFE_FREE(renamed_path);
    }
    if (!node) {
        /* Check if it is ignored */
        node = _csync_check_ignored(tree, cur->path, cur->pathlen);
        /* If it is ignored, other->instruction will be  IGNORE so this one will also be ignored */
    }

    /* file only found on current replica */
    if (node == NULL) {
        switch(cur->instruction) {
        /* file has been modified */
        case CSYNC_INSTRUCTION_EVAL:
            cur->instruction = CSYNC_INSTRUCTION_NEW;
            break;
            /* file has been removed on the opposite replica */
        case CSYNC_INSTRUCTION_NONE:
            cur->instruction = CSYNC_INSTRUCTION_REMOVE;
            break;
        case CSYNC_INSTRUCTION_EVAL_RENAME:
            if(ctx->current == LOCAL_REPLICA ) {
                /* use the old name to find the "other" node */
                tmp = csync_statedb_get_stat_by_inode(ctx, cur->inode);
                CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through inode %" PRIu64 ": %s",
                          cur->inode, tmp ? "true":"false");
            } else if( ctx->current == REMOTE_REPLICA ) {
                tmp = csync_statedb_get_stat_by_file_id(ctx, cur->file_id);
                CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through file ID %s: %s",
                          cur->file_id, tmp ? "true":"false");
            } else {
                CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unknown replica...");
            }

            if( tmp ) {
                if( tmp->path ) {
                    len = strlen( tmp->path );
                    h = c_jhash64((uint8_t *) tmp->path, len, 0);
                    /* First, check that the file is NOT in our tree (another file with the same name was added) */
                    node = c_rbtree_find(ctx->current == REMOTE_REPLICA ? ctx->remote.tree : ctx->local.tree, &h);
                    if (node) {
                        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Origin found in our tree : %s", tmp->path);
                    } else {
                        /* Find the temporar file in the other tree. */
                        node = c_rbtree_find(tree, &h);
                        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "PHash of temporary opposite (%s): %" PRIu64 " %s",
                                tmp->path , h, node ? "found": "not found" );
                        if (node) {
                            other = (csync_file_stat_t*)node->data;
                        } else {
                            /* the renamed file could not be found in the opposite tree. That is because it
                            * is not longer existing there, maybe because it was renamed or deleted.
                            * The journal is cleaned up later after propagation.
                            */
                        }
                    }
                }

                if(!other) {
                    cur->instruction = CSYNC_INSTRUCTION_NEW;
                } else if (other->instruction == CSYNC_INSTRUCTION_NONE
                           || cur->type == CSYNC_FTW_TYPE_DIR) {
                    other->instruction = CSYNC_INSTRUCTION_RENAME;
                    other->destpath = c_strdup( cur->path );
                    if( !c_streq(cur->file_id, "") ) {
                        csync_vio_set_file_id( other->file_id, cur->file_id );
                    }
                    cur->instruction = CSYNC_INSTRUCTION_NONE;
                } else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
                    other->instruction = CSYNC_INSTRUCTION_RENAME;
                    other->destpath = c_strdup( cur->path );

                    if( !c_streq(cur->file_id, "") ) {
                        csync_vio_set_file_id( other->file_id, cur->file_id );
                    }

                    cur->instruction = CSYNC_INSTRUCTION_NONE;
                } else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
                    cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
                } else {
                    cur->instruction = CSYNC_INSTRUCTION_NONE;
                    other->instruction = CSYNC_INSTRUCTION_SYNC;
                }
                csync_file_stat_free(tmp);
           }

            break;
        default:
            break;
        }
    } else {
        bool is_equal_files = false;
        /*
     * file found on the other replica
     */
        other = (csync_file_stat_t *) node->data;

        switch (cur->instruction) {
        case CSYNC_INSTRUCTION_EVAL_RENAME:
            /* If the file already exist on the other side, we have a conflict.
               Abort the rename and consider it is a new file. */
            cur->instruction = CSYNC_INSTRUCTION_NEW;
            /* fall trough */
        /* file on current replica is changed or new */
        case CSYNC_INSTRUCTION_EVAL:
        case CSYNC_INSTRUCTION_NEW:
            // This operation is usually a no-op and will by default return false
            if (csync_file_locked_or_open(ctx->local.uri, cur->path)) {
                CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] IGNORING file %s/%s since it is locked / open", ctx->local.uri, cur->path);
                cur->instruction = CSYNC_INSTRUCTION_ERROR;
                if (cur->error_status == CSYNC_STATUS_OK) // don't overwrite error
                    cur->error_status = CYSNC_STATUS_FILE_LOCKED_OR_OPEN;
                break;
            } else {
                //CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] not ignoring file %s/%s", ctx->local.uri, cur->path);
            }
            switch (other->instruction) {
            /* file on other replica is changed or new */
            case CSYNC_INSTRUCTION_NEW:
            case CSYNC_INSTRUCTION_EVAL:
                if (other->type == CSYNC_VIO_FILE_TYPE_DIRECTORY &&
                        cur->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
                    is_equal_files = (other->modtime == cur->modtime);
                } else {
                    is_equal_files = ((other->size == cur->size) && (other->modtime == cur->modtime));
                }
                if (is_equal_files) {
                    /* The files are considered equal. */
                    cur->instruction = CSYNC_INSTRUCTION_NONE;
                    other->instruction = CSYNC_INSTRUCTION_NONE;

                    if( !cur->etag && other->etag ) cur->etag = c_strdup(other->etag);
                    cur->should_update_etag = true; /* update DB */
                } else if(ctx->current == REMOTE_REPLICA) {
                        cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
                        other->instruction = CSYNC_INSTRUCTION_NONE;
                } else {
                        cur->instruction = CSYNC_INSTRUCTION_NONE;
                        other->instruction = CSYNC_INSTRUCTION_CONFLICT;
                }

                break;
                /* file on the other replica has not been modified */
            case CSYNC_INSTRUCTION_NONE:
                cur->instruction = CSYNC_INSTRUCTION_SYNC;
                break;
            case CSYNC_INSTRUCTION_IGNORE:
                cur->instruction = CSYNC_INSTRUCTION_IGNORE;
            break;
            default:
                break;
            }
        default:
            break;
        }
    }

    //hide instruction NONE messages when log level is set to debug,
    //only show these messages on log level trace
    if(cur->instruction ==CSYNC_INSTRUCTION_NONE)
    {
        if(cur->type == CSYNC_FTW_TYPE_DIR)
        {
            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
                      "%-20s  dir: %s",
                      csync_instruction_str(cur->instruction),
                      cur->path);
        }
        else
        {
            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
                      "%-20s file: %s",
                      csync_instruction_str(cur->instruction),
                      cur->path);
        }
    }
    else
    {
        if(cur->type == CSYNC_FTW_TYPE_DIR)
        {
            CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
                      "%-20s  dir: %s",
                      csync_instruction_str(cur->instruction),
                      cur->path);
        }
        else
        {
            CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
                      "%-20s file: %s",
                      csync_instruction_str(cur->instruction),
                      cur->path);
        }
    }

    return 0;
}
Example #15
0
/* File tree walker */
int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
    unsigned int depth) {
  char *filename = NULL;
  char *d_name = NULL;
  csync_vio_handle_t *dh = NULL;
  csync_vio_file_stat_t *dirent = NULL;
  csync_vio_file_stat_t *fs = NULL;
  csync_file_stat_t *previous_fs = NULL;
  int read_from_db = 0;
  int rc = 0;
  int res = 0;

  bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);

  if (uri[0] == '\0') {
    errno = ENOENT;
    ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
    goto error;
  }

  read_from_db = ctx->remote.read_from_db;

  // if the etag of this dir is still the same, its content is restored from the
  // database.
  if( do_read_from_db ) {
      if( ! fill_tree_from_db(ctx, uri) ) {
        errno = ENOENT;
        ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR;
        goto error;
      }
      goto done;
  }

  if ((dh = csync_vio_opendir(ctx, uri)) == NULL) {
      int asp = 0;
      /* permission denied */
      ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR);
      if (errno == EACCES) {
          return 0;
      } else if(errno == ENOENT) {
          asp = asprintf( &ctx->error_string, "%s", uri);
          if (asp < 0) {
              CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
          }
      } else {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
      }
      goto error;
  }

  while ((dirent = csync_vio_readdir(ctx, dh))) {
    const char *path = NULL;
    size_t ulen = 0;
    int flen;
    int flag;

    d_name = dirent->name;
    if (d_name == NULL) {
      ctx->status_code = CSYNC_STATUS_READDIR_ERROR;
      goto error;
    }

    /* skip "." and ".." */
    if (d_name[0] == '.' && (d_name[1] == '\0'
          || (d_name[1] == '.' && d_name[2] == '\0'))) {
      csync_vio_file_stat_destroy(dirent);
      dirent = NULL;
      continue;
    }

    flen = asprintf(&filename, "%s/%s", uri, d_name);
    if (flen < 0) {
      csync_vio_file_stat_destroy(dirent);
      dirent = NULL;
      ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
      goto error;
    }

    /* Create relative path */
    switch (ctx->current) {
      case LOCAL_REPLICA:
        ulen = strlen(ctx->local.uri) + 1;
        break;
      case REMOTE_REPLICA:
        ulen = strlen(ctx->remote.uri) + 1;
        break;
      default:
        break;
    }

    if (((size_t)flen) < ulen) {
      csync_vio_file_stat_destroy(dirent);
      dirent = NULL;
      ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
      goto error;
    }

    path = filename + ulen;

    /* skip ".csync_journal.db" and ".csync_journal.db.ctmp" */
    if (c_streq(path, ".csync_journal.db")
            || c_streq(path, ".csync_journal.db.ctmp")
            || c_streq(path, ".csync_journal.db.ctmp-journal")
            || c_streq(path, ".csync-progressdatabase")) {
        csync_vio_file_stat_destroy(dirent);
        dirent = NULL;
        SAFE_FREE(filename);
        continue;
    }

    /* Only for the local replica we have to stat(), for the remote one we have all data already */
    if (ctx->replica == LOCAL_REPLICA) {
        fs = csync_vio_file_stat_new();
        res = csync_vio_stat(ctx, filename, fs);
    } else {
        fs = dirent;
        res = 0;
    }

    if( res == 0) {
      switch (fs->type) {
        case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK:
          flag = CSYNC_FTW_FLAG_SLINK;
          break;
        case CSYNC_VIO_FILE_TYPE_DIRECTORY:
          flag = CSYNC_FTW_FLAG_DIR;
          break;
        case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE:
        case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE:
        case CSYNC_VIO_FILE_TYPE_SOCKET:
          flag = CSYNC_FTW_FLAG_SPEC;
          break;
        case CSYNC_VIO_FILE_TYPE_FIFO:
          flag = CSYNC_FTW_FLAG_SPEC;
          break;
        default:
          flag = CSYNC_FTW_FLAG_FILE;
          break;
      };
    } else {
      flag = CSYNC_FTW_FLAG_NSTAT;
    }

    if( ctx->current == LOCAL_REPLICA ) {
        char *etag = NULL;
        int len = strlen( path );
        uint64_t h = c_jhash64((uint8_t *) path, len, 0);
        etag = csync_statedb_get_etag( ctx, h );

        if( etag ) {
            SAFE_FREE(fs->etag);
            fs->etag = etag;
            fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;

            if( c_streq(etag, "")) {
                CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Uniq ID from Database is EMPTY: %s", path);
            } else {
                CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Uniq ID from Database: %s -> %s", path, fs->etag ? fs->etag : "<NULL>" );
            }
        }
    }

    previous_fs = ctx->current_fs;

    /* Call walker function for each file */
    rc = fn(ctx, filename, fs, flag);
    /* this function may update ctx->current and ctx->read_from_db */

    if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) {
        previous_fs->child_modified = ctx->current_fs->child_modified;
    }

    /* Only for the local replica we have to destroy stat(), for the remote one it is a pointer to dirent */
    if (ctx->replica == LOCAL_REPLICA) {
        csync_vio_file_stat_destroy(fs);
    }

    if (rc < 0) {
      if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
          ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
      }

      ctx->current_fs = previous_fs;
      goto error;
    }

    if (flag == CSYNC_FTW_FLAG_DIR && depth
        && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) {
      rc = csync_ftw(ctx, filename, fn, depth - 1);
      if (rc < 0) {
        ctx->current_fs = previous_fs;
        goto error;
      }

      if (ctx->current_fs && !ctx->current_fs->child_modified
          && ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) {
        ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE;
        ctx->current_fs->should_update_etag = true;
      }
    }

    if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs
        && (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
            ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW ||
            ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) {
        ctx->current_fs->should_update_etag = true;
    }

    ctx->current_fs = previous_fs;
    ctx->remote.read_from_db = read_from_db;
    SAFE_FREE(filename);
    csync_vio_file_stat_destroy(dirent);
    dirent = NULL;
  }

  csync_vio_closedir(ctx, dh);
  CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, " <= Closing walk for %s with read_from_db %d", uri, read_from_db);

done:
  csync_vio_file_stat_destroy(dirent);
  SAFE_FREE(filename);
  return rc;
error:
  ctx->remote.read_from_db = read_from_db;
  if (dh != NULL) {
    csync_vio_closedir(ctx, dh);
  }
  SAFE_FREE(filename);
  return -1;
}
Example #16
0
static int _csync_detect_update(CSYNC *ctx, const char *file,
    const csync_vio_file_stat_t *fs, const int type) {
  uint64_t h = 0;
  size_t len = 0;
  size_t size = 0;
  const char *path = NULL;
  csync_file_stat_t *st = NULL;
  csync_file_stat_t *tmp = NULL;
  CSYNC_EXCLUDE_TYPE excluded;

  if ((file == NULL) || (fs == NULL)) {
    errno = EINVAL;
    ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
    return -1;
  }

  path = file;
  switch (ctx->current) {
    case LOCAL_REPLICA:
      if (strlen(path) <= strlen(ctx->local.uri)) {
        ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
        return -1;
      }
      path += strlen(ctx->local.uri) + 1;
      break;
    case REMOTE_REPLICA:
      if (strlen(path) <= strlen(ctx->remote.uri)) {
        ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
        return -1;
      }
      path += strlen(ctx->remote.uri) + 1;
      break;
    default:
      path = NULL;
      ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
      return -1;
  }

  len = strlen(path);

  /* Check if file is excluded */
  excluded = csync_excluded(ctx, path,type);

  if (excluded != CSYNC_NOT_EXCLUDED) {
    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded  (%d)", path, excluded);
    if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
      switch (ctx->current) {
        case LOCAL_REPLICA:
          ctx->local.ignored_cleanup = c_list_append(ctx->local.ignored_cleanup, c_strdup(path));
          break;
        case REMOTE_REPLICA:
          ctx->remote.ignored_cleanup = c_list_append(ctx->remote.ignored_cleanup, c_strdup(path));
          break;
        default:
          break;
      }
      return 0;
    }
    if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
        return 0;
    }
  }

  h = _hash_of_file(ctx, file );
  if( h == 0 ) {
    return -1;
  }
  size = sizeof(csync_file_stat_t) + len + 1;

  st = c_malloc(size);
  if (st == NULL) {
    ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
    return -1;
  }

  /* Set instruction by default to none */
  st->instruction = CSYNC_INSTRUCTION_NONE;
  st->etag = NULL;
  st->child_modified = 0;

  /* check hardlink count */
  if (type == CSYNC_FTW_TYPE_FILE ) {
    if( fs->nlink > 1) {
      st->instruction = CSYNC_INSTRUCTION_IGNORE;
      goto out;
    }

    if (fs->mtime == 0) {
      tmp = csync_statedb_get_stat_by_hash(ctx, h);
      CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
      if (tmp == NULL) {
        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - not found in db, IGNORE!", path);
        st->instruction = CSYNC_INSTRUCTION_IGNORE;
      } else {
        SAFE_FREE(st);
        st = tmp;
        st->instruction = CSYNC_INSTRUCTION_NONE;
        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - tmp non zero, mtime %lu", path, st->modtime );
        tmp = NULL;
      }
      goto fastout; /* Skip copying of the etag. That's an important difference to upstream
                     * without etags. */
    }
  }

  /* Ignore non statable files and other strange cases. */
  if (type == CSYNC_FTW_TYPE_SKIP) {
    st->instruction = CSYNC_INSTRUCTION_NONE;
    goto out;
  }
  if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
      if( type == CSYNC_FTW_TYPE_SLINK ) {
          st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
      }
      st->instruction = CSYNC_INSTRUCTION_IGNORE;
    goto out;
  }

  /* Update detection: Check if a database entry exists.
   * If not, the file is either new or has been renamed. To see if it is
   * renamed, the db gets queried by the inode of the file as that one
   * does not change on rename.
   */
  if (csync_get_statedb_exists(ctx)) {
    tmp = csync_statedb_get_stat_by_hash(ctx, h);

    if(tmp && tmp->phash == h ) { /* there is an entry in the database */
        /* we have an update! */
        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Database entry found, compare: %" PRId64 " <-> %" PRId64 ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64,
                  ((int64_t) fs->mtime), ((int64_t) tmp->modtime), fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode);
        if( !fs->etag) {
            st->instruction = CSYNC_INSTRUCTION_EVAL;
            goto out;
        }
        if((ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag ))
            || (ctx->current == LOCAL_REPLICA && (fs->mtime != tmp->modtime
#if 0
                                                  || fs->inode != tmp->inode
#endif
                                                  ))) {
            /* Comparison of the local inode is disabled because people reported problems
             * on windows with flacky inode values, see github bug #779
             *
             * The inode needs to be observed because:
             * $>  echo a > a.txt ; echo b > b.txt
             * both files have the same mtime
             * sync them.
             * $> rm a.txt && mv b.txt a.txt
             * makes b.txt appearing as a.txt yet a sync is not performed because
             * both have the same modtime as mv does not change that.
             */
            st->instruction = CSYNC_INSTRUCTION_EVAL;
            goto out;
        }
        if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
                && c_streq(fs->file_id, tmp->file_id) && !ctx->read_from_db_disabled) {
            /* If both etag and file id are equal for a directory, read all contents from
             * the database.
             * The comparison of file id ensure that we fetch all the file id when upgrading from
             * owncloud 5 to owncloud 6.
             */
            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
            ctx->remote.read_from_db = true;
        }

        if (!c_streq(fs->file_id, tmp->file_id) && ctx->current == REMOTE_REPLICA) {
            /* file id has changed. Which means we need to update the DB.
             * (upgrade from owncloud 5 to owncloud 6 for instence) */
            st->should_update_etag = true;
        }
        st->instruction = CSYNC_INSTRUCTION_NONE;
    } else {
        enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;

        /* check if it's a file and has been renamed */
        if (ctx->current == LOCAL_REPLICA) {
            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);

            tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);

            /* translate the file type between the two stat types csync has. */
            if( tmp && tmp->type == 0 ) {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR;
            } else if( tmp && tmp->type == 2 ) {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
            } else {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
            }

            if (tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
                    && (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
#ifdef NO_RENAME_EXTENSION
                    && _csync_sameextension(tmp->path, path)
#endif
               ) {
                CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
                /* inode found so the file has been renamed */
                st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
                if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
                    csync_rename_record(ctx, tmp->path, path);
                }
                goto out;
            } else {
                /* file not found in statedb */
                st->instruction = CSYNC_INSTRUCTION_NEW;
                goto out;
            }
        } else {
            /* Remote Replica Rename check */
            tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);
            if(tmp ) {                           /* tmp existing at all */
                if ((tmp->type == CSYNC_FTW_TYPE_DIR && fs->type != CSYNC_VIO_FILE_TYPE_DIRECTORY) ||
                        (tmp->type == CSYNC_FTW_TYPE_FILE && fs->type != CSYNC_VIO_FILE_TYPE_REGULAR)) {
                    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "WARN: file types different is not!");
                    st->instruction = CSYNC_INSTRUCTION_NEW;
                    goto out;
                }
                st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
                if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
                    csync_rename_record(ctx, tmp->path, path);
                } else {
                    if( !c_streq(tmp->etag, fs->etag) ) {
                        /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ETags are different!"); */
                        /* File with different etag, don't do a rename, but download the file again */
                        st->instruction = CSYNC_INSTRUCTION_NEW;
                    }
                }
                goto out;

            } else {
                /* file not found in statedb */
                st->instruction = CSYNC_INSTRUCTION_NEW;
                goto out;
            }
        }
    }
  } else  {
      st->instruction = CSYNC_INSTRUCTION_NEW;
  }

out:

  /* Set the ignored error string. */
  if (st->instruction == CSYNC_INSTRUCTION_IGNORE) {
    if (excluded == CSYNC_FILE_EXCLUDE_LIST) {
      st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
    } else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) {
      st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS;  /* File contains invalid characters. */
    }
  }
  if (st->instruction != CSYNC_INSTRUCTION_NONE && st->instruction != CSYNC_INSTRUCTION_IGNORE
      && type != CSYNC_FTW_TYPE_DIR) {
    st->child_modified = 1;
  }
  ctx->current_fs = st;

  csync_file_stat_free(tmp);
  st->inode = fs->inode;
  st->mode  = fs->mode;
  st->size  = fs->size;
  st->modtime = fs->mtime;
  st->nlink = fs->nlink;
  st->type  = type;
  st->etag   = NULL;
  if( fs->etag ) {
      SAFE_FREE(st->etag);
      st->etag  = c_strdup(fs->etag);
  }
  csync_vio_set_file_id(st->file_id, fs->file_id);
  if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
      SAFE_FREE(st->directDownloadUrl);
      st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
  }
  if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
      SAFE_FREE(st->directDownloadCookies);
      st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
  }


fastout:  /* target if the file information is read from database into st */
  st->phash = h;
  st->pathlen = len;
  memcpy(st->path, (len ? path : ""), len + 1);

  switch (ctx->current) {
    case LOCAL_REPLICA:
      if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
        SAFE_FREE(st);
        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
        return -1;
      }
      break;
    case REMOTE_REPLICA:
      if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
        SAFE_FREE(st);
        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
        return -1;
      }
      break;
    default:
      break;
  }
  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "file: %s, instruction: %s <<=", st->path,
      csync_instruction_str(st->instruction));

  return 0;
}
void fetch_resource_list_recursive(const char *uri, const char *curi)
{
    int ret = 0;
    ne_propfind_handler *hdl = NULL;
    ne_request *request = NULL;
    const char *content_type = NULL;
    const ne_status *req_status = NULL;
    int depth = NE_DEPTH_INFINITE;

    DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi);

    /* do a propfind request and parse the results in the results function, set as callback */
    hdl = ne_propfind_create(dav_session.ctx, curi, depth);

    if(hdl) {
        ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi);
        request = ne_propfind_get_request( hdl );
        req_status = ne_get_status( request );
    }

    if( ret == NE_OK ) {
        /* Check the request status. */
        if( req_status && req_status->klass != 2 ) {
            set_errno_from_http_errcode(req_status->code);
            DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
                         req_status->reason_phrase);
            ret = NE_CONNECT;
            set_error_message(req_status->reason_phrase);
        }
        DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0);
    } else {
        if( ret == NE_ERROR && req_status->code == 404) {
            errno = ENOENT;
        } else {
            set_errno_from_neon_errcode(ret);
        }
    }

    if( ret == NE_OK ) {
        /* Check the content type. If the server has a problem, ie. database is gone or such,
         * the content type is not xml but a html error message. Stop on processing if it's
         * not XML.
         * FIXME: Generate user error message from the reply content.
         */
        content_type =  ne_get_response_header( request, "Content-Type" );
        if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) {
            DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
                         content_type ?  content_type: "<empty>");
            errno = ERRNO_WRONG_CONTENT;
            set_error_message("Server error: PROPFIND reply is not XML formatted!");
            ret = NE_CONNECT;
        }
    }

    if( ret != NE_OK ) {
        const char *err = NULL;

        err = ne_get_error( dav_session.ctx );
        DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
    }

    if( hdl )
        ne_propfind_destroy(hdl);

    if( ret != NE_OK ) {
        return;
    }

    return;
}
Example #18
0
static csync_vio_method_handle_t *owncloud_open(const char *durl,
                                                int flags,
                                                mode_t mode) {
    char *dir = NULL;
    char getUrl[PATH_MAX];
    int put = 0;
    int rc = NE_OK;
#ifdef _WIN32
    int gtp = 0;
    char tmpname[13];
    mbchar_t winTmp[PATH_MAX];
    mbchar_t *winUrlMB = NULL;
    char *winTmpUtf8 = NULL;
    csync_stat_t sb;
#endif

    struct transfer_context *writeCtx = NULL;
    csync_stat_t statBuf;
    memset( getUrl, '\0', PATH_MAX );

    (void) mode; /* unused on webdav server */
    DEBUG_WEBDAV( "=> open called for %s", durl );

    if( rc == NE_OK )
        dav_connect( durl );

    if (flags & O_WRONLY) {
        put = 1;
    }
    if (flags & O_RDWR) {
        put = 1;
    }
    if (flags & O_CREAT) {
        put = 1;
    }

    if( rc == NE_OK && put ) {
      /* check if the dir name exists. Otherwise return ENOENT */
      dir = c_dirname( durl );
      if (dir == NULL) {
        errno = ENOMEM;
        return NULL;
      }
      DEBUG_WEBDAV("Stating directory %s", dir );
      if( c_streq( dir, _lastDir )) {
        DEBUG_WEBDAV("Dir %s is there, we know it already.", dir);
      } else {
        if( owncloud_stat( dir, (csync_vio_method_handle_t*)(&statBuf) ) == 0 ) {
          DEBUG_WEBDAV("Directory of file to open exists.");
          SAFE_FREE( _lastDir );
          _lastDir = c_strdup(dir);

        } else {
          DEBUG_WEBDAV("Directory %s of file to open does NOT exist.", dir );
          /* the directory does not exist. That is an ENOENT */
          errno = ENOENT;
          SAFE_FREE( dir );
          return NULL;
        }
      }
    }

    writeCtx = c_malloc( sizeof(struct transfer_context) );

    writeCtx->url = _cleanPath( durl );
    if( ! writeCtx->url ) {
        DEBUG_WEBDAV("Failed to clean path for %s", durl );
        errno = EACCES;
        rc = NE_ERROR;
    }

    if( rc == NE_OK && put) {
        DEBUG_WEBDAV("PUT request on %s!", writeCtx->url);
        writeCtx->req = ne_request_create(dav_session.ctx, "PUT", writeCtx->url);
        writeCtx->method = "PUT";
    }

    if( rc == NE_OK && ! put ) {
        writeCtx->req = 0;
        writeCtx->method = "GET";

        /* the download via the get function requires a full uri */
        snprintf( getUrl, PATH_MAX, "%s://%s%s", ne_get_scheme( dav_session.ctx),
                  ne_get_server_hostport( dav_session.ctx ), writeCtx->url );
        DEBUG_WEBDAV("GET request on %s", getUrl );

        writeCtx->req = ne_request_create( dav_session.ctx, "GET", getUrl );

        /* Call the progress callback */
        if (_file_progress_cb) {
            ne_set_notifier(dav_session.ctx, ne_notify_status_cb, writeCtx);
            _file_progress_cb( writeCtx->url, CSYNC_NOTIFY_START_DOWNLOAD, 0 , 0, _userdata);
        }
    }

    if( rc != NE_OK ) {
        SAFE_FREE( writeCtx );
        writeCtx = NULL;
    }

    SAFE_FREE( dir );

    return (csync_vio_method_handle_t *) writeCtx;
}
Example #19
0
static int fetch_resource_list( const char *uri,
                                int depth,
                                struct listdir_context *fetchCtx )
{
  int ret = 0;
  ne_propfind_handler *hdl = NULL;
  ne_request *request = NULL;
  const char *content_type = NULL;
  char *curi = NULL;
  const ne_status *req_status = NULL;

  curi = _cleanPath( uri );

  if (!fetchCtx) {
    errno = ENOMEM;
    SAFE_FREE(curi);
    return -1;
  }
  fetchCtx->list = NULL;
  fetchCtx->target = curi;
  fetchCtx->currResource = NULL;

  /* do a propfind request and parse the results in the results function, set as callback */
  hdl = ne_propfind_create(dav_session.ctx, curi, depth);

  if(hdl) {
    ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
    request = ne_propfind_get_request( hdl );
    req_status = ne_get_status( request );
  }

  if( ret == NE_OK ) {
    fetchCtx->currResource = fetchCtx->list;
    /* Check the request status. */
    if( req_status && req_status->klass != 2 ) {
      set_errno_from_http_errcode(req_status->code);
      DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
                   req_status->reason_phrase);
      ret = NE_CONNECT;
      set_error_message(req_status->reason_phrase);
    }
    DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1);
  } else {
    if( ret == NE_ERROR && req_status->code == 404) {
      errno = ENOENT;
    } else {
      set_errno_from_neon_errcode(ret);
    }
  }

  if( ret == NE_OK ) {
    /* Check the content type. If the server has a problem, ie. database is gone or such,
        * the content type is not xml but a html error message. Stop on processing if it's
        * not XML.
        * FIXME: Generate user error message from the reply content.
        */
    content_type =  ne_get_response_header( request, "Content-Type" );
    if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) {
      DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
                   content_type ?  content_type: "<empty>");
      errno = ERRNO_WRONG_CONTENT;
      set_error_message("Server error: PROPFIND reply is not XML formatted!");
      ret = NE_CONNECT;
    }
  }
#ifndef NDEBUG
  if( ret != NE_OK ) {
    const char *err = ne_get_error(dav_session.ctx);
    DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
  }
#endif /* NDEBUG */

  if (hdl != NULL) {
    ne_propfind_destroy(hdl);
  }

#ifndef NDEBUG
  if (ret == NE_REDIRECT) {
    const ne_uri *redir_ne_uri = ne_redirect_location(dav_session.ctx);
    if (redir_ne_uri) {
      char *redir_uri = ne_uri_unparse(redir_ne_uri);
      DEBUG_WEBDAV("Permanently moved to %s", redir_uri);
    }
  }
#endif /* NDEBUG */

  if( ret != NE_OK ) {
    free_fetchCtx(fetchCtx);
    return -1;
  }

  return 0;
}
Example #20
0
CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
  size_t i = 0;
  const char *p = NULL;
  char *bname = NULL;
  char *dname = NULL;
  char *prev_dname = NULL;
  char *conflict = NULL;
  int rc = -1;
  CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
  CSYNC_EXCLUDE_TYPE type  = CSYNC_NOT_EXCLUDED;

    for (p = path; *p; p++) {
      switch (*p) {
        case '\\':
        case ':':
        case '?':
        case '*':
        case '"':
        case '>':
        case '<':
        case '|':
          return CSYNC_FILE_EXCLUDE_INVALID_CHAR;
        default:
          break;
      }
    }

  /* split up the path */
  dname = c_dirname(path);
  bname = c_basename(path);

  if (bname == NULL || dname == NULL) {
      match = CSYNC_NOT_EXCLUDED;
      SAFE_FREE(bname);
      SAFE_FREE(dname);
      goto out;
  }

  rc = csync_fnmatch(".csync_journal.db*", bname, 0);
  if (rc == 0) {
      match = CSYNC_FILE_SILENTLY_EXCLUDED;
      SAFE_FREE(bname);
      SAFE_FREE(dname);
      goto out;
  }

  rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
  if (rc == 0) {
      match = CSYNC_FILE_SILENTLY_EXCLUDED;
      SAFE_FREE(bname);
      SAFE_FREE(dname);
      goto out;
  }

  /* Always ignore conflict files, not only via the exclude list */
  rc = csync_fnmatch("*_conflict-*", bname, 0);
  if (rc == 0) {
      match = CSYNC_FILE_SILENTLY_EXCLUDED;
      SAFE_FREE(bname);
      SAFE_FREE(dname);
      goto out;
  }

  if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) {
      asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME"));
      rc = csync_fnmatch(conflict, path, 0);
      if (rc == 0) {
          match = CSYNC_FILE_SILENTLY_EXCLUDED;
          SAFE_FREE(conflict);
          SAFE_FREE(bname);
          SAFE_FREE(dname);
          goto out;
      }
      SAFE_FREE(conflict);
  }

  SAFE_FREE(bname);
  SAFE_FREE(dname);

  if (ctx->excludes == NULL) {
      goto out;
  }

  /* Loop over all exclude patterns and evaluate the given path */
  for (i = 0; match == CSYNC_NOT_EXCLUDED && i < ctx->excludes->count; i++) {
      bool match_dirs_only = false;
      char *pattern_stored = c_strdup(ctx->excludes->vector[i]);
      char* pattern = pattern_stored;

      type = CSYNC_FILE_EXCLUDE_LIST;
      if (strlen(pattern) < 1) {
          continue;
      }
      /* Ecludes starting with ']' means it can be cleanup */
      if (pattern[0] == ']') {
          ++pattern;
          if (filetype == CSYNC_FTW_TYPE_FILE) {
              type = CSYNC_FILE_EXCLUDE_AND_REMOVE;
          }
      }
      /* Check if the pattern applies to pathes only. */
      if (pattern[strlen(pattern)-1] == '/') {
          match_dirs_only = true;
          pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
      }

      /* check if the pattern contains a / and if, compare to the whole path */
      if (strchr(pattern, '/')) {
          rc = csync_fnmatch(pattern, path, FNM_PATHNAME);
          if( rc == 0 ) {
              match = type;
          }
          /* if the pattern requires a dir, but path is not, its still not excluded. */
          if (match_dirs_only && filetype != CSYNC_FTW_TYPE_DIR) {
              match = CSYNC_NOT_EXCLUDED;
          }
      }

      /* if still not excluded, check each component of the path */
      if (match == CSYNC_NOT_EXCLUDED) {
          int trailing_component = 1;
          dname = c_dirname(path);
          bname = c_basename(path);

          if (bname == NULL || dname == NULL) {
              match = CSYNC_NOT_EXCLUDED;
              goto out;
          }

          /* Check each component of the path */
          do {
              /* Do not check the bname if its a file and the pattern matches dirs only. */
              if ( !(trailing_component == 1 /* it is the trailing component */
                     && match_dirs_only      /* but only directories are matched by the pattern */
                     && filetype == CSYNC_FTW_TYPE_FILE) ) {
                  /* Check the name component against the pattern */
                  rc = csync_fnmatch(pattern, bname, 0);
                  if (rc == 0) {
                      match = type;
                  }
              }
              if (!(c_streq(dname, ".") || c_streq(dname, "/"))) {
                  rc = csync_fnmatch(pattern, dname, 0);
                  if (rc == 0) {
                      match = type;
                  }
              }
              trailing_component = 0;
              prev_dname = dname;
              SAFE_FREE(bname);
              bname = c_basename(prev_dname);
              dname = c_dirname(prev_dname);
              SAFE_FREE(prev_dname);

          } while( match == CSYNC_NOT_EXCLUDED && !c_streq(dname, ".")
                     && !c_streq(dname, "/") );
      }
      SAFE_FREE(pattern_stored);
      SAFE_FREE(bname);
      SAFE_FREE(dname);
  }

out:

  return match;
}
Example #21
0
int c_rmdirs(const char *path) {
  _TDIR *d;
  struct _tdirent *dp;
  csync_stat_t sb;
  char *fname = NULL;
  mbchar_t *wfname = NULL;
  mbchar_t *wpath = c_utf8_to_locale(path);
  char *rd_name = NULL;

  if ((d = _topendir(wpath)) != NULL) {
    while( _tstat(wpath, &sb) == 0) {
      /* if we can remove the directory we're done */
      if (_trmdir(wpath) == 0) {
        break;
      }
      switch (errno) {
        case ENOTEMPTY:
        case EEXIST:
        case EBADF:
          break; /* continue */
        default:
          _tclosedir(d);
	  c_free_locale_string(wpath);
          return 0;
      }

      while ((dp = _treaddir(d)) != NULL) {
        size_t len;
	rd_name = c_utf8_from_locale(dp->d_name);
        /* skip '.' and '..' */
	if( c_streq( rd_name, "." ) || c_streq( rd_name, ".." ) ) {
	  c_free_locale_string(rd_name);
          continue;
        }

        len = strlen(path) + strlen(rd_name) + 2;
        fname = c_malloc(len);
        if (fname == NULL) {
          _tclosedir(d);
	  c_free_locale_string(rd_name);
	  c_free_locale_string(wpath);
          return -1;
        }
        snprintf(fname, len, "%s/%s", path, rd_name);
	wfname = c_utf8_to_locale(fname);

        /* stat the file */
        if (_tstat(wfname, &sb) != -1) {
#ifdef __unix__
          if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) {
#else
          if (S_ISDIR(sb.st_mode)) {
#endif
            if (_trmdir(wfname) < 0) { /* can't be deleted */
              if (errno == EACCES) {
                _tclosedir(d);
                SAFE_FREE(fname);
		c_free_locale_string(wfname);
		c_free_locale_string(rd_name);
		c_free_locale_string(wpath);
                return -1;
              }
              c_rmdirs(fname);
            }
          } else {
            _tunlink(wfname);
          }
        } /* lstat */
        SAFE_FREE(fname);
	c_free_locale_string(wfname);
	c_free_locale_string(rd_name);
      } /* readdir */

      _trewinddir(d);
    }
  } else {
    c_free_locale_string(wpath);
    return -1;
  }

  c_free_locale_string(wpath);
  _tclosedir(d);
  return 0;
}
Example #22
0
/* check if path is a file */
int c_isfile(const char *path) {
  csync_stat_t sb;

  if (lstat (path, &sb) < 0) {
    return 0;
  }

#ifdef __unix__
  if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
#else
  if (S_ISREG(sb.st_mode)) {
#endif
    return 1;
  }

  return 0;
}

/* copy file from src to dst, overwrites dst */
int c_copy(const char* src, const char *dst, mode_t mode) {
  int srcfd = -1;
  int dstfd = -1;
  int rc = -1;
  ssize_t bread, bwritten;
  csync_stat_t sb;
  char buf[4096];

#ifdef _WIN32
  if(src && dst) {
      if (CopyFile(src, dst, FALSE)) {
          return 0;
      }
      errno = GetLastError();

      return -1;
  }
#endif

  if (c_streq(src, dst)) {
    return -1;
  }

  if (lstat(src, &sb) < 0) {
    return -1;
  }

  if (S_ISDIR(sb.st_mode)) {
    errno = EISDIR;
    return -1;
  }

  if (mode == 0) {
    mode = sb.st_mode;
  }

  if (lstat(dst, &sb) == 0) {
    if (S_ISDIR(sb.st_mode)) {
      errno = EISDIR;
      return -1;
    }
  }

  if ((srcfd = open(src, O_RDONLY, 0)) < 0) {
    rc = -1;
    goto out;
  }

  if ((dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode)) < 0) {
    rc = -1;
    goto out;
  }

  for (;;) {
    bread = read(srcfd, buf, sizeof(buf));
    if (bread == 0) {
      /* done */
      break;
    } else if (bread < 0) {
      errno = ENODATA;
      rc = -1;
      goto out;
    }

    bwritten = write(dstfd, buf, bread);
    if (bwritten < 0) {
      errno = ENODATA;
      rc = -1;
      goto out;
    }

    if (bread != bwritten) {
      errno = EFAULT;
      rc = -1;
      goto out;
    }
  }

#ifdef __unix__
  fsync(dstfd);
#endif

  rc = 0;
out:
  if (srcfd > 0) {
    close(srcfd);
  }
  if (dstfd > 0) {
      close(dstfd);
  }
  if (rc < 0) {
    unlink(dst);
  }
  return rc;
}
Example #23
0
/*
 * This function uses the vio_opendir, vio_readdir and vio_closedir functions
 * to traverse a file tree that was created before by the create_dir function.
 *
 * It appends a listing to the result member of the incoming struct in *state
 * that can be compared later to what was expected in the calling functions.
 * 
 * The int parameter cnt contains the number of seen files (not dirs) in the
 * whole tree.
 *
 */
static void traverse_dir(void **state, const char *dir, int *cnt)
{
    csync_vio_handle_t *dh;
    csync_vio_file_stat_t *dirent;
    statevar *sv = (statevar*) *state;
    CSYNC *csync = sv->csync;
    char *subdir;
    char *subdir_out;
    int rc;
    int is_dir;

    /* Format: Smuggle in the C: for unix platforms as its urgently needed
     * on Windows and the test can be nicely cross platform this way. */
#ifdef _WIN32
    const char *format_str = "%s %s";
#else
    const char *format_str = "%s C:%s";
#endif

    dh = csync_vio_opendir(csync, dir);
    assert_non_null(dh);

    while( (dirent = csync_vio_readdir(csync, dh)) ) {
        assert_non_null(dirent);
        if (dirent->original_name) {
            sv->ignored_dir = c_strdup(dirent->original_name);
            continue;
        }

        assert_non_null(dirent->name);
        assert_int_equal( dirent->fields & CSYNC_VIO_FILE_STAT_FIELDS_TYPE, CSYNC_VIO_FILE_STAT_FIELDS_TYPE );

        if( c_streq( dirent->name, "..") || c_streq( dirent->name, "." )) {
          continue;
        }

        is_dir = (dirent->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) ? 1:0;

        assert_int_not_equal( asprintf( &subdir, "%s/%s", dir, dirent->name ), -1 );

        assert_int_not_equal( asprintf( &subdir_out, format_str,
                                        is_dir ? "<DIR>":"     ",
                                        subdir), -1 );

        if( is_dir ) {
            if( !sv->result ) {
                sv->result = c_strdup( subdir_out);
            } else {
                int newlen = 1+strlen(sv->result)+strlen(subdir_out);
                char *tmp = sv->result;
                sv->result = c_malloc(newlen);
                strcpy( sv->result, tmp);
                SAFE_FREE(tmp);

                strcat( sv->result, subdir_out );
            }
        } else {
            *cnt = *cnt +1;
        }
        output(subdir_out);
        if( is_dir ) {
          traverse_dir( state, subdir, cnt);
        }

        SAFE_FREE(subdir);
        SAFE_FREE(subdir_out);
    }

    csync_vio_file_stat_destroy(dirent);
    rc = csync_vio_closedir(csync, dh);
    assert_int_equal(rc, 0);

}
Example #24
0
/* File tree walker */
int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
    unsigned int depth) {
  char *filename = NULL;
  char *d_name = NULL;
  csync_vio_handle_t *dh = NULL;
  csync_vio_file_stat_t *dirent = NULL;
  csync_file_stat_t *previous_fs = NULL;
  int read_from_db = 0;
  int rc = 0;
  int res = 0;

  bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);

  if (uri[0] == '\0') {
    errno = ENOENT;
    ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
    goto error;
  }

  read_from_db = ctx->remote.read_from_db;

  // if the etag of this dir is still the same, its content is restored from the
  // database.
  if( do_read_from_db ) {
      if( ! fill_tree_from_db(ctx, uri) ) {
        errno = ENOENT;
        ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR;
        goto error;
      }
      goto done;
  }

  const char *uri_for_vio = uri;
  if (ctx->current == REMOTE_REPLICA) {
      uri_for_vio += strlen(ctx->remote.uri);
      if (strlen(uri_for_vio) > 0 && uri_for_vio[0] == '/') {
          uri_for_vio++; // cut leading slash
      }
      CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "URI without fuzz for %s is \"%s\"", uri, uri_for_vio);
  }

  if ((dh = csync_vio_opendir(ctx, uri_for_vio)) == NULL) {
      if (ctx->abort) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
          ctx->status_code = CSYNC_STATUS_ABORTED;
          goto error;
      }
      int asp = 0;
      /* permission denied */
      ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR);
      if (errno == EACCES) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Permission denied.");
          if (mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_PERMISSION_DENIED)) {
              goto done;
          }
      } else if(errno == ENOENT) {
          asp = asprintf( &ctx->error_string, "%s", uri);
          if (asp < 0) {
              CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
          }
      }
      // 403 Forbidden can be sent by the server if the file firewall is active.
      // A file or directory should be ignored and sync must continue. See #3490
      else if(errno == ERRNO_FORBIDDEN) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Directory access Forbidden (File Firewall?)");
          if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_FORBIDDEN) ) {
              goto done;
          }
          /* if current_fs is not defined here, better throw an error */
      }
      // The server usually replies with the custom "503 Storage not available"
      // if some path is temporarily unavailable. But in some cases a standard 503
      // is returned too. Thus we can't distinguish the two and will treat any
      // 503 as request to ignore the folder. See #3113 #2884.
      else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!");
          if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_STORAGE_UNAVAILABLE ) ) {
              goto done;
          }
          /* if current_fs is not defined here, better throw an error */
      } else {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
      }
      goto error;
  }

  while ((dirent = csync_vio_readdir(ctx, dh))) {
    const char *path = NULL;
    size_t ulen = 0;
    int flen;
    int flag;

    /* Conversion error */
    if (dirent->name == NULL && dirent->original_name) {
        ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS;
        ctx->error_string = dirent->original_name; // take ownership
        dirent->original_name = NULL;
        goto error;
    }

    d_name = dirent->name;
    if (d_name == NULL) {
      ctx->status_code = CSYNC_STATUS_READDIR_ERROR;
      goto error;
    }

    /* skip "." and ".." */
    if ( (d_name[0] == '.' && d_name[1] == '\0')
          || (d_name[0] == '.' && d_name[1] == '.' && d_name[2] == '\0')) {
      csync_vio_file_stat_destroy(dirent);
      dirent = NULL;
      continue;
    }

    flen = asprintf(&filename, "%s/%s", uri, d_name);
    if (flen < 0) {
      csync_vio_file_stat_destroy(dirent);
      dirent = NULL;
      ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
      goto error;
    }

    /* Create relative path */
    switch (ctx->current) {
      case LOCAL_REPLICA:
        ulen = strlen(ctx->local.uri) + 1;
        break;
      case REMOTE_REPLICA:
        ulen = strlen(ctx->remote.uri) + 1;
        break;
      default:
        break;
    }

    if (((size_t)flen) < ulen) {
      csync_vio_file_stat_destroy(dirent);
      dirent = NULL;
      ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
      goto error;
    }

    path = filename + ulen;

    /* skip ".csync_journal.db" and ".csync_journal.db.ctmp" */
    /* Isn't this done via csync_exclude already? */
    if (c_streq(path, ".csync_journal.db")
            || c_streq(path, ".csync_journal.db.ctmp")
            || c_streq(path, ".csync_journal.db.ctmp-journal")
            || c_streq(path, ".csync-progressdatabase")
            || c_streq(path, ".csync_journal.db-shm")
            || c_streq(path, ".csync_journal.db-wal")
            || c_streq(path, ".csync_journal.db-journal")) {
        csync_vio_file_stat_destroy(dirent);
        dirent = NULL;
        SAFE_FREE(filename);
        continue;
    }

    /* Only for the local replica we have to stat(), for the remote one we have all data already */
    if (ctx->replica == LOCAL_REPLICA) {
        res = csync_vio_stat(ctx, filename, dirent);
    } else {
        res = 0;
    }

    /* if the filename starts with a . we consider it a hidden file
     * For windows, the hidden state is also discovered within the vio
     * local stat function.
     */
    if( d_name[0] == '.' ) {
        if (strcmp(".sys.admin#recall#", d_name) != 0) { /* recall file shall not be ignored (#4420) */
            dirent->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
        }
    }

    if( res == 0) {
      switch (dirent->type) {
        case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK:
          flag = CSYNC_FTW_FLAG_SLINK;
          break;
        case CSYNC_VIO_FILE_TYPE_DIRECTORY:
          flag = CSYNC_FTW_FLAG_DIR;
          break;
        case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE:
        case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE:
        case CSYNC_VIO_FILE_TYPE_SOCKET:
          flag = CSYNC_FTW_FLAG_SPEC;
          break;
        case CSYNC_VIO_FILE_TYPE_FIFO:
          flag = CSYNC_FTW_FLAG_SPEC;
          break;
        default:
          flag = CSYNC_FTW_FLAG_FILE;
          break;
      };
    } else {
      flag = CSYNC_FTW_FLAG_NSTAT;
    }

    previous_fs = ctx->current_fs;

    /* Call walker function for each file */
    rc = fn(ctx, filename, dirent, flag);
    /* this function may update ctx->current and ctx->read_from_db */

    if (rc < 0) {
      if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
          ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
      }

      ctx->current_fs = previous_fs;
      goto error;
    }

    if (flag == CSYNC_FTW_FLAG_DIR && depth && rc == 0
        && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) {
      rc = csync_ftw(ctx, filename, fn, depth - 1);
      if (rc < 0) {
        ctx->current_fs = previous_fs;
        goto error;
      }

      if (ctx->current_fs && !ctx->current_fs->child_modified
          && ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) {
        ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE;
        if (ctx->current == REMOTE_REPLICA) {
          ctx->current_fs->should_update_metadata = true;
        }
      }

      if (ctx->current_fs && previous_fs && ctx->current_fs->has_ignored_files) {
          /* If a directory has ignored files, put the flag on the parent directory as well */
          previous_fs->has_ignored_files = ctx->current_fs->has_ignored_files;
      }
    }

    if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) {
        /* If a directory has modified files, put the flag on the parent directory as well */
        previous_fs->child_modified = ctx->current_fs->child_modified;
    }

    if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs
        && (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
            ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW)) {
        ctx->current_fs->should_update_metadata = true;
    }

    ctx->current_fs = previous_fs;
    ctx->remote.read_from_db = read_from_db;
    SAFE_FREE(filename);
    csync_vio_file_stat_destroy(dirent);
    dirent = NULL;
  }

  csync_vio_closedir(ctx, dh);
  CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, " <= Closing walk for %s with read_from_db %d", uri, read_from_db);

done:
  csync_vio_file_stat_destroy(dirent);
  SAFE_FREE(filename);
  return rc;
error:
  ctx->remote.read_from_db = read_from_db;
  if (dh != NULL) {
    csync_vio_closedir(ctx, dh);
  }
  SAFE_FREE(filename);
  return -1;
}
Example #25
0
static int _csync_detect_update(CSYNC *ctx, const char *file,
    const csync_vio_file_stat_t *fs, const int type) {
  uint64_t h = 0;
  size_t len = 0;
  size_t size = 0;
  const char *path = NULL;
  csync_file_stat_t *st = NULL;
  csync_file_stat_t *tmp = NULL;
  CSYNC_EXCLUDE_TYPE excluded;

  if ((file == NULL) || (fs == NULL)) {
    errno = EINVAL;
    ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
    return -1;
  }

  path = file;
  switch (ctx->current) {
    case LOCAL_REPLICA:
      if (strlen(path) <= strlen(ctx->local.uri)) {
        ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
        return -1;
      }
      path += strlen(ctx->local.uri) + 1;
      break;
    case REMOTE_REPLICA:
      if (strlen(path) <= strlen(ctx->remote.uri)) {
        ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
        return -1;
      }
      path += strlen(ctx->remote.uri) + 1;
      break;
    default:
      path = NULL;
      ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
      return -1;
  }

  len = strlen(path);

  if (type == CSYNC_FTW_TYPE_SKIP) {
      excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED;
  } else {
    /* Check if file is excluded */
    excluded = csync_excluded_traversal(ctx->excludes, path, type);
  }

  if( excluded == CSYNC_NOT_EXCLUDED ) {
      /* Even if it is not excluded by a pattern, maybe it is to be ignored
       * because it's a hidden file that should not be synced.
       * This code should probably be in csync_exclude, but it does not have the fs parameter.
       * Keep it here for now */
      if (ctx->ignore_hidden_files && (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN)) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
          excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
      }
  } else {
      /* File is ignored because it's matched by a user- or system exclude pattern. */
      CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded  (%d)", path, excluded);
      if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
          return 1;
      }
      if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
          return 1;
      }
  }

  if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) {
      if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) {
          return 1;
      }
  }

  h = _hash_of_file(ctx, file );
  if( h == 0 ) {
    return -1;
  }
  size = sizeof(csync_file_stat_t) + len + 1;

  st = c_malloc(size);

  /* Set instruction by default to none */
  st->instruction = CSYNC_INSTRUCTION_NONE;
  st->etag = NULL;
  st->child_modified = 0;
  st->has_ignored_files = 0;
  if (type == CSYNC_FTW_TYPE_FILE ) {
    if (fs->mtime == 0) {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
    }
  }

  if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
      st->instruction = CSYNC_INSTRUCTION_IGNORE;
      if (ctx->current_fs) {
          ctx->current_fs->has_ignored_files = true;
      }

      goto out;
  }

  /* Update detection: Check if a database entry exists.
   * If not, the file is either new or has been renamed. To see if it is
   * renamed, the db gets queried by the inode of the file as that one
   * does not change on rename.
   */
  if (csync_get_statedb_exists(ctx)) {
    tmp = csync_statedb_get_stat_by_hash(ctx, h);

    if(_last_db_return_error(ctx)) {
        SAFE_FREE(st);
        SAFE_FREE(tmp);
        ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
        return -1;
    }

    if(tmp && tmp->phash == h ) { /* there is an entry in the database */
        /* we have an update! */
        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Database entry found, compare: %" PRId64 " <-> %" PRId64
                                            ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
                                            ", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s, ignore: %d",
                  ((int64_t) fs->mtime), ((int64_t) tmp->modtime),
                  fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
                  (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
        if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) {
            st->instruction = CSYNC_INSTRUCTION_EVAL;

            // Preserve the EVAL flag later on if the type has changed.
            if (_csync_filetype_different(tmp, fs)) {
                st->child_modified = 1;
            }

            goto out;
        }
        if (ctx->current == LOCAL_REPLICA &&
                (!_csync_mtime_equal(fs->mtime, tmp->modtime)
                 // zero size in statedb can happen during migration
                 || (tmp->size != 0 && fs->size != tmp->size))) {

            // Checksum comparison at this stage is only enabled for .eml files,
            // check #4754 #4755
            bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0;
            if (isEmlFile && fs->size == tmp->size && tmp->checksumTypeId) {
                if (ctx->callbacks.checksum_hook) {
                    st->checksum = ctx->callbacks.checksum_hook(
                                file, tmp->checksumTypeId,
                                ctx->callbacks.checksum_userdata);
                }
                bool checksumIdentical = false;
                if (st->checksum) {
                    st->checksumTypeId = tmp->checksumTypeId;
                    checksumIdentical = strncmp(st->checksum, tmp->checksum, 1000) == 0;
                }
                if (checksumIdentical) {
                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
                    st->instruction = CSYNC_INSTRUCTION_NONE;
                    st->should_update_metadata = true;
                    goto out;
                }
            }

            // Preserve the EVAL flag later on if the type has changed.
            if (_csync_filetype_different(tmp, fs)) {
                st->child_modified = 1;
            }

            st->instruction = CSYNC_INSTRUCTION_EVAL;
            goto out;
        }
        bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
                                                            || !c_streq(fs->remotePerm, tmp->remotePerm)))
                             || (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
        if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
                && !metadata_differ && ctx->read_remote_from_db) {
            /* If both etag and file id are equal for a directory, read all contents from
             * the database.
             * The metadata comparison ensure that we fetch all the file id or permission when
             * upgrading owncloud
             */
            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
            ctx->remote.read_from_db = true;
        }
        if (metadata_differ) {
            /* file id or permissions has changed. Which means we need to update them in the DB. */
            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
            st->should_update_metadata = true;
        }
        /* If it was remembered in the db that the remote dir has ignored files, store
         * that so that the reconciler can make advantage of.
         */
        if( ctx->current == REMOTE_REPLICA ) {
            st->has_ignored_files = tmp->has_ignored_files;
        }
        st->instruction = CSYNC_INSTRUCTION_NONE;
    } else {
        enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;

        /* tmp might point to malloc mem, so free it here before reusing tmp  */
        SAFE_FREE(tmp);

        /* check if it's a file and has been renamed */
        if (ctx->current == LOCAL_REPLICA) {
            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);

            tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);

            if(_last_db_return_error(ctx)) {
                SAFE_FREE(st);
                ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
                return -1;
            }

            /* translate the file type between the two stat types csync has. */
            if( tmp && tmp->type == CSYNC_FTW_TYPE_FILE ) {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR;
            } else if( tmp && tmp->type == CSYNC_FTW_TYPE_DIR) {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
            } else if( tmp && tmp->type == CSYNC_FTW_TYPE_SLINK ) {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
            } else {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
            }

            // Default to NEW unless we're sure it's a rename.
            st->instruction = CSYNC_INSTRUCTION_NEW;

            bool isRename =
                tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
                    && (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
#ifdef NO_RENAME_EXTENSION
                    && _csync_sameextension(tmp->path, path)
#endif
                ;


            // Verify the checksum where possible
            if (isRename && tmp->checksumTypeId && ctx->callbacks.checksum_hook
                    && fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) {
                st->checksum = ctx->callbacks.checksum_hook(
                            file, tmp->checksumTypeId,
                            ctx->callbacks.checksum_userdata);
                if (st->checksum) {
                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksum, tmp->checksum);
                    st->checksumTypeId = tmp->checksumTypeId;
                    isRename = strncmp(st->checksum, tmp->checksum, 1000) == 0;
                }
            }

            if (isRename) {
                CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
                /* inode found so the file has been renamed */
                st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
                if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
                    csync_rename_record(ctx, tmp->path, path);
                }
            }
            goto out;

        } else {
            /* Remote Replica Rename check */
            tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);

            if(_last_db_return_error(ctx)) {
                SAFE_FREE(st);
                ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
                return -1;
            }
            if(tmp ) {                           /* tmp existing at all */
                if ( _csync_filetype_different(tmp, fs)) {
                    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "WARN: file types different is not!");
                    st->instruction = CSYNC_INSTRUCTION_NEW;
                    goto out;
                }
                CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path, file);
                st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
                if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
                    csync_rename_record(ctx, tmp->path, path);
                } else {
                    if( !c_streq(tmp->etag, fs->etag) ) {
                        /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ETags are different!"); */
                        /* File with different etag, don't do a rename, but download the file again */
                        st->instruction = CSYNC_INSTRUCTION_NEW;
                    }
                }
                goto out;

            } else {
                /* file not found in statedb */
                st->instruction = CSYNC_INSTRUCTION_NEW;

                if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
                    if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path)) {
                        SAFE_FREE(st);
                        return 1;
                    }
                }
                goto out;
            }
        }
    }
  } else  {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unable to open statedb" );
      SAFE_FREE(st);
      ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
      return -1;
  }

out:

  /* Set the ignored error string. */
  if (st->instruction == CSYNC_INSTRUCTION_IGNORE) {
      if( type == CSYNC_FTW_TYPE_SLINK ) {
          st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
      } else {
          if (excluded == CSYNC_FILE_EXCLUDE_LIST) {
              st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
          } else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) {
              st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS;  /* File contains invalid characters. */
          } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
              st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
          } else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) {
              st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN;
          } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) {
              st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED;
          }
      }
  }
  if (st->instruction != CSYNC_INSTRUCTION_NONE && st->instruction != CSYNC_INSTRUCTION_IGNORE
      && type != CSYNC_FTW_TYPE_DIR) {
    st->child_modified = 1;
  }
  ctx->current_fs = st;

  csync_file_stat_free(tmp);
  st->inode = fs->inode;
  st->mode  = fs->mode;
  st->size  = fs->size;
  st->modtime = fs->mtime;
  st->type  = type;
  st->etag   = NULL;
  if( fs->etag ) {
      SAFE_FREE(st->etag);
      st->etag  = c_strdup(fs->etag);
  }
  csync_vio_set_file_id(st->file_id, fs->file_id);
  if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
      SAFE_FREE(st->directDownloadUrl);
      st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
  }
  if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
      SAFE_FREE(st->directDownloadCookies);
      st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
  }
  if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_PERM) {
      strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
  }

  st->phash = h;
  st->pathlen = len;
  memcpy(st->path, (len ? path : ""), len + 1);

  switch (ctx->current) {
    case LOCAL_REPLICA:
      if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
        SAFE_FREE(st);
        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
        return -1;
      }
      break;
    case REMOTE_REPLICA:
      if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
        SAFE_FREE(st);
        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
        return -1;
      }
      break;
    default:
      break;
  }
  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "file: %s, instruction: %s <<=", st->path,
      csync_instruction_str(st->instruction));

  return 0;
}
Example #26
0
/*
 * local visitor which calls the user visitor with repacked stat info.
 */
static int _csync_treewalk_visitor(void *obj, void *data) {
    int rc = 0;
    csync_file_stat_t *cur         = NULL;
    CSYNC *ctx                     = NULL;
    c_rbtree_visit_func *visitor   = NULL;
    _csync_treewalk_context *twctx = NULL;
    TREE_WALK_FILE trav;
    c_rbtree_t *other_tree = NULL;
    c_rbnode_t *other_node = NULL;

    cur = (csync_file_stat_t *) obj;
    ctx = (CSYNC *) data;

    if (ctx == NULL) {
      return -1;
    }

    /* we need the opposite tree! */
    switch (ctx->current) {
    case LOCAL_REPLICA:
        other_tree = ctx->remote.tree;
        break;
    case REMOTE_REPLICA:
        other_tree = ctx->local.tree;
        break;
    default:
        break;
    }

    other_node = c_rbtree_find(other_tree, &cur->phash);

    if (!other_node) {
        /* Check the renamed path as well. */
        int len;
        uint64_t h = 0;
        char *renamed_path = csync_rename_adjust_path(ctx, cur->path);

        if (!c_streq(renamed_path, cur->path)) {
            len = strlen( renamed_path );
            h = c_jhash64((uint8_t *) renamed_path, len, 0);
            other_node = c_rbtree_find(other_tree, &h);
        }
        SAFE_FREE(renamed_path);
    }

    if (obj == NULL || data == NULL) {
      ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
      return -1;
    }
    ctx->status_code = CSYNC_STATUS_OK;

    twctx = (_csync_treewalk_context*) ctx->callbacks.userdata;
    if (twctx == NULL) {
      ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
      return -1;
    }

    if (twctx->instruction_filter > 0 &&
        !(twctx->instruction_filter & cur->instruction) ) {
        return 0;
    }

    visitor = (c_rbtree_visit_func*)(twctx->user_visitor);
    if (visitor != NULL) {
      trav.path         = cur->path;
      trav.size         = cur->size;
      trav.modtime      = cur->modtime;
      trav.uid          = cur->uid;
      trav.gid          = cur->gid;
      trav.mode         = cur->mode;
      trav.type         = cur->type;
      trav.instruction  = cur->instruction;
      trav.rename_path  = cur->destpath;
      trav.etag         = cur->etag;
      trav.file_id      = cur->file_id;

      trav.error_status = cur->error_status;
      trav.should_update_etag = cur->should_update_etag;

      if( other_node ) {
          csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data;
          trav.other.etag = other_stat->etag;
          trav.other.file_id = other_stat->file_id;
          trav.other.instruction = other_stat->instruction;
          trav.other.modtime = other_stat->modtime;
          trav.other.size = other_stat->size;
      } else {
          trav.other.etag = 0;
          trav.other.file_id = 0;
          trav.other.instruction = CSYNC_INSTRUCTION_NONE;
          trav.other.modtime = 0;
          trav.other.size = 0;
      }

      rc = (*visitor)(&trav, twctx->userdata);
      cur->instruction = trav.instruction;
      if (trav.etag != cur->etag) {
          SAFE_FREE(cur->etag);
          cur->etag = c_strdup(trav.etag);
      }

      return rc;
    }
    ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
    return -1;
}
Example #27
0
static int _csync_statedb_check(const char *statedb) {
  int fd = -1, rc;
  ssize_t r;
  char buf[BUF_SIZE] = {0};
  sqlite3 *db = NULL;
  csync_stat_t sb;

  mbchar_t *wstatedb = c_utf8_to_locale(statedb);

  if (wstatedb == NULL) {
    return -1;
  }

  /* check db version */
#ifdef _WIN32
    _fmode = _O_BINARY;
#endif

    fd = _topen(wstatedb, O_RDONLY);

    if (fd >= 0) {
        /* Check size. Size of zero is a valid database actually. */
        rc = _tfstat(fd, &sb);

        if (rc == 0) {
            if (sb.st_size == 0) {
                CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Database size is zero byte!");
                close(fd);
            } else {
                r = read(fd, (void *) buf, sizeof(buf) - 1);
                close(fd);
                if (r >= 0) {
                    buf[BUF_SIZE - 1] = '\0';
                    if (c_streq(buf, "SQLite format 3")) {
                        if (sqlite3_open(statedb, &db ) == SQLITE_OK) {
                            rc = _csync_check_db_integrity(db);
                            if( sqlite3_close(db) != 0 ) {
                                CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "WARN: sqlite3_close error!");
                            }

                            if( rc >= 0 ) {
                                /* everything is fine */
                                c_free_locale_string(wstatedb);
                                return 0;
                            }
                            CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Integrity check failed!");
                        } else {
                            /* resources need to be freed even when open failed */
                            sqlite3_close(db);
                            CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "database corrupted, removing!");
                        }
                    } else {
                        CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "sqlite version mismatch");
                    }
                }
            }
        }
        /* if it comes here, the database is broken and should be recreated. */
        _tunlink(wstatedb);
    }

  c_free_locale_string(wstatedb);

  /* create database */
  rc = sqlite3_open(statedb, &db);
  if (rc == SQLITE_OK) {
    sqlite3_close(db);
    _csync_win32_hide_file(statedb);
    return 1;
  }
  sqlite3_close(db);
   CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_open failed: %s %s", sqlite3_errmsg(db), statedb);
   return -1;
}
Example #28
0
END_TEST

START_TEST (check_c_streq_not_equal)
{
  fail_if(c_streq("test", "test2"), NULL);
}
Example #29
0
int csync_config_parse_file(CSYNC *ctx, const char *config)
{
    unsigned int count = 0;
    char line[1024] = {0};
    char *s;
    FILE *f;

    /* copy default config, if no config exists */
    if (! c_isfile(config)) {
        /* check if there is still one csync.conf left over in $HOME/.csync
        * and copy it over (migration path)
        */
        char *home = NULL;
        char *home_config = NULL;
        char *config_file = NULL;

        /* there is no statedb at the expected place. */
        home = csync_get_user_home_dir();
        if( !c_streq(home, ctx->options.config_dir) ) {
            int rc = -1;

            config_file = c_basename(config);
            if( config_file ) {
                rc = asprintf(&home_config, "%s/%s/%s", home, CSYNC_CONF_DIR, config_file);
                SAFE_FREE(config_file);
            }

            if (rc >= 0) {
                CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "config file %s not found, checking %s",
                            config, home_config);

                /* check the home file and copy to new statedb if existing. */
                if(c_isfile(home_config)) {
                    if (c_copy(home_config, config, 0644) < 0) {
                        /* copy failed, but that is not reason to die. */
                        CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Could not copy config %s => %s",
                                    home_config, config);
                    } else {
                        CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "Copied %s => %s",
                                    home_config, config);
                    }
                }
            }
            SAFE_FREE(home_config);
        }
        SAFE_FREE(home);
        /* Still install the default one if nothing is there. */
        if( ! c_isfile(config)) {
            if (_csync_config_copy_default(config) < 0) {
                return -1;
            }
        }
    }

    f = fopen(config, "r");
    if (f == NULL) {
        return 0;
    }

    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
            "Reading configuration data from %s",
            config);

    s = fgets(line, sizeof(line), f);
    while (s != NULL) {
        int rc;
        count++;

        rc = csync_config_parse_line(ctx, line, count);
        if (rc < 0) {
            fclose(f);
            return -1;
        }
        s = fgets(line, sizeof(line), f);
    }

    fclose(f);

    return 0;
}
Example #30
0
/*
 * file functions
 */
static int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
    /* get props:
     *   modtime
     *   creattime
     *   size
     */
    int rc = 0;
    csync_vio_file_stat_t *lfs = NULL;
    struct listdir_context  *fetchCtx = NULL;
    char *curi = NULL;
    char *decodedUri = NULL;
    char strbuf[PATH_MAX +1];
    int len = 0;

    DEBUG_WEBDAV("owncloud_stat %s called", uri );

    buf->name = c_basename(uri);

    if (buf->name == NULL) {
        csync_vio_file_stat_destroy(buf);
        errno = ENOMEM;
        return -1;
    }

    /* check if the data in the static 'cache' fs is for the same file.
     * The cache is filled by readdir which is often called directly before
     * stat. If the cache matches, a http call is saved.
     */
    if( _fs.name && strcmp( buf->name, _fs.name ) == 0 ) {
        buf->fields  = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
        buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
        buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
        buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
        buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;

        buf->fields = _fs.fields;
        buf->type   = _fs.type;
        buf->mtime  = _fs.mtime;
        buf->size   = _fs.size;
        buf->mode   = _stat_perms( _fs.type );
    } else {
        /* fetch data via a propfind call. */
        fetchCtx = c_malloc( sizeof( struct listdir_context ));
        if( ! fetchCtx ) {
            errno = ENOMEM;
            return -1;
        }

        curi = _cleanPath( uri );

        DEBUG_WEBDAV("I have no stat cache, call propfind for %s.", curi );
        fetchCtx->list = NULL;
        fetchCtx->target = curi;
        fetchCtx->include_target = 1;
        fetchCtx->currResource = NULL;

        rc = fetch_resource_list( curi, NE_DEPTH_ONE, fetchCtx );
        if( rc != NE_OK ) {
          if( errno != ENOENT ) {
            set_errno_from_session();
          }
          DEBUG_WEBDAV("stat fails with errno %d", errno );

          return -1;
        }

        if( fetchCtx ) {
            struct resource *res = fetchCtx->list;
            while( res ) {
                /* remove trailing slashes */
                len = strlen(res->uri);
                while( len > 0 && res->uri[len-1] == '/' ) --len;
                memset( strbuf, 0, PATH_MAX+1);
                strncpy( strbuf, res->uri, len < PATH_MAX ? len : PATH_MAX );
                decodedUri = ne_path_unescape( curi ); /* allocates memory */
                if( c_streq(strbuf, decodedUri )) {
                    SAFE_FREE( decodedUri );
                    break;
                }
                res = res->next;
                SAFE_FREE( decodedUri );
            }
            DEBUG_WEBDAV("Working on file %s", res ? res->name : "NULL");

            lfs = resourceToFileStat( res );
            if( lfs ) {
                buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
                buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
                buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
                buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
                buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;

                buf->fields = lfs->fields;
                buf->type   = lfs->type;
                buf->mtime  = lfs->mtime;
                buf->size   = lfs->size;
                buf->mode   = _stat_perms( lfs->type );

                csync_vio_file_stat_destroy( lfs );
            }
            SAFE_FREE( fetchCtx );
        }
    }
    DEBUG_WEBDAV("STAT result: %s, type=%d", buf->name ? buf->name:"NULL",
                  buf->type );
    return 0;
}