📄 lock.c
字号:
err = do_close(lock, cleanup, TRUE); /* ### Is this the correct way to handle the error? */ if (err) { apr_status_t apr_err = err->apr_err; svn_error_clear(err); return apr_err; } else return APR_SUCCESS;}/* An APR pool cleanup handler. This is a child handler, it removes the main pool handler. */static apr_status_tpool_cleanup_child(void *p){ svn_wc_adm_access_t *lock = p; apr_pool_cleanup_kill(lock->pool, lock, pool_cleanup); return APR_SUCCESS;}/* Allocate from POOL, intialise and return an access baton. TYPE and PATH are used to initialise the baton. */static svn_wc_adm_access_t *adm_access_alloc(enum svn_wc__adm_access_type type, const char *path, apr_pool_t *pool){ svn_wc_adm_access_t *lock = apr_palloc(pool, sizeof(*lock)); lock->type = type; lock->entries = NULL; lock->entries_hidden = NULL; lock->wcprops = NULL; lock->wc_format = 0; lock->set = NULL; lock->lock_exists = FALSE; lock->set_owner = FALSE; lock->path = apr_pstrdup(pool, path); lock->pool = pool; return lock;}static voidadm_ensure_set(svn_wc_adm_access_t *adm_access){ if (! adm_access->set) { adm_access->set_owner = TRUE; adm_access->set = apr_hash_make(adm_access->pool); apr_hash_set(adm_access->set, adm_access->path, APR_HASH_KEY_STRING, adm_access); }}static svn_error_t *probe(const char **dir, const char *path, int *wc_format, apr_pool_t *pool){ svn_node_kind_t kind; SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind == svn_node_dir) SVN_ERR(svn_wc_check_wc(path, wc_format, pool)); else *wc_format = 0; /* a "version" of 0 means a non-wc directory */ if (kind != svn_node_dir || *wc_format == 0) { /* Passing a path ending in "." or ".." to svn_path_dirname() is probably always a bad idea; certainly it is in this case. Unfortunately, svn_path_dirname()'s current signature can't return an error, so we have to insert the protection in this caller, as making the larger API change would be very destabilizing right now (just before 1.0). See issue #1617. */ const char *base_name = svn_path_basename(path, pool); if ((strcmp(base_name, "..") == 0) || (strcmp(base_name, ".") == 0)) { return svn_error_createf (SVN_ERR_WC_BAD_PATH, NULL, _("Path '%s' ends in '%s', " "which is unsupported for this operation"), svn_path_local_style(path, pool), base_name); } *dir = svn_path_dirname(path, pool); } else *dir = path; return SVN_NO_ERROR;}svn_error_t *svn_wc__adm_steal_write_lock(svn_wc_adm_access_t **adm_access, svn_wc_adm_access_t *associated, const char *path, apr_pool_t *pool){ svn_error_t *err; svn_wc_adm_access_t *lock = adm_access_alloc(svn_wc__adm_access_write_lock, path, pool); err = create_lock(lock, 0, pool); if (err) { if (err->apr_err == SVN_ERR_WC_LOCKED) svn_error_clear(err); /* Steal existing lock */ else return err; } if (associated) { adm_ensure_set(associated); lock->set = associated->set; apr_hash_set(lock->set, lock->path, APR_HASH_KEY_STRING, lock); } /* We have a write lock. If the working copy has an old format, this is the time to upgrade it. */ SVN_ERR(svn_wc_check_wc(path, &lock->wc_format, pool)); SVN_ERR(maybe_upgrade_format(lock, pool)); lock->lock_exists = TRUE; *adm_access = lock; return SVN_NO_ERROR;}/* This is essentially the guts of svn_wc_adm_open3, with the additional * parameter UNDER_CONSTRUCTION that gets set TRUE only when locking the * admin directory during initial creation. */static svn_error_t *do_open(svn_wc_adm_access_t **adm_access, svn_wc_adm_access_t *associated, const char *path, svn_boolean_t write_lock, int depth, svn_boolean_t under_construction, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool){ svn_wc_adm_access_t *lock; int wc_format; svn_error_t *err; apr_pool_t *subpool = svn_pool_create(pool); if (associated) { adm_ensure_set(associated); lock = apr_hash_get(associated->set, path, APR_HASH_KEY_STRING); if (lock && lock != &missing) /* Already locked. The reason we don't return the existing baton here is that the user is supposed to know whether a directory is locked: if it's not locked call svn_wc_adm_open, if it is locked call svn_wc_adm_retrieve. */ return svn_error_createf(SVN_ERR_WC_LOCKED, NULL, _("Working copy '%s' locked"), svn_path_local_style(path, pool)); } if (! under_construction) { /* By reading the format file we check both that PATH is a directory and that it is a working copy. */ /* ### We will read the entries file later. Maybe read the whole file here instead to avoid reopening it. */ err = svn_io_read_version_file(&wc_format, svn_wc__adm_path(path, FALSE, subpool, SVN_WC__ADM_ENTRIES, NULL), subpool); /* If the entries file doesn't start with a version number, we're dealing with a pre-format 7 working copy, so we need to get the format from the format file instead. */ if (err && err->apr_err == SVN_ERR_BAD_VERSION_FILE_FORMAT) { svn_error_clear(err); err = svn_io_read_version_file(&wc_format, svn_wc__adm_path(path, FALSE, subpool, SVN_WC__ADM_FORMAT, NULL), subpool); } if (err) { return svn_error_createf(SVN_ERR_WC_NOT_DIRECTORY, err, _("'%s' is not a working copy"), svn_path_local_style(path, pool)); } SVN_ERR(svn_wc__check_format(wc_format, svn_path_local_style(path, subpool), subpool)); } /* Need to create a new lock */ if (write_lock) { lock = adm_access_alloc(svn_wc__adm_access_write_lock, path, pool); SVN_ERR(create_lock(lock, 0, subpool)); lock->lock_exists = TRUE; } else { lock = adm_access_alloc(svn_wc__adm_access_unlocked, path, pool); } if (! under_construction) { lock->wc_format = wc_format; if (write_lock) SVN_ERR(maybe_upgrade_format(lock, subpool)); } if (depth != 0) { apr_hash_t *entries; apr_hash_index_t *hi; /* Reduce depth since we are about to recurse */ if (depth > 0) depth--; SVN_ERR(svn_wc_entries_read(&entries, lock, FALSE, subpool)); /* Use a temporary hash until all children have been opened. */ if (associated) lock->set = apr_hash_make(subpool); /* Open the tree */ for (hi = apr_hash_first(subpool, entries); hi; hi = apr_hash_next(hi)) { void *val; const svn_wc_entry_t *entry; svn_wc_adm_access_t *entry_access; const char *entry_path; /* See if someone wants to cancel this operation. */ if (cancel_func) { err = cancel_func(cancel_baton); if (err) { /* This closes all the children in temporary hash as well */ svn_error_clear(svn_wc_adm_close(lock)); svn_pool_destroy(subpool); lock->set = NULL; return err; } } apr_hash_this(hi, NULL, NULL, &val); entry = val; if (entry->kind != svn_node_dir || ! strcmp(entry->name, SVN_WC_ENTRY_THIS_DIR)) continue; entry_path = svn_path_join(lock->path, entry->name, subpool); /* Don't use the subpool pool here, the lock needs to persist */ err = do_open(&entry_access, lock, entry_path, write_lock, depth, FALSE, cancel_func, cancel_baton, lock->pool); if (err) { if (err->apr_err != SVN_ERR_WC_NOT_DIRECTORY) { /* This closes all the children in temporary hash as well */ svn_error_clear(svn_wc_adm_close(lock)); svn_pool_destroy(subpool); lock->set = NULL; return err; } /* It's missing or obstructed, so store a placeholder */ svn_error_clear(err); adm_ensure_set(lock); apr_hash_set(lock->set, apr_pstrdup(lock->pool, entry_path), APR_HASH_KEY_STRING, &missing); continue; } /* ### Perhaps we should verify that the parent and child agree ### about the URL of the child? */ } /* Switch from temporary hash to permanent hash */ if (associated) { for (hi = apr_hash_first(subpool, lock->set); hi; hi = apr_hash_next(hi)) { const void *key; void *val; const char *entry_path; svn_wc_adm_access_t *entry_access; apr_hash_this(hi, &key, NULL, &val); entry_path = key; entry_access = val; apr_hash_set(associated->set, entry_path, APR_HASH_KEY_STRING, entry_access); entry_access->set = associated->set; } lock->set = associated->set; } } if (associated) { lock->set = associated->set; apr_hash_set(lock->set, lock->path, APR_HASH_KEY_STRING, lock); } /* It's important that the cleanup handler is registered *after* at least one UTF8 conversion has been done, since such a conversion may create the apr_xlate_t object in the pool, and that object must be around when the cleanup handler runs. If the apr_xlate_t cleanup handler were to run *before* the access baton cleanup handler, then the access baton's handler won't work. */ apr_pool_cleanup_register(lock->pool, lock, pool_cleanup, pool_cleanup_child); *adm_access = lock; svn_pool_destroy(subpool); return SVN_NO_ERROR;}/* To preserve API compatibility with Subversion 1.0.0 */svn_error_t *svn_wc_adm_open(svn_wc_adm_access_t **adm_access, svn_wc_adm_access_t *associated, const char *path, svn_boolean_t write_lock, svn_boolean_t tree_lock, apr_pool_t *pool){ return svn_wc_adm_open3(adm_access, associated, path, write_lock, (tree_lock ? -1 : 0), NULL, NULL, pool);}svn_error_t *svn_wc_adm_open2(svn_wc_adm_access_t **adm_access, svn_wc_adm_access_t *associated, const char *path, svn_boolean_t write_lock, int depth, apr_pool_t *pool){ return svn_wc_adm_open3(adm_access, associated, path, write_lock, depth, NULL, NULL, pool);}svn_error_t *svn_wc_adm_open3(svn_wc_adm_access_t **adm_access, svn_wc_adm_access_t *associated, const char *path, svn_boolean_t write_lock, int depth, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool){ return do_open(adm_access, associated, path, write_lock, depth, FALSE, cancel_func, cancel_baton, pool);}svn_error_t *svn_wc__adm_pre_open(svn_wc_adm_access_t **adm_access, const char *path, apr_pool_t *pool){ return do_open(adm_access, NULL, path, TRUE, 0, TRUE, NULL, NULL, pool);}/* To preserve API compatibility with Subversion 1.0.0 */svn_error_t *svn_wc_adm_probe_open(svn_wc_adm_access_t **adm_access, svn_wc_adm_access_t *associated, const char *path, svn_boolean_t write_lock,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -