Index: subversion/tests/libsvn_fs/fs-test.c =================================================================== --- subversion/tests/libsvn_fs/fs-test.c (revision 21525) +++ subversion/tests/libsvn_fs/fs-test.c (working copy) @@ -4458,7 +4458,7 @@ SVN_TEST_PASS(medium_file_integrity), SVN_TEST_PASS(large_file_integrity), SVN_TEST_PASS(check_root_revision), - SVN_TEST_XFAIL(test_node_created_rev), /* Fails on FSFS, Issue #2608 */ + SVN_TEST_PASS(test_node_created_rev), SVN_TEST_PASS(check_related), SVN_TEST_PASS(branch_test), SVN_TEST_PASS(verify_checksum), Index: subversion/tests/cmdline/prop_tests.py =================================================================== --- subversion/tests/cmdline/prop_tests.py (revision 21525) +++ subversion/tests/cmdline/prop_tests.py (working copy) @@ -1215,7 +1215,7 @@ downdate_props, remove_props, update_conflict_props, - XFail(commit_conflict_dirprops, svntest.main.is_fs_type_fsfs), + commit_conflict_dirprops, commit_replacement_props, revert_replacement_props, inappropriate_props, Index: subversion/libsvn_fs_fs/tree.c =================================================================== --- subversion/libsvn_fs_fs/tree.c (revision 21525) +++ subversion/libsvn_fs_fs/tree.c (working copy) @@ -1196,7 +1196,7 @@ noderev->predecessor_count = source_pred_count; if (noderev->predecessor_count != -1) noderev->predecessor_count++; - SVN_ERR(svn_fs_fs__put_node_revision(fs, target_id, noderev, pool)); + SVN_ERR(svn_fs_fs__put_node_revision(fs, target_id, noderev, FALSE, pool)); return SVN_NO_ERROR; } Index: subversion/libsvn_fs_fs/fs_fs.c =================================================================== --- subversion/libsvn_fs_fs/fs_fs.c (revision 21525) +++ subversion/libsvn_fs_fs/fs_fs.c (working copy) @@ -86,6 +86,7 @@ #define HEADER_PRED "pred" #define HEADER_COPYFROM "copyfrom" #define HEADER_COPYROOT "copyroot" +#define HEADER_FRESHTXNRT "is-fresh-txn-root" /* Kinds that a change can be. */ #define ACTION_MODIFY "modify" @@ -793,6 +794,10 @@ noderev->copyfrom_path = apr_pstrdup(pool, last_str); } + /* Get whether this is a fresh txn root. */ + value = apr_hash_get(headers, HEADER_FRESHTXNRT, APR_HASH_KEY_STRING); + noderev->is_fresh_txn_root = (value != NULL); + *noderev_p = noderev; return SVN_NO_ERROR; @@ -872,6 +877,9 @@ noderev->copyroot_rev, noderev->copyroot_path)); + if (noderev->is_fresh_txn_root) + SVN_ERR(svn_stream_printf(outfile, pool, HEADER_FRESHTXNRT ": y\n")); + SVN_ERR(svn_stream_printf(outfile, pool, "\n")); return SVN_NO_ERROR; @@ -881,11 +889,14 @@ svn_fs_fs__put_node_revision(svn_fs_t *fs, const svn_fs_id_t *id, node_revision_t *noderev, + svn_boolean_t fresh_txn_root, apr_pool_t *pool) { apr_file_t *noderev_file; const char *txn_id = svn_fs_fs__id_txn_id(id); + noderev->is_fresh_txn_root = fresh_txn_root; + if (! txn_id) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Attempted to write to non-transaction")); @@ -2430,7 +2441,8 @@ } /* Copy a revision node-rev SRC into the current transaction TXN_ID in - the filesystem FS. Allocations are from POOL. */ + the filesystem FS. This is only used to create the root of a transaction. + Allocations are from POOL. */ static svn_error_t * create_new_txn_noderev_from_rev(svn_fs_t *fs, const char *txn_id, @@ -2457,7 +2469,7 @@ copy_id = svn_fs_fs__id_copy_id(noderev->id); noderev->id = svn_fs_fs__id_txn_create(node_id, copy_id, txn_id, pool); - SVN_ERR(svn_fs_fs__put_node_revision(fs, noderev->id, noderev, pool)); + SVN_ERR(svn_fs_fs__put_node_revision(fs, noderev->id, noderev, TRUE, pool)); return SVN_NO_ERROR; } @@ -2737,7 +2749,7 @@ noderev->id = id; - SVN_ERR(svn_fs_fs__put_node_revision(fs, noderev->id, noderev, pool)); + SVN_ERR(svn_fs_fs__put_node_revision(fs, noderev->id, noderev, FALSE, pool)); *id_p = id; @@ -2854,7 +2866,7 @@ rep->txn_id = txn_id; parent_noderev->data_rep = rep; SVN_ERR(svn_fs_fs__put_node_revision(fs, parent_noderev->id, - parent_noderev, pool)); + parent_noderev, FALSE, pool)); } else { @@ -3226,7 +3238,7 @@ b->noderev->data_rep = rep; /* Write out the new node-rev information. */ - SVN_ERR(svn_fs_fs__put_node_revision(b->fs, b->noderev->id, b->noderev, + SVN_ERR(svn_fs_fs__put_node_revision(b->fs, b->noderev->id, b->noderev, FALSE, b->pool)); SVN_ERR(svn_io_file_close(b->file, b->pool)); @@ -3299,7 +3311,7 @@ new_noderev->copyroot_rev = svn_fs_fs__id_rev(new_noderev->id); } - SVN_ERR(svn_fs_fs__put_node_revision(fs, new_noderev->id, new_noderev, + SVN_ERR(svn_fs_fs__put_node_revision(fs, new_noderev->id, new_noderev, FALSE, pool)); *new_id_p = id; @@ -3330,7 +3342,7 @@ { noderev->prop_rep = apr_pcalloc(pool, sizeof(*noderev->prop_rep)); noderev->prop_rep->txn_id = svn_fs_fs__id_txn_id(noderev->id); - SVN_ERR(svn_fs_fs__put_node_revision(fs, noderev->id, noderev, pool)); + SVN_ERR(svn_fs_fs__put_node_revision(fs, noderev->id, noderev, FALSE, pool)); } return SVN_NO_ERROR; @@ -3569,7 +3581,7 @@ /* Write out our new node-revision. */ SVN_ERR(write_noderev_txn(file, noderev, pool)); - SVN_ERR(svn_fs_fs__put_node_revision(fs, id, noderev, pool)); + SVN_ERR(svn_fs_fs__put_node_revision(fs, id, noderev, FALSE, pool)); /* Return our ID that references the revision file. */ *new_id_p = noderev->id; Index: subversion/libsvn_fs_fs/fs_fs.h =================================================================== --- subversion/libsvn_fs_fs/fs_fs.h (revision 21525) +++ subversion/libsvn_fs_fs/fs_fs.h (working copy) @@ -40,10 +40,12 @@ apr_pool_t *pool); /* Store NODEREV as the node-revision for the node whose id is ID in - FS. Do any necessary temporary allocation in POOL. */ + FS, after setting its is_fresh_txn_root to FRESH_TXN_ROOT. Do any + necessary temporary allocation in POOL. */ svn_error_t *svn_fs_fs__put_node_revision(svn_fs_t *fs, const svn_fs_id_t *id, node_revision_t *noderev, + svn_boolean_t fresh_txn_root, apr_pool_t *pool); /* Set *YOUNGEST to the youngest revision in filesystem FS. Do any Index: subversion/libsvn_fs_fs/fs.h =================================================================== --- subversion/libsvn_fs_fs/fs.h (revision 21525) +++ subversion/libsvn_fs_fs/fs.h (working copy) @@ -168,6 +168,9 @@ /* path at which this node first came into existence. */ const char *created_path; + /* is this the unmodified root of a transaction? */ + svn_boolean_t is_fresh_txn_root; + } node_revision_t; Index: subversion/libsvn_fs_fs/dag.c =================================================================== --- subversion/libsvn_fs_fs/dag.c (revision 21525) +++ subversion/libsvn_fs_fs/dag.c (working copy) @@ -54,6 +54,12 @@ /* The node revision ID for this dag node, allocated in POOL. */ svn_fs_id_t *id; + /* In the special case that this node is the root of a transaction + that has not yet been modified, the node revision ID for this dag + node's predecessor; otherwise NULL. (Used in + svn_fs_node_created_rev.) */ + const svn_fs_id_t *fresh_root_predecessor_id; + /* The node's type (file, dir, etc.) */ svn_node_kind_t kind; @@ -186,6 +192,11 @@ new_node->kind = noderev->kind; new_node->created_path = apr_pstrdup(pool, noderev->created_path); + if (noderev->is_fresh_txn_root) + new_node->fresh_root_predecessor_id = noderev->predecessor_id; + else + new_node->fresh_root_predecessor_id = NULL; + /* Return a fresh new node */ *node = new_node; return SVN_NO_ERROR; @@ -197,8 +208,14 @@ dag_node_t *node, apr_pool_t *pool) { + /* In the special case that this is an unmodified transaction root, + we need to actually get the revision of the noderev's predecessor + (the revision root); see Issue #2608. */ + const svn_fs_id_t *correct_id = node->fresh_root_predecessor_id + ? node->fresh_root_predecessor_id : node->id; + /* Look up the committed revision from the Node-ID. */ - *rev = svn_fs_fs__id_rev(node->id); + *rev = svn_fs_fs__id_rev(correct_id); return SVN_NO_ERROR; }