/* Return the path to something in PATH's administrative area. * * First, the adm subdir is appended to PATH as a component, then the * "tmp" directory is added iff USE_TMP is set, then each of the * varargs in AP (char *'s) is appended as a path component. The list * must be terminated with a NULL argument. * * Adding an empty component results in no effect (i.e., the separator * char is not doubled). * * If EXTENSION is non-null, it will be appended to the final string * without a separator character. */ static const char * v_extend_with_adm_name(const char *path, const char *extension, svn_boolean_t use_tmp, apr_pool_t *pool, va_list ap) { const char *this; /* Tack on the administrative subdirectory. */ path = svn_path_join(path, adm_dir_name, pool); /* If this is a tmp file, name it into the tmp area. */ if (use_tmp) path = svn_path_join(path, SVN_WC__ADM_TMP, pool); /* Tack on everything else. */ while ((this = va_arg(ap, const char *)) != NULL) { if (this[0] == '\0') continue; path = svn_path_join(path, this, pool); } if (extension) path = apr_pstrcat(pool, path, extension, NULL); return path; }
/* Return filename for ACTIVITY_ID under the repository in REPOS. */ static const char * activity_pathname(const dav_svn_repos *repos, const char *activity_id) { return svn_path_join(repos->activities_db, escape_activity(activity_id, repos->pool), repos->pool); }
static svn_error_t * svn_ra_local__get_mergeinfo(svn_ra_session_t *session, svn_mergeinfo_catalog_t *catalog, const apr_array_header_t *paths, svn_revnum_t revision, svn_mergeinfo_inheritance_t inherit, svn_boolean_t include_descendants, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; svn_mergeinfo_catalog_t tmp_catalog; int i; apr_array_header_t *abs_paths = apr_array_make(pool, 0, sizeof(const char *)); for (i = 0; i < paths->nelts; i++) { const char *relative_path = APR_ARRAY_IDX(paths, i, const char *); APR_ARRAY_PUSH(abs_paths, const char *) = svn_path_join(sess->fs_path->data, relative_path, pool); } SVN_ERR(svn_repos_fs_get_mergeinfo(&tmp_catalog, sess->repos, abs_paths, revision, inherit, include_descendants, NULL, NULL, pool)); if (apr_hash_count(tmp_catalog) > 0) SVN_ERR(svn_mergeinfo__remove_prefix_from_catalog(catalog, tmp_catalog, sess->fs_path->data, pool)); else *catalog = NULL; return SVN_NO_ERROR; }
/* Make a new entry named NAME in PARENT. If IS_DIR is true, then the node revision the new entry points to will be a directory, else it will be a file. The new node will be allocated in POOL. PARENT must be mutable, and must not have an entry named NAME. */ static svn_error_t * make_entry(dag_node_t **child_p, dag_node_t *parent, const char *parent_path, const char *name, svn_boolean_t is_dir, const char *txn_id, apr_pool_t *pool) { const svn_fs_id_t *new_node_id; node_revision_t new_noderev, *parent_noderev; /* Make sure that NAME is a single path component. */ if (! svn_path_is_single_path_component(name)) return svn_error_createf (SVN_ERR_FS_NOT_SINGLE_PATH_COMPONENT, NULL, _("Attempted to create a node with an illegal name '%s'"), name); /* Make sure that parent is a directory */ if (parent->kind != svn_node_dir) return svn_error_create (SVN_ERR_FS_NOT_DIRECTORY, NULL, _("Attempted to create entry in non-directory parent")); /* Check that the parent is mutable. */ if (! svn_fs_fs__dag_check_mutable(parent)) return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, _("Attempted to clone child of non-mutable node")); /* Create the new node's NODE-REVISION */ memset(&new_noderev, 0, sizeof(new_noderev)); new_noderev.kind = is_dir ? svn_node_dir : svn_node_file; new_noderev.created_path = svn_path_join(parent_path, name, pool); SVN_ERR(get_node_revision(&parent_noderev, parent, pool)); new_noderev.copyroot_path = apr_pstrdup(pool, parent_noderev->copyroot_path); new_noderev.copyroot_rev = parent_noderev->copyroot_rev; new_noderev.copyfrom_rev = SVN_INVALID_REVNUM; new_noderev.copyfrom_path = NULL; SVN_ERR(svn_fs_fs__create_node (&new_node_id, svn_fs_fs__dag_get_fs(parent), &new_noderev, svn_fs_fs__id_copy_id(svn_fs_fs__dag_get_id(parent)), txn_id, pool)); /* Create a new dag_node_t for our new node */ SVN_ERR(svn_fs_fs__dag_get_node(child_p, svn_fs_fs__dag_get_fs(parent), new_node_id, pool)); /* We can safely call set_entry because we already know that PARENT is mutable, and we just created CHILD, so we know it has no ancestors (therefore, PARENT cannot be an ancestor of CHILD) */ return set_entry(parent, name, svn_fs_fs__dag_get_id(*child_p), new_noderev.kind, txn_id, pool); }
/* Getting just one file. */ static svn_error_t * svn_ra_local__get_file(svn_ra_session_t *session, const char *path, svn_revnum_t revision, svn_stream_t *stream, svn_revnum_t *fetched_rev, apr_hash_t **props, apr_pool_t *pool) { svn_fs_root_t *root; svn_stream_t *contents; svn_revnum_t youngest_rev; svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); /* Open the revision's root. */ if (! SVN_IS_VALID_REVNUM(revision)) { SVN_ERR(svn_fs_youngest_rev(&youngest_rev, sess->fs, pool)); SVN_ERR(svn_fs_revision_root(&root, sess->fs, youngest_rev, pool)); if (fetched_rev != NULL) *fetched_rev = youngest_rev; } else SVN_ERR(svn_fs_revision_root(&root, sess->fs, revision, pool)); if (stream) { /* Get a stream representing the file's contents. */ SVN_ERR(svn_fs_file_contents(&contents, root, abs_path, pool)); /* Now push data from the fs stream back at the caller's stream. Note that this particular RA layer does not computing a checksum as we go, and confirming it against the repository's checksum when done. That's because it calls svn_fs_file_contents() directly, which already checks the stored checksum, and all we're doing here is writing bytes in a loop. Truly, Nothing Can Go Wrong :-). But RA layers that go over a network should confirm the checksum. Note: we are not supposed to close the passed-in stream, so disown the thing. */ SVN_ERR(svn_stream_copy3(contents, svn_stream_disown(stream, pool), sess->callbacks ? sess->callbacks->cancel_func : NULL, sess->callback_baton, pool)); } /* Handle props if requested. */ if (props) SVN_ERR(get_node_props(props, sess, root, abs_path, pool)); return SVN_NO_ERROR; }
static svn_error_t * svn_ra_local__lock(svn_ra_session_t *session, apr_hash_t *path_revs, const char *comment, svn_boolean_t force, svn_ra_lock_callback_t lock_func, void *lock_baton, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; apr_hash_index_t *hi; apr_pool_t *iterpool = svn_pool_create(pool); /* A username is absolutely required to lock a path. */ SVN_ERR(get_username(session, pool)); for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi)) { svn_lock_t *lock; const void *key; const char *path; void *val; svn_revnum_t *revnum; const char *abs_path; svn_error_t *err, *callback_err = NULL; svn_pool_clear(iterpool); apr_hash_this(hi, &key, NULL, &val); path = key; revnum = val; abs_path = svn_path_join(sess->fs_path->data, path, iterpool); /* This wrapper will call pre- and post-lock hooks. */ err = svn_repos_fs_lock(&lock, sess->repos, abs_path, NULL, comment, FALSE /* not DAV comment */, 0 /* no expiration */, *revnum, force, iterpool); if (err && !SVN_ERR_IS_LOCK_ERROR(err)) return err; if (lock_func) callback_err = lock_func(lock_baton, path, TRUE, err ? NULL : lock, err, iterpool); svn_error_clear(err); if (callback_err) return callback_err; } svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
static svn_error_t * svn_ra_local__get_lock(svn_ra_session_t *session, svn_lock_t **lock, const char *path, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); return svn_fs_get_lock(lock, sess->fs, abs_path, pool); }
static svn_error_t * svn_ra_local__unlock(svn_ra_session_t *session, apr_hash_t *path_tokens, svn_boolean_t force, svn_ra_lock_callback_t lock_func, void *lock_baton, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; apr_hash_index_t *hi; apr_pool_t *iterpool = svn_pool_create(pool); /* A username is absolutely required to unlock a path. */ SVN_ERR(get_username(session, pool)); for (hi = apr_hash_first(pool, path_tokens); hi; hi = apr_hash_next(hi)) { const void *key; const char *path; void *val; const char *abs_path, *token; svn_error_t *err, *callback_err = NULL; svn_pool_clear(iterpool); apr_hash_this(hi, &key, NULL, &val); path = key; /* Since we can't store NULL values in a hash, we turn "" to NULL here. */ if (strcmp(val, "") != 0) token = val; else token = NULL; abs_path = svn_path_join(sess->fs_path->data, path, iterpool); /* This wrapper will call pre- and post-unlock hooks. */ err = svn_repos_fs_unlock(sess->repos, abs_path, token, force, iterpool); if (err && !SVN_ERR_IS_UNLOCK_ERROR(err)) return err; if (lock_func) callback_err = lock_func(lock_baton, path, FALSE, NULL, err, iterpool); svn_error_clear(err); if (callback_err) return callback_err; } svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
static svn_error_t * svn_ra_local__get_log(svn_ra_session_t *session, const apr_array_header_t *paths, svn_revnum_t start, svn_revnum_t end, int limit, svn_boolean_t discover_changed_paths, svn_boolean_t strict_node_history, svn_boolean_t include_merged_revisions, const apr_array_header_t *revprops, svn_log_entry_receiver_t receiver, void *receiver_baton, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; int i; struct log_baton lb; apr_array_header_t *abs_paths = apr_array_make(pool, 0, sizeof(const char *)); if (paths) { for (i = 0; i < paths->nelts; i++) { const char *relative_path = APR_ARRAY_IDX(paths, i, const char *); APR_ARRAY_PUSH(abs_paths, const char *) = svn_path_join(sess->fs_path->data, relative_path, pool); } } if (sess->callbacks && sess->callbacks->cancel_func) { lb.real_cb = receiver; lb.real_baton = receiver_baton; lb.sess = sess; receiver = cancellation_log_receiver; receiver_baton = &lb; } return svn_repos_get_logs4(sess->repos, abs_paths, start, end, limit, discover_changed_paths, strict_node_history, include_merged_revisions, revprops, NULL, NULL, receiver, receiver_baton, pool); }
static svn_error_t * svn_ra_local__get_session_url(svn_ra_session_t *session, const char **url, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; *url = svn_path_join(sess->repos_url, svn_path_uri_encode(sess->fs_path->data + 1, pool), pool); return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__dag_copy(dag_node_t *to_node, const char *entry, dag_node_t *from_node, svn_boolean_t preserve_history, svn_revnum_t from_rev, const char *from_path, const char *txn_id, apr_pool_t *pool) { const svn_fs_id_t *id; if (preserve_history) { node_revision_t *from_noderev, *to_noderev; const char *copy_id; const svn_fs_id_t *src_id = svn_fs_fs__dag_get_id(from_node); svn_fs_t *fs = svn_fs_fs__dag_get_fs(from_node); /* Make a copy of the original node revision. */ SVN_ERR(get_node_revision(&from_noderev, from_node, pool)); to_noderev = copy_node_revision(from_noderev, pool); /* Reserve a copy ID for this new copy. */ SVN_ERR(svn_fs_fs__reserve_copy_id(©_id, fs, txn_id, pool)); /* Create a successor with its predecessor pointing at the copy source. */ to_noderev->predecessor_id = svn_fs_fs__id_copy(src_id, pool); if (to_noderev->predecessor_count != -1) to_noderev->predecessor_count++; to_noderev->created_path = svn_path_join(svn_fs_fs__dag_get_created_path(to_node), entry, pool); to_noderev->copyfrom_path = apr_pstrdup(pool, from_path); to_noderev->copyfrom_rev = from_rev; /* Set the copyroot equal to our own id. */ to_noderev->copyroot_path = NULL; SVN_ERR(svn_fs_fs__create_successor(&id, fs, src_id, to_noderev, copy_id, txn_id, pool)); } else /* don't preserve history */ { id = svn_fs_fs__dag_get_id(from_node); } /* Set the entry in to_node to the new id. */ return svn_fs_fs__dag_set_entry(to_node, entry, id, from_node->kind, txn_id, pool); }
/* This implements 'svn_commit_callback_t'. Its invokes the original (wrapped) callback, but also does deltification on the new revision and possibly unlocks committed paths. BATON is 'struct deltify_etc_baton *'. */ static svn_error_t * deltify_etc(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool) { struct deltify_etc_baton *db = baton; svn_error_t *err1, *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); /* Maybe unlock the paths. */ if (db->lock_tokens) { iterpool = svn_pool_create(db->pool); for (hi = apr_hash_first(db->pool, db->lock_tokens); hi; hi = apr_hash_next(hi)) { const void *rel_path; void *val; const char *abs_path, *token; svn_pool_clear(iterpool); apr_hash_this(hi, &rel_path, NULL, &val); token = val; abs_path = svn_path_join(db->fs_path, rel_path, iterpool); /* We may get errors here if the lock was broken or stolen after the commit succeeded. This is fine and should be ignored. */ svn_error_clear(svn_repos_fs_unlock(db->repos, abs_path, token, FALSE, iterpool)); } svn_pool_destroy(iterpool); } /* But, deltification shouldn't be stopped just because someone's random callback failed, so proceed unconditionally on to deltification. */ err2 = svn_fs_deltify_revision(db->fs, commit_info->revision, db->pool); /* It's more interesting if the original callback failed, so let that one dominate. */ if (err1) { svn_error_clear(err2); return err1; } return err2; }
static svn_error_t * test_delete_entry(const char *path, svn_revnum_t revision, void *parent_baton, apr_pool_t *pool) { struct dir_baton *pb = parent_baton; /* Construct the full path of this entry and delete it from the txn. */ return svn_fs_delete(pb->edit_baton->txn_root, svn_path_join(pb->edit_baton->root_path, path, pool), pool); }
static svn_error_t * svn_ra_local__get_locks(svn_ra_session_t *session, apr_hash_t **locks, const char *path, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); /* 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); }
static svn_error_t * svn_ra_local__get_locations(svn_ra_session_t *session, apr_hash_t **locations, const char *path, svn_revnum_t peg_revision, apr_array_header_t *location_revisions, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); return svn_repos_trace_node_locations(sess->fs, locations, abs_path, peg_revision, location_revisions, NULL, NULL, pool); }
/* Write the format number and maximum number of files per directory to a new format file in PATH, overwriting a previously existing file. Use POOL for temporary allocation. This implementation is largely stolen from libsvn_fs_fs/fs_fs.c. */ static svn_error_t * write_format(const char *path, int format, int max_files_per_dir, apr_pool_t *pool) { const char *contents; path = svn_path_join(path, "format", pool); if (format >= SVN_FS_FS__MIN_LAYOUT_FORMAT_OPTION_FORMAT) { if (max_files_per_dir) contents = apr_psprintf(pool, "%d\n" "layout sharded %d\n", format, max_files_per_dir); else contents = apr_psprintf(pool, "%d\n" "layout linear", format); } else { contents = apr_psprintf(pool, "%d\n", format); } { const char *path_tmp; SVN_ERR(svn_io_write_unique(&path_tmp, svn_path_dirname(path, pool), contents, strlen(contents), 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)); } /* And set the perms to make it read only */ return svn_io_set_file_read_only(path, FALSE, pool); }
static svn_error_t * svn_ra_local__do_check_path(svn_ra_session_t *session, const char *path, svn_revnum_t revision, svn_node_kind_t *kind, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; svn_fs_root_t *root; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); if (! SVN_IS_VALID_REVNUM(revision)) SVN_ERR(svn_fs_youngest_rev(&revision, sess->fs, pool)); SVN_ERR(svn_fs_revision_root(&root, sess->fs, revision, pool)); return svn_fs_check_path(kind, root, abs_path, pool); }
static svn_error_t * svn_ra_local__get_file_revs(svn_ra_session_t *session, const char *path, svn_revnum_t start, svn_revnum_t end, svn_boolean_t include_merged_revisions, svn_file_rev_handler_t handler, void *handler_baton, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); return svn_repos_get_file_revs2(sess->repos, abs_path, start, end, include_merged_revisions, NULL, NULL, handler, handler_baton, pool); }
static svn_error_t * svn_ra_local__get_location_segments(svn_ra_session_t *session, const char *path, svn_revnum_t peg_revision, svn_revnum_t start_rev, svn_revnum_t end_rev, svn_location_segment_receiver_t receiver, void *receiver_baton, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); return svn_repos_node_location_segments(sess->repos, abs_path, peg_revision, start_rev, end_rev, receiver, receiver_baton, NULL, NULL, pool); }
/* A callback function used when the RA layer needs a handle to a temporary file. This is a reduced version of the callback used in the official svn cmdline client. */ static svn_error_t * open_tmp_file (apr_file_t **fp, void *callback_baton, apr_pool_t *pool) { const char *path; const char *ignored_filename; SVN_ERR (svn_io_temp_dir (&path, pool)); path = svn_path_join (path, "tempfile", pool); /* Open a unique file, with delete-on-close set. */ SVN_ERR (svn_io_open_unique_file2 (fp, &ignored_filename, path, ".tmp", svn_io_file_del_on_close, pool)); return SVN_NO_ERROR; }
dav_svn_get_repos_path(request_rec *r, const char *root_path, const char **repos_path) { const char *fs_path; const char *fs_parent_path; const char *repos_name; const char *ignored_path_in_repos; const char *ignored_cleaned_uri; const char *ignored_relative; int ignored_had_slash; dav_error *derr; /* Handle the SVNPath case. */ fs_path = dav_svn__get_fs_path(r); if (fs_path != NULL) { *repos_path = fs_path; return NULL; } /* Handle the SVNParentPath case. If neither directive was used, dav_svn_split_uri will throw a suitable error for us - we do not need to check that here. */ fs_parent_path = dav_svn__get_fs_parent_path(r); /* Split the svn URI to get the name of the repository below the parent path. */ derr = dav_svn_split_uri(r, r->uri, root_path, &ignored_cleaned_uri, &ignored_had_slash, &repos_name, &ignored_relative, &ignored_path_in_repos); if (derr) return derr; /* Construct the full path from the parent path base directory and the repository name. */ *repos_path = svn_path_join(fs_parent_path, repos_name, r->pool); return NULL; }
static svn_error_t * svn_ra_local__get_deleted_rev(svn_ra_session_t *session, const char *path, svn_revnum_t peg_revision, svn_revnum_t end_revision, svn_revnum_t *revision_deleted, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); SVN_ERR(svn_repos_deleted_rev(sess->fs, abs_path, peg_revision, end_revision, revision_deleted, pool)); return SVN_NO_ERROR; }
static svn_error_t * test_open_file(const char *path, void *parent_baton, svn_revnum_t base_revision, apr_pool_t *file_pool, void **file_baton) { struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; struct file_baton *fb = apr_pcalloc(file_pool, sizeof(*fb)); svn_fs_root_t *rev_root = NULL; /* Fill in the file baton. */ fb->path = svn_path_join(eb->root_path, path, eb->pool); fb->edit_baton = eb; SVN_ERR(svn_fs_revision_root(&rev_root, eb->fs, base_revision, file_pool)); SVN_ERR(svn_fs_revision_link(rev_root, eb->txn_root, fb->path, file_pool)); *file_baton = fb; return SVN_NO_ERROR; }
static svn_error_t * test_open_directory(const char *path, void *parent_baton, svn_revnum_t base_revision, apr_pool_t *dir_pool, void **child_baton) { struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; struct dir_baton *db = apr_pcalloc(dir_pool, sizeof(*db)); svn_fs_root_t *rev_root = NULL; /* Construct the full path of the new directory */ db->full_path = svn_path_join(eb->root_path, path, eb->pool); db->edit_baton = eb; SVN_ERR(svn_fs_revision_root(&rev_root, eb->fs, base_revision, dir_pool)); SVN_ERR(svn_fs_revision_link(rev_root, eb->txn_root, db->full_path, dir_pool)); *child_baton = db; return SVN_NO_ERROR; }
static void find_real_base_location(const char **path_p, svn_revnum_t *rev_p, svn_repos_node_t *node, apr_pool_t *pool) { /* If NODE is an add-with-history, then its real base location is the copy source. */ if ((node->action == 'A') && node->copyfrom_path && SVN_IS_VALID_REVNUM(node->copyfrom_rev)) { *path_p = node->copyfrom_path; *rev_p = node->copyfrom_rev; return; } /* Otherwise, if NODE has a parent, we'll recurse, and add NODE's name to whatever the parent's real base path turns out to be (and pass the base revision on through). */ if (node->parent) { const char *path; svn_revnum_t rev; find_real_base_location(&path, &rev, node->parent, pool); *path_p = svn_path_join(path, node->name, pool); *rev_p = rev; return; } /* Finally, if the node has no parent, then its name is "/", and it has no interesting base revision. */ *path_p = "/"; *rev_p = SVN_INVALID_REVNUM; return; }
static svn_error_t * test_add_file(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_revision, apr_pool_t *file_pool, void **file_baton) { struct dir_baton *db = parent_baton; struct edit_baton *eb = db->edit_baton; struct file_baton *fb = apr_pcalloc(file_pool, sizeof(*fb)); /* Fill in the file baton. */ fb->path = svn_path_join(eb->root_path, path, eb->pool); fb->edit_baton = eb; if (copyfrom_path) /* add with history */ { svn_fs_root_t *rev_root = NULL; SVN_ERR(svn_fs_revision_root(&rev_root, eb->fs, copyfrom_revision, file_pool)); SVN_ERR(svn_fs_copy(rev_root, copyfrom_path, eb->txn_root, fb->path, file_pool)); } else /* add without history */ SVN_ERR(svn_fs_make_file(eb->txn_root, fb->path, file_pool)); *file_baton = fb; return SVN_NO_ERROR; }
static svn_error_t * test_add_directory(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_revision, apr_pool_t *dir_pool, void **child_baton) { struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; struct dir_baton *db = apr_pcalloc(dir_pool, sizeof(*db)); /* Construct the full path of the new directory */ db->full_path = svn_path_join(eb->root_path, path, eb->pool); db->edit_baton = eb; if (copyfrom_path) /* add with history */ { svn_fs_root_t *rev_root = NULL; SVN_ERR(svn_fs_revision_root(&rev_root, eb->fs, copyfrom_revision, dir_pool)); SVN_ERR(svn_fs_copy(rev_root, copyfrom_path, eb->txn_root, db->full_path, dir_pool)); } else /* add without history */ SVN_ERR(svn_fs_make_dir(eb->txn_root, db->full_path, dir_pool)); *child_baton = db; return SVN_NO_ERROR; }
/* Respond to a S:deleted-rev-report request. */ dav_error * dav_svn__get_deleted_rev_report(const dav_resource *resource, const apr_xml_doc *doc, ap_filter_t *output) { apr_xml_elem *child; int ns; const char *rel_path = NULL, *abs_path; svn_revnum_t peg_rev = SVN_INVALID_REVNUM, end_rev = SVN_INVALID_REVNUM, deleted_rev; apr_bucket_brigade *bb; svn_error_t *err; apr_status_t apr_err; dav_error *derr = NULL; /* Sanity check. */ ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0, "The request does not contain the 'svn:' " "namespace, so it is not going to have " "certain required elements.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); for (child = doc->root->first_child; child != NULL; child = child->next) { /* If this element isn't one of ours, then skip it. */ if (child->ns != ns ) continue; if (strcmp(child->name, "peg-revision") == 0) { peg_rev = SVN_STR_TO_REV(dav_xml_get_cdata(child, resource->pool, 1)); } else if (strcmp(child->name, "end-revision") == 0) { end_rev = SVN_STR_TO_REV(dav_xml_get_cdata(child, resource->pool, 1)); } else if (strcmp(child->name, "path") == 0) { rel_path = dav_xml_get_cdata(child, resource->pool, 0); if ((derr = dav_svn__test_canonical(rel_path, resource->pool))) return derr; } } /* Check that all parameters are present. */ if (! (rel_path && SVN_IS_VALID_REVNUM(peg_rev) && SVN_IS_VALID_REVNUM(end_rev))) { return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0, "Not all parameters passed.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } /* Append the relative path to the base FS path to get an absolute repository path. */ abs_path = svn_path_join(resource->info->repos_path, rel_path, resource->pool); /* Do what we actually came here for: Find the rev abs_path was deleted. */ err = svn_repos_deleted_rev(resource->info->repos->fs, abs_path, peg_rev, end_rev, &deleted_rev, resource->pool); if (err) { svn_error_clear(err); return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not find revision path was deleted."); } bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); apr_err = ap_fprintf(output, bb, DAV_XML_HEADER DEBUG_CR "<S:get-deleted-rev-report xmlns:S=\"" SVN_XML_NAMESPACE "\" xmlns:D=\"DAV:\">" DEBUG_CR "<D:" SVN_DAV__VERSION_NAME ">%ld</D:" SVN_DAV__VERSION_NAME ">""</S:get-deleted-rev-report>", deleted_rev); if (apr_err) derr = dav_svn__convert_err(svn_error_create(apr_err, 0, NULL), HTTP_INTERNAL_SERVER_ERROR, "Error writing REPORT response.", resource->pool); return dav_svn__final_flush_or_error(resource->info->r, bb, output, derr, resource->pool); }
svn_error_t * svn_client_blame4(const char *target, const svn_opt_revision_t *peg_revision, const svn_opt_revision_t *start, const svn_opt_revision_t *end, const svn_diff_file_options_t *diff_options, svn_boolean_t ignore_mime_type, svn_boolean_t include_merged_revisions, svn_client_blame_receiver2_t receiver, void *receiver_baton, svn_client_ctx_t *ctx, apr_pool_t *pool) { struct file_rev_baton frb; svn_ra_session_t *ra_session; const char *url; svn_revnum_t start_revnum, end_revnum; struct blame *walk, *walk_merged = NULL; apr_file_t *file; apr_pool_t *iterpool; svn_stream_t *stream; if (start->kind == svn_opt_revision_unspecified || end->kind == svn_opt_revision_unspecified) return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL); else if (start->kind == svn_opt_revision_working || end->kind == svn_opt_revision_working) return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("blame of the WORKING revision is not supported")); /* Get an RA plugin for this filesystem object. */ SVN_ERR(svn_client__ra_session_from_path(&ra_session, &end_revnum, &url, target, NULL, peg_revision, end, ctx, pool)); SVN_ERR(svn_client__get_revision_number(&start_revnum, NULL, ra_session, start, target, pool)); if (end_revnum < start_revnum) return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL, _("Start revision must precede end revision")); frb.start_rev = start_revnum; frb.end_rev = end_revnum; frb.target = target; frb.ctx = ctx; frb.diff_options = diff_options; frb.ignore_mime_type = ignore_mime_type; frb.include_merged_revisions = include_merged_revisions; frb.last_filename = NULL; frb.last_original_filename = NULL; frb.chain = apr_palloc(pool, sizeof(*frb.chain)); frb.chain->blame = NULL; frb.chain->avail = NULL; frb.chain->pool = pool; if (include_merged_revisions) { frb.merged_chain = apr_palloc(pool, sizeof(*frb.merged_chain)); frb.merged_chain->blame = NULL; frb.merged_chain->avail = NULL; frb.merged_chain->pool = pool; } SVN_ERR(svn_io_temp_dir(&frb.tmp_path, pool)); frb.tmp_path = svn_path_join(frb.tmp_path, "tmp", pool), frb.mainpool = pool; /* The callback will flip the following two pools, because it needs information from the previous call. Obviously, it can't rely on the lifetime of the pool provided by get_file_revs. */ frb.lastpool = svn_pool_create(pool); frb.currpool = svn_pool_create(pool); if (include_merged_revisions) { frb.filepool = svn_pool_create(pool); frb.prevfilepool = svn_pool_create(pool); } /* Collect all blame information. We need to ensure that we get one revision before the start_rev, if available so that we can know what was actually changed in the start revision. */ SVN_ERR(svn_ra_get_file_revs2(ra_session, "", start_revnum - (start_revnum > 0 ? 1 : 0), end_revnum, include_merged_revisions, file_rev_handler, &frb, pool)); /* Report the blame to the caller. */ /* The callback has to have been called at least once. */ assert(frb.last_filename != NULL); /* Create a pool for the iteration below. */ iterpool = svn_pool_create(pool); /* Open the last file and get a stream. */ SVN_ERR(svn_io_file_open(&file, frb.last_filename, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool)); stream = svn_subst_stream_translated(svn_stream_from_aprfile(file, pool), "\n", TRUE, NULL, FALSE, pool); /* Perform optional merged chain normalization. */ if (include_merged_revisions) { /* If we never created any blame for the original chain, create it now, with the most recent changed revision. This could occur if a file was created on a branch and them merged to another branch. This is semanticly a copy, and we want to use the revision on the branch as the most recently changed revision. ### Is this really what we want to do here? Do the sematics of copy change? */ if (!frb.chain->blame) frb.chain->blame = blame_create(frb.chain, frb.rev, 0); normalize_blames(frb.chain, frb.merged_chain, pool); walk_merged = frb.merged_chain->blame; } /* Process each blame item. */ for (walk = frb.chain->blame; walk; walk = walk->next) { apr_off_t line_no; svn_revnum_t merged_rev; const char *merged_author, *merged_date, *merged_path; if (walk_merged) { merged_rev = walk_merged->rev->revision; merged_author = walk_merged->rev->author; merged_date = walk_merged->rev->date; merged_path = walk_merged->rev->path; } else { merged_rev = SVN_INVALID_REVNUM; merged_author = NULL; merged_date = NULL; merged_path = NULL; } for (line_no = walk->start; !walk->next || line_no < walk->next->start; ++line_no) { svn_boolean_t eof; svn_stringbuf_t *sb; svn_pool_clear(iterpool); SVN_ERR(svn_stream_readline(stream, &sb, "\n", &eof, iterpool)); if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); if (!eof || sb->len) SVN_ERR(receiver(receiver_baton, line_no, walk->rev->revision, walk->rev->author, walk->rev->date, merged_rev, merged_author, merged_date, merged_path, sb->data, iterpool)); if (eof) break; } if (walk_merged) walk_merged = walk_merged->next; } SVN_ERR(svn_stream_close(stream)); /* We don't need the temp file any more. */ SVN_ERR(svn_io_file_close(file, pool)); svn_pool_destroy(frb.lastpool); svn_pool_destroy(frb.currpool); if (include_merged_revisions) { svn_pool_destroy(frb.filepool); svn_pool_destroy(frb.prevfilepool); } svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
svn_error_t * svn_nls_init(void) { svn_error_t *err = SVN_NO_ERROR; #ifdef ENABLE_NLS #ifdef WIN32 { WCHAR ucs2_path[MAX_PATH]; char* utf8_path; const char* internal_path; apr_pool_t* pool; apr_status_t apr_err; apr_size_t inwords, outbytes, outlength; apr_pool_create(&pool, 0); /* get exe name - our locale info will be in '../share/locale' */ inwords = GetModuleFileNameW(0, ucs2_path, sizeof(ucs2_path) / sizeof(ucs2_path[0])); if (! inwords) { /* We must be on a Win9x machine, so attempt to get an ANSI path, and convert it to Unicode. */ CHAR ansi_path[MAX_PATH]; if (GetModuleFileNameA(0, ansi_path, sizeof(ansi_path))) { inwords = MultiByteToWideChar(CP_ACP, 0, ansi_path, -1, ucs2_path, sizeof(ucs2_path) / sizeof(ucs2_path[0])); if (! inwords) { err = svn_error_createf(APR_EINVAL, NULL, _("Can't convert string to UCS-2: '%s'"), ansi_path); } } else { err = svn_error_create(APR_EINVAL, NULL, _("Can't get module file name")); } } if (! err) { outbytes = outlength = 3 * (inwords + 1); utf8_path = apr_palloc(pool, outlength); apr_err = apr_conv_ucs2_to_utf8(ucs2_path, &inwords, utf8_path, &outbytes); if (!apr_err && (inwords > 0 || outbytes == 0)) apr_err = APR_INCOMPLETE; if (apr_err) { err = svn_error_createf(apr_err, NULL, _("Can't convert module path " "to UTF-8 from UCS-2: '%s'"), ucs2_path); } else { utf8_path[outlength - outbytes] = '\0'; internal_path = svn_path_internal_style(utf8_path, pool); /* get base path name */ internal_path = svn_path_dirname(internal_path, pool); internal_path = svn_path_join(internal_path, SVN_LOCALE_RELATIVE_PATH, pool); bindtextdomain(PACKAGE_NAME, internal_path); } } svn_pool_destroy(pool); } #else bindtextdomain(PACKAGE_NAME, SVN_LOCALE_DIR); #ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset(PACKAGE_NAME, "UTF-8"); #endif #endif #endif return err; }