|
Packit |
ae9e2a |
#include "sortedcache.h"
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
int git_sortedcache_new(
|
|
Packit |
ae9e2a |
git_sortedcache **out,
|
|
Packit |
ae9e2a |
size_t item_path_offset,
|
|
Packit |
ae9e2a |
git_sortedcache_free_item_fn free_item,
|
|
Packit |
ae9e2a |
void *free_item_payload,
|
|
Packit |
ae9e2a |
git_vector_cmp item_cmp,
|
|
Packit |
ae9e2a |
const char *path)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
git_sortedcache *sc;
|
|
Packit |
ae9e2a |
size_t pathlen, alloclen;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
pathlen = path ? strlen(path) : 0;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_sortedcache), pathlen);
|
|
Packit |
ae9e2a |
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
|
|
Packit |
ae9e2a |
sc = git__calloc(1, alloclen);
|
|
Packit |
ae9e2a |
GITERR_CHECK_ALLOC(sc);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
git_pool_init(&sc->pool, 1);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (git_vector_init(&sc->items, 4, item_cmp) < 0 ||
|
|
Packit |
ae9e2a |
git_strmap_alloc(&sc->map) < 0)
|
|
Packit |
ae9e2a |
goto fail;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (git_rwlock_init(&sc->lock)) {
|
|
Packit |
ae9e2a |
giterr_set(GITERR_OS, "failed to initialize lock");
|
|
Packit |
ae9e2a |
goto fail;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
sc->item_path_offset = item_path_offset;
|
|
Packit |
ae9e2a |
sc->free_item = free_item;
|
|
Packit |
ae9e2a |
sc->free_item_payload = free_item_payload;
|
|
Packit |
ae9e2a |
GIT_REFCOUNT_INC(sc);
|
|
Packit |
ae9e2a |
if (pathlen)
|
|
Packit |
ae9e2a |
memcpy(sc->path, path, pathlen);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
*out = sc;
|
|
Packit |
ae9e2a |
return 0;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
fail:
|
|
Packit |
ae9e2a |
git_strmap_free(sc->map);
|
|
Packit |
ae9e2a |
git_vector_free(&sc->items);
|
|
Packit |
ae9e2a |
git_pool_clear(&sc->pool);
|
|
Packit |
ae9e2a |
git__free(sc);
|
|
Packit |
ae9e2a |
return -1;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
void git_sortedcache_incref(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
GIT_REFCOUNT_INC(sc);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
const char *git_sortedcache_path(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
return sc->path;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
static void sortedcache_clear(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
git_strmap_clear(sc->map);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (sc->free_item) {
|
|
Packit |
ae9e2a |
size_t i;
|
|
Packit |
ae9e2a |
void *item;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
git_vector_foreach(&sc->items, i, item) {
|
|
Packit |
ae9e2a |
sc->free_item(sc->free_item_payload, item);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
git_vector_clear(&sc->items);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
git_pool_clear(&sc->pool);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
static void sortedcache_free(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
/* acquire write lock to make sure everyone else is done */
|
|
Packit |
ae9e2a |
if (git_sortedcache_wlock(sc) < 0)
|
|
Packit |
ae9e2a |
return;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
sortedcache_clear(sc);
|
|
Packit |
ae9e2a |
git_vector_free(&sc->items);
|
|
Packit |
ae9e2a |
git_strmap_free(sc->map);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
git_sortedcache_wunlock(sc);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
git_rwlock_free(&sc->lock);
|
|
Packit |
ae9e2a |
git__free(sc);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
void git_sortedcache_free(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
if (!sc)
|
|
Packit |
ae9e2a |
return;
|
|
Packit |
ae9e2a |
GIT_REFCOUNT_DEC(sc, sortedcache_free);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
static int sortedcache_copy_item(void *payload, void *tgt_item, void *src_item)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
git_sortedcache *sc = payload;
|
|
Packit |
ae9e2a |
/* path will already have been copied by upsert */
|
|
Packit |
ae9e2a |
memcpy(tgt_item, src_item, sc->item_path_offset);
|
|
Packit |
ae9e2a |
return 0;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* copy a sorted cache */
|
|
Packit |
ae9e2a |
int git_sortedcache_copy(
|
|
Packit |
ae9e2a |
git_sortedcache **out,
|
|
Packit |
ae9e2a |
git_sortedcache *src,
|
|
Packit |
ae9e2a |
bool lock,
|
|
Packit |
ae9e2a |
int (*copy_item)(void *payload, void *tgt_item, void *src_item),
|
|
Packit |
ae9e2a |
void *payload)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
int error = 0;
|
|
Packit |
ae9e2a |
git_sortedcache *tgt;
|
|
Packit |
ae9e2a |
size_t i;
|
|
Packit |
ae9e2a |
void *src_item, *tgt_item;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* just use memcpy if no special copy fn is passed in */
|
|
Packit |
ae9e2a |
if (!copy_item) {
|
|
Packit |
ae9e2a |
copy_item = sortedcache_copy_item;
|
|
Packit |
ae9e2a |
payload = src;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if ((error = git_sortedcache_new(
|
|
Packit |
ae9e2a |
&tgt, src->item_path_offset,
|
|
Packit |
ae9e2a |
src->free_item, src->free_item_payload,
|
|
Packit |
ae9e2a |
src->items._cmp, src->path)) < 0)
|
|
Packit |
ae9e2a |
return error;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (lock && git_sortedcache_rlock(src) < 0) {
|
|
Packit |
ae9e2a |
git_sortedcache_free(tgt);
|
|
Packit |
ae9e2a |
return -1;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
git_vector_foreach(&src->items, i, src_item) {
|
|
Packit |
ae9e2a |
char *path = ((char *)src_item) + src->item_path_offset;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if ((error = git_sortedcache_upsert(&tgt_item, tgt, path)) < 0 ||
|
|
Packit |
ae9e2a |
(error = copy_item(payload, tgt_item, src_item)) < 0)
|
|
Packit |
ae9e2a |
break;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (lock)
|
|
Packit |
ae9e2a |
git_sortedcache_runlock(src);
|
|
Packit |
ae9e2a |
if (error)
|
|
Packit |
ae9e2a |
git_sortedcache_free(tgt);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
*out = !error ? tgt : NULL;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
return error;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* lock sortedcache while making modifications */
|
|
Packit |
ae9e2a |
int git_sortedcache_wlock(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
GIT_UNUSED(sc); /* prevent warning when compiled w/o threads */
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (git_rwlock_wrlock(&sc->lock) < 0) {
|
|
Packit |
ae9e2a |
giterr_set(GITERR_OS, "unable to acquire write lock on cache");
|
|
Packit |
ae9e2a |
return -1;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
return 0;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* unlock sorted cache when done with modifications */
|
|
Packit |
ae9e2a |
void git_sortedcache_wunlock(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
git_vector_sort(&sc->items);
|
|
Packit |
ae9e2a |
git_rwlock_wrunlock(&sc->lock);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* lock sortedcache for read */
|
|
Packit |
ae9e2a |
int git_sortedcache_rlock(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
GIT_UNUSED(sc); /* prevent warning when compiled w/o threads */
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (git_rwlock_rdlock(&sc->lock) < 0) {
|
|
Packit |
ae9e2a |
giterr_set(GITERR_OS, "unable to acquire read lock on cache");
|
|
Packit |
ae9e2a |
return -1;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
return 0;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* unlock sorted cache when done reading */
|
|
Packit |
ae9e2a |
void git_sortedcache_runlock(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
GIT_UNUSED(sc); /* prevent warning when compiled w/o threads */
|
|
Packit |
ae9e2a |
git_rwlock_rdunlock(&sc->lock);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* if the file has changed, lock cache and load file contents into buf;
|
|
Packit |
ae9e2a |
* returns <0 on error, >0 if file has not changed
|
|
Packit |
ae9e2a |
*/
|
|
Packit |
ae9e2a |
int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
int error, fd;
|
|
Packit |
ae9e2a |
struct stat st;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if ((error = git_sortedcache_wlock(sc)) < 0)
|
|
Packit |
ae9e2a |
return error;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if ((error = git_futils_filestamp_check(&sc->stamp, sc->path)) <= 0)
|
|
Packit |
ae9e2a |
goto unlock;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if ((fd = git_futils_open_ro(sc->path)) < 0) {
|
|
Packit |
ae9e2a |
error = fd;
|
|
Packit |
ae9e2a |
goto unlock;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (p_fstat(fd, &st) < 0) {
|
|
Packit |
ae9e2a |
giterr_set(GITERR_OS, "failed to stat file");
|
|
Packit |
ae9e2a |
error = -1;
|
|
Packit |
ae9e2a |
(void)p_close(fd);
|
|
Packit |
ae9e2a |
goto unlock;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (!git__is_sizet(st.st_size)) {
|
|
Packit |
ae9e2a |
giterr_set(GITERR_INVALID, "unable to load file larger than size_t");
|
|
Packit |
ae9e2a |
error = -1;
|
|
Packit |
ae9e2a |
(void)p_close(fd);
|
|
Packit |
ae9e2a |
goto unlock;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (buf)
|
|
Packit |
ae9e2a |
error = git_futils_readbuffer_fd(buf, fd, (size_t)st.st_size);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
(void)p_close(fd);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (error < 0)
|
|
Packit |
ae9e2a |
goto unlock;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
return 1; /* return 1 -> file needs reload and was successfully loaded */
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
unlock:
|
|
Packit |
ae9e2a |
git_sortedcache_wunlock(sc);
|
|
Packit |
ae9e2a |
return error;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
void git_sortedcache_updated(git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
/* update filestamp to latest value */
|
|
Packit |
ae9e2a |
git_futils_filestamp_check(&sc->stamp, sc->path);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* release all items in sorted cache */
|
|
Packit |
ae9e2a |
int git_sortedcache_clear(git_sortedcache *sc, bool wlock)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
if (wlock && git_sortedcache_wlock(sc) < 0)
|
|
Packit |
ae9e2a |
return -1;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
sortedcache_clear(sc);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (wlock)
|
|
Packit |
ae9e2a |
git_sortedcache_wunlock(sc);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
return 0;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* find and/or insert item, returning pointer to item data */
|
|
Packit |
ae9e2a |
int git_sortedcache_upsert(void **out, git_sortedcache *sc, const char *key)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
int error = 0;
|
|
Packit |
ae9e2a |
khiter_t pos;
|
|
Packit |
ae9e2a |
void *item;
|
|
Packit |
ae9e2a |
size_t keylen, itemlen;
|
|
Packit |
ae9e2a |
char *item_key;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
pos = git_strmap_lookup_index(sc->map, key);
|
|
Packit |
ae9e2a |
if (git_strmap_valid_index(sc->map, pos)) {
|
|
Packit |
ae9e2a |
item = git_strmap_value_at(sc->map, pos);
|
|
Packit |
ae9e2a |
goto done;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
keylen = strlen(key);
|
|
Packit |
ae9e2a |
itemlen = sc->item_path_offset + keylen + 1;
|
|
Packit |
ae9e2a |
itemlen = (itemlen + 7) & ~7;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if ((item = git_pool_mallocz(&sc->pool, (uint32_t)itemlen)) == NULL) {
|
|
Packit |
ae9e2a |
/* don't use GITERR_CHECK_ALLOC b/c of lock */
|
|
Packit |
ae9e2a |
error = -1;
|
|
Packit |
ae9e2a |
goto done;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* one strange thing is that even if the vector or hash table insert
|
|
Packit |
ae9e2a |
* fail, there is no way to free the pool item so we just abandon it
|
|
Packit |
ae9e2a |
*/
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
item_key = ((char *)item) + sc->item_path_offset;
|
|
Packit |
ae9e2a |
memcpy(item_key, key, keylen);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
pos = git_strmap_put(sc->map, item_key, &error);
|
|
Packit |
ae9e2a |
if (error < 0)
|
|
Packit |
ae9e2a |
goto done;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (!error)
|
|
Packit |
ae9e2a |
git_strmap_set_key_at(sc->map, pos, item_key);
|
|
Packit |
ae9e2a |
git_strmap_set_value_at(sc->map, pos, item);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
error = git_vector_insert(&sc->items, item);
|
|
Packit |
ae9e2a |
if (error < 0)
|
|
Packit |
ae9e2a |
git_strmap_delete_at(sc->map, pos);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
done:
|
|
Packit |
ae9e2a |
if (out)
|
|
Packit |
ae9e2a |
*out = !error ? item : NULL;
|
|
Packit |
ae9e2a |
return error;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* lookup item by key */
|
|
Packit |
ae9e2a |
void *git_sortedcache_lookup(const git_sortedcache *sc, const char *key)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
khiter_t pos = git_strmap_lookup_index(sc->map, key);
|
|
Packit |
ae9e2a |
if (git_strmap_valid_index(sc->map, pos))
|
|
Packit |
ae9e2a |
return git_strmap_value_at(sc->map, pos);
|
|
Packit |
ae9e2a |
return NULL;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* find out how many items are in the cache */
|
|
Packit |
ae9e2a |
size_t git_sortedcache_entrycount(const git_sortedcache *sc)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
return git_vector_length(&sc->items);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* lookup item by index */
|
|
Packit |
ae9e2a |
void *git_sortedcache_entry(git_sortedcache *sc, size_t pos)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
/* make sure the items are sorted so this gets the correct item */
|
|
Packit |
ae9e2a |
if (!git_vector_is_sorted(&sc->items))
|
|
Packit |
ae9e2a |
git_vector_sort(&sc->items);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
return git_vector_get(&sc->items, pos);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* helper struct so bsearch callback can know offset + key value for cmp */
|
|
Packit |
ae9e2a |
struct sortedcache_magic_key {
|
|
Packit |
ae9e2a |
size_t offset;
|
|
Packit |
ae9e2a |
const char *key;
|
|
Packit |
ae9e2a |
};
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
static int sortedcache_magic_cmp(const void *key, const void *value)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
const struct sortedcache_magic_key *magic = key;
|
|
Packit |
ae9e2a |
const char *value_key = ((const char *)value) + magic->offset;
|
|
Packit |
ae9e2a |
return strcmp(magic->key, value_key);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* lookup index of item by key */
|
|
Packit |
ae9e2a |
int git_sortedcache_lookup_index(
|
|
Packit |
ae9e2a |
size_t *out, git_sortedcache *sc, const char *key)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
struct sortedcache_magic_key magic;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
magic.offset = sc->item_path_offset;
|
|
Packit |
ae9e2a |
magic.key = key;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
return git_vector_bsearch2(out, &sc->items, sortedcache_magic_cmp, &magic);
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* remove entry from cache */
|
|
Packit |
ae9e2a |
int git_sortedcache_remove(git_sortedcache *sc, size_t pos)
|
|
Packit |
ae9e2a |
{
|
|
Packit |
ae9e2a |
char *item;
|
|
Packit |
ae9e2a |
khiter_t mappos;
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
/* because of pool allocation, this can't actually remove the item,
|
|
Packit |
ae9e2a |
* but we can remove it from the items vector and the hash table.
|
|
Packit |
ae9e2a |
*/
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if ((item = git_vector_get(&sc->items, pos)) == NULL) {
|
|
Packit |
ae9e2a |
giterr_set(GITERR_INVALID, "removing item out of range");
|
|
Packit |
ae9e2a |
return GIT_ENOTFOUND;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
(void)git_vector_remove(&sc->items, pos);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
mappos = git_strmap_lookup_index(sc->map, item + sc->item_path_offset);
|
|
Packit |
ae9e2a |
git_strmap_delete_at(sc->map, mappos);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
if (sc->free_item)
|
|
Packit |
ae9e2a |
sc->free_item(sc->free_item_payload, item);
|
|
Packit |
ae9e2a |
|
|
Packit |
ae9e2a |
return 0;
|
|
Packit |
ae9e2a |
}
|
|
Packit |
ae9e2a |
|