Commit 29e1789b by Vicent Marti

Fix the git_tree_write implementation

parent 47d8ec56
...@@ -134,21 +134,27 @@ GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry); ...@@ -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
......
...@@ -137,7 +137,7 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf ...@@ -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) ...@@ -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 (subdir_written == GIT_ENOMEM) if (entry->mode != S_IFDIR) {
return GIT_ENOMEM; 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;
}
nr += subdir_written; nr = subdir_written - 1;
/* 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; offset += write_entry(buffer + offset, write_mode, filename, entrylen, write_oid);
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 = git_odb_write(oid, index->repository->db, buffer, offset, GIT_OBJ_TREE);
error = stream->finalize_write(oid, stream); free(buffer);
stream->free(stream);
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;
return nr; error = write_index(oid, index, "", 0, 0, git_index_entrycount(index));
return (error < GIT_SUCCESS) ? error : GIT_SUCCESS;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment