static void check_c_basename_uri(void **state) { char *bname = NULL; (void) state; /* unused */ bname = c_basename("smb://server/share/dir/"); assert_string_equal(bname, "dir"); free(bname); }
static void check_c_basename(void **state) { char *bname; (void) state; /* unused */ bname = c_basename("/usr/lib"); assert_string_equal(bname, "lib"); free(bname); bname = c_basename("/usr//"); assert_string_equal(bname, "usr"); free(bname); bname = c_basename("usr"); assert_string_equal(bname, "usr"); free(bname); bname = c_basename("///"); assert_string_equal(bname, "/"); free(bname); bname = c_basename("/"); assert_string_equal(bname, "/"); free(bname); bname = c_basename("."); assert_string_equal(bname, "."); free(bname); bname = c_basename(".."); assert_string_equal(bname, ".."); free(bname); bname = c_basename(""); assert_string_equal(bname, "."); free(bname); bname = c_basename(NULL); assert_string_equal(bname, "."); free(bname); }
static int dummy_stat(const char *uri, csync_vio_file_stat_t *buf) { time_t now; buf->name = c_basename(uri); if (buf->name == NULL) { csync_vio_file_stat_destroy(buf); } buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; time(&now); buf->mtime = now; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; return 0; }
int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { csync_stat_t sb; mbchar_t *wuri = c_utf8_to_locale( uri ); if( _tstat(wuri, &sb) < 0) { c_free_locale_string(wuri); return -1; } buf->name = c_basename(uri); if (buf->name == NULL) { csync_vio_file_stat_destroy(buf); c_free_locale_string(wuri); return -1; } buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; switch(sb.st_mode & S_IFMT) { case S_IFBLK: buf->type = CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE; break; case S_IFCHR: buf->type = CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE; break; case S_IFDIR: buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; break; case S_IFIFO: buf->type = CSYNC_VIO_FILE_TYPE_FIFO; break; case S_IFREG: buf->type = CSYNC_VIO_FILE_TYPE_REGULAR; break; case S_IFLNK: buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; break; case S_IFSOCK: buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; break; default: buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; break; } buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; buf->mode = sb.st_mode; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MODE; if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) { /* FIXME: handle symlink */ buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK; } else { buf->flags = CSYNC_VIO_FILE_FLAGS_NONE; } buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; buf->device = sb.st_dev; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE; buf->inode = sb.st_ino; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE; buf->atime = sb.st_atime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; buf->mtime = sb.st_mtime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; buf->ctime = sb.st_ctime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; buf->nlink = sb.st_nlink; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT; buf->size = sb.st_size; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; c_free_locale_string(wuri); return 0; }
int csync_excluded(CSYNC *ctx, const char *path) { size_t i; const char *p; char *bname; int rc; int match = 0; if (! ctx->options.unix_extensions) { for (p = path; *p; p++) { switch (*p) { case '\\': case ':': case '?': case '*': case '"': case '>': case '<': case '|': return 1; default: break; } } } rc = csync_fnmatch(".csync_journal.db*", path, 0); if (rc == 0) { return 1; } bname = c_basename(path); if (bname == NULL) { return 0; } rc = csync_fnmatch(".csync_journal.db*", bname, 0); if (rc == 0) { match = 1; goto out; } if (ctx->excludes == NULL) { goto out; } for (i = 0; match == 0 && i < ctx->excludes->count; i++) { rc = csync_fnmatch(ctx->excludes->vector[i], path, 0); if (rc == 0) { match = 1; } rc = csync_fnmatch(ctx->excludes->vector[i], bname, 0); if (rc == 0) { match = 1; } } out: free(bname); return match; }
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; }
static int _stat(const char *uri, csync_vio_file_stat_t *buf) { struct stat sb; if (smbc_stat(uri, &sb) < 0) { return -1; } buf->name = c_basename(uri); if (buf->name == NULL) { csync_vio_file_stat_destroy(buf); return -1; } buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; switch(sb.st_mode & S_IFMT) { case S_IFBLK: buf->type = CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE; break; case S_IFCHR: buf->type = CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE; break; case S_IFDIR: buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; break; case S_IFIFO: buf->type = CSYNC_VIO_FILE_TYPE_FIFO; break; case S_IFLNK: buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; break; case S_IFREG: buf->type = CSYNC_VIO_FILE_TYPE_REGULAR; break; case S_IFSOCK: buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; default: buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; break; } buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; buf->mode = sb.st_mode; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS; if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) { /* FIXME: handle symlink */ buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK; } else { buf->flags = CSYNC_VIO_FILE_FLAGS_NONE; } buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; buf->device = sb.st_dev; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE; buf->inode = sb.st_ino; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE; buf->nlink = sb.st_nlink; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT; buf->uid = sb.st_uid; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID; buf->gid = sb.st_gid; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID; buf->size = sb.st_size; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; buf->blksize = sb.st_blksize; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE; buf->blkcount = sb.st_blocks; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT; buf->atime = sb.st_atime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; buf->mtime = sb.st_mtime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; buf->ctime = sb.st_ctime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; return 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; }
/* * 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; }
/* * result parsing list. * This function is called to parse the result of the propfind request * to list directories on the WebDAV server. I takes a single resource * and fills a resource struct and stores it to the result list which * is stored in the listdir_context. */ static void results(void *userdata, const ne_uri *uri, const ne_prop_result_set *set) { struct listdir_context *fetchCtx = userdata; struct resource *newres = 0; const char *clength, *modtime = NULL; const char *resourcetype = NULL; const ne_status *status = NULL; char *path = ne_path_unescape( uri->path ); (void) status; if( ! fetchCtx ) { DEBUG_WEBDAV("No valid fetchContext"); return; } DEBUG_WEBDAV("** propfind result found: %s", path ); if( ! fetchCtx->target ) { DEBUG_WEBDAV("error: target must not be zero!" ); return; } if (ne_path_compare(fetchCtx->target, uri->path) == 0 && !fetchCtx->include_target) { /* This is the target URI */ DEBUG_WEBDAV( "Skipping target resource."); /* Free the private structure. */ SAFE_FREE( path ); return; } /* Fill the resource structure with the data about the file */ newres = c_malloc(sizeof(struct resource)); newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */ newres->name = c_basename( path ); modtime = ne_propset_value( set, &ls_props[0] ); clength = ne_propset_value( set, &ls_props[1] ); resourcetype = ne_propset_value( set, &ls_props[2] ); newres->type = resr_normal; if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) { newres->type = resr_collection; } if (modtime) newres->modtime = ne_httpdate_parse(modtime); if (clength) { char *p; newres->size = DAV_STRTOL(clength, &p, 10); if (*p) { newres->size = 0; } } /* prepend the new resource to the result list */ newres->next = fetchCtx->list; fetchCtx->list = newres; fetchCtx->result_count = fetchCtx->result_count + 1; DEBUG_WEBDAV( "results for URI %s: %d %d", newres->name, (int)newres->size, (int)newres->type ); }
static void propfind_results_recursive(void *userdata, const ne_uri *uri, const ne_prop_result_set *set) { struct resource *newres = 0; const char *clength, *modtime, *file_id = NULL; const char *resourcetype = NULL; const char *md5sum = NULL; const ne_status *status = NULL; char *path = ne_path_unescape( uri->path ); char *parentPath; char *propfindRootUri = (char*) userdata; propfind_recursive_element_t *element = NULL; propfind_recursive_element_t *pElement = NULL; int depth = 0; (void) status; (void) propfindRootUri; if (!propfind_recursive_cache) { c_rbtree_create(&propfind_recursive_cache, _key_cmp, _data_cmp); } /* Fill the resource structure with the data about the file */ newres = c_malloc(sizeof(struct resource)); ZERO_STRUCTP(newres); newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */ newres->name = c_basename( path ); modtime = ne_propset_value( set, &ls_props[0] ); clength = ne_propset_value( set, &ls_props[1] ); resourcetype = ne_propset_value( set, &ls_props[2] ); md5sum = ne_propset_value( set, &ls_props[3] ); file_id = ne_propset_value( set, &ls_props[4] ); newres->type = resr_normal; if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) { newres->type = resr_collection; propfind_recursive_cache_folder_count++; } else { /* DEBUG_WEBDAV("propfind_results_recursive %s [%d]", newres->uri, newres->type); */ propfind_recursive_cache_file_count++; } if (modtime) { newres->modtime = oc_httpdate_parse(modtime); } /* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */ newres->size = 0; if (clength) { newres->size = atoll(clength); /* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */ } if( md5sum ) { newres->md5 = csync_normalize_etag(md5sum); } csync_vio_set_file_id(newres->file_id, file_id); /* DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5); */ /* Create new item in rb tree */ if (newres->type == resr_collection) { DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri); /* Check if in rb tree */ element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,uri->path)); /* If not, create a new item and insert it */ if (!element) { element = c_malloc(sizeof(propfind_recursive_element_t)); element->self = resource_dup(newres); element->children = NULL; element->parent = NULL; c_rbtree_insert(propfind_recursive_cache, element); /* DEBUG_WEBDAV("results_recursive Added collection %s", newres->uri); */ } } /* Check for parent in tree. If exists: Insert it into the children elements there */ parentPath = ne_path_parent(uri->path); if (parentPath) { propfind_recursive_element_t *parentElement = NULL; parentElement = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,parentPath)); free(parentPath); if (parentElement) { newres->next = parentElement->children; parentElement->children = newres; /* If the current result is a collection we also need to set its parent */ if (element) element->parent = parentElement; pElement = element; while (pElement) { depth++; pElement = pElement->parent; } if (depth > propfind_recursive_cache_depth) { DEBUG_WEBDAV("propfind_results_recursive %s new maximum tree depth %d", newres->uri, depth); propfind_recursive_cache_depth = depth; } /* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */ } else { /* DEBUG_WEBDAV("results_recursive No parent %s found for child %s", parentPath, newres->uri); */ resource_free(newres); newres = NULL; } } }
static int _sftp_stat(const char *uri, csync_vio_file_stat_t *buf) { sftp_attributes attrs; char *path = NULL; int rc = -1; if (_sftp_connect(uri) < 0) { return -1; } if (c_parse_uri(uri, NULL, NULL, NULL, NULL, NULL, &path) < 0) { return -1; } attrs = sftp_lstat(_sftp_session, path); if (attrs == NULL) { rc = -1; goto out; } buf->name = c_basename(path); if (buf->name == NULL) { csync_vio_file_stat_destroy(buf); goto out; } buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; switch (attrs->type) { case SSH_FILEXFER_TYPE_REGULAR: buf->type = CSYNC_VIO_FILE_TYPE_REGULAR; break; case SSH_FILEXFER_TYPE_DIRECTORY: buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; break; case SSH_FILEXFER_TYPE_SYMLINK: buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; break; case SSH_FILEXFER_TYPE_SPECIAL: case SSH_FILEXFER_TYPE_UNKNOWN: buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; break; } buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; buf->mode = attrs->permissions; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS; if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) { /* FIXME: handle symlink */ buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK; } else { buf->flags = CSYNC_VIO_FILE_FLAGS_NONE; } buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; buf->uid = attrs->uid; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID; buf->uid = attrs->gid; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID; buf->size = attrs->size; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; buf->atime = attrs->atime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; buf->mtime = attrs->mtime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; buf->ctime = attrs->createtime; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; rc = 0; out: if (rc < 0) { errno = _sftp_portable_to_errno(sftp_get_error(_sftp_session)); } SAFE_FREE(path); sftp_attributes_free(attrs); return rc; }
static void propfind_results_recursive_callback(void *userdata, const ne_uri *uri, const ne_prop_result_set *set) { struct resource *newres = 0; const ne_status *status = NULL; char *path = ne_path_unescape( uri->path ); char *parentPath; propfind_recursive_element_t *element = NULL; propfind_recursive_element_t *pElement = NULL; int depth = 0; csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata; (void) status; if (!ctx->propfind_recursive_cache) { c_rbtree_create(&ctx->propfind_recursive_cache, _key_cmp, _data_cmp); } /* Fill the resource structure with the data about the file */ newres = c_malloc(sizeof(struct resource)); newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */ newres->name = c_basename( path ); fill_webdav_properties_into_resource(newres, set); if( newres->type == resr_collection) { ctx->propfind_recursive_cache_folder_count++; } else { ctx->propfind_recursive_cache_file_count++; } /* Create new item in rb tree */ if (newres->type == resr_collection) { DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri); /* Check if in rb tree */ element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,uri->path)); /* If not, create a new item and insert it */ if (!element) { element = c_malloc(sizeof(propfind_recursive_element_t)); element->self = resource_dup(newres); element->self->next = 0; element->children = NULL; element->parent = NULL; c_rbtree_insert(ctx->propfind_recursive_cache, element); /* DEBUG_WEBDAV("results_recursive Added collection %s", newres->uri); */ } } /* Check for parent in tree. If exists: Insert it into the children elements there */ parentPath = ne_path_parent(uri->path); if (parentPath) { propfind_recursive_element_t *parentElement = NULL; parentElement = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,parentPath)); free(parentPath); if (parentElement) { newres->next = parentElement->children; parentElement->children = newres; /* If the current result is a collection we also need to set its parent */ if (element) element->parent = parentElement; pElement = element; while (pElement) { depth++; pElement = pElement->parent; } if (depth > ctx->propfind_recursive_cache_depth) { DEBUG_WEBDAV("propfind_results_recursive %s new maximum tree depth %d", newres->uri, depth); ctx->propfind_recursive_cache_depth = depth; } /* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */ return; } } resource_free(newres); newres = NULL; }
/* * file functions */ int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) { /* get props: * modtime * creattime * size */ csync_vio_file_stat_t *lfs = NULL; struct listdir_context *fetchCtx = NULL; char *decodedUri = NULL; int len = 0; errno = 0; DEBUG_WEBDAV("owncloud_stat %s called", uri ); buf->name = c_basename(uri); if (buf->name == NULL) { errno = ENOMEM; return -1; } if( _stat_cache.name && strcmp( buf->name, _stat_cache.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 = _stat_cache.fields; buf->type = _stat_cache.type; buf->mtime = _stat_cache.mtime; buf->size = _stat_cache.size; buf->mode = _stat_perms( _stat_cache.type ); buf->etag = NULL; if( _stat_cache.etag ) { buf->etag = c_strdup( _stat_cache.etag ); buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG; } csync_vio_file_stat_set_file_id( buf, _stat_cache.file_id ); return 0; } DEBUG_WEBDAV("owncloud_stat => Could not find in stat cache %s", uri); /* fetch data via a propfind call. */ /* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE); */ fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE); DEBUG_WEBDAV("=> Errno after fetch resource list for %s: %d", uri, errno); if (!fetchCtx) { 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; decodedUri = ne_path_unescape( fetchCtx->target ); /* allocates memory */ /* Only do the comparaison of the part of the string without the trailing slashes, and make sure decodedUri is not too large */ if( strncmp(res->uri, decodedUri, len ) == 0 && decodedUri[len] == '\0') { SAFE_FREE( decodedUri ); break; } res = res->next; SAFE_FREE( decodedUri ); } if( res ) { DEBUG_WEBDAV("Working on file %s", res->name ); } else { DEBUG_WEBDAV("ERROR: Result struct not valid!"); } 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 |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG; buf->fields = lfs->fields; buf->type = lfs->type; buf->mtime = lfs->mtime; buf->size = lfs->size; buf->mode = _stat_perms( lfs->type ); buf->etag = NULL; if( lfs->etag ) { buf->etag = c_strdup( lfs->etag ); } csync_vio_file_stat_set_file_id( buf, lfs->file_id ); /* fill the static stat buf as input for the stat function */ csync_vio_file_stat_destroy( lfs ); } free_fetchCtx( fetchCtx ); } DEBUG_WEBDAV("STAT result from propfind: %s, mtime: %llu", buf->name ? buf->name:"NULL", (unsigned long long) buf->mtime ); return 0; }
/* * result parsing list. * This function is called to parse the result of the propfind request * to list directories on the WebDAV server. I takes a single resource * and fills a resource struct and stores it to the result list which * is stored in the listdir_context. */ static void results(void *userdata, const ne_uri *uri, const ne_prop_result_set *set) { struct listdir_context *fetchCtx = userdata; struct resource *newres = 0; const char *clength, *modtime = NULL; const char *resourcetype = NULL; const char *md5sum = NULL; const char *file_id = NULL; const ne_status *status = NULL; char *path = ne_path_unescape( uri->path ); (void) status; if( ! fetchCtx ) { DEBUG_WEBDAV("No valid fetchContext"); return; } if( ! fetchCtx->target ) { DEBUG_WEBDAV("error: target must not be zero!" ); return; } /* Fill the resource structure with the data about the file */ newres = c_malloc(sizeof(struct resource)); ZERO_STRUCTP(newres); newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */ newres->name = c_basename( path ); modtime = ne_propset_value( set, &ls_props[0] ); clength = ne_propset_value( set, &ls_props[1] ); resourcetype = ne_propset_value( set, &ls_props[2] ); md5sum = ne_propset_value( set, &ls_props[3] ); file_id = ne_propset_value( set, &ls_props[4] ); newres->type = resr_normal; if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) { newres->type = resr_collection; } if (modtime) { newres->modtime = oc_httpdate_parse(modtime); } /* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */ newres->size = 0; if (clength) { newres->size = atoll(clength); /* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */ } if( md5sum ) { newres->md5 = csync_normalize_etag(md5sum); } csync_vio_set_file_id(newres->file_id, file_id); /* prepend the new resource to the result list */ newres->next = fetchCtx->list; fetchCtx->list = newres; fetchCtx->result_count = fetchCtx->result_count + 1; /* DEBUG_WEBDAV( "results for URI %s: %d %d", newres->name, (int)newres->size, (int)newres->type ); */ }