📄 adm_crawler.c
字号:
/* * adm_crawler.c: report local WC mods to an Editor. * * ==================================================================== * 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 <string.h>#include <apr_pools.h>#include <apr_file_io.h>#include <apr_hash.h>#include <apr_md5.h>#include <assert.h>#include "svn_types.h"#include "svn_pools.h"#include "svn_wc.h"#include "svn_io.h"#include "svn_md5.h"#include "svn_base64.h"#include "svn_delta.h"#include "svn_path.h"#include "wc.h"#include "adm_files.h"#include "props.h"#include "translate.h"#include "entries.h"#include "lock.h"#include "svn_private_config.h"/* Helper for report_revisions(). Perform an atomic restoration of the file FILE_PATH; that is, copy the file's text-base to the administrative tmp area, and then move that file to FILE_PATH with possible translations/expansions. If USE_COMMIT_TIMES is set, then set working file's timestamp to last-commit-time. Either way, set entry-timestamp to match that of the working file when all is finished. */static svn_error_t *restore_file(const char *file_path, svn_wc_adm_access_t *adm_access, svn_boolean_t use_commit_times, apr_pool_t *pool){ const char *tmp_file, *text_base_path; svn_wc_entry_t newentry; const char *bname; svn_boolean_t special; text_base_path = svn_wc__text_base_path(file_path, FALSE, pool); bname = svn_path_basename(file_path, pool); /* Copy / translate into a temporary file, which afterwards can be atomically moved over the original working copy file. */ SVN_ERR(svn_wc_translated_file2(&tmp_file, text_base_path, file_path, adm_access, SVN_WC_TRANSLATE_FROM_NF | SVN_WC_TRANSLATE_FORCE_COPY, pool)); SVN_ERR(svn_io_file_rename(tmp_file, file_path, pool)); SVN_ERR(svn_wc__maybe_set_read_only(NULL, file_path, adm_access, pool)); /* If necessary, tweak the new working file's executable bit. */ SVN_ERR(svn_wc__maybe_set_executable(NULL, file_path, adm_access, pool)); /* Remove any text conflict */ SVN_ERR(svn_wc_resolved_conflict2(file_path, adm_access, TRUE, FALSE, FALSE, NULL, NULL, NULL, NULL, pool)); if (use_commit_times) { SVN_ERR(svn_wc__get_special(&special, file_path, adm_access, pool)); } /* Possibly set timestamp to last-commit-time. */ if (use_commit_times && (! special)) { const svn_wc_entry_t *entry; SVN_ERR(svn_wc_entry(&entry, file_path, adm_access, FALSE, pool)); assert(entry != NULL); SVN_ERR(svn_io_set_file_affected_time(entry->cmt_date, file_path, pool)); newentry.text_time = entry->cmt_date; } else { SVN_ERR(svn_io_file_affected_time(&newentry.text_time, file_path, pool)); } /* Modify our entry's text-timestamp to match the working file. */ SVN_ERR(svn_wc__entry_modify(adm_access, bname, &newentry, SVN_WC__ENTRY_MODIFY_TEXT_TIME, TRUE /* do_sync now */, pool)); return SVN_NO_ERROR;}/* The recursive crawler that describes a mixed-revision working copy to an RA layer. Used to initiate updates. This is a depth-first recursive walk of DIR_PATH under ADM_ACCESS. Look at each entry and check if its revision is different than DIR_REV. If so, report this fact to REPORTER. If an entry is missing from disk, report its absence to REPORTER. If an entry has a different URL than expected, report that to REPORTER. Finally, if REPORT_EVERYTHING is set, then report all children unconditionally. If TRAVERSAL_INFO is non-null, record this directory's value of svn:externals in both TRAVERSAL_INFO->externals_old and TRAVERSAL_INFO->externals_new, using wc_path + dir_path as the key, and the raw (unparsed) value of the property as the value. NOTE: We set the value in both places, because its absence in just one or the other place signals that the property was added or deleted; thus, storing it in both places signals that it is present and, by default, unchanged. If RESTORE_FILES is set, then unexpectedly missing working files will be restored from text-base and NOTIFY_FUNC/NOTIFY_BATON will be called to report the restoration. USE_COMMIT_TIMES is passed to restore_file() helper. */static svn_error_t *report_revisions(svn_wc_adm_access_t *adm_access, const char *dir_path, svn_revnum_t dir_rev, const svn_ra_reporter2_t *reporter, void *report_baton, svn_wc_notify_func2_t notify_func, void *notify_baton, svn_boolean_t restore_files, svn_boolean_t recurse, svn_boolean_t report_everything, svn_boolean_t use_commit_times, svn_wc_traversal_info_t *traversal_info, apr_pool_t *pool){ apr_hash_t *entries, *dirents; apr_hash_index_t *hi; apr_pool_t *subpool = svn_pool_create(pool), *iterpool; const svn_wc_entry_t *dot_entry; const char *this_url, *this_path, *full_path, *this_full_path; svn_wc_adm_access_t *dir_access; svn_wc_notify_t *notify; /* Get both the SVN Entries and the actual on-disk entries. Also notice that we're picking up hidden entries too. */ full_path = svn_path_join(svn_wc_adm_access_path(adm_access), dir_path, subpool); SVN_ERR(svn_wc_adm_retrieve(&dir_access, adm_access, full_path, subpool)); SVN_ERR(svn_wc_entries_read(&entries, dir_access, TRUE, subpool)); SVN_ERR(svn_io_get_dir_filenames(&dirents, full_path, subpool)); /*** Do the real reporting and recursing. ***/ /* First, look at "this dir" to see what its URL is. */ dot_entry = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING); /* If "this dir" has "svn:externals" property set on it, store its name in traversal_info. */ if (traversal_info) { const svn_string_t *val; SVN_ERR(svn_wc_prop_get(&val, SVN_PROP_EXTERNALS, full_path, adm_access, subpool)); if (val) { apr_pool_t *dup_pool = traversal_info->pool; const char *dup_path = apr_pstrdup(dup_pool, full_path); const char *dup_val = apr_pstrmemdup(dup_pool, val->data, val->len); apr_hash_set(traversal_info->externals_old, dup_path, APR_HASH_KEY_STRING, dup_val); apr_hash_set(traversal_info->externals_new, dup_path, APR_HASH_KEY_STRING, dup_val); } } /* Looping over current directory's SVN entries: */ iterpool = svn_pool_create(subpool); for (hi = apr_hash_first(subpool, entries); hi; hi = apr_hash_next(hi)) { const void *key; apr_ssize_t klen; void *val; const svn_wc_entry_t *current_entry; svn_io_dirent_t *dirent; svn_node_kind_t dirent_kind; svn_boolean_t missing = FALSE; /* Clear the iteration subpool here because the loop has a bunch of 'continue' jump statements. */ svn_pool_clear(iterpool); /* Get the next entry */ apr_hash_this(hi, &key, &klen, &val); current_entry = val; /* Compute the name of the entry. Skip THIS_DIR altogether. */ if (! strcmp(key, SVN_WC_ENTRY_THIS_DIR)) continue; /* Compute the paths and URLs we need. */ this_url = svn_path_join(dot_entry->url, svn_path_uri_encode(key, iterpool), iterpool); this_path = svn_path_join(dir_path, key, iterpool); this_full_path = svn_path_join(full_path, key, iterpool); /*** The Big Tests: ***/ /* If the entry is 'deleted' or 'absent', make sure the server knows it's gone... */ if (current_entry->deleted || current_entry->absent) { /* ...unless we're reporting everything, in which case it's already missing on the server. */ if (! report_everything) SVN_ERR(reporter->delete_path(report_baton, this_path, iterpool)); continue; } /* Is the entry on disk? Set a flag if not. */ dirent = apr_hash_get(dirents, key, klen); if (! dirent) { /* It is possible on a case insensitive system that the entry is not really missing, so we call our trusty but expensive friend svn_io_check_path to be sure. */ SVN_ERR(svn_io_check_path(this_full_path, &dirent_kind, iterpool)); if (dirent_kind == svn_node_none) missing = TRUE; } /* From here on out, ignore any entry scheduled for addition */ if (current_entry->schedule == svn_wc_schedule_add) continue; /*** Files ***/ if (current_entry->kind == svn_node_file) { /* If the item is missing from disk, and we're supposed to restore missing things, and it isn't missing as a result of a scheduling operation, then ... */ if (missing && restore_files && (current_entry->schedule != svn_wc_schedule_delete) && (current_entry->schedule != svn_wc_schedule_replace)) { /* ... recreate file from text-base, and ... */ SVN_ERR(restore_file(this_full_path, dir_access, use_commit_times, iterpool)); /* ... report the restoration to the caller. */ if (notify_func != NULL) { notify = svn_wc_create_notify(this_full_path, svn_wc_notify_restore, iterpool); notify->kind = svn_node_file; (*notify_func)(notify_baton, notify, iterpool); } } if (report_everything) { /* Report the file unconditionally, one way or another. */ if (strcmp(current_entry->url, this_url) != 0) SVN_ERR(reporter->link_path(report_baton, this_path, current_entry->url, current_entry->revision, FALSE, current_entry->lock_token, iterpool)); else SVN_ERR(reporter->set_path(report_baton, this_path, current_entry->revision, FALSE, current_entry->lock_token, iterpool)); } /* Possibly report a disjoint URL ... */ else if ((current_entry->schedule != svn_wc_schedule_add) && (current_entry->schedule != svn_wc_schedule_replace) && (strcmp(current_entry->url, this_url) != 0)) SVN_ERR(reporter->link_path(report_baton, this_path, current_entry->url, current_entry->revision, FALSE, current_entry->lock_token, iterpool)); /* ... or perhaps just a differing revision or lock token. */ else if (current_entry->revision != dir_rev || current_entry->lock_token) SVN_ERR(reporter->set_path(report_baton, this_path, current_entry->revision, FALSE, current_entry->lock_token,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -