📄 adm_ops.c
字号:
### Does this mean that a file committed with only prop mods ### will still get its text base checksum recomputed? Yes it ### does, sadly. But it's not enough to just check for that ### condition, because in the case of an added file, there ### may not be a pre-existing checksum in the entry. ### Probably the best solution is to compute (or copy) the ### checksum at 'svn add' (or 'svn cp') time, instead of ### waiting until commit time. */ latest_base = svn_wc__text_base_path(path, TRUE, pool); SVN_ERR(svn_io_check_path(latest_base, &kind, pool)); if (kind == svn_node_none) { latest_base = svn_wc__text_base_path(path, FALSE, pool); SVN_ERR(svn_io_check_path(latest_base, &kind, pool)); } if (kind == svn_node_file) { unsigned char local_digest[APR_MD5_DIGESTSIZE]; SVN_ERR(svn_io_file_checksum(local_digest, latest_base, pool)); hex_digest = svn_md5_digest_to_cstring(local_digest, pool); } } /* Oh, and recursing at this point isn't really sensible. */ if (recurse) *recurse = FALSE; } else { /* PATH must be a dir */ base_name = SVN_WC_ENTRY_THIS_DIR; } /* Append a log command to set (overwrite) the 'committed-rev', 'committed-date', 'last-author', and possibly 'checksum' attributes in the entry. Note: it's important that this log command come *before* the LOG_COMMITTED command, because log_do_committed() might actually remove the entry! */ if (rev_date) { tmp_entry.cmt_rev = new_revnum; SVN_ERR(svn_time_from_cstring(&tmp_entry.cmt_date, rev_date, pool)); modify_flags |= SVN_WC__ENTRY_MODIFY_CMT_REV | SVN_WC__ENTRY_MODIFY_CMT_DATE; } if (rev_author) { tmp_entry.cmt_rev = new_revnum; tmp_entry.cmt_author = rev_author; modify_flags |= SVN_WC__ENTRY_MODIFY_CMT_REV | SVN_WC__ENTRY_MODIFY_CMT_AUTHOR; } if (hex_digest) { tmp_entry.checksum = hex_digest; modify_flags |= SVN_WC__ENTRY_MODIFY_CHECKSUM; } SVN_ERR(svn_wc__loggy_entry_modify(&logtags, adm_access, base_name, &tmp_entry, modify_flags, pool)); if (remove_lock) SVN_ERR(svn_wc__loggy_delete_lock(&logtags, adm_access, base_name, pool)); /* Regardless of whether it's a file or dir, the "main" logfile contains a command to bump the revision attribute (and timestamp). */ SVN_ERR(svn_wc__loggy_committed(&logtags, adm_access, base_name, new_revnum, pool)); /* Do wcprops in the same log txn as revision, etc. */ if (wcprop_changes && (wcprop_changes->nelts > 0)) { int i; for (i = 0; i < wcprop_changes->nelts; i++) { svn_prop_t *prop = APR_ARRAY_IDX(wcprop_changes, i, svn_prop_t *); SVN_ERR(svn_wc__loggy_modify_wcprop (&logtags, adm_access, base_name, prop->name, prop->value ? prop->value->data : NULL, pool)); } } /* Write our accumulation of log entries into a log file */ SVN_ERR(svn_wc__write_log(adm_access, log_number, logtags, pool)); return SVN_NO_ERROR;}svn_error_t *svn_wc_process_committed3(const char *path, svn_wc_adm_access_t *adm_access, svn_boolean_t recurse, svn_revnum_t new_revnum, const char *rev_date, const char *rev_author, apr_array_header_t *wcprop_changes, svn_boolean_t remove_lock, const unsigned char *digest, apr_pool_t *pool){ int log_number = 1; SVN_ERR(process_committed_leaf(0, path, adm_access, &recurse, new_revnum, rev_date, rev_author, wcprop_changes, remove_lock, digest, pool)); if (recurse) { apr_hash_t *entries; apr_hash_index_t *hi; apr_pool_t *subpool = svn_pool_create(pool); /* Read PATH's entries; this is the absolute path. */ SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE, pool)); /* Recursively loop over all children. */ for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) { const void *key; void *val; const char *name; const svn_wc_entry_t *current_entry; const char *this_path; svn_wc_adm_access_t *child_access; svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, &val); name = key; current_entry = val; /* Ignore the "this dir" entry. */ if (! strcmp(name, SVN_WC_ENTRY_THIS_DIR)) continue; /* Create child path by telescoping the main path. */ this_path = svn_path_join(path, name, subpool); if (current_entry->kind == svn_node_dir) SVN_ERR(svn_wc_adm_retrieve(&child_access, adm_access, this_path, subpool)); else child_access = adm_access; /* Recurse, but only allow further recursion if the child is a directory. Pass null for wcprop_changes, because the ones present in the current call are only applicable to this one committed item. */ if (current_entry->kind == svn_node_dir) SVN_ERR(svn_wc_process_committed2 (this_path, child_access, (current_entry->kind == svn_node_dir) ? TRUE : FALSE, new_revnum, rev_date, rev_author, NULL, FALSE, subpool)); else { /* No log file is executed at this time. In case this folder gets replaced, the entries file might still contain files scheduled for deletion. No need to process those here, they will be when the parent is processed. */ if (current_entry->schedule == svn_wc_schedule_delete) { svn_wc_entry_t *parent_entry; parent_entry = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING); if (parent_entry->schedule == svn_wc_schedule_replace) continue; } SVN_ERR(process_committed_leaf (log_number++, this_path, adm_access, NULL, new_revnum, rev_date, rev_author, FALSE, FALSE, NULL, subpool)); } } svn_pool_destroy(subpool); } /* Run the log file(s) we just created. */ SVN_ERR(svn_wc__run_log(adm_access, NULL, pool)); return SVN_NO_ERROR;}svn_error_t *svn_wc_process_committed2(const char *path, svn_wc_adm_access_t *adm_access, svn_boolean_t recurse, svn_revnum_t new_revnum, const char *rev_date, const char *rev_author, apr_array_header_t *wcprop_changes, svn_boolean_t remove_lock, apr_pool_t *pool){ return svn_wc_process_committed3(path, adm_access, recurse, new_revnum, rev_date, rev_author, wcprop_changes, remove_lock, NULL, pool);}svn_error_t *svn_wc_process_committed(const char *path, svn_wc_adm_access_t *adm_access, svn_boolean_t recurse, svn_revnum_t new_revnum, const char *rev_date, const char *rev_author, apr_array_header_t *wcprop_changes, apr_pool_t *pool){ return svn_wc_process_committed2(path, adm_access, recurse, new_revnum, rev_date, rev_author, wcprop_changes, FALSE, pool);}/* Remove FILE if it exists and is a file. If it does not exist, do nothing. If it is not a file, error. */static svn_error_t *remove_file_if_present(const char *file, apr_pool_t *pool){ svn_error_t *err; /* Try to remove the file. */ err = svn_io_remove_file(file, pool); /* Ignore file not found error. */ if (err && APR_STATUS_IS_ENOENT(err->apr_err)) { svn_error_clear(err); err = SVN_NO_ERROR; } return err;}/* Recursively mark a tree ADM_ACCESS with a SCHEDULE and/or COPIED flag, depending on the state of MODIFY_FLAGS. */static svn_error_t *mark_tree(svn_wc_adm_access_t *adm_access, apr_uint32_t modify_flags, svn_wc_schedule_t schedule, svn_boolean_t copied, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func2_t notify_func, void *notify_baton, apr_pool_t *pool){ apr_pool_t *subpool = svn_pool_create(pool); apr_hash_t *entries; apr_hash_index_t *hi; const svn_wc_entry_t *entry; /* Read the entries file for this directory. */ SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool)); /* Mark each entry in the entries file. */ for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) { const char *fullpath; const void *key; void *val; const char *base_name; svn_wc_entry_t *dup_entry; /* Clear our per-iteration pool. */ svn_pool_clear(subpool); /* Get the next entry */ apr_hash_this(hi, &key, NULL, &val); entry = val; /* Skip "this dir". */ if (! strcmp((const char *)key, SVN_WC_ENTRY_THIS_DIR)) continue; base_name = key; fullpath = svn_path_join(svn_wc_adm_access_path(adm_access), base_name, subpool); /* If this is a directory, recurse. */ if (entry->kind == svn_node_dir) { svn_wc_adm_access_t *child_access; SVN_ERR(svn_wc_adm_retrieve(&child_access, adm_access, fullpath, subpool)); SVN_ERR(mark_tree(child_access, modify_flags, schedule, copied, cancel_func, cancel_baton, notify_func, notify_baton, subpool)); } /* Need to duplicate the entry because we are changing the scheduling */ dup_entry = svn_wc_entry_dup(entry, subpool); dup_entry->schedule = schedule; dup_entry->copied = copied; SVN_ERR(svn_wc__entry_modify(adm_access, base_name, dup_entry, modify_flags, TRUE, subpool)); /* Tell someone what we've done. */ if (schedule == svn_wc_schedule_delete && notify_func != NULL) (*notify_func)(notify_baton, svn_wc_create_notify(fullpath, svn_wc_notify_delete, subpool), pool); } /* Handle "this dir" for states that need it done post-recursion. */ entry = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING); /* Uncommitted directories (schedule add) that are to be scheduled for deletion are a special case, they don't need to be changed as they will be removed from their parent's entry list. */ if (! (entry->schedule == svn_wc_schedule_add && schedule == svn_wc_schedule_delete)) { /* Need to duplicate the entry because we are changing the scheduling */ svn_wc_entry_t *dup_entry = svn_wc_entry_dup(entry, subpool); if (modify_flags & SVN_WC__ENTRY_MODIFY_SCHEDULE) dup_entry->schedule = schedule; if (modify_flags & SVN_WC__ENTRY_MODIFY_COPIED) dup_entry->copied = copied; SVN_ERR(svn_wc__entry_modify(adm_access, NULL, dup_entry, modify_flags, TRUE, subpool)); } /* Destroy our per-iteration pool. */ svn_pool_destroy(subpool); return SVN_NO_ERROR;}/* Remove/erase PATH from the working copy. This involves deleting PATH * from the physical filesystem. PATH is assumed to be an unversioned file * or directory. * * If CANCEL_FUNC is non-null, invoke it with CANCEL_BATON at various * points, return any error immediately. */static svn_error_t *erase_unversioned_from_wc(const char *path, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -