📄 dump.c
字号:
/* dump.c --- writing filesystem contents into a portable 'dumpfile' format. * * ==================================================================== * Copyright (c) 2000-2006 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include "svn_private_config.h"#include "svn_pools.h"#include "svn_error.h"#include "svn_fs.h"#include "svn_repos.h"#include "svn_string.h"#include "svn_path.h"#include "svn_time.h"#include "svn_md5.h"#include "svn_props.h"#define ARE_VALID_COPY_ARGS(p,r) ((p && SVN_IS_VALID_REVNUM(r)) ? 1 : 0)/*----------------------------------------------------------------------*//** A variant of our hash-writing routine in libsvn_subr; this one writes to a stringbuf instead of a file, and outputs PROPS-END instead of END. If OLDHASH is not NULL, then only properties which vary from OLDHASH will be written, and properties which exist only in OLDHASH will be written out with "D" entries (like "K" entries but with no corresponding value). **/static voidwrite_hash_to_stringbuf(apr_hash_t *hash, apr_hash_t *oldhash, svn_stringbuf_t **strbuf, apr_pool_t *pool){ apr_hash_index_t *this; /* current hash entry */ *strbuf = svn_stringbuf_create("", pool); for (this = apr_hash_first(pool, hash); this; this = apr_hash_next(this)) { const void *key; void *val; apr_ssize_t keylen; svn_string_t *value; /* Get this key and val. */ apr_hash_this(this, &key, &keylen, &val); value = val; /* Don't output properties equal to the ones in oldhash, if present. */ if (oldhash) { svn_string_t *oldvalue = apr_hash_get(oldhash, key, keylen); if (oldvalue && svn_string_compare(value, oldvalue)) continue; } /* Output name length, then name. */ svn_stringbuf_appendcstr(*strbuf, apr_psprintf(pool, "K %" APR_SSIZE_T_FMT "\n", keylen)); svn_stringbuf_appendbytes(*strbuf, (const char *) key, keylen); svn_stringbuf_appendbytes(*strbuf, "\n", 1); /* Output value length, then value. */ svn_stringbuf_appendcstr(*strbuf, apr_psprintf(pool, "V %" APR_SIZE_T_FMT "\n", value->len)); svn_stringbuf_appendbytes(*strbuf, value->data, value->len); svn_stringbuf_appendbytes(*strbuf, "\n", 1); } if (oldhash) { /* Output a "D " entry for each property in oldhash but not hash. */ for (this = apr_hash_first(pool, oldhash); this; this = apr_hash_next(this)) { const void *key; void *val; apr_ssize_t keylen; /* Get this key and val. */ apr_hash_this(this, &key, &keylen, &val); /* Only output values deleted in hash. */ if (apr_hash_get(hash, key, keylen)) continue; /* Output name length, then name. */ svn_stringbuf_appendcstr(*strbuf, apr_psprintf(pool, "D %" APR_SSIZE_T_FMT "\n", keylen)); svn_stringbuf_appendbytes(*strbuf, (const char *) key, keylen); svn_stringbuf_appendbytes(*strbuf, "\n", 1); } } svn_stringbuf_appendbytes(*strbuf, "PROPS-END\n", 10);}/* Compute the delta between OLDROOT/OLDPATH and NEWROOT/NEWPATH and store it into a new temporary file *TEMPFILE. OLDROOT may be NULL, in which case the delta will be computed against an empty file, as per the svn_fs_get_file_delta_stream docstring. Record the length of the temporary file in *LEN, and rewind the file before returning. */static svn_error_t *store_delta(apr_file_t **tempfile, svn_filesize_t *len, svn_fs_root_t *oldroot, const char *oldpath, svn_fs_root_t *newroot, const char *newpath, apr_pool_t *pool){ const char *tempdir; svn_stream_t *temp_stream; apr_off_t offset = 0; svn_txdelta_stream_t *delta_stream; svn_txdelta_window_handler_t wh; void *whb; /* Create a temporary file and open a stream to it. */ SVN_ERR(svn_io_temp_dir(&tempdir, pool)); SVN_ERR(svn_io_open_unique_file2(tempfile, NULL, apr_psprintf(pool, "%s/dump", tempdir), ".tmp", svn_io_file_del_on_close, pool)); temp_stream = svn_stream_from_aprfile(*tempfile, pool); /* Compute the delta and send it to the temporary file. */ SVN_ERR(svn_fs_get_file_delta_stream(&delta_stream, oldroot, oldpath, newroot, newpath, pool)); svn_txdelta_to_svndiff2(&wh, &whb, temp_stream, 0, pool); SVN_ERR(svn_txdelta_send_txstream(delta_stream, wh, whb, pool)); /* Get the length of the temporary file and rewind it. */ SVN_ERR(svn_io_file_seek(*tempfile, APR_CUR, &offset, pool)); *len = offset; offset = 0; SVN_ERR(svn_io_file_seek(*tempfile, APR_SET, &offset, pool)); return SVN_NO_ERROR;}/*----------------------------------------------------------------------*//** An editor which dumps node-data in 'dumpfile format' to a file. **//* Look, mom! No file batons! */struct edit_baton{ /* The path which implicitly prepends all full paths coming into this editor. This will almost always be "" or "/". */ const char *path; /* The stream to dump to. */ svn_stream_t *stream; /* Send feedback here, if non-NULL */ svn_stream_t *feedback_stream; /* The fs revision root, so we can read the contents of paths. */ svn_fs_root_t *fs_root; svn_revnum_t current_rev; /* True if dumped nodes should output deltas instead of full text. */ svn_boolean_t use_deltas; /* The first revision dumped in this dumpstream. */ svn_revnum_t oldest_dumped_rev; /* reusable buffer for writing file contents */ char buffer[SVN__STREAM_CHUNK_SIZE]; apr_size_t bufsize;};struct dir_baton{ struct edit_baton *edit_baton; struct dir_baton *parent_dir_baton; /* is this directory a new addition to this revision? */ svn_boolean_t added; /* has this directory been written to the output stream? */ svn_boolean_t written_out; /* the absolute path to this directory */ const char *path; /* the comparison path and revision of this directory. if both of these are valid, use them as a source against which to compare the directory instead of the default comparison source of PATH in the previous revision. */ const char *cmp_path; svn_revnum_t cmp_rev; /* hash of paths that need to be deleted, though some -might- be replaced. maps const char * paths to this dir_baton. (they're full paths, because that's what the editor driver gives us. but really, they're all within this directory.) */ apr_hash_t *deleted_entries; /* pool to be used for deleting the hash items */ apr_pool_t *pool;};/* Make a directory baton to represent the directory was path (relative to EDIT_BATON's path) is PATH. CMP_PATH/CMP_REV are the path/revision against which this directory should be compared for changes. If either is omitted (NULL for the path, SVN_INVALID_REVNUM for the rev), just compare this directory PATH against itself in the previous revision. PARENT_DIR_BATON is the directory baton of this directory's parent, or NULL if this is the top-level directory of the edit. ADDED indicated if this directory is newly added in this revision. Perform all allocations in POOL. */static struct dir_baton *make_dir_baton(const char *path, const char *cmp_path, svn_revnum_t cmp_rev, void *edit_baton, void *parent_dir_baton, svn_boolean_t added, apr_pool_t *pool){ struct edit_baton *eb = edit_baton; struct dir_baton *pb = parent_dir_baton; struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db)); const char *full_path; /* A path relative to nothing? I don't think so. */ if (path && (! pb)) abort(); /* Construct the full path of this node. */ if (pb) full_path = svn_path_join(eb->path, path, pool); else full_path = apr_pstrdup(pool, eb->path); /* Remove leading slashes from copyfrom paths. */ if (cmp_path) cmp_path = ((*cmp_path == '/') ? cmp_path + 1 : cmp_path); new_db->edit_baton = eb; new_db->parent_dir_baton = pb; new_db->path = full_path; new_db->cmp_path = cmp_path ? apr_pstrdup(pool, cmp_path) : NULL; new_db->cmp_rev = cmp_rev; new_db->added = added; new_db->written_out = FALSE; new_db->deleted_entries = apr_hash_make(pool); new_db->pool = pool; return new_db;}/* This helper is the main "meat" of the editor -- it does all the work of writing a node record. Write out a node record for PATH of type KIND under EB->FS_ROOT. ACTION describes what is happening to the node (see enum svn_node_action). Write record to writable EB->STREAM, using EB->BUFFER to write in chunks. If the node was itself copied, IS_COPY is TRUE and the path/revision of the copy source are in CMP_PATH/CMP_REV. If IS_COPY is FALSE, yet CMP_PATH/CMP_REV are valid, this node is part of a copied subtree. */static svn_error_t *dump_node(struct edit_baton *eb, const char *path, /* an absolute path. */ svn_node_kind_t kind, enum svn_node_action action, svn_boolean_t is_copy, const char *cmp_path, svn_revnum_t cmp_rev, apr_pool_t *pool){ svn_stringbuf_t *propstring; svn_filesize_t content_length = 0; apr_size_t len; svn_boolean_t must_dump_text = FALSE, must_dump_props = FALSE; const char *compare_path = path; svn_revnum_t compare_rev = eb->current_rev - 1; svn_fs_root_t *compare_root = NULL; apr_file_t *delta_file = NULL; /* Write out metadata headers for this file node. */ SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n", (*path == '/') ? path + 1 : path)); if (kind == svn_node_file) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_KIND ": file\n")); else if (kind == svn_node_dir) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n")); /* Remove leading slashes from copyfrom paths. */ if (cmp_path) cmp_path = ((*cmp_path == '/') ? cmp_path + 1 : cmp_path); /* Validate the comparison path/rev. */ if (ARE_VALID_COPY_ARGS(cmp_path, cmp_rev)) { compare_path = cmp_path; compare_rev = cmp_rev; } if (action == svn_node_action_change) { SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n")); /* either the text or props changed, or possibly both. */ SVN_ERR(svn_fs_revision_root(&compare_root, svn_fs_root_fs(eb->fs_root), compare_rev, pool)); SVN_ERR(svn_fs_props_changed(&must_dump_props, compare_root, compare_path, eb->fs_root, path, pool)); if (kind == svn_node_file) SVN_ERR(svn_fs_contents_changed(&must_dump_text, compare_root, compare_path, eb->fs_root, path, pool)); } else if (action == svn_node_action_replace) { if (! is_copy) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -