📄 status.c
字号:
/* Create a new dir_baton for subdir PATH. */static svn_error_t *make_dir_baton(void **dir_baton, const char *path, struct edit_baton *edit_baton, struct dir_baton *parent_baton, apr_pool_t *pool){ struct dir_baton *pb = parent_baton; struct edit_baton *eb = edit_baton; struct dir_baton *d = apr_pcalloc(pool, sizeof(*d)); const char *full_path; svn_wc_status2_t *parent_status; /* Don't do this. Just do NOT do this to me. */ if (pb && (! path)) abort(); /* Construct the full path of this directory. */ if (pb) full_path = svn_path_join(eb->anchor, path, pool); else full_path = apr_pstrdup(pool, eb->anchor); /* Finish populating the baton members. */ d->path = full_path; d->name = path ? (svn_path_basename(path, pool)) : NULL; d->edit_baton = edit_baton; d->parent_baton = parent_baton; d->pool = pool; d->statii = apr_hash_make(pool); d->url = apr_pstrdup(pool, find_dir_url(d, pool)); d->ood_last_cmt_rev = SVN_INVALID_REVNUM; d->ood_last_cmt_date = 0; d->ood_kind = svn_node_dir; d->ood_last_cmt_author = NULL; /* Get the status for this path's children. Of course, we only want to do this if the path is versioned as a directory. */ if (pb) parent_status = apr_hash_get(pb->statii, d->path, APR_HASH_KEY_STRING); else parent_status = eb->anchor_status; /* Order is important here. We can't depend on parent_status->entry being non-NULL until after we've checked all the conditions that might indicate that the parent is unversioned ("unversioned" for our purposes includes being an external or ignored item). */ if (parent_status && (parent_status->text_status != svn_wc_status_unversioned) && (parent_status->text_status != svn_wc_status_deleted) && (parent_status->text_status != svn_wc_status_missing) && (parent_status->text_status != svn_wc_status_obstructed) && (parent_status->text_status != svn_wc_status_external) && (parent_status->text_status != svn_wc_status_ignored) && (parent_status->entry->kind == svn_node_dir) && (eb->descend || (! pb))) { svn_wc_adm_access_t *dir_access; apr_array_header_t *ignores = eb->ignores; SVN_ERR(svn_wc_adm_retrieve(&dir_access, eb->adm_access, d->path, pool)); SVN_ERR(get_dir_status(eb, parent_status->entry, dir_access, NULL, ignores, FALSE, TRUE, TRUE, TRUE, hash_stash, d->statii, NULL, NULL, pool)); } *dir_baton = d; return SVN_NO_ERROR;}/* Make a file baton, using a new subpool of PARENT_DIR_BATON's pool. NAME is just one component, not a path. */static struct file_baton *make_file_baton(struct dir_baton *parent_dir_baton, const char *path, apr_pool_t *pool){ struct dir_baton *pb = parent_dir_baton; struct edit_baton *eb = pb->edit_baton; struct file_baton *f = apr_pcalloc(pool, sizeof(*f)); const char *full_path; /* Construct the full path of this file. */ full_path = svn_path_join(eb->anchor, path, pool); /* Finish populating the baton members. */ f->path = full_path; f->name = svn_path_basename(path, pool); f->pool = pool; f->dir_baton = pb; f->edit_baton = eb; f->url = svn_path_url_add_component(find_dir_url(pb, pool), svn_path_basename(full_path, pool), pool); f->ood_last_cmt_rev = SVN_INVALID_REVNUM; f->ood_last_cmt_date = 0; f->ood_kind = svn_node_file; f->ood_last_cmt_author = NULL; return f;}/* Return a boolean answer to the question "Is STATUS something that should be reported?". EB is the edit baton. */static svn_boolean_t is_sendable_status(svn_wc_status2_t *status, struct edit_baton *eb){ /* If the repository status was touched at all, it's interesting. */ if (status->repos_text_status != svn_wc_status_none) return TRUE; if (status->repos_prop_status != svn_wc_status_none) return TRUE; /* If there is a lock in the repository, send it. */ if (status->repos_lock) return TRUE; /* If the item is ignored, and we don't want ignores, skip it. */ if ((status->text_status == svn_wc_status_ignored) && (! eb->no_ignore)) return FALSE; /* If we want everything, we obviously want this single-item subset of everything. */ if (eb->get_all) return TRUE; /* If the item is unversioned, display it. */ if (status->text_status == svn_wc_status_unversioned) return TRUE; /* If the text or property states are interesting, send it. */ if ((status->text_status != svn_wc_status_none) && (status->text_status != svn_wc_status_normal)) return TRUE; if ((status->prop_status != svn_wc_status_none) && (status->prop_status != svn_wc_status_normal)) return TRUE; /* If it's locked or switched, send it. */ if (status->locked) return TRUE; if (status->switched) return TRUE; /* If there is a lock token, send it. */ if (status->entry && status->entry->lock_token) return TRUE; /* Otherwise, don't send it. */ return FALSE;}/* Baton for mark_status. */struct status_baton{ svn_wc_status_func2_t real_status_func; /* real status function */ void *real_status_baton; /* real status baton */};/* A status callback function which wraps the *real* status function/baton. It simply sets the "repos_text_status" field of the STATUS to svn_wc_status_deleted and passes it off to the real status func/baton. */static voidmark_deleted(void *baton, const char *path, svn_wc_status2_t *status){ struct status_baton *sb = baton; status->repos_text_status = svn_wc_status_deleted; sb->real_status_func(sb->real_status_baton, path, status);}/* Handle a directory's STATII hash. EB is the edit baton. DIR_PATH and DIR_ENTRY are the on-disk path and entry, respectively, for the directory itself. If DESCEND is set, this function will recurse into subdirectories. Also, if DIR_WAS_DELETED is set, each status that is reported through this function will have its repos_text_status field showing a deletion. Use POOL for all allocations. */static svn_error_t *handle_statii(struct edit_baton *eb, svn_wc_entry_t *dir_entry, const char *dir_path, apr_hash_t *statii, svn_boolean_t dir_was_deleted, svn_boolean_t descend, apr_pool_t *pool){ apr_array_header_t *ignores = eb->ignores; apr_hash_index_t *hi; apr_pool_t *subpool = svn_pool_create(pool); svn_wc_status_func2_t status_func = eb->status_func; void *status_baton = eb->status_baton; struct status_baton sb; if (dir_was_deleted) { sb.real_status_func = eb->status_func; sb.real_status_baton = eb->status_baton; status_func = mark_deleted; status_baton = &sb; } /* Loop over all the statuses still in our hash, handling each one. */ for (hi = apr_hash_first(pool, statii); hi; hi = apr_hash_next(hi)) { const void *key; void *val; svn_wc_status2_t *status; apr_hash_this(hi, &key, NULL, &val); status = val; /* Clear the subpool. */ svn_pool_clear(subpool); /* Now, handle the status. */ if (svn_wc__adm_missing(eb->adm_access, key)) status->text_status = svn_wc_status_missing; else if (descend && status->entry && status->entry->kind == svn_node_dir) { svn_wc_adm_access_t *dir_access; SVN_ERR(svn_wc_adm_retrieve(&dir_access, eb->adm_access, key, subpool)); SVN_ERR(get_dir_status(eb, dir_entry, dir_access, NULL, ignores, TRUE, eb->get_all, eb->no_ignore, TRUE, status_func, status_baton, eb->cancel_func, eb->cancel_baton, subpool)); } if (dir_was_deleted) status->repos_text_status = svn_wc_status_deleted; if (is_sendable_status(status, eb)) (eb->status_func)(eb->status_baton, key, status); } /* Destroy the subpool. */ svn_pool_destroy(subpool); return SVN_NO_ERROR;}/*----------------------------------------------------------------------*//*** The callbacks we'll plug into an svn_delta_editor_t structure. ***/static svn_error_t *set_target_revision(void *edit_baton, svn_revnum_t target_revision, apr_pool_t *pool){ struct edit_baton *eb = edit_baton; *(eb->target_revision) = target_revision; return SVN_NO_ERROR;}static svn_error_t *open_root(void *edit_baton, svn_revnum_t base_revision, apr_pool_t *pool, void **dir_baton){ struct edit_baton *eb = edit_baton; eb->root_opened = TRUE; return make_dir_baton(dir_baton, NULL, eb, NULL, pool);}static svn_error_t *delete_entry(const char *path, svn_revnum_t revision, void *parent_baton, apr_pool_t *pool){ struct dir_baton *db = parent_baton; struct edit_baton *eb = db->edit_baton; apr_hash_t *entries; const char *name = svn_path_basename(path, pool); const char *full_path = svn_path_join(eb->anchor, path, pool); const char *dir_path; svn_node_kind_t kind; svn_wc_adm_access_t *adm_access; const char *hash_key; svn_error_t *err; /* Note: when something is deleted, it's okay to tweak the statushash immediately. No need to wait until close_file or close_dir, because there's no risk of having to honor the 'added' flag. We already know this item exists in the working copy. */ /* Read the parent's entries file. If the deleted thing is not versioned in this working copy, it was probably deleted via this working copy. No need to report such a thing. */ /* ### use svn_wc_entry() instead? */ SVN_ERR(svn_io_check_path(full_path, &kind, pool)); if (kind == svn_node_dir) { dir_path = full_path; hash_key = SVN_WC_ENTRY_THIS_DIR; } else { dir_path = svn_path_dirname(full_path, pool); hash_key = name; } err = svn_wc_adm_retrieve(&adm_access, eb->adm_access, dir_path, pool); if (err) { if ((kind == svn_node_none) && (err->apr_err == SVN_ERR_WC_NOT_LOCKED)) { /* We're probably dealing with a non-recursive, (or partially non-recursive, working copy. Due to deep bugs in how the client reports the state of non-recursive working copies, the repository can report that a path is deleted in an area where we not only don't have the path in question, we don't even have its parent(s). A complete fix would require a serious revamp of how non-recursive working copies store and report themselves, plus some thinking about the UI behavior we want when someone runs 'svn st -u' in a [partially] non-recursive working copy. For now, we just do our best to detect the condition and not report an error if it holds. See issue #2122. */ svn_error_clear(err); return SVN_NO_ERROR; } else return err; } SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool)); if (apr_hash_get(entries, hash_key, APR_HASH_KEY_STRING)) SVN_ERR(tweak_statushash(db, TRUE, eb->adm_access, full_path, kind == svn_node_dir, svn_wc_status_deleted, 0, NULL)); /* Mark the parent dir -- it lost an entry (unless that parent dir is the root node and we're not supposed to report on the root node). */ if (db->parent_baton && (! *eb->target)) SVN_ERR(tweak_statushash(db->parent_baton, TRUE, eb->adm_access, db->path, kind == svn_node_dir, svn_wc_status_modified, 0, NULL)); return SVN_NO_ERROR;}static svn_error_t *add_directory(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_revision, apr_pool_t *pool, void **child_baton){ struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; struct dir_baton *new_db; SVN_ERR(make_dir_baton(child_baton, path, eb, pb, pool)); /* Make this dir as added. */ new_db = *child_baton; new_db->added = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -