mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-06 07:00:27 +00:00
Fix the git_tree_write implementation
This commit is contained in:
parent
47d8ec56e9
commit
29e1789b34
@ -134,21 +134,27 @@ GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry);
|
|||||||
* @param object pointer to the converted object
|
* @param object pointer to the converted object
|
||||||
* @param repo repository where to lookup the pointed object
|
* @param repo repository where to lookup the pointed object
|
||||||
* @param entry a tree entry
|
* @param entry a tree entry
|
||||||
* @return a reference to the pointed object in the repository
|
* @return 0 on success; error code otherwise
|
||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry);
|
GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create tree by scanning the index file.
|
* Write a tree to the ODB from the index file
|
||||||
*
|
*
|
||||||
* @param object identity for the tree
|
* This method will scan the index and write a representation
|
||||||
* @param repository where to lookup for object db
|
* of its current state back to disk; it recursively creates
|
||||||
* @param base directory path
|
* tree objects for each of the subtrees stored in the index,
|
||||||
* @param path length for base
|
* but only returns the OID of the root tree. This is the OID
|
||||||
* @param index entry offset to start scan
|
* that can be used e.g. to create a commit.
|
||||||
* @return number of items added to the tree
|
*
|
||||||
|
* The index instance cannot be bare, and needs to be associated
|
||||||
|
* to an existing repository.
|
||||||
|
*
|
||||||
|
* @param oid Pointer where to store the written tree
|
||||||
|
* @param index Index to write
|
||||||
|
* @return 0 on success; error code otherwise
|
||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_tree_create(git_oid *oid, git_repository *repo, const char *base, int baselen, int entry_no);
|
GIT_EXTERN(int) git_tree_create_fromindex(git_oid *oid, git_index *index);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
GIT_END_DECL
|
GIT_END_DECL
|
||||||
|
116
src/tree.c
116
src/tree.c
@ -137,7 +137,7 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf
|
|||||||
while (buffer < buffer_end) {
|
while (buffer < buffer_end) {
|
||||||
git_tree_entry *entry;
|
git_tree_entry *entry;
|
||||||
|
|
||||||
entry = git__malloc(sizeof(git_tree_entry));
|
entry = git__calloc(1, sizeof(git_tree_entry));
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
error = GIT_ENOMEM;
|
error = GIT_ENOMEM;
|
||||||
break;
|
break;
|
||||||
@ -178,90 +178,98 @@ int git_tree__parse(git_tree *tree, git_odb_object *obj)
|
|||||||
return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len);
|
return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_tree_create(git_oid *oid, git_repository *repo, const char *base, int baselen, int entry_no)
|
static int write_entry(char *buffer, int mode, const char *path, size_t path_len, const git_oid *oid)
|
||||||
{
|
{
|
||||||
unsigned long size, offset;
|
int written;
|
||||||
|
written = sprintf(buffer, "%o %.*s%c", mode, (int)path_len, path, 0);
|
||||||
|
memcpy(buffer + written, &oid->id, GIT_OID_RAWSZ);
|
||||||
|
return written + GIT_OID_RAWSZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_index(git_oid *oid, git_index *index, const char *base, int baselen, int entry_no, int maxentries)
|
||||||
|
{
|
||||||
|
size_t size, offset;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
int nr, maxentries;
|
int nr, error;
|
||||||
git_index *index;
|
|
||||||
git_odb_stream *stream;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
git_index_open_inrepo(&index,repo);
|
|
||||||
maxentries = git_index_entrycount (index);
|
|
||||||
|
|
||||||
/* FIXME: A matching error code could not be found. Hence used a close error code GIT_EBAREINDEX */
|
|
||||||
if (maxentries <= 0) {
|
|
||||||
return GIT_EBAREINDEX;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Guess at some random initial size */
|
/* Guess at some random initial size */
|
||||||
size = 8192;
|
size = maxentries * 40;
|
||||||
buffer = git__malloc(size);
|
buffer = git__malloc(size);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return GIT_ENOMEM;
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
nr = entry_no;
|
|
||||||
|
|
||||||
do {
|
for (nr = entry_no; nr < maxentries; ++nr) {
|
||||||
git_index_entry *entry = git_index_get(index, nr);
|
git_index_entry *entry = git_index_get(index, nr);
|
||||||
|
|
||||||
const char *pathname = entry->path, *filename, *dirname;
|
const char *pathname = entry->path, *filename, *dirname;
|
||||||
int pathlen = strlen(pathname), entrylen;
|
int pathlen = strlen(pathname), entrylen;
|
||||||
git_oid *entry_oid;
|
|
||||||
unsigned int mode;
|
unsigned int write_mode;
|
||||||
unsigned char *sha1;
|
git_oid subtree_oid;
|
||||||
|
git_oid *write_oid;
|
||||||
|
|
||||||
/* Did we hit the end of the directory? Return how many we wrote */
|
/* Did we hit the end of the directory? Return how many we wrote */
|
||||||
if (baselen >= pathlen || memcmp(base, pathname, baselen))
|
if (baselen >= pathlen || memcmp(base, pathname, baselen) != 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
entry_oid = &entry->oid;
|
|
||||||
mode = entry->mode;
|
|
||||||
sha1 = entry_oid->id;
|
|
||||||
|
|
||||||
/* Do we have _further_ subdirectories? */
|
/* Do we have _further_ subdirectories? */
|
||||||
filename = pathname + baselen;
|
filename = pathname + baselen;
|
||||||
dirname = strchr(filename, '/');
|
dirname = strchr(filename, '/');
|
||||||
|
|
||||||
|
write_oid = &entry->oid;
|
||||||
|
write_mode = entry->mode;
|
||||||
|
|
||||||
if (dirname) {
|
if (dirname) {
|
||||||
int subdir_written;
|
int subdir_written;
|
||||||
subdir_written = git_tree_create(oid, repo, pathname, dirname-pathname+1, nr);
|
|
||||||
|
#if 0
|
||||||
|
if (entry->mode != S_IFDIR) {
|
||||||
|
free(buffer);
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
subdir_written = write_index(&subtree_oid, index, pathname, dirname - pathname + 1, nr, maxentries);
|
||||||
|
|
||||||
|
if (subdir_written < GIT_SUCCESS) {
|
||||||
|
free(buffer);
|
||||||
|
return subdir_written;
|
||||||
|
}
|
||||||
|
|
||||||
if (subdir_written == GIT_ENOMEM)
|
nr = subdir_written - 1;
|
||||||
return GIT_ENOMEM;
|
|
||||||
|
|
||||||
nr += subdir_written;
|
|
||||||
|
|
||||||
/* Now we need to write out the directory entry into this tree.. */
|
/* Now we need to write out the directory entry into this tree.. */
|
||||||
mode = S_IFDIR;
|
|
||||||
pathlen = dirname - pathname;
|
pathlen = dirname - pathname;
|
||||||
|
write_oid = &subtree_oid;
|
||||||
/* ..but the directory entry doesn't count towards the total count */
|
write_mode = S_IFDIR;
|
||||||
nr--;
|
|
||||||
sha1 = oid->id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entrylen = pathlen - baselen;
|
entrylen = pathlen - baselen;
|
||||||
if (offset + entrylen + 100 > size) {
|
if (offset + entrylen + 32 > size) {
|
||||||
size = alloc_nr(offset + entrylen + 100);
|
size = alloc_nr(offset + entrylen + 32);
|
||||||
buffer = git__realloc(buffer, size);
|
buffer = git__realloc(buffer, size);
|
||||||
|
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return GIT_ENOMEM;
|
return GIT_ENOMEM;
|
||||||
}
|
}
|
||||||
offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename);
|
|
||||||
buffer[offset++] = 0;
|
|
||||||
memcpy(buffer + offset, sha1, GIT_OID_RAWSZ);
|
|
||||||
offset += GIT_OID_RAWSZ;
|
|
||||||
nr++;
|
|
||||||
} while (nr < maxentries);
|
|
||||||
|
|
||||||
if ((error = git_odb_open_wstream(&stream, repo->db, offset, GIT_OBJ_TREE)) < GIT_SUCCESS)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
stream->write(stream, buffer, offset);
|
|
||||||
error = stream->finalize_write(oid, stream);
|
|
||||||
stream->free(stream);
|
|
||||||
|
|
||||||
return nr;
|
offset += write_entry(buffer + offset, write_mode, filename, entrylen, write_oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = git_odb_write(oid, index->repository->db, buffer, offset, GIT_OBJ_TREE);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return (error == GIT_SUCCESS) ? nr : error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_tree_create_fromindex(git_oid *oid, git_index *index)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (index->repository == NULL)
|
||||||
|
return GIT_EBAREINDEX;
|
||||||
|
|
||||||
|
error = write_index(oid, index, "", 0, 0, git_index_entrycount(index));
|
||||||
|
return (error < GIT_SUCCESS) ? error : GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user