diff options
author | Vicent Marti <tanoku@gmail.com> | 2011-04-04 12:14:03 +0300 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2011-04-04 12:14:43 +0300 |
commit | 29e1789b34d9aa5e486ca12937899a43f2e2407b (patch) | |
tree | 21d5bc9822893d3b9ea52bb14e1f6ae6cd8af1de | |
parent | 47d8ec56e917adda2e336c29420f527fca733866 (diff) | |
download | libgit2-29e1789b34d9aa5e486ca12937899a43f2e2407b.tar.gz |
Fix the git_tree_write implementation
-rw-r--r-- | include/git2/tree.h | 26 | ||||
-rw-r--r-- | src/tree.c | 114 |
2 files changed, 77 insertions, 63 deletions
diff --git a/include/git2/tree.h b/include/git2/tree.h index bd1f97073..60150b309 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -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 repo repository where to lookup the pointed object * @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); /** - * Create tree by scanning the index file. - * - * @param object identity for the tree - * @param repository where to lookup for object db - * @param base directory path - * @param path length for base - * @param index entry offset to start scan - * @return number of items added to the tree + * Write a tree to the ODB from the index file + * + * This method will scan the index and write a representation + * of its current state back to disk; it recursively creates + * tree objects for each of the subtrees stored in the index, + * but only returns the OID of the root tree. This is the OID + * that can be used e.g. to create a commit. + * + * 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 diff --git a/src/tree.c b/src/tree.c index 299fc696c..588b5e9a0 100644 --- a/src/tree.c +++ b/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) { git_tree_entry *entry; - entry = git__malloc(sizeof(git_tree_entry)); + entry = git__calloc(1, sizeof(git_tree_entry)); if (entry == NULL) { error = GIT_ENOMEM; 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); } -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; - int nr, maxentries; - 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; - } - + int nr, error; + /* Guess at some random initial size */ - size = 8192; + size = maxentries * 40; buffer = git__malloc(size); if (buffer == NULL) return GIT_ENOMEM; offset = 0; - nr = entry_no; - do { + for (nr = entry_no; nr < maxentries; ++nr) { git_index_entry *entry = git_index_get(index, nr); + const char *pathname = entry->path, *filename, *dirname; int pathlen = strlen(pathname), entrylen; - git_oid *entry_oid; - unsigned int mode; - unsigned char *sha1; + + unsigned int write_mode; + git_oid subtree_oid; + git_oid *write_oid; /* 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; - entry_oid = &entry->oid; - mode = entry->mode; - sha1 = entry_oid->id; - /* Do we have _further_ subdirectories? */ filename = pathname + baselen; dirname = strchr(filename, '/'); + + write_oid = &entry->oid; + write_mode = entry->mode; + if (dirname) { int subdir_written; - subdir_written = git_tree_create(oid, repo, pathname, dirname-pathname+1, nr); - - if (subdir_written == GIT_ENOMEM) - return GIT_ENOMEM; + +#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; + } - nr += subdir_written; + nr = subdir_written - 1; /* Now we need to write out the directory entry into this tree.. */ - mode = S_IFDIR; pathlen = dirname - pathname; - - /* ..but the directory entry doesn't count towards the total count */ - nr--; - sha1 = oid->id; + write_oid = &subtree_oid; + write_mode = S_IFDIR; } - + entrylen = pathlen - baselen; - if (offset + entrylen + 100 > size) { - size = alloc_nr(offset + entrylen + 100); + if (offset + entrylen + 32 > size) { + size = alloc_nr(offset + entrylen + 32); buffer = git__realloc(buffer, size); if (buffer == NULL) 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; + + offset += write_entry(buffer + offset, write_mode, filename, entrylen, write_oid); + } - stream->write(stream, buffer, offset); - error = stream->finalize_write(oid, stream); - stream->free(stream); + 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; - return nr; + error = write_index(oid, index, "", 0, 0, git_index_entrycount(index)); + return (error < GIT_SUCCESS) ? error : GIT_SUCCESS; } |