* @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
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;
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;
}