You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/09/15 21:32:38 UTC
svn commit: r997472 [14/41] - in /subversion/branches/py-tests-as-modules:
./ build/ build/ac-macros/ build/generator/ build/generator/templates/
contrib/server-side/ notes/ notes/tree-conflicts/ notes/wc-ng/
subversion/bindings/javahl/native/ subversi...
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/fs_fs.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/fs_fs.c Wed Sep 15 19:32:26 2010
@@ -44,9 +44,11 @@
#include "svn_hash.h"
#include "svn_props.h"
#include "svn_sorts.h"
+#include "svn_string.h"
#include "svn_time.h"
#include "svn_mergeinfo.h"
#include "svn_config.h"
+#include "svn_ctype.h"
#include "fs.h"
#include "err.h"
@@ -150,6 +152,9 @@ read_min_unpacked_rev(svn_revnum_t *min_
static svn_error_t *
update_min_unpacked_rev(svn_fs_t *fs, apr_pool_t *pool);
+static svn_error_t *
+update_min_unpacked_revprop(svn_fs_t *fs, apr_pool_t *pool);
+
/* Pathname helper functions */
/* Return TRUE is REV is packed in FS, FALSE otherwise. */
@@ -250,6 +255,14 @@ svn_fs_fs__path_rev_absolute(const char
svn_revnum_t rev,
apr_pool_t *pool)
{
+ fs_fs_data_t *ffd = fs->fsap_data;
+
+ if (ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT)
+ {
+ *path = path_rev(fs, rev, pool);
+ return SVN_NO_ERROR;
+ }
+
if (! is_packed_rev(fs, rev))
{
svn_node_kind_t kind;
@@ -317,6 +330,7 @@ path_revprops(svn_fs_t *fs, svn_revnum_t
static APR_INLINE const char *
path_txn_dir(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
{
+ SVN_ERR_ASSERT_NO_RETURN(txn_id != NULL);
return svn_dirent_join_many(pool, fs->path, PATH_TXNS_DIR,
apr_pstrcat(pool, txn_id, PATH_EXT_TXN, NULL),
NULL);
@@ -558,7 +572,8 @@ get_lock_on_filesystem(const char *lock_
BATON and that subpool, destroy the subpool (releasing the write
lock) and return what BODY returned. */
static svn_error_t *
-with_some_lock(svn_error_t *(*body)(void *baton,
+with_some_lock(svn_fs_t *fs,
+ svn_error_t *(*body)(void *baton,
apr_pool_t *pool),
void *baton,
const char *lock_filename,
@@ -585,7 +600,14 @@ with_some_lock(svn_error_t *(*body)(void
err = get_lock_on_filesystem(lock_filename, subpool);
if (!err)
- err = body(baton, subpool);
+ {
+ fs_fs_data_t *ffd = fs->fsap_data;
+ if (ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
+ SVN_ERR(update_min_unpacked_rev(fs, pool));
+ if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
+ SVN_ERR(update_min_unpacked_revprop(fs, pool));
+ err = body(baton, subpool);
+ }
svn_pool_destroy(subpool);
@@ -613,7 +635,7 @@ svn_fs_fs__with_write_lock(svn_fs_t *fs,
apr_thread_mutex_t *mutex = ffsd->fs_write_lock;
#endif
- return with_some_lock(body, baton,
+ return with_some_lock(fs, body, baton,
path_lock(fs, pool),
#if SVN_FS_FS__USE_LOCK_MUTEX
mutex,
@@ -636,7 +658,7 @@ with_txn_current_lock(svn_fs_t *fs,
apr_thread_mutex_t *mutex = ffsd->txn_current_lock;
#endif
- return with_some_lock(body, baton,
+ return with_some_lock(fs, body, baton,
path_txn_current_lock(fs, pool),
#if SVN_FS_FS__USE_LOCK_MUTEX
mutex,
@@ -885,21 +907,21 @@ get_file_offset(apr_off_t *offset_p, apr
}
-/* Check that BUF, a buffer of text from format file PATH, contains
- only digits, raising error SVN_ERR_BAD_VERSION_FILE_FORMAT if not.
+/* Check that BUF, a nul-terminated buffer of text from format file PATH,
+ contains only digits at OFFSET and beyond, raising an error if not.
Uses POOL for temporary allocation. */
static svn_error_t *
-check_format_file_buffer_numeric(const char *buf, const char *path,
- apr_pool_t *pool)
+check_format_file_buffer_numeric(const char *buf, apr_off_t offset,
+ const char *path, apr_pool_t *pool)
{
const char *p;
- for (p = buf; *p; p++)
- if (!apr_isdigit(*p))
+ for (p = buf + offset; *p; p++)
+ if (!svn_ctype_isdigit(*p))
return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL,
- _("Format file '%s' contains an unexpected non-digit"),
- svn_dirent_local_style(path, pool));
+ _("Format file '%s' contains unexpected non-digit '%c' within '%s'"),
+ svn_dirent_local_style(path, pool), *p, buf);
return SVN_NO_ERROR;
}
@@ -953,8 +975,8 @@ read_format(int *pformat, int *max_files
SVN_ERR(err);
/* Check that the first line contains only digits. */
- SVN_ERR(check_format_file_buffer_numeric(buf, path, pool));
- *pformat = atoi(buf);
+ SVN_ERR(check_format_file_buffer_numeric(buf, 0, path, pool));
+ SVN_ERR(svn_cstring_atoi(pformat, buf));
/* Set the default values for anything that can be set via an option. */
*max_files_per_dir = 0;
@@ -984,8 +1006,8 @@ read_format(int *pformat, int *max_files
if (strncmp(buf+7, "sharded ", 8) == 0)
{
/* Check that the argument is numeric. */
- SVN_ERR(check_format_file_buffer_numeric(buf+15, path, pool));
- *max_files_per_dir = atoi(buf+15);
+ SVN_ERR(check_format_file_buffer_numeric(buf, 15, path, pool));
+ SVN_ERR(svn_cstring_atoi(max_files_per_dir, buf + 15));
continue;
}
}
@@ -1042,12 +1064,6 @@ write_format(const char *path, int forma
contents->data, contents->len,
svn_io_file_del_none, pool));
-#ifdef WIN32
- /* make the destination writable, but only on Windows, because
- Windows does not let us replace read-only files. */
- SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
-#endif /* WIN32 */
-
/* rename the temp file as the real destination */
SVN_ERR(svn_io_file_rename(path_tmp, path, pool));
}
@@ -1173,6 +1189,8 @@ update_min_unpacked_rev(svn_fs_t *fs, ap
{
fs_fs_data_t *ffd = fs->fsap_data;
+ SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT);
+
return read_min_unpacked_rev(&ffd->min_unpacked_rev,
path_min_unpacked_rev(fs, pool),
pool);
@@ -1183,6 +1201,8 @@ update_min_unpacked_revprop(svn_fs_t *fs
{
fs_fs_data_t *ffd = fs->fsap_data;
+ SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT);
+
return read_min_unpacked_rev(&ffd->min_unpacked_revprop,
path_min_unpacked_revprop(fs, pool),
pool);
@@ -1268,11 +1288,32 @@ upgrade_body(void *baton, apr_pool_t *po
fs_fs_data_t *ffd = fs->fsap_data;
int format, max_files_per_dir;
const char *format_path = path_format(fs, pool);
+ svn_node_kind_t kind;
/* Read the FS format number and max-files-per-dir setting. */
SVN_ERR(read_format(&format, &max_files_per_dir, format_path, pool));
- /* If we're already up-to-date, there's nothing to be done here. */
+ /* If the config file does not exist, create one. */
+ SVN_ERR(svn_io_check_path(svn_dirent_join(fs->path, PATH_CONFIG, pool),
+ &kind, pool));
+ switch (kind)
+ {
+ case svn_node_none:
+ SVN_ERR(write_config(fs, pool));
+ break;
+ case svn_node_file:
+ break;
+ default:
+ return svn_error_return(svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
+ _("'%s' is not a regular file."
+ " Please move it out of "
+ "the way and try again"),
+ svn_dirent_join(fs->path,
+ PATH_CONFIG,
+ pool)));
+ }
+
+ /* If we're already up-to-date, there's nothing else to be done here. */
if (format == SVN_FS_FS__FORMAT_NUMBER)
return SVN_NO_ERROR;
@@ -1489,15 +1530,69 @@ svn_fs_fs__hotcopy(const char *src_path,
pool));
SVN_ERR(check_format(format));
+ /* Try to copy the config.
+ *
+ * ### We try copying the config file before doing anything else,
+ * ### because higher layers will abort the hotcopy if we throw
+ * ### an error from this function, and that renders the hotcopy
+ * ### unusable anyway. */
+ if (format >= SVN_FS_FS__MIN_CONFIG_FILE)
+ {
+ svn_error_t *err;
+
+ err = svn_io_dir_file_copy(src_path, dst_path, PATH_CONFIG, pool);
+ if (err)
+ {
+ if (APR_STATUS_IS_ENOENT(err->apr_err))
+ {
+ /* 1.6.0 to 1.6.11 did not copy the configuration file during
+ * hotcopy. So if we're hotcopying a repository which has been
+ * created as a hotcopy itself, it's possible that fsfs.conf
+ * does not exist. Ask the user to re-create it.
+ *
+ * ### It would be nice to make this a non-fatal error,
+ * ### but this function does not get an svn_fs_t object
+ * ### so we have no way of just printing a warning via
+ * ### the fs->warning() callback. */
+
+ const char *msg;
+ const char *src_abspath;
+ const char *dst_abspath;
+ const char *config_relpath;
+ svn_error_t *err2;
+
+ config_relpath = svn_dirent_join(src_path, PATH_CONFIG, pool);
+ err2 = svn_dirent_get_absolute(&src_abspath, src_path, pool);
+ if (err2)
+ return svn_error_return(svn_error_compose_create(err, err2));
+ err2 = svn_dirent_get_absolute(&dst_abspath, dst_path, pool);
+ if (err2)
+ return svn_error_return(svn_error_compose_create(err, err2));
+
+ /* ### hack: strip off the 'db/' directory from paths so
+ * ### they make sense to the user */
+ src_abspath = svn_dirent_dirname(src_abspath, pool);
+ dst_abspath = svn_dirent_dirname(dst_abspath, pool);
+
+ msg = apr_psprintf(pool,
+ _("Failed to create hotcopy at '%s'. "
+ "The file '%s' is missing from the source "
+ "repository. Please create this file, for "
+ "instance by running 'svnadmin upgrade %s'"),
+ dst_abspath, config_relpath, src_abspath);
+ return svn_error_return(svn_error_quick_wrap(err, msg));
+ }
+ else
+ return svn_error_return(err);
+ }
+ }
+
/* Copy the 'current' file. */
SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_CURRENT, pool));
/* Copy the uuid. */
SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_UUID, pool));
- /* Copy the config. */
- SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_CONFIG, pool));
-
/* Copy the rep cache before copying the rev files to make sure all
cached references will be present in the copy. */
src_subdir = svn_dirent_join(src_path, REP_CACHE_DB_NAME, pool);
@@ -1568,8 +1663,8 @@ svn_fs_fs__hotcopy(const char *src_path,
{
SVN_ERR(svn_io_dir_make(dst_subdir_shard, APR_OS_DEFAULT,
iterpool));
- SVN_ERR(svn_fs_fs__dup_perms(dst_subdir_shard, dst_subdir,
- iterpool));
+ SVN_ERR(svn_io_copy_perms(dst_subdir, dst_subdir_shard,
+ iterpool));
}
}
@@ -1630,8 +1725,8 @@ svn_fs_fs__hotcopy(const char *src_path,
{
SVN_ERR(svn_io_dir_make(dst_subdir_shard, APR_OS_DEFAULT,
iterpool));
- SVN_ERR(svn_fs_fs__dup_perms(dst_subdir_shard, dst_subdir,
- iterpool));
+ SVN_ERR(svn_io_copy_perms(dst_subdir, dst_subdir_shard,
+ iterpool));
}
}
@@ -1851,18 +1946,20 @@ get_packed_offset(apr_off_t *rev_offset,
{
svn_stringbuf_t *sb;
svn_boolean_t eof;
+ apr_int64_t val;
+ svn_error_t *err;
svn_pool_clear(iterpool);
SVN_ERR(svn_stream_readline(manifest_stream, &sb, "\n", &eof, iterpool));
if (eof)
break;
- errno = 0; /* apr_atoi64() in APR-0.9 does not always set errno */
- APR_ARRAY_PUSH(manifest, apr_off_t) =
- apr_atoi64(svn_string_create_from_buf(sb, iterpool)->data);
- if (errno == ERANGE)
- return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
- "Manifest offset too large");
+ err = svn_cstring_atoi64(&val, sb->data);
+ if (err)
+ return svn_error_return(
+ svn_error_create(SVN_ERR_FS_CORRUPT, err,
+ _("Manifest offset too large")));
+ APR_ARRAY_PUSH(manifest, apr_off_t) = (apr_off_t)val;
}
svn_pool_destroy(iterpool);
@@ -1963,6 +2060,7 @@ read_rep_offsets(representation_t **rep_
{
representation_t *rep;
char *str, *last_str;
+ apr_int64_t val;
rep = apr_pcalloc(pool, sizeof(*rep));
*rep_p = rep;
@@ -1986,21 +2084,24 @@ read_rep_offsets(representation_t **rep_
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Malformed text representation offset line in node-rev"));
- rep->offset = apr_atoi64(str);
+ SVN_ERR(svn_cstring_atoi64(&val, str));
+ rep->offset = (apr_off_t)val;
str = apr_strtok(NULL, " ", &last_str);
if (str == NULL)
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Malformed text representation offset line in node-rev"));
- rep->size = apr_atoi64(str);
+ SVN_ERR(svn_cstring_atoi64(&val, str));
+ rep->size = (svn_filesize_t)val;
str = apr_strtok(NULL, " ", &last_str);
if (str == NULL)
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Malformed text representation offset line in node-rev"));
- rep->expanded_size = apr_atoi64(str);
+ SVN_ERR(svn_cstring_atoi64(&val, str));
+ rep->expanded_size = (svn_filesize_t)val;
/* Read in the MD5 hash. */
str = apr_strtok(NULL, " ", &last_str);
@@ -2116,7 +2217,10 @@ svn_fs_fs__read_noderev(node_revision_t
/* Read the 'count' field. */
value = apr_hash_get(headers, HEADER_COUNT, APR_HASH_KEY_STRING);
- noderev->predecessor_count = (value == NULL) ? 0 : atoi(value);
+ if (value)
+ SVN_ERR(svn_cstring_atoi(&noderev->predecessor_count, value));
+ else
+ noderev->predecessor_count = 0;
/* Get the properties location. */
value = apr_hash_get(headers, HEADER_PROPS, APR_HASH_KEY_STRING);
@@ -2207,7 +2311,10 @@ svn_fs_fs__read_noderev(node_revision_t
/* Get the mergeinfo count. */
value = apr_hash_get(headers, HEADER_MINFO_CNT, APR_HASH_KEY_STRING);
- noderev->mergeinfo_count = (value == NULL) ? 0 : apr_atoi64(value);
+ if (value)
+ SVN_ERR(svn_cstring_atoi64(&noderev->mergeinfo_count, value));
+ else
+ noderev->mergeinfo_count = 0;
/* Get whether *this* node has mergeinfo. */
value = apr_hash_get(headers, HEADER_MINFO_HERE, APR_HASH_KEY_STRING);
@@ -2394,6 +2501,7 @@ read_rep_line(struct rep_args **rep_args
apr_size_t limit;
struct rep_args *rep_args;
char *str, *last_str;
+ apr_int64_t val;
limit = sizeof(buffer);
SVN_ERR(svn_io_read_length_line(file, buffer, &limit, pool));
@@ -2421,24 +2529,30 @@ read_rep_line(struct rep_args **rep_args
/* We have hopefully a DELTA vs. a non-empty base revision. */
str = apr_strtok(buffer, " ", &last_str);
- if (! str || (strcmp(str, REP_DELTA) != 0)) goto err;
+ if (! str || (strcmp(str, REP_DELTA) != 0))
+ goto error;
str = apr_strtok(NULL, " ", &last_str);
- if (! str) goto err;
+ if (! str)
+ goto error;
rep_args->base_revision = SVN_STR_TO_REV(str);
str = apr_strtok(NULL, " ", &last_str);
- if (! str) goto err;
- rep_args->base_offset = (apr_off_t) apr_atoi64(str);
+ if (! str)
+ goto error;
+ SVN_ERR(svn_cstring_atoi64(&val, str));
+ rep_args->base_offset = (apr_off_t)val;
str = apr_strtok(NULL, " ", &last_str);
- if (! str) goto err;
- rep_args->base_length = (apr_size_t) apr_atoi64(str);
+ if (! str)
+ goto error;
+ SVN_ERR(svn_cstring_atoi64(&val, str));
+ rep_args->base_length = (apr_size_t)val;
*rep_args_p = rep_args;
return SVN_NO_ERROR;
- err:
+ error:
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Malformed representation header"));
}
@@ -2501,6 +2615,7 @@ get_root_changes_offset(apr_off_t *root_
apr_off_t rev_offset;
char buf[64];
int i, num_bytes;
+ const char *str;
apr_size_t len;
apr_seek_where_t seek_relative;
@@ -2555,7 +2670,8 @@ get_root_changes_offset(apr_off_t *root_
/* Look for the next previous newline. */
for (i = num_bytes - 2; i >= 0; i--)
{
- if (buf[i] == '\n') break;
+ if (buf[i] == '\n')
+ break;
}
if (i < 0)
@@ -2566,24 +2682,42 @@ get_root_changes_offset(apr_off_t *root_
}
i++;
-
- if (root_offset)
- *root_offset = rev_offset + apr_atoi64(&buf[i]);
+ str = &buf[i];
/* find the next space */
for ( ; i < (num_bytes - 2) ; i++)
- if (buf[i] == ' ') break;
+ if (buf[i] == ' ')
+ break;
if (i == (num_bytes - 2))
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Final line in revision file missing space"));
+ if (root_offset)
+ {
+ apr_int64_t val;
+
+ buf[i] = '\0';
+ SVN_ERR(svn_cstring_atoi64(&val, str));
+ *root_offset = rev_offset + (apr_off_t)val;
+ }
+
i++;
+ str = &buf[i];
+
+ /* find the next newline */
+ for ( ; i < num_bytes; i++)
+ if (buf[i] == '\n')
+ break;
- /* note that apr_atoi64() will stop reading as soon as it encounters
- the final newline. */
if (changes_offset)
- *changes_offset = rev_offset + apr_atoi64(&buf[i]);
+ {
+ apr_int64_t val;
+
+ buf[i] = '\0';
+ SVN_ERR(svn_cstring_atoi64(&val, str));
+ *changes_offset = rev_offset + (apr_off_t)val;
+ }
return SVN_NO_ERROR;
}
@@ -2591,7 +2725,10 @@ get_root_changes_offset(apr_off_t *root_
/* Move a file into place from OLD_FILENAME in the transactions
directory to its final location NEW_FILENAME in the repository. On
Unix, match the permissions of the new file to the permissions of
- PERMS_REFERENCE. Temporary allocations are from POOL. */
+ PERMS_REFERENCE. Temporary allocations are from POOL.
+
+ This function almost duplicates svn_io_file_move(), but it tries to
+ guarantee a flush. */
static svn_error_t *
move_into_place(const char *old_filename,
const char *new_filename,
@@ -2600,7 +2737,7 @@ move_into_place(const char *old_filename
{
svn_error_t *err;
- SVN_ERR(svn_fs_fs__dup_perms(old_filename, perms_reference, pool));
+ SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, pool));
/* Move the file into place. */
err = svn_io_file_rename(old_filename, new_filename, pool);
@@ -2616,6 +2753,11 @@ move_into_place(const char *old_filename
/* Flush the target of the copy to disk. */
SVN_ERR(svn_io_file_open(&file, new_filename, APR_READ,
APR_OS_DEFAULT, pool));
+ /* ### BH: Does this really guarantee a flush of the data written
+ ### via a completely different handle on all operating systems?
+ ###
+ ### Maybe we should perform the copy ourselves instead of making
+ ### apr do that and flush the real handle? */
SVN_ERR(svn_io_file_flush_to_disk(file, pool));
SVN_ERR(svn_io_file_close(file, pool));
}
@@ -2819,9 +2961,11 @@ svn_fs_fs__revision_proplist(apr_hash_t
apr_pool_t *pool)
{
svn_error_t *err;
+ fs_fs_data_t *ffd = fs->fsap_data;
err = revision_proplist(proplist_p, fs, rev, pool);
- if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
+ if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION
+ && ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
{
/* If a pack is occurring simultaneously, the min-unpacked-revprop value
could change, so reload it and then attempt to fetch these revprops
@@ -4584,6 +4728,13 @@ get_txn_proplist(apr_hash_t *proplist,
{
svn_stream_t *stream;
+ /* Check for issue #3696. (When we find and fix the cause, we can change
+ * this to an assertion.) */
+ if (txn_id == NULL)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Internal error: a null transaction id was "
+ "passed to get_txn_proplist()"));
+
/* Open the transaction properties file. */
SVN_ERR(svn_stream_open_readonly(&stream, path_txn_props(fs, txn_id, pool),
pool, pool));
@@ -5709,34 +5860,6 @@ write_final_changed_path_info(apr_off_t
return SVN_NO_ERROR;
}
-
-svn_error_t *
-svn_fs_fs__dup_perms(const char *filename,
- const char *perms_reference,
- apr_pool_t *pool)
-{
-#ifndef WIN32
- apr_status_t status;
- apr_finfo_t finfo;
- const char *filename_apr, *perms_reference_apr;
-
- SVN_ERR(svn_path_cstring_from_utf8(&filename_apr, filename, pool));
- SVN_ERR(svn_path_cstring_from_utf8(&perms_reference_apr, perms_reference,
- pool));
-
- status = apr_stat(&finfo, perms_reference_apr, APR_FINFO_PROT, pool);
- if (status)
- return svn_error_wrap_apr(status, _("Can't stat '%s'"),
- svn_dirent_local_style(perms_reference, pool));
- status = apr_file_perms_set(filename_apr, finfo.protection);
- if (status)
- return svn_error_wrap_apr(status, _("Can't chmod '%s'"),
- svn_dirent_local_style(filename, pool));
-#endif
- return SVN_NO_ERROR;
-}
-
-
/* Atomically update the 'current' file to hold the specifed REV,
NEXT_NODE_ID, and NEXT_COPY_ID. (The two next-ID parameters are
ignored and may be NULL if the FS format does not use them.)
@@ -5980,13 +6103,12 @@ commit_body(void *baton, apr_pool_t *poo
const char *new_dir = path_rev_shard(cb->fs, new_rev, pool);
err = svn_io_dir_make(new_dir, APR_OS_DEFAULT, pool);
if (err && !APR_STATUS_IS_EEXIST(err->apr_err))
- SVN_ERR(err);
+ return svn_error_return(err);
svn_error_clear(err);
- SVN_ERR(svn_fs_fs__dup_perms(new_dir,
- svn_dirent_join(cb->fs->path,
- PATH_REVS_DIR,
- pool),
- pool));
+ SVN_ERR(svn_io_copy_perms(svn_dirent_join(cb->fs->path,
+ PATH_REVS_DIR,
+ pool),
+ new_dir, pool));
if (ffd->format < SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT ||
new_rev >= ffd->min_unpacked_revprop)
@@ -5996,11 +6118,10 @@ commit_body(void *baton, apr_pool_t *poo
if (err && !APR_STATUS_IS_EEXIST(err->apr_err))
SVN_ERR(err);
svn_error_clear(err);
- SVN_ERR(svn_fs_fs__dup_perms(new_dir,
- svn_dirent_join(cb->fs->path,
- PATH_REVPROPS_DIR,
- pool),
- pool));
+ SVN_ERR(svn_io_copy_perms(svn_dirent_join(cb->fs->path,
+ PATH_REVPROPS_DIR,
+ pool),
+ new_dir, pool));
}
}
@@ -6305,11 +6426,12 @@ svn_fs_fs__reserve_copy_id(const char **
static svn_error_t *
write_revision_zero(svn_fs_t *fs)
{
+ const char *path_revision_zero = path_rev(fs, 0, fs->pool);
apr_hash_t *proplist;
svn_string_t date;
/* Write out a rev file for revision 0. */
- SVN_ERR(svn_io_file_create(path_rev(fs, 0, fs->pool),
+ SVN_ERR(svn_io_file_create(path_revision_zero,
"PLAIN\nEND\nENDREP\n"
"id: 0.0.r0/17\n"
"type: dir\n"
@@ -6318,6 +6440,7 @@ write_revision_zero(svn_fs_t *fs)
"2d2977d1c96f487abe4a1e202dd03b4e\n"
"cpath: /\n"
"\n\n17 107\n", fs->pool));
+ SVN_ERR(svn_io_set_file_read_only(path_revision_zero, FALSE, fs->pool));
/* Set a date on revision 0. */
date.data = svn_time_to_cstring(apr_time_now(), fs->pool);
@@ -6555,7 +6678,7 @@ recover_find_max_ids(svn_fs_t *fs, svn_r
{
apr_hash_t *headers;
char *value;
- node_revision_t noderev;
+ representation_t *data_rep;
struct rep_args *ra;
struct recover_read_from_file_baton baton;
svn_stream_t *stream;
@@ -6568,10 +6691,6 @@ recover_find_max_ids(svn_fs_t *fs, svn_r
pool),
pool));
- /* We're going to populate a skeletal noderev - just the id and data_rep. */
- value = apr_hash_get(headers, HEADER_ID, APR_HASH_KEY_STRING);
- noderev.id = svn_fs_fs__id_parse(value, strlen(value), pool);
-
/* Check that this is a directory. It should be. */
value = apr_hash_get(headers, HEADER_TYPE, APR_HASH_KEY_STRING);
if (value == NULL || strcmp(value, KIND_DIR) != 0)
@@ -6582,18 +6701,18 @@ recover_find_max_ids(svn_fs_t *fs, svn_r
value = apr_hash_get(headers, HEADER_TEXT, APR_HASH_KEY_STRING);
if (!value)
return SVN_NO_ERROR;
- SVN_ERR(read_rep_offsets(&noderev.data_rep, value, NULL, FALSE, pool));
+ SVN_ERR(read_rep_offsets(&data_rep, value, NULL, FALSE, pool));
/* If the directory's data representation wasn't changed in this revision,
we've already scanned the directory's contents for noderevs, so we don't
need to again. This will occur if a property is changed on a directory
without changing the directory's contents. */
- if (noderev.data_rep->revision != rev)
+ if (data_rep->revision != rev)
return SVN_NO_ERROR;
/* We could use get_dir_contents(), but this is much cheaper. It does
rely on directory entries being stored as PLAIN reps, though. */
- offset = noderev.data_rep->offset;
+ offset = data_rep->offset;
SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool));
SVN_ERR(read_rep_line(&ra, rev_file, pool));
if (ra->is_delta)
@@ -6605,7 +6724,7 @@ recover_find_max_ids(svn_fs_t *fs, svn_r
stored in the representation. */
baton.file = rev_file;
baton.pool = pool;
- baton.remaining = noderev.data_rep->expanded_size;
+ baton.remaining = data_rep->expanded_size;
stream = svn_stream_create(&baton, pool);
svn_stream_set_read(stream, read_handler_recover);
@@ -6896,7 +7015,7 @@ svn_fs_fs__ensure_dir_exists(const char
/* We successfully created a new directory. Dup the permissions
from FS->path. */
- return svn_fs_fs__dup_perms(path, fs->path, pool);
+ return svn_io_copy_perms(path, fs->path, pool);
}
/* Set *NODE_ORIGINS to a hash mapping 'const char *' node IDs to
@@ -7047,7 +7166,7 @@ svn_fs_fs__list_transactions(apr_array_h
txn_dir = svn_dirent_join(fs->path, PATH_TXNS_DIR, pool);
/* Now find a listing of this directory. */
- SVN_ERR(svn_io_get_dirents2(&dirents, txn_dir, pool));
+ SVN_ERR(svn_io_get_dirents3(&dirents, txn_dir, TRUE, pool, pool));
/* Loop through all the entries and return anything that ends with '.txn'. */
for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi))
@@ -7419,7 +7538,9 @@ pack_shard(const char *revs_dir,
SVN_ERR(svn_stream_close(manifest_stream));
SVN_ERR(svn_stream_close(pack_stream));
- SVN_ERR(svn_fs_fs__dup_perms(pack_file_dir, shard_path, pool));
+ SVN_ERR(svn_io_copy_perms(shard_path, pack_file_dir, pool));
+ SVN_ERR(svn_io_set_file_read_only(pack_file_path, FALSE, pool));
+ SVN_ERR(svn_io_set_file_read_only(manifest_file_path, FALSE, pool));
/* Update the min-unpacked-rev file to reflect our newly packed shard.
* (ffd->min_unpacked_rev will be updated by open_pack_or_rev_file().)
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/fs_fs.h?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/fs_fs.h Wed Sep 15 19:32:26 2010
@@ -401,12 +401,6 @@ svn_error_t *svn_fs_fs__move_into_place(
const char *perms_reference,
apr_pool_t *pool);
-/* Match the perms on FILENAME to the PERMS_REFERENCE file if we're
- not on a win32 system. On win32, this is a no-op. */
-svn_error_t *svn_fs_fs__dup_perms(const char *filename,
- const char *perms_reference,
- apr_pool_t *pool);
-
/* Sets *PATH to the path of REV in FS, whether in a pack file or not.
Allocate in POOL. */
svn_error_t *
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/id.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/id.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/id.c Wed Sep 15 19:32:26 2010
@@ -275,6 +275,9 @@ svn_fs_fs__id_parse(const char *data,
if (str[0] == 'r')
{
+ apr_int64_t val;
+ svn_error_t *err;
+
/* This is a revision type ID */
pvt->txn_id = NULL;
@@ -286,7 +289,13 @@ svn_fs_fs__id_parse(const char *data,
str = apr_strtok(NULL, "/", &last_str);
if (str == NULL)
return NULL;
- pvt->offset = apr_atoi64(str);
+ err = svn_cstring_atoi64(&val, str);
+ if (err)
+ {
+ svn_error_clear(err);
+ return NULL;
+ }
+ pvt->offset = (apr_off_t)val;
}
else if (str[0] == 't')
{
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/lock.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/lock.c Wed Sep 15 19:32:26 2010
@@ -192,7 +192,7 @@ write_digest_file(apr_hash_t *children,
svn_stringbuf_appendbytes(children_list,
svn__apr_hash_index_key(hi),
svn__apr_hash_index_klen(hi));
- svn_stringbuf_appendbytes(children_list, "\n", 1);
+ svn_stringbuf_appendbyte(children_list, '\n');
}
hash_store(hash, CHILDREN_KEY, sizeof(CHILDREN_KEY)-1,
children_list->data, children_list->len, pool);
@@ -213,7 +213,7 @@ write_digest_file(apr_hash_t *children,
SVN_ERR(svn_stream_close(stream));
SVN_ERR(svn_io_file_rename(tmp_path, digest_path, pool));
SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, fs, 0, pool));
- return svn_fs_fs__dup_perms(digest_path, rev_0_path, pool);
+ return svn_io_copy_perms(rev_0_path, digest_path, pool);
}
@@ -325,7 +325,7 @@ set_lock(svn_fs_t *fs,
apr_pool_t *pool)
{
svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool);
- svn_stringbuf_t *last_child = svn_stringbuf_create("", pool);
+ const char *lock_digest_path = NULL;
apr_pool_t *subpool;
SVN_ERR_ASSERT(lock);
@@ -356,15 +356,16 @@ set_lock(svn_fs_t *fs,
{
this_lock = lock;
lock = NULL;
- svn_stringbuf_set(last_child, digest_file);
+ lock_digest_path = apr_pstrdup(pool, digest_file);
}
else
{
/* If we already have an entry for this path, we're done. */
- if (apr_hash_get(this_children, last_child->data, last_child->len))
+ if (apr_hash_get(this_children, lock_digest_path,
+ APR_HASH_KEY_STRING))
break;
- apr_hash_set(this_children, last_child->data,
- last_child->len, (void *)1);
+ apr_hash_set(this_children, lock_digest_path,
+ APR_HASH_KEY_STRING, (void *)1);
}
SVN_ERR(write_digest_file(this_children, this_lock, fs,
digest_path, subpool));
@@ -387,13 +388,13 @@ delete_lock(svn_fs_t *fs,
apr_pool_t *pool)
{
svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool);
- svn_stringbuf_t *child_to_kill = svn_stringbuf_create("", pool);
+ const char *child_to_kill = NULL;
apr_pool_t *subpool;
SVN_ERR_ASSERT(lock);
/* Iterate in reverse, deleting the lock for LOCK->path, and then
- pruning entries from its parents. */
+ deleting its entry as it appears in each of its parents. */
subpool = svn_pool_create(pool);
while (1729)
{
@@ -411,31 +412,27 @@ delete_lock(svn_fs_t *fs,
SVN_ERR(read_digest_file(&this_children, &this_lock, fs,
digest_path, subpool));
- /* If we are supposed to drop the last entry from this path's
- children list, do so. */
- if (child_to_kill->len)
- apr_hash_set(this_children, child_to_kill->data,
- child_to_kill->len, NULL);
-
/* Delete the lock (first time through only). */
if (lock)
{
this_lock = NULL;
lock = NULL;
+ child_to_kill = apr_pstrdup(pool, digest_file);
}
+ if (child_to_kill)
+ apr_hash_set(this_children, child_to_kill, APR_HASH_KEY_STRING, NULL);
+
if (! (this_lock || apr_hash_count(this_children) != 0))
{
/* Special case: no goodz, no file. And remember to nix
the entry for it in its parent. */
- svn_stringbuf_set(child_to_kill, digest_file);
SVN_ERR(svn_io_remove_file2(digest_path, FALSE, subpool));
}
else
{
SVN_ERR(write_digest_file(this_children, this_lock, fs,
digest_path, subpool));
- svn_stringbuf_setempty(child_to_kill);
}
/* Prep for next iteration, or bail if we're done. */
@@ -465,7 +462,7 @@ get_lock(svn_lock_t **lock_p,
SVN_ERR(read_digest_file(NULL, &lock, fs, digest_path, pool));
if (! lock)
- return SVN_FS__ERR_NO_SUCH_LOCK(fs, path);
+ return SVN_FS__ERR_NO_SUCH_LOCK(fs, path, pool);
/* Don't return an expired lock. */
if (lock->expiration_date && (apr_time_now() > lock->expiration_date))
@@ -475,7 +472,7 @@ get_lock(svn_lock_t **lock_p,
if (have_write_lock)
SVN_ERR(delete_lock(fs, lock, pool));
*lock_p = NULL;
- return SVN_FS__ERR_LOCK_EXPIRED(fs, lock->token);
+ return SVN_FS__ERR_LOCK_EXPIRED(fs, lock->token, pool);
}
*lock_p = lock;
@@ -679,7 +676,7 @@ lock_body(void *baton, apr_pool_t *pool)
SVN_ERR(lb->fs->vtable->revision_root(&root, lb->fs, youngest, pool));
SVN_ERR(svn_fs_fs__check_path(&kind, root, lb->path, pool));
if (kind == svn_node_dir)
- return SVN_FS__ERR_NOT_FILE(lb->fs, lb->path);
+ return SVN_FS__ERR_NOT_FILE(lb->fs, lb->path, pool);
/* While our locking implementation easily supports the locking of
nonexistent paths, we deliberately choose not to allow such madness. */
@@ -699,7 +696,7 @@ lock_body(void *baton, apr_pool_t *pool)
/* We need to have a username attached to the fs. */
if (!lb->fs->access_ctx || !lb->fs->access_ctx->username)
- return SVN_FS__ERR_NO_USER(lb->fs);
+ return SVN_FS__ERR_NO_USER(lb->fs, pool);
/* Is the caller attempting to lock an out-of-date working file? */
if (SVN_IS_VALID_REVNUM(lb->current_rev))
@@ -745,7 +742,7 @@ lock_body(void *baton, apr_pool_t *pool)
if (! lb->steal_lock)
{
/* Sorry, the path is already locked. */
- return SVN_FS__ERR_PATH_ALREADY_LOCKED(lb->fs, existing_lock);
+ return SVN_FS__ERR_PATH_ALREADY_LOCKED(lb->fs, existing_lock, pool);
}
else
{
@@ -800,16 +797,16 @@ unlock_body(void *baton, apr_pool_t *poo
{
/* Sanity check: the incoming token should match lock->token. */
if (strcmp(ub->token, lock->token) != 0)
- return SVN_FS__ERR_NO_SUCH_LOCK(ub->fs, lock->path);
+ return SVN_FS__ERR_NO_SUCH_LOCK(ub->fs, lock->path, pool);
/* There better be a username attached to the fs. */
if (! (ub->fs->access_ctx && ub->fs->access_ctx->username))
- return SVN_FS__ERR_NO_USER(ub->fs);
+ return SVN_FS__ERR_NO_USER(ub->fs, pool);
/* And that username better be the same as the lock's owner. */
if (strcmp(ub->fs->access_ctx->username, lock->owner) != 0)
- return SVN_FS__ERR_LOCK_OWNER_MISMATCH
- (ub->fs, ub->fs->access_ctx->username, lock->owner);
+ return SVN_FS__ERR_LOCK_OWNER_MISMATCH(
+ ub->fs, ub->fs->access_ctx->username, lock->owner, pool);
}
/* Remove lock and lock token files. */
@@ -901,20 +898,82 @@ svn_fs_fs__get_lock(svn_lock_t **lock_p,
}
+/* Baton for get_locks_filter_func(). */
+typedef struct
+{
+ const char *path;
+ svn_depth_t requested_depth;
+ svn_fs_get_locks_callback_t get_locks_func;
+ void *get_locks_baton;
+
+} get_locks_filter_baton_t;
+
+
+/* A wrapper for the GET_LOCKS_FUNC passed to svn_fs_fs__get_locks()
+ which filters out locks on paths that aren't within
+ BATON->requested_depth of BATON->path before called
+ BATON->get_locks_func() with BATON->get_locks_baton.
+
+ NOTE: See issue #3660 for details about how the FSFS lock
+ management code is inconsistent. Until that inconsistency is
+ resolved, we take this filtering approach rather than honoring
+ depth requests closer to the crawling code. In other words, once
+ we decide how to resolve issue #3660, there might be a more
+ performant way to honor the depth passed to svn_fs_fs__get_locks(). */
+static svn_error_t *
+get_locks_filter_func(void *baton,
+ svn_lock_t *lock,
+ apr_pool_t *pool)
+{
+ get_locks_filter_baton_t *b = baton;
+
+ /* Filter out unwanted paths. Since Subversion only allows
+ locks on files, we can treat depth=immediates the same as
+ depth=files for filtering purposes. Meaning, we'll keep
+ this lock if:
+
+ a) its path is the very path we queried, or
+ b) we've asked for a fully recursive answer, or
+ c) we've asked for depth=files or depth=immediates, and this
+ lock is on an immediate child of our query path.
+ */
+ if ((strcmp(b->path, lock->path) == 0)
+ || (b->requested_depth == svn_depth_infinity))
+ {
+ SVN_ERR(b->get_locks_func(b->get_locks_baton, lock, pool));
+ }
+ else if ((b->requested_depth == svn_depth_files) ||
+ (b->requested_depth == svn_depth_immediates))
+ {
+ const char *rel_uri = svn_uri_is_child(b->path, lock->path, pool);
+ if (rel_uri && (svn_path_component_count(rel_uri) == 1))
+ SVN_ERR(b->get_locks_func(b->get_locks_baton, lock, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_fs_fs__get_locks(svn_fs_t *fs,
const char *path,
+ svn_depth_t depth,
svn_fs_get_locks_callback_t get_locks_func,
void *get_locks_baton,
apr_pool_t *pool)
{
const char *digest_path;
+ get_locks_filter_baton_t glfb;
SVN_ERR(svn_fs__check_fs(fs, TRUE));
path = svn_fs__canonicalize_abspath(path, pool);
+ glfb.path = path;
+ glfb.requested_depth = depth;
+ glfb.get_locks_func = get_locks_func;
+ glfb.get_locks_baton = get_locks_baton;
+
/* Get the top digest path in our tree of interest, and then walk it. */
digest_path = digest_path_from_path(fs, path, pool);
- return walk_digest_files(fs, digest_path, get_locks_func,
- get_locks_baton, FALSE, pool);
+ return walk_digest_files(fs, digest_path, get_locks_filter_func, &glfb,
+ FALSE, pool);
}
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/lock.h
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/lock.h?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/lock.h (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/lock.h Wed Sep 15 19:32:26 2010
@@ -60,6 +60,7 @@ svn_error_t *svn_fs_fs__get_lock(svn_loc
svn_error_t *svn_fs_fs__get_locks(svn_fs_t *fs,
const char *path,
+ svn_depth_t depth,
svn_fs_get_locks_callback_t get_locks_func,
void *get_locks_baton,
apr_pool_t *pool);
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/structure?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/structure Wed Sep 15 19:32:26 2010
@@ -59,7 +59,7 @@ repository) is:
format File containing the format number of this filesystem
fsfs.conf Configuration file
min-unpacked-rev File containing the oldest revision not in a pack file
- min-unpacked_revprop File containing the oldest revision of unpacked revprop
+ min-unpacked-revprop File containing the oldest revision of unpacked revprop
rep-cache.db SQLite database mapping rep checksums to locations
revprops.db SQLite database of the packed revision properties
@@ -102,10 +102,8 @@ When representation sharing is enabled,
representation checksum and location mappings using a SQLite database in
"rep-cache.db". The database has a single table, which stores the sha1
hash text as the primary key, mapped to the representation revision, offset,
-size and expanded size. A final field, reuse count, is currently used
-for distinguishing representations which are shared. This file is not
-required, and may be removed at an abritrary time, with the subsequent
-loss of rep-sharing capabilities.
+size and expanded size. This file is not required, and may be removed at an
+abritrary time, with the subsequent loss of rep-sharing capabilities.
Filesystem formats
------------------
@@ -500,7 +498,8 @@ names are the first 3 characters of the
Also stored in the digest file for a given FS path are pointers to
other digest files which contain information associated with other FS
-paths that are our path's immediate children.
+paths that are beneath our path (an immediate child thereof, or a
+grandchild, or a great-grandchild, ...).
To answer the question, "Does path FOO have a lock associated with
it?", one need only generate the MD5 digest of FOO's
@@ -515,4 +514,4 @@ To inquire about locks on children of th
reference the same path as above, but look for a list of children in
that file (instead of lock information). Children are listed as MD5
digests, too, so you would simply iterate over those digests and
-consult the files they reference, and so on, recursively.
+consult the files they reference for lock information.
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/tree.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_fs_fs/tree.c Wed Sep 15 19:32:26 2010
@@ -358,7 +358,7 @@ mutable_root_node(dag_node_t **node_p,
return svn_fs_fs__dag_clone_root(node_p, root->fs, root->txn, pool);
else
/* If it's not a transaction root, we can't change its contents. */
- return SVN_FS__ERR_NOT_MUTABLE(root->fs, root->rev, error_path);
+ return SVN_FS__ERR_NOT_MUTABLE(root->fs, root->rev, error_path, pool);
}
@@ -692,7 +692,7 @@ open_path(parent_path_t **parent_path_p,
/* The path isn't finished yet; we'd better be in a directory. */
if (svn_fs_fs__dag_node_kind(child) != svn_node_dir)
- SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far),
+ SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far, pool),
apr_psprintf(pool, _("Failure opening '%s'"), path));
rest = next;
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra/compat.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra/compat.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra/compat.c Wed Sep 15 19:32:26 2010
@@ -663,24 +663,24 @@ svn_ra__file_revs_from_log(svn_ra_sessio
svn_stream_t *last_stream;
apr_pool_t *currpool, *lastpool;
+ /* Check to make sure we're dealing with a file. */
+ SVN_ERR(svn_ra_check_path(ra_session, path, end, &kind, pool));
+
+ if (kind == svn_node_dir)
+ return svn_error_createf(SVN_ERR_FS_NOT_FILE, NULL,
+ _("'%s' is not a file"), path);
+
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_url, pool));
SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, pool));
/* Create the initial path, using the repos_url and session_url */
- tmp = svn_path_is_child(repos_url, session_url, pool);
+ tmp = svn_uri_is_child(repos_url, session_url, pool);
repos_abs_path = apr_palloc(pool, strlen(tmp) + 1);
repos_abs_path[0] = '/';
memcpy(repos_abs_path + 1, tmp, strlen(tmp));
- /* Check to make sure we're dealing with a file. */
- SVN_ERR(svn_ra_check_path(ra_session, "", end, &kind, pool));
-
- if (kind == svn_node_dir)
- return svn_error_createf(SVN_ERR_FS_NOT_FILE, NULL,
- _("'%s' is not a file"), repos_abs_path);
-
condensed_targets = apr_array_make(pool, 1, sizeof(const char *));
- APR_ARRAY_PUSH(condensed_targets, const char *) = "";
+ APR_ARRAY_PUSH(condensed_targets, const char *) = path;
lmb.path = svn_path_uri_decode(repos_abs_path, pool);
lmb.eldest = NULL;
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra/deprecated.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra/deprecated.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra/deprecated.c Wed Sep 15 19:32:26 2010
@@ -30,6 +30,7 @@
#include "svn_path.h"
#include "svn_compat.h"
#include "svn_props.h"
+#include "svn_pools.h"
#include "ra_loader.h"
@@ -148,6 +149,18 @@ static svn_ra_reporter2_t reporter_3in2_
abort_report
};
+svn_error_t *svn_ra_open3(svn_ra_session_t **session_p,
+ const char *repos_URL,
+ const char *uuid,
+ const svn_ra_callbacks2_t *callbacks,
+ void *callback_baton,
+ apr_hash_t *config,
+ apr_pool_t *pool)
+{
+ return svn_ra_open4(session_p, NULL, repos_URL, uuid,
+ callbacks, callback_baton, config, pool);
+}
+
svn_error_t *svn_ra_open2(svn_ra_session_t **session_p,
const char *repos_URL,
const svn_ra_callbacks2_t *callbacks,
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra/ra_loader.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra/ra_loader.c Wed Sep 15 19:32:26 2010
@@ -268,7 +268,8 @@ svn_ra_create_callbacks(svn_ra_callbacks
return SVN_NO_ERROR;
}
-svn_error_t *svn_ra_open3(svn_ra_session_t **session_p,
+svn_error_t *svn_ra_open4(svn_ra_session_t **session_p,
+ const char **corrected_url_p,
const char *repos_URL,
const char *uuid,
const svn_ra_callbacks2_t *callbacks,
@@ -276,6 +277,7 @@ svn_error_t *svn_ra_open3(svn_ra_session
apr_hash_t *config,
apr_pool_t *pool)
{
+ apr_pool_t *sesspool = svn_pool_create(pool);
svn_ra_session_t *session;
const struct ra_lib_defn *defn;
const svn_ra__vtable_t *vtable = NULL;
@@ -294,6 +296,10 @@ svn_error_t *svn_ra_open3(svn_ra_session
svn_boolean_t store_pp = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
const char *store_pp_plaintext
= SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
+ const char *corrected_url;
+
+ /* Initialize the return variable. */
+ *session_p = NULL;
if (callbacks->auth_baton)
{
@@ -357,7 +363,7 @@ svn_error_t *svn_ra_open3(svn_ra_session
/* Find out where we're about to connect to, and
* try to pick a server group based on the destination. */
- apr_err = apr_uri_parse(pool, repos_URL, &repos_URI);
+ apr_err = apr_uri_parse(sesspool, repos_URL, &repos_URI);
/* ### Should apr_uri_parse leave hostname NULL? It doesn't
* for "file:///" URLs, only for bogus URLs like "bogus".
* If this is the right behavior for apr_uri_parse, maybe we
@@ -367,7 +373,8 @@ svn_error_t *svn_ra_open3(svn_ra_session
_("Illegal repository URL '%s'"),
repos_URL);
server_group = svn_config_find_group(servers, repos_URI.hostname,
- SVN_CONFIG_SECTION_GROUPS, pool);
+ SVN_CONFIG_SECTION_GROUPS,
+ sesspool);
if (server_group)
{
@@ -458,12 +465,12 @@ svn_error_t *svn_ra_open3(svn_ra_session
if (! initfunc)
SVN_ERR(load_ra_module(&initfunc, NULL, defn->ra_name,
- pool));
+ sesspool));
if (! initfunc)
/* Library not found. */
continue;
- SVN_ERR(initfunc(svn_ra_version(), &vtable, pool));
+ SVN_ERR(initfunc(svn_ra_version(), &vtable, sesspool));
SVN_ERR(check_ra_version(vtable->get_version(), scheme));
@@ -477,25 +484,36 @@ svn_error_t *svn_ra_open3(svn_ra_session
repos_URL);
/* Create the session object. */
- session = apr_pcalloc(pool, sizeof(*session));
+ session = apr_pcalloc(sesspool, sizeof(*session));
session->vtable = vtable;
- session->pool = pool;
+ session->pool = sesspool;
/* Ask the library to open the session. */
- SVN_ERR_W(vtable->open_session(session, repos_URL, callbacks, callback_baton,
- config, pool),
+ SVN_ERR_W(vtable->open_session(session, &corrected_url, repos_URL,
+ callbacks, callback_baton, config, sesspool),
apr_psprintf(pool, "Unable to connect to a repository at URL '%s'",
repos_URL));
-
+
+ /* If the session open stuff detected a server-provided URL
+ correction (a 301 or 302 redirect response during the initial
+ OPTIONS request), then kill the session so the caller can decide
+ what to do. */
+ if (corrected_url_p && corrected_url)
+ {
+ *corrected_url_p = apr_pstrdup(pool, corrected_url);
+ svn_pool_destroy(sesspool);
+ return SVN_NO_ERROR;
+ }
+
/* Check the UUID. */
if (uuid)
{
const char *repository_uuid;
SVN_ERR(vtable->get_uuid(session, &repository_uuid, pool));
-
if (strcmp(uuid, repository_uuid) != 0)
{
+ svn_pool_destroy(sesspool);
return svn_error_createf(SVN_ERR_RA_UUID_MISMATCH, NULL,
_("Repository UUID '%s' doesn't match "
"expected UUID '%s'"),
@@ -623,6 +641,28 @@ svn_error_t *svn_ra_rev_prop(svn_ra_sess
return session->vtable->rev_prop(session, rev, name, value, pool);
}
+struct ccw_baton
+{
+ svn_commit_callback2_t original_callback;
+ void *original_baton;
+
+ svn_ra_session_t *session;
+};
+
+/* Wrapper which populates the repos_root field of the commit_info struct */
+static svn_error_t *
+commit_callback_wrapper(const svn_commit_info_t *commit_info,
+ void *baton,
+ apr_pool_t *pool)
+{
+ struct ccw_baton *ccwb = baton;
+ svn_commit_info_t *ci = svn_commit_info_dup(commit_info, pool);
+
+ SVN_ERR(svn_ra_get_repos_root2(ccwb->session, &ci->repos_root, pool));
+
+ return ccwb->original_callback(ci, ccwb->original_baton, pool);
+}
+
svn_error_t *svn_ra_get_commit_editor3(svn_ra_session_t *session,
const svn_delta_editor_t **editor,
void **edit_baton,
@@ -633,10 +673,21 @@ svn_error_t *svn_ra_get_commit_editor3(s
svn_boolean_t keep_locks,
apr_pool_t *pool)
{
+ /* Allocate this in a pool, since the callback will be called long after
+ this function as returned. */
+ struct ccw_baton *ccwb = apr_palloc(pool, sizeof(*ccwb));
+
+ ccwb->original_callback = callback;
+ ccwb->original_baton = callback_baton;
+ ccwb->session = session;
+
return session->vtable->get_commit_editor(session, editor, edit_baton,
- revprop_table, callback,
- callback_baton, lock_tokens,
- keep_locks, pool);
+ revprop_table,
+ callback
+ ? commit_callback_wrapper
+ : NULL,
+ callback ? ccwb : NULL,
+ lock_tokens, keep_locks, pool);
}
svn_error_t *svn_ra_get_file(svn_ra_session_t *session,
@@ -1014,13 +1065,26 @@ svn_error_t *svn_ra_get_lock(svn_ra_sess
return session->vtable->get_lock(session, lock, path, pool);
}
+svn_error_t *svn_ra_get_locks2(svn_ra_session_t *session,
+ apr_hash_t **locks,
+ const char *path,
+ svn_depth_t depth,
+ apr_pool_t *pool)
+{
+ SVN_ERR_ASSERT(*path != '/');
+ SVN_ERR_ASSERT((depth == svn_depth_empty) ||
+ (depth == svn_depth_files) ||
+ (depth == svn_depth_immediates) ||
+ (depth == svn_depth_infinity));
+ return session->vtable->get_locks(session, locks, path, depth, pool);
+}
+
svn_error_t *svn_ra_get_locks(svn_ra_session_t *session,
apr_hash_t **locks,
const char *path,
apr_pool_t *pool)
{
- SVN_ERR_ASSERT(*path != '/');
- return session->vtable->get_locks(session, locks, path, pool);
+ return svn_ra_get_locks2(session, locks, path, svn_depth_infinity, pool);
}
svn_error_t *svn_ra_replay(svn_ra_session_t *session,
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra/ra_loader.h?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra/ra_loader.h Wed Sep 15 19:32:26 2010
@@ -54,6 +54,7 @@ typedef struct svn_ra__vtable_t {
/* All fields in SESSION, except priv, have been initialized by the
time this is called. SESSION->priv may be set by this function. */
svn_error_t *(*open_session)(svn_ra_session_t *session,
+ const char **corrected_url,
const char *repos_URL,
const svn_ra_callbacks2_t *callbacks,
void *callback_baton,
@@ -230,6 +231,7 @@ typedef struct svn_ra__vtable_t {
svn_error_t *(*get_locks)(svn_ra_session_t *session,
apr_hash_t **locks,
const char *path,
+ svn_depth_t depth,
apr_pool_t *pool);
svn_error_t *(*replay)(svn_ra_session_t *session,
svn_revnum_t revision,
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra/wrapper_template.h
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra/wrapper_template.h?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra/wrapper_template.h (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra/wrapper_template.h Wed Sep 15 19:32:26 2010
@@ -71,12 +71,15 @@ static svn_error_t *compat_open(void **s
* the alternative (creating a new ra_util library) would be massive
* overkill for the time being. Just be sure to keep the following
* line and the code of svn_ra_create_callbacks in sync. */
- svn_ra_callbacks2_t *callbacks2 = apr_pcalloc(pool,
+ apr_pool_t *sesspool = svn_pool_create(pool);
+ svn_ra_callbacks2_t *callbacks2 = apr_pcalloc(sesspool,
sizeof(*callbacks2));
- svn_ra_session_t *sess = apr_pcalloc(pool, sizeof(*sess));
+ svn_ra_session_t *sess = apr_pcalloc(sesspool, sizeof(*sess));
+ const char *session_url;
+
sess->vtable = &VTBL;
- sess->pool = pool;
+ sess->pool = sesspool;
callbacks2->open_tmp_file = callbacks->open_tmp_file;
callbacks2->auth_baton = callbacks->auth_baton;
@@ -87,8 +90,18 @@ static svn_error_t *compat_open(void **s
callbacks2->progress_func = NULL;
callbacks2->progress_baton = NULL;
- SVN_ERR(VTBL.open_session(sess, repos_URL, callbacks2, callback_baton,
- config, pool));
+ SVN_ERR(VTBL.open_session(sess, &session_url, repos_URL,
+ callbacks2, callback_baton, config, sesspool));
+
+ if (strcmp(repos_URL, session_url) != 0)
+ {
+ svn_pool_destroy(sesspool);
+ return svn_error_createf(SVN_ERR_RA_SESSION_URL_MISMATCH, NULL,
+ _("Session URL '%s' does not match requested "
+ " URL '%s', and redirection was disallowed."),
+ session_url, repos_URL);
+ }
+
*session_baton = sess;
return SVN_NO_ERROR;
}
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_local/ra_plugin.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_local/ra_plugin.c Wed Sep 15 19:32:26 2010
@@ -115,12 +115,12 @@ get_username(svn_ra_session_t *session,
if (*sess->username)
{
SVN_ERR(svn_fs_create_access(&access_ctx, sess->username,
- pool));
+ session->pool));
SVN_ERR(svn_fs_set_access(sess->fs, access_ctx));
/* Make sure this context is disassociated when the pool gets
destroyed. */
- apr_pool_cleanup_register(pool, sess->fs, cleanup_access,
+ apr_pool_cleanup_register(session->pool, sess->fs, cleanup_access,
apr_pool_cleanup_null);
}
@@ -341,14 +341,16 @@ deltify_etc(const svn_commit_info_t *com
void *baton, apr_pool_t *pool)
{
struct deltify_etc_baton *db = baton;
- svn_error_t *err1, *err2;
+ svn_error_t *err1 = SVN_NO_ERROR;
+ svn_error_t *err2;
apr_hash_index_t *hi;
apr_pool_t *iterpool;
/* Invoke the original callback first, in case someone's waiting to
know the revision number so they can go off and annotate an
issue or something. */
- err1 = (*db->callback)(commit_info, db->callback_baton, pool);
+ if (*db->callback)
+ err1 = (*db->callback)(commit_info, db->callback_baton, pool);
/* Maybe unlock the paths. */
if (db->lock_tokens)
@@ -435,6 +437,7 @@ ignore_warnings(void *baton,
static svn_error_t *
svn_ra_local__open(svn_ra_session_t *session,
+ const char **corrected_url,
const char *repos_URL,
const svn_ra_callbacks2_t *callbacks,
void *callback_baton,
@@ -444,6 +447,10 @@ svn_ra_local__open(svn_ra_session_t *ses
svn_ra_local__session_baton_t *sess;
const char *fs_path;
+ /* We don't support redirections in ra-local. */
+ if (corrected_url)
+ *corrected_url = NULL;
+
/* Allocate and stash the session_sess args we have already. */
sess = apr_pcalloc(pool, sizeof(*sess));
sess->callbacks = callbacks;
@@ -1323,6 +1330,7 @@ static svn_error_t *
svn_ra_local__get_locks(svn_ra_session_t *session,
apr_hash_t **locks,
const char *path,
+ svn_depth_t depth,
apr_pool_t *pool)
{
svn_ra_local__session_baton_t *sess = session->priv;
@@ -1330,8 +1338,8 @@ svn_ra_local__get_locks(svn_ra_session_t
/* Kinda silly to call the repos wrapper, since we have no authz
func to give it. But heck, why not. */
- return svn_repos_fs_get_locks(locks, sess->repos, abs_path,
- NULL, NULL, pool);
+ return svn_repos_fs_get_locks2(locks, sess->repos, abs_path, depth,
+ NULL, NULL, pool);
}
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_local/split_url.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_local/split_url.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_local/split_url.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_local/split_url.c Wed Sep 15 19:32:26 2010
@@ -24,6 +24,7 @@
#include "ra_local.h"
#include <string.h>
#include "svn_path.h"
+#include "svn_dirent_uri.h"
#include "svn_private_config.h"
@@ -35,129 +36,23 @@ svn_ra_local__split_URL(svn_repos_t **re
apr_pool_t *pool)
{
svn_error_t *err = SVN_NO_ERROR;
- const char *repos_root;
- const char *hostname, *path;
+ const char *repos_dirent;
+ const char *repos_root_dirent;
svn_stringbuf_t *urlbuf;
- /* Verify that the URL is well-formed (loosely) */
-
- /* First, check for the "file://" prefix. */
- if (strncmp(URL, "file://", 7) != 0)
- return svn_error_createf
- (SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("Local URL '%s' does not contain 'file://' prefix"), URL);
-
- /* Then, skip what's between the "file://" prefix and the next
- occurance of '/' -- this is the hostname, and we are considering
- everything from that '/' until the end of the URL to be the
- absolute path portion of the URL.
- If we got just "file://", treat it the same as "file:///". */
- hostname = URL + 7;
- if (*hostname == '\0')
- {
- path = "/";
- hostname = NULL;
- }
- else
- {
- path = strchr(hostname, '/');
- if (! path)
- return svn_error_createf
- (SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("Local URL '%s' contains only a hostname, no path"), URL);
-
- /* Treat localhost as an empty hostname. */
- if (hostname != path)
- {
- hostname = svn_path_uri_decode(apr_pstrmemdup(pool, hostname,
- path - hostname), pool);
- if (strncmp(hostname, "localhost", 9) == 0)
- hostname = NULL;
- }
- else
- hostname = NULL;
- }
-
- /* Duplicate the URL, starting at the top of the path.
- At the same time, we URI-decode the path. */
-#if defined(WIN32) || defined(__CYGWIN__)
- /* On Windows, we'll typically have to skip the leading / if the
- path starts with a drive letter. Like most Web browsers, We
- support two variants of this scheme:
-
- file:///X:/path and
- file:///X|/path
-
- Note that, at least on WinNT and above, file:////./X:/path will
- also work, so we must make sure the transformation doesn't break
- that, and file:///path (that looks within the current drive
- only) should also keep working.
- If we got a non-empty hostname other than localhost, we convert this
- into an UNC path. In this case, we obviously don't strip the slash
- even if the path looks like it starts with a drive letter.
- Another thing to remember is that the form file:///\machine/share
- was the only way to access UNC paths in svn before 1.2. We
- need to support that for compatibility with old working copies.
- */
- {
- static const char valid_drive_letters[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- /* Casting away const! */
- char *dup_path = (char *)svn_path_uri_decode(path, pool);
- if (!hostname && dup_path[1] && strchr(valid_drive_letters, dup_path[1])
- && (dup_path[2] == ':' || dup_path[2] == '|')
- && (dup_path[3] == '/' || dup_path[3] == '\0'))
- {
- /* Skip the leading slash. */
- ++dup_path;
- /* We're using path below to calculate fs_path, so keep it in sync. */
- ++path;
- if (dup_path[1] == '|')
- dup_path[1] = ':';
-
- if (dup_path[3] == '\0')
- {
- /* A valid dirent for the driveroot must be like "C:/" instead of
- just "C:" or svn_dirent_join() will use the current directory
- on the drive instead */
-
- char *new_path = apr_pcalloc(pool, 4);
- new_path[0] = dup_path[0];
- new_path[1] = ':';
- new_path[2] = '/';
- new_path[3] = '\0';
- }
- }
- if (hostname)
- /* We still know that the path starts with a slash. */
- repos_root = apr_pstrcat(pool, "//", hostname, path, NULL);
- else
- repos_root = dup_path;
- }
-#else
- /* Currently, the only hostnames we are allowing on non-Win32 platforms
- are the empty string and 'localhost'. */
- if (hostname)
- return svn_error_createf
- (SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("Local URL '%s' contains unsupported hostname"), URL);
-
- repos_root = svn_path_uri_decode(path, pool);
-#endif
+ SVN_ERR(svn_uri_get_dirent_from_file_url(&repos_dirent, URL, pool));
/* Search for a repository in the full path. */
- repos_root = svn_repos_find_root_path(repos_root, pool);
- if (!repos_root)
- return svn_error_createf
- (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, NULL,
- _("Unable to open repository '%s'"), URL);
+ repos_root_dirent = svn_repos_find_root_path(repos_dirent, pool);
+ if (!repos_root_dirent)
+ return svn_error_createf(SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, NULL,
+ _("Unable to open repository '%s'"), URL);
/* Attempt to open a repository at URL. */
- err = svn_repos_open(repos, repos_root, pool);
+ err = svn_repos_open(repos, repos_root_dirent, pool);
if (err)
- return svn_error_createf
- (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, err,
- _("Unable to open repository '%s'"), URL);
+ return svn_error_createf(SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, err,
+ _("Unable to open repository '%s'"), URL);
/* Assert capabilities directly, since client == server. */
{
@@ -166,26 +61,17 @@ svn_ra_local__split_URL(svn_repos_t **re
SVN_ERR(svn_repos_remember_client_capabilities(*repos, caps));
}
- /* What remains of URL after being hacked at in the previous step is
- REPOS_URL. FS_PATH is what we've hacked off in the process.
- Note that path is not encoded and what we gave to svn_root_find_root_path
- may have been destroyed by that function. So we have to decode it once
- more. But then, it is ours...
- We want the suffix of path after the repos root part. Note that
- repos_root may contain //hostname, but path doesn't. */
- *fs_path = svn_path_uri_decode(path, pool)
- + (strlen(repos_root)
- - (hostname ? strlen(hostname) + 2 : 0));
-
- /* Ensure that *FS_PATH has its leading slash. */
- if (**fs_path != '/')
- *fs_path = apr_pstrcat(pool, "/", *fs_path, NULL);
+ *fs_path = &repos_dirent[strlen(repos_root_dirent)];
+
+ if (**fs_path == '\0')
+ *fs_path = "/";
/* Remove the path components in *fs_path from the original URL, to get
the URL to the repository root. */
urlbuf = svn_stringbuf_create(URL, pool);
svn_path_remove_components(urlbuf,
- svn_path_component_count(*fs_path));
+ svn_path_component_count(repos_dirent)
+ - svn_path_component_count(repos_root_dirent));
*repos_url = urlbuf->data;
return SVN_NO_ERROR;
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/commit.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/commit.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/commit.c Wed Sep 15 19:32:26 2010
@@ -416,8 +416,8 @@ static svn_error_t * do_checkout(commit_
### place result into res->wr_url and return it */
/* create/prep the request */
- request =
- svn_ra_neon__request_create(cc->ras, "CHECKOUT", vsn_url, pool);
+ SVN_ERR(svn_ra_neon__request_create(&request, cc->ras, "CHECKOUT", vsn_url,
+ pool));
/* ### store this into cc to avoid pool growth */
body = apr_psprintf(request->pool,
@@ -807,9 +807,8 @@ static svn_error_t * commit_delete_entry
APR_HASH_KEY_STRING)))
apr_hash_set(child_tokens, path, APR_HASH_KEY_STRING, token);
-
- request =
- svn_ra_neon__request_create(parent->cc->ras, "DELETE", child, pool);
+ SVN_ERR(svn_ra_neon__request_create(&request, parent->cc->ras, "DELETE",
+ child, pool));
err = svn_ra_neon__assemble_locktoken_body(&locks_list,
child_tokens, request->pool);
@@ -1274,7 +1273,8 @@ static svn_error_t * commit_close_file(v
svn_error_t *err = SVN_NO_ERROR;
/* create/prep the request */
- request = svn_ra_neon__request_create(cc->ras, "PUT", url, pool);
+ SVN_ERR(svn_ra_neon__request_create(&request, cc->ras, "PUT", url,
+ pool));
extra_headers = apr_hash_make(request->pool);
@@ -1355,9 +1355,8 @@ static svn_error_t * commit_close_edit(v
cc->disable_merge_response,
pool));
SVN_ERR(delete_activity(edit_baton, pool));
- SVN_ERR(svn_ra_neon__maybe_store_auth_info(cc->ras, pool));
- if (commit_info->revision != SVN_INVALID_REVNUM)
+ if (cc->callback && commit_info->revision != SVN_INVALID_REVNUM)
SVN_ERR(cc->callback(commit_info, cc->callback_baton, pool));
return SVN_NO_ERROR;
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/fetch.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/fetch.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/fetch.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/fetch.c Wed Sep 15 19:32:26 2010
@@ -394,7 +394,7 @@ static svn_error_t *custom_get_request(s
delta_base = NULL;
}
- request = svn_ra_neon__request_create(ras, "GET", url, pool);
+ SVN_ERR(svn_ra_neon__request_create(&request, ras, "GET", url, pool));
if (delta_base)
{
@@ -1097,7 +1097,8 @@ svn_error_t *svn_ra_neon__get_latest_rev
PROPFINDs. */
if (SVN_RA_NEON__HAVE_HTTPV2_SUPPORT(ras))
{
- SVN_ERR(svn_ra_neon__exchange_capabilities(ras, latest_revnum, pool));
+ SVN_ERR(svn_ra_neon__exchange_capabilities(ras, NULL,
+ latest_revnum, pool));
if (! SVN_IS_VALID_REVNUM(*latest_revnum))
return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
_("The OPTIONS response did not include "
@@ -1111,7 +1112,6 @@ svn_error_t *svn_ra_neon__get_latest_rev
ras, ras->root.path,
SVN_INVALID_REVNUM, pool));
}
- SVN_ERR(svn_ra_neon__maybe_store_auth_info(ras, pool));
return NULL;
}
@@ -1713,8 +1713,10 @@ start_element(int *elem, void *userdata,
if (! rb->receiving_all)
break;
+ base_checksum = svn_xml_get_attr_value("base-checksum", atts);
+
SVN_ERR((*rb->editor->apply_textdelta)(rb->file_baton,
- NULL, /* ### base_checksum */
+ base_checksum,
rb->file_pool,
&(rb->whandler),
&(rb->whandler_baton)));
@@ -2439,8 +2441,7 @@ static svn_error_t * reporter_finish_rep
_("REPORT response handling failed to complete the editor drive"));
}
- /* store auth info if we can. */
- return svn_ra_neon__maybe_store_auth_info(rb->ras, pool);
+ return SVN_NO_ERROR;
}
static const svn_ra_reporter3_t ra_neon_reporter = {
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/get_locks.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/get_locks.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/get_locks.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/get_locks.c Wed Sep 15 19:32:26 2010
@@ -85,7 +85,7 @@ static const svn_ra_neon__xml_elm_t getl
* The get-locks-report xml request body is super-simple.
* The server doesn't need anything but the URI in the REPORT request line.
*
- * <S:get-locks-report xmlns...>
+ * <S:get-locks-report [depth=DEPTH] xmlns...>
* </S:get-locks-report>
*
* The get-locks-report xml response is just a list of svn_lock_t's
@@ -121,6 +121,8 @@ static const svn_ra_neon__xml_elm_t getl
/* Context for parsing server's response. */
typedef struct {
+ const char *path; /* target of the report */
+ svn_depth_t requested_depth; /* requested depth of the report */
svn_lock_t *current_lock; /* the lock being constructed */
svn_stringbuf_t *cdata_accum; /* a place to accumulate cdata */
const char *encoding; /* normally NULL, else the value of
@@ -235,8 +237,33 @@ getlocks_end_element(void *userdata, int
SVN_ERR(svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
_("Incomplete lock data returned")));
- apr_hash_set(baton->lock_hash, baton->current_lock->path,
- APR_HASH_KEY_STRING, baton->current_lock);
+ /* Filter out unwanted paths. Since Subversion only allows
+ locks on files, we can treat depth=immediates the same as
+ depth=files for filtering purposes. Meaning, we'll keep
+ this lock if:
+
+ a) its path is the very path we queried, or
+ b) we've asked for a fully recursive answer, or
+ c) we've asked for depth=files or depth=immediates, and this
+ lock is on an immediate child of our query path.
+ */
+ if ((strcmp(baton->path, baton->current_lock->path) == 0)
+ || (baton->requested_depth == svn_depth_infinity))
+ {
+ apr_hash_set(baton->lock_hash, baton->current_lock->path,
+ APR_HASH_KEY_STRING, baton->current_lock);
+ }
+ else if ((baton->requested_depth == svn_depth_files) ||
+ (baton->requested_depth == svn_depth_immediates))
+ {
+ const char *rel_uri = svn_uri_is_child(baton->path,
+ baton->current_lock->path,
+ baton->scratchpool);
+ if (rel_uri && (svn_path_component_count(rel_uri) == 1))
+ apr_hash_set(baton->lock_hash, baton->current_lock->path,
+ APR_HASH_KEY_STRING, baton->current_lock);
+ svn_pool_clear(baton->scratchpool);
+ }
break;
case ELEM_lock_path:
@@ -330,20 +357,30 @@ getlocks_end_element(void *userdata, int
}
-
svn_error_t *
svn_ra_neon__get_locks(svn_ra_session_t *session,
apr_hash_t **locks,
const char *path,
+ svn_depth_t depth,
apr_pool_t *pool)
{
svn_ra_neon__session_t *ras = session->priv;
- const char *body, *url;
+ const char *body, *url, *rel_path;
svn_error_t *err;
int status_code = 0;
get_locks_baton_t baton;
+ /* We always run the report on the 'public' URL, which represents
+ HEAD anyway. If the path doesn't exist in HEAD, then there can't
+ possibly be a lock, so we just return no locks. */
+ url = svn_path_url_add_component2(ras->url->data, path, pool);
+
+ SVN_ERR(svn_ra_neon__get_path_relative_to_root(session, &rel_path,
+ url, pool));
+
baton.lock_hash = apr_hash_make(pool);
+ baton.path = apr_pstrcat(pool, "/", rel_path, NULL);
+ baton.requested_depth = depth;
baton.pool = pool;
baton.scratchpool = svn_pool_create(pool);
baton.current_lock = NULL;
@@ -353,14 +390,9 @@ svn_ra_neon__get_locks(svn_ra_session_t
body = apr_psprintf(pool,
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<S:get-locks-report xmlns:S=\"" SVN_XML_NAMESPACE "\" "
- "xmlns:D=\"DAV:\">"
- "</S:get-locks-report>");
-
-
- /* We always run the report on the 'public' URL, which represents
- HEAD anyway. If the path doesn't exist in HEAD, then there can't
- possibly be a lock, so we just return no locks. */
- url = svn_path_url_add_component(ras->url->data, path, pool);
+ "xmlns:D=\"DAV:\" depth=\"%s\">"
+ "</S:get-locks-report>",
+ svn_depth_to_word(depth));
err = svn_ra_neon__parsed_request(ras, "REPORT", url,
body, NULL, NULL,
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/lock.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/lock.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/lock.c Wed Sep 15 19:32:26 2010
@@ -32,6 +32,7 @@
#include "svn_ra.h"
#include "../libsvn_ra/ra_loader.h"
#include "svn_path.h"
+#include "svn_string.h"
#include "svn_time.h"
#include "svn_private_config.h"
@@ -209,8 +210,9 @@ lock_from_baton(svn_lock_t **lock,
{
if (strncmp("Second-", timeout_str, strlen("Second-")) == 0)
{
- int time_offset = atoi(&(timeout_str[7]));
-
+ int time_offset;
+
+ SVN_ERR(svn_cstring_atoi(&time_offset, &(timeout_str[7])));
lck->expiration_date = lck->creation_date
+ apr_time_from_sec(time_offset);
}
@@ -259,7 +261,7 @@ do_lock(svn_lock_t **lock,
_("Failed to parse URI '%s'"), url);
}
- req = svn_ra_neon__request_create(ras, "LOCK", uri.path, pool);
+ SVN_ERR(svn_ra_neon__request_create(&req, ras, "LOCK", uri.path, pool));
ne_uri_free(&uri);
lrb->pool = pool;
@@ -532,7 +534,7 @@ svn_ra_neon__get_lock_internal(svn_ra_ne
url = apr_pstrdup(pool, uri.path);
ne_uri_free(&uri);
- req = svn_ra_neon__request_create(ras, "PROPFIND", url, pool);
+ SVN_ERR(svn_ra_neon__request_create(&req, ras, "PROPFIND", url, pool));
lrb->pool = pool;
lrb->xml_table = lock_elements;
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/options.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/options.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/options.c Wed Sep 15 19:32:26 2010
@@ -144,6 +144,8 @@ parse_capabilities(ne_request *req,
*youngest_rev = SVN_INVALID_REVNUM;
/* Start out assuming all capabilities are unsupported. */
+ apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
+ APR_HASH_KEY_STRING, capability_no);
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_DEPTH,
APR_HASH_KEY_STRING, capability_no);
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
@@ -249,6 +251,7 @@ parse_capabilities(ne_request *req,
svn_error_t *
svn_ra_neon__exchange_capabilities(svn_ra_neon__session_t *ras,
+ const char **relocation_location,
svn_revnum_t *youngest_rev,
apr_pool_t *pool)
{
@@ -262,8 +265,11 @@ svn_ra_neon__exchange_capabilities(svn_r
oc.cdata = svn_stringbuf_create("", pool);
*youngest_rev = SVN_INVALID_REVNUM;
+ if (relocation_location)
+ *relocation_location = NULL;
- req = svn_ra_neon__request_create(ras, "OPTIONS", ras->url->data, pool);
+ SVN_ERR(svn_ra_neon__request_create(&req, ras, "OPTIONS", ras->url->data,
+ pool));
/* ### Use a symbolic name somewhere for this MIME type? */
ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
@@ -280,9 +286,17 @@ svn_ra_neon__exchange_capabilities(svn_r
"<D:options xmlns:D=\"DAV:\">"
"<D:activity-collection-set/>"
"</D:options>",
- 200, 0, pool)))
+ 200,
+ relocation_location ? 301 : 0,
+ pool)))
goto cleanup;
+ if (req->code == 301)
+ {
+ *relocation_location = svn_ra_neon__request_get_location(req, pool);
+ goto cleanup;
+ }
+
/* Was there an XML parse error somewhere? */
err = svn_ra_neon__check_parse_error("OPTIONS", parser, ras->url->data);
if (err)
@@ -316,7 +330,8 @@ svn_ra_neon__get_activity_collection(con
{
svn_revnum_t ignored_revnum;
if (! ras->act_coll)
- SVN_ERR(svn_ra_neon__exchange_capabilities(ras, &ignored_revnum, pool));
+ SVN_ERR(svn_ra_neon__exchange_capabilities(ras, NULL,
+ &ignored_revnum, pool));
*activity_coll = svn_string_create(ras->act_coll, pool);
return SVN_NO_ERROR;
}
@@ -346,7 +361,8 @@ svn_ra_neon__has_capability(svn_ra_sessi
if (cap_result == NULL)
{
svn_revnum_t ignored_revnum;
- SVN_ERR(svn_ra_neon__exchange_capabilities(ras, &ignored_revnum, pool));
+ SVN_ERR(svn_ra_neon__exchange_capabilities(ras, NULL,
+ &ignored_revnum, pool));
}