mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-02 14:37:30 +00:00
I broke your bindings
Hey. Apologies in advance -- I broke your bindings. This is a major commit that includes a long-overdue redesign of the whole object-database structure. This is expected to be the last major external API redesign of the library until the first non-alpha release. Please get your bindings up to date with these changes. They will be included in the next minor release. Sorry again! Major features include: - Real caching and refcounting on parsed objects - Real caching and refcounting on objects read from the ODB - Streaming writes & reads from the ODB - Single-method writes for all object types - The external API is now partially thread-safe The speed increases are significant in all aspects, specially when reading an object several times from the ODB (revwalking) and when writing big objects to the ODB. Here's a full changelog for the external API: blob.h ------ - Remove `git_blob_new` - Remove `git_blob_set_rawcontent` - Remove `git_blob_set_rawcontent_fromfile` - Rename `git_blob_writefile` -> `git_blob_create_fromfile` - Change `git_blob_create_fromfile`: The `path` argument is now relative to the repository's working dir - Add `git_blob_create_frombuffer` commit.h -------- - Remove `git_commit_new` - Remove `git_commit_add_parent` - Remove `git_commit_set_message` - Remove `git_commit_set_committer` - Remove `git_commit_set_author` - Remove `git_commit_set_tree` - Add `git_commit_create` - Add `git_commit_create_v` - Add `git_commit_create_o` - Add `git_commit_create_ov` tag.h ----- - Remove `git_tag_new` - Remove `git_tag_set_target` - Remove `git_tag_set_name` - Remove `git_tag_set_tagger` - Remove `git_tag_set_message` - Add `git_tag_create` - Add `git_tag_create_o` tree.h ------ - Change `git_tree_entry_2object`: New signature is `(git_object **object_out, git_repository *repo, git_tree_entry *entry)` - Remove `git_tree_new` - Remove `git_tree_add_entry` - Remove `git_tree_remove_entry_byindex` - Remove `git_tree_remove_entry_byname` - Remove `git_tree_clearentries` - Remove `git_tree_entry_set_id` - Remove `git_tree_entry_set_name` - Remove `git_tree_entry_set_attributes` object.h ------------ - Remove `git_object_new - Remove `git_object_write` - Change `git_object_close`: This method is now *mandatory*. Not closing an object causes a memory leak. odb.h ----- - Remove type `git_rawobj` - Remove `git_rawobj_close` - Rename `git_rawobj_hash` -> `git_odb_hash` - Change `git_odb_hash`: New signature is `(git_oid *id, const void *data, size_t len, git_otype type)` - Add type `git_odb_object` - Add `git_odb_object_close` - Change `git_odb_read`: New signature is `(git_odb_object **out, git_odb *db, const git_oid *id)` - Change `git_odb_read_header`: New signature is `(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)` - Remove `git_odb_write` - Add `git_odb_open_wstream` - Add `git_odb_open_rstream` odb_backend.h ------------- - Change type `git_odb_backend`: New internal signatures are as follows int (* read)(void **, size_t *, git_otype *, struct git_odb_backend *, const git_oid *) int (* read_header)(size_t *, git_otype *, struct git_odb_backend *, const git_oid *) int (* writestream)(struct git_odb_stream **, struct git_odb_backend *, size_t, git_otype) int (* readstream)( struct git_odb_stream **, struct git_odb_backend *, const git_oid *) - Add type `git_odb_stream` - Add enum `git_odb_streammode` Signed-off-by: Vicent Marti <tanoku@gmail.com>
This commit is contained in:
parent
bb3de0c472
commit
72a3fe42fb
@ -41,8 +41,6 @@ GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Lookup a blob object from a repository.
|
||||
* The generated blob object is owned by the revision
|
||||
* repo and shall not be freed by the user.
|
||||
*
|
||||
* @param blob pointer to the looked up blob
|
||||
* @param repo the repo to use when locating the blob.
|
||||
@ -54,50 +52,13 @@ GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git
|
||||
return git_object_lookup((git_object **)blob, repo, id, GIT_OBJ_BLOB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new in-memory git_blob.
|
||||
*
|
||||
* The blob object must be manually filled using
|
||||
* the 'set_rawcontent' methods before it can
|
||||
* be written back to disk.
|
||||
*
|
||||
* @param blob pointer to the new blob
|
||||
* @param repo The repository where the object will reside
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_INLINE(int) git_blob_new(git_blob **blob, git_repository *repo)
|
||||
{
|
||||
return git_object_new((git_object **)blob, repo, GIT_OBJ_BLOB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill a blob with the contents inside
|
||||
* the pointed file.
|
||||
*
|
||||
* @param blob pointer to the new blob
|
||||
* @param filename name of the file to read
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_set_rawcontent_fromfile(git_blob *blob, const char *filename);
|
||||
|
||||
/**
|
||||
* Fill a blob with the contents inside
|
||||
* the pointed buffer
|
||||
*
|
||||
* @param blob pointer to the blob
|
||||
* @param buffer buffer with the contents for the blob
|
||||
* @param len size of the buffer
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_set_rawcontent(git_blob *blob, const void *buffer, size_t len);
|
||||
|
||||
/**
|
||||
* Get a read-only buffer with the raw content of a blob.
|
||||
*
|
||||
* A pointer to the raw content of a blob is returned;
|
||||
* this pointer is owned internally by the object and shall
|
||||
* not be free'd. The pointer may be invalidated at a later
|
||||
* time (e.g. when changing the contents of the blob).
|
||||
* time.
|
||||
*
|
||||
* @param blob pointer to the blob
|
||||
* @return the pointer; NULL if the blob has no contents
|
||||
@ -114,14 +75,28 @@ GIT_EXTERN(int) git_blob_rawsize(git_blob *blob);
|
||||
|
||||
/**
|
||||
* Read a file from the working folder of a repository
|
||||
* and write it to the Object Database as a loose blob,
|
||||
* if such doesn't exist yet.
|
||||
* and write it to the Object Database as a loose blob
|
||||
*
|
||||
* @param written_id return the id of the written blob
|
||||
* @param repo repository where the blob will be written
|
||||
* @param path file from which the blob will be created
|
||||
* @param oid return the id of the written blob
|
||||
* @param repo repository where the blob will be written.
|
||||
* this repository cannot be bare
|
||||
* @param path file from which the blob will be created,
|
||||
* relative to the repository's working dir
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_writefile(git_oid *written_id, git_repository *repo, const char *path);
|
||||
GIT_EXTERN(int) git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path);
|
||||
|
||||
|
||||
/**
|
||||
* Write an in-memory buffer to the ODB as a blob
|
||||
*
|
||||
* @param oid return the oid of the written blob
|
||||
* @param repo repository where to blob will be written
|
||||
* @param buffer data to be written into the blob
|
||||
* @param len length of the data
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -41,8 +41,6 @@ GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Lookup a commit object from a repository.
|
||||
* The generated commit object is owned by the revision
|
||||
* repo and shall not be freed by the user.
|
||||
*
|
||||
* @param commit pointer to the looked up commit
|
||||
* @param repo the repo to use when locating the commit.
|
||||
@ -55,24 +53,9 @@ GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, con
|
||||
return git_object_lookup((git_object **)commit, repo, id, GIT_OBJ_COMMIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new in-memory git_commit.
|
||||
*
|
||||
* The commit object must be manually filled using
|
||||
* setter methods before it can be written to its
|
||||
* repository.
|
||||
*
|
||||
* @param commit pointer to the new commit
|
||||
* @param repo The repository where the object will reside
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_INLINE(int) git_commit_new(git_commit **commit, git_repository *repo)
|
||||
{
|
||||
return git_object_new((git_object **)commit, repo, GIT_OBJ_COMMIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return object identity for the commit.
|
||||
*/
|
||||
@ -80,6 +63,7 @@ GIT_EXTERN(const git_oid *) git_commit_id(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the short (one line) message of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the short message of a commit
|
||||
*/
|
||||
@ -87,6 +71,7 @@ GIT_EXTERN(const char *) git_commit_message_short(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the full message of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the message of a commit
|
||||
*/
|
||||
@ -94,6 +79,7 @@ GIT_EXTERN(const char *) git_commit_message(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the commit time (i.e. committer time) of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the time of a commit
|
||||
*/
|
||||
@ -101,6 +87,7 @@ GIT_EXTERN(time_t) git_commit_time(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the commit timezone offset (i.e. committer's preferred timezone) of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return positive or negative timezone offset, in minutes from UTC
|
||||
*/
|
||||
@ -108,6 +95,7 @@ GIT_EXTERN(int) git_commit_time_offset(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the committer of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the committer of a commit
|
||||
*/
|
||||
@ -115,6 +103,7 @@ GIT_EXTERN(const git_signature *) git_commit_committer(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the author of a commit.
|
||||
*
|
||||
* @param commit a previously loaded commit.
|
||||
* @return the author of a commit
|
||||
*/
|
||||
@ -122,6 +111,7 @@ GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit);
|
||||
|
||||
/**
|
||||
* Get the tree pointed to by a commit.
|
||||
*
|
||||
* @param tree_out pointer where to store the tree object
|
||||
* @param commit a previously loaded commit.
|
||||
* @return 0 on success; error code otherwise
|
||||
@ -146,42 +136,129 @@ GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit);
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n);
|
||||
|
||||
|
||||
/**
|
||||
* Add a new parent commit to an existing commit
|
||||
* @param commit the commit object
|
||||
* @param new_parent the new commit which will be a parent
|
||||
* Create a new commit in the repository
|
||||
*
|
||||
*
|
||||
* @param oid Pointer where to store the OID of the
|
||||
* newly created commit
|
||||
*
|
||||
* @param repo Repository where to store the commit
|
||||
*
|
||||
* @param update_ref If not NULL, name of the reference that
|
||||
* will be updated to point to this commit. If the reference
|
||||
* is not direct, it will be resolved to a direct reference.
|
||||
* Use "HEAD" to update the HEAD of the current branch and
|
||||
* make it point to this commit
|
||||
*
|
||||
* @param author Signature representing the author and the authory
|
||||
* time of this commit
|
||||
*
|
||||
* @param committer Signature representing the committer and the
|
||||
* commit time of this commit
|
||||
*
|
||||
* @param message Full message for this commit
|
||||
*
|
||||
* @param tree_oid Object ID of the tree for this commit. Note that
|
||||
* no validation is performed on this OID. Use the _o variants of
|
||||
* this method to assure a proper tree is passed to the commit.
|
||||
*
|
||||
* @param parent_count Number of parents for this commit
|
||||
*
|
||||
* @param parents Array of pointers to parent OIDs for this commit.
|
||||
* Note that no validation is performed on these OIDs. Use the _o
|
||||
* variants of this method to assure that are parents for the commit
|
||||
* are proper objects.
|
||||
*
|
||||
* @return 0 on success; error code otherwise
|
||||
* The created commit will be written to the Object Database and
|
||||
* the given reference will be updated to point to it
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_add_parent(git_commit *commit, git_commit *new_parent);
|
||||
GIT_EXTERN(int) git_commit_create(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_oid *tree_oid,
|
||||
int parent_count,
|
||||
const git_oid *parent_oids[]);
|
||||
|
||||
/**
|
||||
* Set the message of a commit
|
||||
* @param commit the commit object
|
||||
* @param message the new message
|
||||
* Create a new commit in the repository using `git_object`
|
||||
* instances as parameters.
|
||||
*
|
||||
* The `tree_oid` and `parent_oids` paremeters now take a instance
|
||||
* of `git_tree` and `git_commit`, respectively.
|
||||
*
|
||||
* All other parameters remain the same
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(void) git_commit_set_message(git_commit *commit, const char *message);
|
||||
GIT_EXTERN(int) git_commit_create_o(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
const git_commit *parents[]);
|
||||
|
||||
/**
|
||||
* Set the committer of a commit
|
||||
* @param commit the commit object
|
||||
* @param author_sig signature of the committer
|
||||
* Create a new commit in the repository using `git_object`
|
||||
* instances and a variable argument list.
|
||||
*
|
||||
* The `tree_oid` paremeter now takes a instance
|
||||
* of `const git_tree *`.
|
||||
*
|
||||
* The parents for the commit are specified as a variable
|
||||
* list of pointers to `const git_commit *`. Note that this
|
||||
* is a convenience method which may not be safe to export
|
||||
* for certain languages or compilers
|
||||
*
|
||||
* All other parameters remain the same
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const git_signature *committer_sig);
|
||||
GIT_EXTERN(int) git_commit_create_ov(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
...);
|
||||
|
||||
|
||||
/**
|
||||
* Set the author of a commit
|
||||
* @param commit the commit object
|
||||
* @param author_sig signature of the author
|
||||
* Create a new commit in the repository using
|
||||
* a variable argument list.
|
||||
*
|
||||
* The parents for the commit are specified as a variable
|
||||
* list of pointers to `const git_oid *`. Note that this
|
||||
* is a convenience method which may not be safe to export
|
||||
* for certain languages or compilers
|
||||
*
|
||||
* All other parameters remain the same
|
||||
*
|
||||
* @see git_commit_create
|
||||
*/
|
||||
GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const git_signature *author_sig);
|
||||
|
||||
/**
|
||||
* Set the tree which is pointed to by a commit
|
||||
* @param commit the commit object
|
||||
* @param tree the new tree
|
||||
* @param 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_commit_set_tree(git_commit *commit, git_tree *tree);
|
||||
GIT_EXTERN(int) git_commit_create_v(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_oid *tree_oid,
|
||||
int parent_count,
|
||||
...);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -158,6 +158,9 @@
|
||||
/** The state of the reference is not valid */
|
||||
#define GIT_EINVALIDREFSTATE (GIT_ERROR - 21)
|
||||
|
||||
/** This feature has not been implemented yet */
|
||||
#define GIT_ENOTIMPLEMENTED (GIT_ERROR - 22)
|
||||
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
typedef struct {
|
||||
|
@ -42,7 +42,8 @@ GIT_BEGIN_DECL
|
||||
* Lookup a reference to one of the objects in a repostory.
|
||||
*
|
||||
* The generated reference is owned by the repository and
|
||||
* should not be freed by the user.
|
||||
* should be closed with the `git_object_close` method
|
||||
* instead of free'd manually.
|
||||
*
|
||||
* The 'type' parameter must match the type of the object
|
||||
* in the odb; the method will fail otherwise.
|
||||
@ -57,55 +58,9 @@ GIT_BEGIN_DECL
|
||||
*/
|
||||
GIT_EXTERN(int) git_object_lookup(git_object **object, git_repository *repo, const git_oid *id, git_otype type);
|
||||
|
||||
/**
|
||||
* Create a new in-memory repository object with
|
||||
* the given type.
|
||||
*
|
||||
* The object's attributes can be filled in using the
|
||||
* corresponding setter methods.
|
||||
*
|
||||
* The object will be written back to given git_repository
|
||||
* when the git_object_write() function is called; objects
|
||||
* cannot be written to disk until all their main
|
||||
* attributes have been properly filled.
|
||||
*
|
||||
* Objects are instantiated with no SHA1 id; their id
|
||||
* will be automatically generated when writing to the
|
||||
* repository.
|
||||
*
|
||||
* @param object pointer to the new object
|
||||
* @parem repo Repository where the object belongs
|
||||
* @param type Type of the object to be created
|
||||
* @return the new object
|
||||
*/
|
||||
GIT_EXTERN(int) git_object_new(git_object **object, git_repository *repo, git_otype type);
|
||||
|
||||
|
||||
/**
|
||||
* Write back an object to disk.
|
||||
*
|
||||
* The object will be written to its corresponding
|
||||
* repository.
|
||||
*
|
||||
* If the object has no changes since it was first
|
||||
* read from the repository, no actions will take place.
|
||||
*
|
||||
* If the object has been modified since it was read from
|
||||
* the repository, or it has been created from scratch
|
||||
* in memory, it will be written to the repository and
|
||||
* its SHA1 ID will be updated accordingly.
|
||||
*
|
||||
* @param object Git object to write back
|
||||
* @return 0 on success; otherwise an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_object_write(git_object *object);
|
||||
|
||||
/**
|
||||
* Get the id (SHA1) of a repository object
|
||||
*
|
||||
* In-memory objects created by git_object_new() do not
|
||||
* have a SHA1 ID until they are written on a repository.
|
||||
*
|
||||
* @param obj the repository object
|
||||
* @return the SHA1 id
|
||||
*/
|
||||
@ -137,14 +92,8 @@ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj);
|
||||
* by the repository.
|
||||
*
|
||||
* IMPORTANT:
|
||||
* It is *not* necessary to call this method when you stop using
|
||||
* an object, since all object memory is automatically reclaimed
|
||||
* by the repository when it is freed.
|
||||
*
|
||||
* Forgetting to call `git_object_close` does not cause memory
|
||||
* leaks, but it's is recommended to close as soon as possible
|
||||
* the biggest objects (e.g. blobs) to prevent wasting memory
|
||||
* space.
|
||||
* It *is* necessary to call this method when you stop using
|
||||
* an object. Failure to do so will cause a memory leak.
|
||||
*
|
||||
* @param object the object to close
|
||||
*/
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "oid.h"
|
||||
#include "odb_backend.h"
|
||||
|
||||
/**
|
||||
* @file git2/odb.h
|
||||
@ -100,61 +101,49 @@ GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, in
|
||||
|
||||
/**
|
||||
* Close an open object database.
|
||||
*
|
||||
* @param db database pointer to close. If NULL no action is taken.
|
||||
*/
|
||||
GIT_EXTERN(void) git_odb_close(git_odb *db);
|
||||
|
||||
/** An object read from the database. */
|
||||
typedef struct {
|
||||
void *data; /**< Raw, decompressed object data. */
|
||||
size_t len; /**< Total number of bytes in data. */
|
||||
git_otype type; /**< Type of this object. */
|
||||
} git_rawobj;
|
||||
|
||||
/**
|
||||
* Read an object from the database.
|
||||
*
|
||||
* If GIT_ENOTFOUND then out->data is set to NULL.
|
||||
* This method queries all avaiable ODB backends
|
||||
* trying to read the given OID.
|
||||
*
|
||||
* @param out object descriptor to populate upon reading.
|
||||
* The returned object is reference counted and
|
||||
* internally cached, so it should be closed
|
||||
* by the user once it's no longer in use.
|
||||
*
|
||||
* @param out pointer where to store the read object
|
||||
* @param db database to search for the object in.
|
||||
* @param id identity of the object to read.
|
||||
* @return
|
||||
* - GIT_SUCCESS if the object was read;
|
||||
* - GIT_ENOTFOUND if the object is not in the database.
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id);
|
||||
GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Read the header of an object from the database, without
|
||||
* reading its full contents.
|
||||
*
|
||||
* Only the 'type' and 'len' fields of the git_rawobj structure
|
||||
* are filled. The 'data' pointer will always be NULL.
|
||||
* The header includes the length and the type of an object.
|
||||
*
|
||||
* The raw object pointed by 'out' doesn't need to be manually
|
||||
* closed with git_rawobj_close().
|
||||
* Note that most backends do not support reading only the header
|
||||
* of an object, so the whole object will be read and then the
|
||||
* header will be returned.
|
||||
*
|
||||
* @param out object descriptor to populate upon reading.
|
||||
* @param len_p pointer where to store the length
|
||||
* @param type_p pointer where to store the type
|
||||
* @param db database to search for the object in.
|
||||
* @param id identity of the object to read.
|
||||
* @return
|
||||
* - GIT_SUCCESS if the object was read;
|
||||
* - GIT_ENOTFOUND if the object is not in the database.
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Write an object to the database.
|
||||
*
|
||||
* @param id identity of the object written.
|
||||
* @param db database to which the object should be written.
|
||||
* @param obj object descriptor for the object to write.
|
||||
* @return
|
||||
* - GIT_SUCCESS if the object was written;
|
||||
* - GIT_ERROR otherwise.
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj);
|
||||
GIT_EXTERN(int) git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id);
|
||||
|
||||
/**
|
||||
* Determine if the given object can be found in the object database.
|
||||
@ -162,39 +151,89 @@ GIT_EXTERN(int) git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj);
|
||||
* @param db database to be searched for the given object.
|
||||
* @param id the object to search for.
|
||||
* @return
|
||||
* - true, if the object was found
|
||||
* - false, otherwise
|
||||
* - 1, if the object was found
|
||||
* - 0, otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Open a stream to write an object into the ODB
|
||||
*
|
||||
* The type and final length of the object must be specified
|
||||
* when opening the stream.
|
||||
*
|
||||
* The returned stream will be of type `GIT_STREAM_WRONLY` and
|
||||
* will have the following methods:
|
||||
*
|
||||
* - stream->write: write `n` bytes into the stream
|
||||
* - stream->finalize_write: close the stream and store the object in
|
||||
* the odb
|
||||
* - stream->free: free the stream
|
||||
*
|
||||
* The streaming write won't be effective until `stream->finalize_write`
|
||||
* is called and returns without an error
|
||||
*
|
||||
* The stream must always be free'd or will leak memory.
|
||||
*
|
||||
* @see git_odb_stream
|
||||
*
|
||||
* @param stream pointer where to store the stream
|
||||
* @param db object database where the stream will write
|
||||
* @param size final size of the object that will be written
|
||||
* @para type type of the object that will be written
|
||||
* @return 0 if the stream was created; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_otype type);
|
||||
|
||||
/**
|
||||
* Determine the object-ID (sha1 hash) of the given git_rawobj.
|
||||
* Open a stream to read an object from the ODB
|
||||
*
|
||||
* The input obj must be a valid loose object type and the data
|
||||
* pointer must not be NULL, unless the len field is also zero.
|
||||
* Note that most backends do *not* support streaming reads
|
||||
* because they store their objects as compressed/delta'ed blobs.
|
||||
*
|
||||
* It's recommended to use `git_odb_read` instead, which is
|
||||
* assured to work on all backends.
|
||||
*
|
||||
* The returned stream will be of type `GIT_STREAM_RDONLY` and
|
||||
* will have the following methods:
|
||||
*
|
||||
* - stream->read: read `n` bytes from the stream
|
||||
* - stream->free: free the stream
|
||||
*
|
||||
* The stream must always be free'd or will leak memory.
|
||||
*
|
||||
* @see git_odb_stream
|
||||
*
|
||||
* @param stream pointer where to store the stream
|
||||
* @param db object database where the stream will read from
|
||||
* @param oid oid of the object the stream will read from
|
||||
* @return 0 if the stream was created; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid);
|
||||
|
||||
/**
|
||||
* Determine the object-ID (sha1 hash) of a data buffer
|
||||
*
|
||||
* The resulting SHA-1 OID will the itentifier for the data
|
||||
* buffer as if the data buffer it were to written to the ODB.
|
||||
*
|
||||
* @param id the resulting object-ID.
|
||||
* @param obj the object whose hash is to be determined.
|
||||
* @return
|
||||
* - GIT_SUCCESS if the object-ID was correctly determined.
|
||||
* - GIT_ERROR if the given object is malformed.
|
||||
* @param data data to hash
|
||||
* @param len size of the data
|
||||
* @param type of the data to hash
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_rawobj_hash(git_oid *id, git_rawobj *obj);
|
||||
GIT_EXTERN(int) git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type);
|
||||
|
||||
/**
|
||||
* Release all memory used by the obj structure.
|
||||
* Close an ODB object
|
||||
*
|
||||
* As a result of this call, obj->data will be set to NULL.
|
||||
* This method must always be called once a `git_odb_object` is no
|
||||
* longer needed, otherwise memory will leak.
|
||||
*
|
||||
* If obj->data is already NULL, nothing happens.
|
||||
*
|
||||
* @param obj object descriptor to free.
|
||||
* @param object object to close
|
||||
*/
|
||||
GIT_EXTERN(void) git_rawobj_close(git_rawobj *obj);
|
||||
GIT_EXTERN(void) git_odb_object_close(git_odb_object *object);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -39,24 +39,32 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
struct git_odb_stream;
|
||||
|
||||
/** An instance for a custom backend */
|
||||
struct git_odb_backend {
|
||||
git_odb *odb;
|
||||
|
||||
int (* read)(
|
||||
git_rawobj *,
|
||||
void **, size_t *, git_otype *,
|
||||
struct git_odb_backend *,
|
||||
const git_oid *);
|
||||
|
||||
int (* read_header)(
|
||||
git_rawobj *,
|
||||
size_t *, git_otype *,
|
||||
struct git_odb_backend *,
|
||||
const git_oid *);
|
||||
|
||||
int (* write)(
|
||||
git_oid *id,
|
||||
int (* writestream)(
|
||||
struct git_odb_stream **,
|
||||
struct git_odb_backend *,
|
||||
git_rawobj *obj);
|
||||
size_t,
|
||||
git_otype);
|
||||
|
||||
int (* readstream)(
|
||||
struct git_odb_stream **,
|
||||
struct git_odb_backend *,
|
||||
const git_oid *);
|
||||
|
||||
int (* exists)(
|
||||
struct git_odb_backend *,
|
||||
@ -65,12 +73,28 @@ struct git_odb_backend {
|
||||
void (* free)(struct git_odb_backend *);
|
||||
};
|
||||
|
||||
/** A stream to read/write from a backend */
|
||||
struct git_odb_stream {
|
||||
struct git_odb_backend *backend;
|
||||
int mode;
|
||||
|
||||
int (*read)(struct git_odb_stream *stream, char *buffer, size_t len);
|
||||
int (*write)(struct git_odb_stream *stream, const char *buffer, size_t len);
|
||||
int (*finalize_write)(git_oid *oid_p, struct git_odb_stream *stream);
|
||||
void (*free)(struct git_odb_stream *stream);
|
||||
};
|
||||
|
||||
/** Streaming mode */
|
||||
typedef enum {
|
||||
GIT_STREAM_RDONLY = (1 << 1),
|
||||
GIT_STREAM_WRONLY = (1 << 2),
|
||||
GIT_STREAM_RW = (GIT_STREAM_RDONLY | GIT_STREAM_WRONLY),
|
||||
} git_odb_streammode;
|
||||
|
||||
|
||||
GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir);
|
||||
GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir);
|
||||
|
||||
#ifdef GIT2_SQLITE_BACKEND
|
||||
GIT_EXTERN(int) git_odb_backend_sqlite(git_odb_backend **backend_out, const char *sqlite_db);
|
||||
#endif
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
|
@ -41,8 +41,6 @@ GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Lookup a tag object from the repository.
|
||||
* The generated tag object is owned by the revision
|
||||
* repo and shall not be freed by the user.
|
||||
*
|
||||
* @param tag pointer to the looked up tag
|
||||
* @param repo the repo to use when locating the tag.
|
||||
@ -54,24 +52,9 @@ GIT_INLINE(int) git_tag_lookup(git_tag **tag, git_repository *repo, const git_oi
|
||||
return git_object_lookup((git_object **)tag, repo, id, (git_otype)GIT_OBJ_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new in-memory git_tag.
|
||||
*
|
||||
* The tag object must be manually filled using
|
||||
* setter methods before it can be written to its
|
||||
* repository.
|
||||
*
|
||||
* @param tag pointer to the new tag
|
||||
* @param repo The repository where the object will reside
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_INLINE(int) git_tag_new(git_tag **tag, git_repository *repo)
|
||||
{
|
||||
return git_object_new((git_object **)tag, repo, (git_otype)GIT_OBJ_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of a tag.
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return object identity for the tag.
|
||||
*/
|
||||
@ -79,6 +62,10 @@ GIT_EXTERN(const git_oid *) git_tag_id(git_tag *tag);
|
||||
|
||||
/**
|
||||
* Get the tagged object of a tag
|
||||
*
|
||||
* This method performs a repository lookup for the
|
||||
* given object and returns it
|
||||
*
|
||||
* @param target pointer where to store the target
|
||||
* @param tag a previously loaded tag.
|
||||
* @return 0 on success; error code otherwise
|
||||
@ -87,6 +74,7 @@ GIT_EXTERN(int) git_tag_target(git_object **target, git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the OID of the tagged object of a tag
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return pointer to the OID
|
||||
*/
|
||||
@ -94,6 +82,7 @@ GIT_EXTERN(const git_oid *) git_tag_target_oid(git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the type of a tag's tagged object
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return type of the tagged object
|
||||
*/
|
||||
@ -101,6 +90,7 @@ GIT_EXTERN(git_otype) git_tag_type(git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the name of a tag
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return name of the tag
|
||||
*/
|
||||
@ -108,6 +98,7 @@ GIT_EXTERN(const char *) git_tag_name(git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the tagger (author) of a tag
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return reference to the tag's author
|
||||
*/
|
||||
@ -115,39 +106,69 @@ GIT_EXTERN(const git_signature *) git_tag_tagger(git_tag *t);
|
||||
|
||||
/**
|
||||
* Get the message of a tag
|
||||
*
|
||||
* @param tag a previously loaded tag.
|
||||
* @return message of the tag
|
||||
*/
|
||||
GIT_EXTERN(const char *) git_tag_message(git_tag *t);
|
||||
|
||||
/**
|
||||
* Set the target of a tag (i.e. the object that the tag points to)
|
||||
* @param tag The tag to modify
|
||||
* @param target the new tagged target
|
||||
*/
|
||||
GIT_EXTERN(int) git_tag_set_target(git_tag *tag, git_object *target);
|
||||
|
||||
/**
|
||||
* Set the name of a tag
|
||||
* @param tag The tag to modify
|
||||
* @param name the new name for the tag
|
||||
* Create a new tag in the repository from an OID
|
||||
*
|
||||
* @param oid Pointer where to store the OID of the
|
||||
* newly created tag
|
||||
*
|
||||
* @param repo Repository where to store the tag
|
||||
*
|
||||
* @param tag_name Name for the tag; this name is validated
|
||||
* for consistency
|
||||
*
|
||||
* @param target OID to which this tag points; note that no
|
||||
* validation is done on this OID. Use the _o version of this
|
||||
* method to assure a proper object is being tagged
|
||||
*
|
||||
* @param target_type Type of the tagged OID; note that no
|
||||
* validation is performed here either
|
||||
*
|
||||
* @param tagger Signature of the tagger for this tag, and
|
||||
* of the tagging time
|
||||
*
|
||||
* @param message Full message for this tag
|
||||
*
|
||||
* @return 0 on success; error code otherwise.
|
||||
* A tag object is written to the ODB, and a proper reference
|
||||
* is written in the /refs/tags folder, pointing to it
|
||||
*/
|
||||
GIT_EXTERN(void) git_tag_set_name(git_tag *tag, const char *name);
|
||||
GIT_EXTERN(int) git_tag_create(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *tag_name,
|
||||
const git_oid *target,
|
||||
git_otype target_type,
|
||||
const git_signature *tagger,
|
||||
const char *message);
|
||||
|
||||
|
||||
/**
|
||||
* Set the tagger of a tag
|
||||
* @param tag The tag to modify
|
||||
* @param tagger_sig signature of the tagging action
|
||||
* @return 0 on success; error code otherwise
|
||||
* Create a new tag in the repository from an existing
|
||||
* `git_object` instance
|
||||
*
|
||||
* This method replaces the `target` and `target_type`
|
||||
* paremeters of `git_tag_create` by a single instance
|
||||
* of a `const git_object *`, which is assured to be
|
||||
* a proper object in the ODB and hence will create
|
||||
* a valid tag
|
||||
*
|
||||
* @see git_tag_create
|
||||
*/
|
||||
GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig);
|
||||
|
||||
/**
|
||||
* Set the message of a tag
|
||||
* @param tag The tag to modify
|
||||
* @param message the new tagger for the tag
|
||||
*/
|
||||
GIT_EXTERN(void) git_tag_set_message(git_tag *tag, const char *message);
|
||||
GIT_EXTERN(int) git_tag_create_o(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *tag_name,
|
||||
const git_object *target,
|
||||
const git_signature *tagger,
|
||||
const char *message);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -41,8 +41,6 @@ GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Lookup a tree object from the repository.
|
||||
* The generated tree object is owned by the revision
|
||||
* repo and shall not be freed by the user.
|
||||
*
|
||||
* @param tree pointer to the looked up tree
|
||||
* @param repo the repo to use when locating the tree.
|
||||
@ -54,32 +52,17 @@ GIT_INLINE(int) git_tree_lookup(git_tree **tree, git_repository *repo, const git
|
||||
return git_object_lookup((git_object **)tree, repo, id, GIT_OBJ_TREE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new in-memory git_tree.
|
||||
*
|
||||
* The tree object must be manually filled using
|
||||
* setter methods before it can be written to its
|
||||
* repository.
|
||||
*
|
||||
* @param tree pointer to the new tree
|
||||
* @param repo The repository where the object will reside
|
||||
* @return 0 on success; error code otherwise
|
||||
*/
|
||||
GIT_INLINE(int) git_tree_new(git_tree **tree, git_repository *repo)
|
||||
{
|
||||
return git_object_new((git_object **)tree, repo, GIT_OBJ_TREE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of a tree.
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @return object identity for the tree.
|
||||
*/
|
||||
GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree);
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of entries listed in a tree
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @return the number of entries in the tree
|
||||
*/
|
||||
@ -87,6 +70,7 @@ GIT_EXTERN(size_t) git_tree_entrycount(git_tree *tree);
|
||||
|
||||
/**
|
||||
* Lookup a tree entry by its filename
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @param filename the filename of the desired entry
|
||||
* @return the tree entry; NULL if not found
|
||||
@ -95,6 +79,7 @@ GIT_EXTERN(git_tree_entry *) git_tree_entry_byname(git_tree *tree, const char *f
|
||||
|
||||
/**
|
||||
* Lookup a tree entry by its position in the tree
|
||||
*
|
||||
* @param tree a previously loaded tree.
|
||||
* @param idx the position in the entry list
|
||||
* @return the tree entry; NULL if not found
|
||||
@ -103,6 +88,7 @@ GIT_EXTERN(git_tree_entry *) git_tree_entry_byindex(git_tree *tree, int idx);
|
||||
|
||||
/**
|
||||
* Get the UNIX file attributes of a tree entry
|
||||
*
|
||||
* @param entry a tree entry
|
||||
* @return attributes as an integer
|
||||
*/
|
||||
@ -110,6 +96,7 @@ GIT_EXTERN(unsigned int) git_tree_entry_attributes(git_tree_entry *entry);
|
||||
|
||||
/**
|
||||
* Get the filename of a tree entry
|
||||
*
|
||||
* @param entry a tree entry
|
||||
* @return the name of the file
|
||||
*/
|
||||
@ -117,6 +104,7 @@ GIT_EXTERN(const char *) git_tree_entry_name(git_tree_entry *entry);
|
||||
|
||||
/**
|
||||
* Get the id of the object pointed by the entry
|
||||
*
|
||||
* @param entry a tree entry
|
||||
* @return the oid of the object
|
||||
*/
|
||||
@ -126,97 +114,11 @@ GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry);
|
||||
* Convert a tree entry to the git_object it points too.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_entry_2object(git_object **object, git_tree_entry *entry);
|
||||
|
||||
/**
|
||||
* Add a new entry to a tree and return the new entry.
|
||||
*
|
||||
* This will mark the tree as modified; the new entry will
|
||||
* be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param entry_out Pointer to the entry that just got
|
||||
* created. May be NULL if you are not interested on
|
||||
* getting the new entry
|
||||
* @param tree Tree object to store the entry
|
||||
* @iparam id OID for the tree entry
|
||||
* @param filename Filename for the tree entry
|
||||
* @param attributes UNIX file attributes for the entry
|
||||
* @return 0 on success; otherwise error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes);
|
||||
|
||||
/**
|
||||
* Remove an entry by its index.
|
||||
*
|
||||
* Index must be >= 0 and < than git_tree_entrycount().
|
||||
*
|
||||
* This will mark the tree as modified; the modified entry will
|
||||
* be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param tree Tree where to remove the entry
|
||||
* @param idx index of the entry
|
||||
* @return 0 on successful removal; GIT_ENOTFOUND if the entry wasn't found
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_remove_entry_byindex(git_tree *tree, int idx);
|
||||
|
||||
/**
|
||||
* Remove an entry by its filename.
|
||||
*
|
||||
* This will mark the tree as modified; the modified entry will
|
||||
* be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param tree Tree where to remove the entry
|
||||
* @param filename File name of the entry
|
||||
* @return 0 on successful removal; GIT_ENOTFOUND if the entry wasn't found
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_remove_entry_byname(git_tree *tree, const char *filename);
|
||||
|
||||
/**
|
||||
* Clear all the entries in a tree.
|
||||
*
|
||||
* This will mark the tree as modified; the modified entry will
|
||||
* be written back to disk on the next git_object_write().
|
||||
*
|
||||
* @param tree Tree object whose entries are to be sorted
|
||||
*/
|
||||
GIT_EXTERN(void) git_tree_clear_entries(git_tree *tree);
|
||||
|
||||
/**
|
||||
* Change the SHA1 id of a tree entry.
|
||||
*
|
||||
* This will mark the tree that contains the entry as modified;
|
||||
* the modified entry will be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param entry Entry object which will be modified
|
||||
* @param oid new SHA1 oid for the entry
|
||||
*/
|
||||
GIT_EXTERN(void) git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid);
|
||||
|
||||
/**
|
||||
* Change the filename of a tree entry.
|
||||
*
|
||||
* This will mark the tree that contains the entry as modified;
|
||||
* the modified entry will be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param entry Entry object which will be modified
|
||||
* @param oid new filename for the entry
|
||||
*/
|
||||
GIT_EXTERN(void) git_tree_entry_set_name(git_tree_entry *entry, const char *name);
|
||||
|
||||
/**
|
||||
* Change the attributes of a tree entry.
|
||||
*
|
||||
* This will mark the tree that contains the entry as modified;
|
||||
* the modified entry will be written back to disk on the next git_object_write()
|
||||
*
|
||||
* @param entry Entry object which will be modified
|
||||
* @param oid new attributes for the entry
|
||||
* @return 0 if the attributes were properly set; error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_tree_entry_set_attributes(git_tree_entry *entry, unsigned int attr);
|
||||
GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
|
@ -71,7 +71,6 @@ typedef time_t git_time_t;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Basic type (loose or packed) of any Git object. */
|
||||
typedef enum {
|
||||
GIT_OBJ_ANY = -2, /**< Object can be any of the following */
|
||||
@ -92,6 +91,12 @@ typedef struct git_odb git_odb;
|
||||
/** A custom backend in an ODB */
|
||||
typedef struct git_odb_backend git_odb_backend;
|
||||
|
||||
/** An object read from the ODB */
|
||||
typedef struct git_odb_object git_odb_object;
|
||||
|
||||
/** A stream to read/write from the ODB */
|
||||
typedef struct git_odb_stream git_odb_stream;
|
||||
|
||||
/**
|
||||
* Representation of an existing git repository,
|
||||
* including all its object contents
|
||||
|
@ -272,4 +272,13 @@ cleanup:
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int git_odb_backend_sqlite(git_odb_backend **GIT_UNUSED(backend_out), const char *GIT_UNUSED(sqlite_db))
|
||||
{
|
||||
GIT_UNUSED_ARG(backend_out);
|
||||
GIT_UNUSED_ARG(sqlite_db);
|
||||
return GIT_ENOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SQLITE3 */
|
||||
|
135
src/blob.c
135
src/blob.c
@ -33,104 +33,89 @@
|
||||
const void *git_blob_rawcontent(git_blob *blob)
|
||||
{
|
||||
assert(blob);
|
||||
|
||||
if (blob->content.data != NULL)
|
||||
return blob->content.data;
|
||||
|
||||
if (blob->object.in_memory)
|
||||
return NULL;
|
||||
|
||||
if (!blob->object.source.open && git_object__source_open((git_object *)blob) < GIT_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
return blob->object.source.raw.data;
|
||||
return blob->odb_object->raw.data;
|
||||
}
|
||||
|
||||
int git_blob_rawsize(git_blob *blob)
|
||||
{
|
||||
assert(blob);
|
||||
|
||||
if (blob->content.data != NULL)
|
||||
return blob->content.len;
|
||||
|
||||
return blob->object.source.raw.len;
|
||||
return blob->odb_object->raw.len;
|
||||
}
|
||||
|
||||
void git_blob__free(git_blob *blob)
|
||||
{
|
||||
gitfo_free_buf(&blob->content);
|
||||
git_odb_object_close(blob->odb_object);
|
||||
free(blob);
|
||||
}
|
||||
|
||||
int git_blob__parse(git_blob *blob)
|
||||
int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
|
||||
{
|
||||
assert(blob);
|
||||
git_cached_obj_incref((git_cached_obj *)odb_obj);
|
||||
blob->odb_object = odb_obj;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_blob__writeback(git_blob *blob, git_odb_source *src)
|
||||
{
|
||||
assert(blob->object.modified);
|
||||
|
||||
if (blob->content.data == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
return git__source_write(src, blob->content.data, blob->content.len);
|
||||
}
|
||||
|
||||
int git_blob_set_rawcontent(git_blob *blob, const void *buffer, size_t len)
|
||||
{
|
||||
assert(blob && buffer);
|
||||
|
||||
blob->object.modified = 1;
|
||||
|
||||
git_object__source_close((git_object *)blob);
|
||||
|
||||
if (blob->content.data != NULL)
|
||||
gitfo_free_buf(&blob->content);
|
||||
|
||||
blob->content.data = git__malloc(len);
|
||||
blob->content.len = len;
|
||||
|
||||
if (blob->content.data == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
memcpy(blob->content.data, buffer, len);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_blob_set_rawcontent_fromfile(git_blob *blob, const char *filename)
|
||||
{
|
||||
assert(blob && filename);
|
||||
blob->object.modified = 1;
|
||||
|
||||
if (blob->content.data != NULL)
|
||||
gitfo_free_buf(&blob->content);
|
||||
|
||||
return gitfo_read_file(&blob->content, filename);
|
||||
}
|
||||
|
||||
int git_blob_writefile(git_oid *written_id, git_repository *repo, const char *path)
|
||||
int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len)
|
||||
{
|
||||
int error;
|
||||
git_blob *blob;
|
||||
git_odb_stream *stream;
|
||||
|
||||
if (gitfo_exists(path) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if ((error = git_blob_new(&blob, repo)) < GIT_SUCCESS)
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if ((error = git_blob_set_rawcontent_fromfile(blob, path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
stream->write(stream, buffer, len);
|
||||
|
||||
if ((error = git_object_write((git_object *)blob)) < GIT_SUCCESS)
|
||||
return error;
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
git_oid_cpy(written_id, git_object_id((git_object *)blob));
|
||||
|
||||
git_object_close((git_object*)blob);
|
||||
return GIT_SUCCESS;
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
|
||||
{
|
||||
int error, fd;
|
||||
char full_path[GIT_PATH_MAX];
|
||||
char buffer[2048];
|
||||
git_off_t size;
|
||||
git_odb_stream *stream;
|
||||
|
||||
if (repo->path_workdir == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
git__joinpath(full_path, repo->path_workdir, path);
|
||||
|
||||
if ((fd = gitfo_open(full_path, O_RDONLY)) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
if ((size = gitfo_size(fd)) < 0 || !git__is_sizet(size)) {
|
||||
gitfo_close(fd);
|
||||
return GIT_EOSERR;
|
||||
}
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) {
|
||||
gitfo_close(fd);
|
||||
return error;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
ssize_t read_len;
|
||||
|
||||
read_len = read(fd, buffer, sizeof(buffer));
|
||||
|
||||
if (read_len < 0) {
|
||||
gitfo_close(fd);
|
||||
stream->free(stream);
|
||||
return GIT_EOSERR;
|
||||
}
|
||||
|
||||
stream->write(stream, buffer, read_len);
|
||||
size -= read_len;
|
||||
}
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -3,15 +3,15 @@
|
||||
|
||||
#include "git2/blob.h"
|
||||
#include "repository.h"
|
||||
#include "odb.h"
|
||||
#include "fileops.h"
|
||||
|
||||
struct git_blob {
|
||||
git_object object;
|
||||
gitfo_buf content;
|
||||
git_odb_object *odb_object;
|
||||
};
|
||||
|
||||
void git_blob__free(git_blob *blob);
|
||||
int git_blob__parse(git_blob *blob);
|
||||
int git_blob__writeback(git_blob *blob, git_odb_source *src);
|
||||
int git_blob__parse(git_blob *blob, git_odb_object *obj);
|
||||
|
||||
#endif
|
||||
|
46
src/cache.c
46
src/cache.c
@ -32,23 +32,6 @@
|
||||
#define GIT_CACHE_OPENADR 3
|
||||
|
||||
|
||||
GIT_INLINE(int) cached_obj_compare(git_cached_obj *obj, const git_oid *oid)
|
||||
{
|
||||
return git_oid_cmp(&obj->oid, oid);
|
||||
}
|
||||
|
||||
GIT_INLINE(void) cached_obj_incref(git_cached_obj *obj)
|
||||
{
|
||||
git_atomic_inc(&obj->refcount);
|
||||
}
|
||||
|
||||
GIT_INLINE(void) cached_obj_decref(git_cached_obj *obj, git_cached_obj_freeptr free_obj)
|
||||
{
|
||||
if (git_atomic_dec(&obj->refcount) == 0)
|
||||
free_obj(obj);
|
||||
}
|
||||
|
||||
|
||||
void git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
|
||||
{
|
||||
size_t i;
|
||||
@ -82,7 +65,9 @@ void git_cache_free(git_cache *cache)
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (cache->size_mask + 1); ++i) {
|
||||
cached_obj_decref(cache->nodes[i].ptr, cache->free_obj);
|
||||
if (cache->nodes[i].ptr)
|
||||
git_cached_obj_decref(cache->nodes[i].ptr, cache->free_obj);
|
||||
|
||||
git_mutex_free(&cache->nodes[i].lock);
|
||||
}
|
||||
|
||||
@ -103,8 +88,8 @@ void *git_cache_get(git_cache *cache, const git_oid *oid)
|
||||
|
||||
git_mutex_lock(&node->lock);
|
||||
{
|
||||
if (cached_obj_compare(node->ptr, oid) == 0) {
|
||||
cached_obj_incref(node->ptr);
|
||||
if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) {
|
||||
git_cached_obj_incref(node->ptr);
|
||||
node->lru = ++cache->lru_count;
|
||||
found = 1;
|
||||
}
|
||||
@ -121,14 +106,14 @@ void *git_cache_try_store(git_cache *cache, void *entry)
|
||||
cache_node *nodes[GIT_CACHE_OPENADR], *lru_node;
|
||||
const uint32_t *hash;
|
||||
const git_oid *oid;
|
||||
size_t i, stored = 0;
|
||||
size_t i;
|
||||
|
||||
oid = &((git_cached_obj*)entry)->oid;
|
||||
hash = (const uint32_t *)oid->id;
|
||||
|
||||
/* increase the refcount on this object, because
|
||||
* the cache now owns it */
|
||||
cached_obj_incref(entry);
|
||||
git_cached_obj_incref(entry);
|
||||
|
||||
for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
|
||||
size_t pos = hash[i] & cache->size_mask;
|
||||
@ -139,34 +124,35 @@ void *git_cache_try_store(git_cache *cache, void *entry)
|
||||
|
||||
lru_node = nodes[0];
|
||||
|
||||
for (i = 0; !stored && entry && i < GIT_CACHE_OPENADR; ++i) {
|
||||
for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
|
||||
|
||||
if (nodes[i]->ptr == NULL) {
|
||||
nodes[i]->ptr = entry;
|
||||
nodes[i]->lru = ++cache->lru_count;
|
||||
stored = 1;
|
||||
} else if (cached_obj_compare(nodes[i]->ptr, oid) == 0) {
|
||||
cached_obj_decref(entry, cache->free_obj);
|
||||
break;
|
||||
} else if (git_cached_obj_compare(nodes[i]->ptr, oid) == 0) {
|
||||
git_cached_obj_decref(entry, cache->free_obj);
|
||||
entry = nodes[i]->ptr;
|
||||
stored = 1;
|
||||
nodes[i]->lru = ++cache->lru_count;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nodes[i]->lru < lru_node->lru)
|
||||
lru_node = nodes[i];
|
||||
}
|
||||
|
||||
if (!stored) {
|
||||
if (i == GIT_CACHE_OPENADR) {
|
||||
void *old_entry = lru_node->ptr;
|
||||
assert(old_entry);
|
||||
|
||||
cached_obj_decref(old_entry, cache->free_obj);
|
||||
git_cached_obj_decref(old_entry, cache->free_obj);
|
||||
lru_node->ptr = entry;
|
||||
lru_node->lru = ++cache->lru_count;
|
||||
}
|
||||
|
||||
/* increase the refcount again, because we are
|
||||
* returning it to the user */
|
||||
cached_obj_incref(entry);
|
||||
git_cached_obj_incref(entry);
|
||||
|
||||
for (i = 0; i < GIT_CACHE_OPENADR; ++i)
|
||||
git_mutex_unlock(&nodes[i]->lock);
|
||||
|
21
src/cache.h
21
src/cache.h
@ -7,6 +7,8 @@
|
||||
|
||||
#include "thread-utils.h"
|
||||
|
||||
#define GIT_DEFAULT_CACHE_SIZE 128
|
||||
|
||||
typedef void (*git_cached_obj_freeptr)(void *);
|
||||
|
||||
typedef struct {
|
||||
@ -35,4 +37,23 @@ void git_cache_free(git_cache *cache);
|
||||
void *git_cache_try_store(git_cache *cache, void *entry);
|
||||
void *git_cache_get(git_cache *cache, const git_oid *oid);
|
||||
|
||||
|
||||
GIT_INLINE(int) git_cached_obj_compare(git_cached_obj *obj, const git_oid *oid)
|
||||
{
|
||||
return git_oid_cmp(&obj->oid, oid);
|
||||
}
|
||||
|
||||
GIT_INLINE(void) git_cached_obj_incref(git_cached_obj *obj)
|
||||
{
|
||||
git_atomic_inc(&obj->refcount);
|
||||
}
|
||||
|
||||
GIT_INLINE(void) git_cached_obj_decref(git_cached_obj *obj, git_cached_obj_freeptr free_obj)
|
||||
{
|
||||
if (git_atomic_dec(&obj->refcount) == 0)
|
||||
free_obj(obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
278
src/commit.c
278
src/commit.c
@ -29,9 +29,12 @@
|
||||
#include "git2/signature.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "odb.h"
|
||||
#include "commit.h"
|
||||
#include "signature.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define COMMIT_BASIC_PARSE 0x0
|
||||
#define COMMIT_FULL_PARSE 0x1
|
||||
|
||||
@ -71,35 +74,165 @@ const git_oid *git_commit_id(git_commit *c)
|
||||
return git_object_id((git_object *)c);
|
||||
}
|
||||
|
||||
int git_commit__writeback(git_commit *commit, git_odb_source *src)
|
||||
|
||||
int git_commit_create_v(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_oid *tree_oid,
|
||||
int parent_count,
|
||||
...)
|
||||
{
|
||||
unsigned int i;
|
||||
va_list ap;
|
||||
int i, error;
|
||||
const git_oid **oids;
|
||||
|
||||
git__write_oid(src, "tree", &commit->tree_oid);
|
||||
oids = git__malloc(parent_count * sizeof(git_oid *));
|
||||
|
||||
for (i = 0; i < commit->parent_oids.length; ++i) {
|
||||
git_oid *parent_oid;
|
||||
va_start(ap, parent_count);
|
||||
for (i = 0; i < parent_count; ++i)
|
||||
oids[i] = va_arg(ap, const git_oid *);
|
||||
va_end(ap);
|
||||
|
||||
parent_oid = git_vector_get(&commit->parent_oids, i);
|
||||
git__write_oid(src, "parent", parent_oid);
|
||||
error = git_commit_create(
|
||||
oid, repo, update_ref, author, committer, message,
|
||||
tree_oid, parent_count, oids);
|
||||
|
||||
free(oids);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_commit_create_ov(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
int i, error;
|
||||
const git_oid **oids;
|
||||
|
||||
oids = git__malloc(parent_count * sizeof(git_oid *));
|
||||
|
||||
va_start(ap, parent_count);
|
||||
for (i = 0; i < parent_count; ++i)
|
||||
oids[i] = git_object_id(va_arg(ap, const git_object *));
|
||||
va_end(ap);
|
||||
|
||||
error = git_commit_create(
|
||||
oid, repo, update_ref, author, committer, message,
|
||||
git_object_id((git_object *)tree),
|
||||
parent_count, oids);
|
||||
|
||||
free(oids);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_commit_create_o(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_tree *tree,
|
||||
int parent_count,
|
||||
const git_commit *parents[])
|
||||
{
|
||||
int i, error;
|
||||
const git_oid **oids;
|
||||
|
||||
oids = git__malloc(parent_count * sizeof(git_oid *));
|
||||
|
||||
for (i = 0; i < parent_count; ++i)
|
||||
oids[i] = git_object_id((git_object *)parents[i]);
|
||||
|
||||
error = git_commit_create(
|
||||
oid, repo, update_ref, author, committer, message,
|
||||
git_object_id((git_object *)tree),
|
||||
parent_count, oids);
|
||||
|
||||
free(oids);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_commit_create(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *update_ref,
|
||||
const git_signature *author,
|
||||
const git_signature *committer,
|
||||
const char *message,
|
||||
const git_oid *tree_oid,
|
||||
int parent_count,
|
||||
const git_oid *parents[])
|
||||
{
|
||||
size_t final_size = 0;
|
||||
int message_length, author_length, committer_length;
|
||||
|
||||
char *author_str, *committer_str;
|
||||
|
||||
int error, i;
|
||||
git_odb_stream *stream;
|
||||
|
||||
message_length = strlen(message);
|
||||
author_length = git_signature__write(&author_str, "author", author);
|
||||
committer_length = git_signature__write(&committer_str, "committer", committer);
|
||||
|
||||
if (author_length < 0 || committer_length < 0)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
final_size += GIT_OID_LINE_LENGTH("tree");
|
||||
final_size += GIT_OID_LINE_LENGTH("parent") * parent_count;
|
||||
final_size += author_length;
|
||||
final_size += committer_length;
|
||||
final_size += 1 + message_length;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_COMMIT)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
git__write_oid(stream, "tree", tree_oid);
|
||||
|
||||
for (i = 0; i < parent_count; ++i)
|
||||
git__write_oid(stream, "parent", parents[i]);
|
||||
|
||||
stream->write(stream, author_str, author_length);
|
||||
free(author_str);
|
||||
|
||||
stream->write(stream, committer_str, committer_length);
|
||||
free(committer_str);
|
||||
|
||||
|
||||
stream->write(stream, "\n", 1);
|
||||
stream->write(stream, message, message_length);
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
if (error == GIT_SUCCESS && update_ref != NULL) {
|
||||
git_reference *head;
|
||||
|
||||
error = git_reference_lookup(&head, repo, update_ref);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (git_reference_type(head) == GIT_REF_SYMBOLIC) {
|
||||
if ((error = git_reference_resolve(&head, head)) < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = git_reference_set_oid(head, oid);
|
||||
}
|
||||
|
||||
if (commit->author == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
git_signature__write(src, "author", commit->author);
|
||||
|
||||
if (commit->committer == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
git_signature__write(src, "committer", commit->committer);
|
||||
|
||||
if (commit->message != NULL) {
|
||||
git__source_write(src, "\n", 1);
|
||||
git__source_write(src, commit->message, strlen(commit->message));
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
return error;
|
||||
}
|
||||
|
||||
int commit_parse_buffer(git_commit *commit, void *data, size_t len)
|
||||
@ -110,12 +243,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len)
|
||||
git_oid parent_oid;
|
||||
int error;
|
||||
|
||||
/* first parse; the vector hasn't been initialized yet */
|
||||
if (commit->parent_oids.contents == NULL) {
|
||||
git_vector_init(&commit->parent_oids, 4, NULL);
|
||||
}
|
||||
|
||||
clear_parents(commit);
|
||||
git_vector_init(&commit->parent_oids, 4, NULL);
|
||||
|
||||
if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)
|
||||
return error;
|
||||
@ -134,17 +262,11 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len)
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
if (commit->author)
|
||||
git_signature_free(commit->author);
|
||||
|
||||
commit->author = git__malloc(sizeof(git_signature));
|
||||
if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Always parse the committer; we need the commit time */
|
||||
if (commit->committer)
|
||||
git_signature_free(commit->committer);
|
||||
|
||||
commit->committer = git__malloc(sizeof(git_signature));
|
||||
if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS)
|
||||
return error;
|
||||
@ -176,11 +298,10 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_commit__parse(git_commit *commit)
|
||||
int git_commit__parse(git_commit *commit, git_odb_object *obj)
|
||||
{
|
||||
assert(commit && commit->object.source.open);
|
||||
return commit_parse_buffer(commit,
|
||||
commit->object.source.raw.data, commit->object.source.raw.len);
|
||||
assert(commit);
|
||||
return commit_parse_buffer(commit, obj->raw.data, obj->raw.len);
|
||||
}
|
||||
|
||||
#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
|
||||
@ -218,82 +339,3 @@ int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n)
|
||||
}
|
||||
|
||||
|
||||
|
||||
int git_commit_set_tree(git_commit *commit, git_tree *tree)
|
||||
{
|
||||
const git_oid *oid;
|
||||
|
||||
assert(commit && tree);
|
||||
|
||||
if ((oid = git_object_id((git_object *)tree)) == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
commit->object.modified = 1;
|
||||
git_oid_cpy(&commit->tree_oid, oid);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_commit_add_parent(git_commit *commit, git_commit *new_parent)
|
||||
{
|
||||
const git_oid *parent_oid;
|
||||
git_oid *new_oid;
|
||||
assert(commit && new_parent);
|
||||
|
||||
if ((parent_oid = git_object_id((git_object *)new_parent)) == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
new_oid = git__malloc(sizeof(git_oid));
|
||||
if (new_oid == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
commit->object.modified = 1;
|
||||
git_oid_cpy(new_oid, parent_oid);
|
||||
return git_vector_insert(&commit->parent_oids, new_oid);
|
||||
}
|
||||
|
||||
void git_commit_set_author(git_commit *commit, const git_signature *author_sig)
|
||||
{
|
||||
assert(commit && author_sig);
|
||||
commit->object.modified = 1;
|
||||
|
||||
git_signature_free(commit->author);
|
||||
commit->author = git_signature_dup(author_sig);
|
||||
}
|
||||
|
||||
void git_commit_set_committer(git_commit *commit, const git_signature *committer_sig)
|
||||
{
|
||||
assert(commit && committer_sig);
|
||||
commit->object.modified = 1;
|
||||
|
||||
git_signature_free(commit->committer);
|
||||
commit->committer = git_signature_dup(committer_sig);
|
||||
}
|
||||
|
||||
void git_commit_set_message(git_commit *commit, const char *message)
|
||||
{
|
||||
const char *line_end;
|
||||
size_t message_len;
|
||||
|
||||
commit->object.modified = 1;
|
||||
|
||||
if (commit->message)
|
||||
free(commit->message);
|
||||
|
||||
if (commit->message_short)
|
||||
free(commit->message_short);
|
||||
|
||||
commit->message = git__strdup(message);
|
||||
|
||||
/* Short message */
|
||||
if((line_end = strchr(message, '\n')) == NULL) {
|
||||
commit->message_short = git__strdup(message);
|
||||
return;
|
||||
}
|
||||
|
||||
message_len = line_end - message;
|
||||
|
||||
commit->message_short = git__malloc(message_len + 1);
|
||||
memcpy(commit->message_short, message, message_len);
|
||||
commit->message_short[message_len] = 0;
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,6 @@ struct git_commit {
|
||||
};
|
||||
|
||||
void git_commit__free(git_commit *c);
|
||||
int git_commit__parse(git_commit *commit);
|
||||
|
||||
int git_commit__writeback(git_commit *commit, git_odb_source *src);
|
||||
int git_commit__parse(git_commit *commit, git_odb_object *obj);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef INCLUDE_delta_apply_h__
|
||||
#define INCLUDE_delta_apply_h__
|
||||
|
||||
#include "odb.h"
|
||||
|
||||
/**
|
||||
* Apply a git binary delta to recover the original content.
|
||||
*
|
||||
|
@ -27,7 +27,8 @@ static struct {
|
||||
{GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"},
|
||||
{GIT_EINVALIDPATH, "The path is invalid" },
|
||||
{GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},
|
||||
{GIT_EINVALIDREFSTATE, "The state of the reference is not valid"}
|
||||
{GIT_EINVALIDREFSTATE, "The state of the reference is not valid"},
|
||||
{GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"}
|
||||
};
|
||||
|
||||
const char *git_strerror(int num)
|
||||
|
190
src/filebuf.c
190
src/filebuf.c
@ -77,43 +77,81 @@ void git_filebuf_cleanup(git_filebuf *file)
|
||||
if (file->fd >= 0)
|
||||
gitfo_close(file->fd);
|
||||
|
||||
if (gitfo_exists(file->path_lock) == GIT_SUCCESS)
|
||||
if (file->path_lock && gitfo_exists(file->path_lock) == GIT_SUCCESS)
|
||||
gitfo_unlink(file->path_lock);
|
||||
|
||||
if (file->digest)
|
||||
git_hash_free_ctx(file->digest);
|
||||
|
||||
free(file->buffer);
|
||||
free(file->z_buf);
|
||||
|
||||
#ifdef GIT_FILEBUF_THREADS
|
||||
free(file->buffer_back);
|
||||
#endif
|
||||
deflateEnd(&file->zs);
|
||||
|
||||
free(file->path_original);
|
||||
free(file->path_lock);
|
||||
}
|
||||
|
||||
static int flush_buffer(git_filebuf *file)
|
||||
GIT_INLINE(int) flush_buffer(git_filebuf *file)
|
||||
{
|
||||
int result = GIT_SUCCESS;
|
||||
int result = file->write(file, file->buffer, file->buf_pos);
|
||||
file->buf_pos = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (file->buf_pos > 0) {
|
||||
result = gitfo_write(file->fd, file->buffer, file->buf_pos);
|
||||
static int write_normal(git_filebuf *file, const void *source, size_t len)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (len > 0) {
|
||||
result = gitfo_write(file->fd, (void *)source, len);
|
||||
if (file->digest)
|
||||
git_hash_update(file->digest, file->buffer, file->buf_pos);
|
||||
|
||||
file->buf_pos = 0;
|
||||
git_hash_update(file->digest, source, len);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int write_deflate(git_filebuf *file, const void *source, size_t len)
|
||||
{
|
||||
int result = Z_OK;
|
||||
z_stream *zs = &file->zs;
|
||||
|
||||
if (len > 0 || file->flush_mode == Z_FINISH) {
|
||||
zs->next_in = (void *)source;
|
||||
zs->avail_in = len;
|
||||
|
||||
do {
|
||||
int have;
|
||||
|
||||
zs->next_out = file->z_buf;
|
||||
zs->avail_out = file->buf_size;
|
||||
|
||||
result = deflate(zs, file->flush_mode);
|
||||
assert(result != Z_STREAM_ERROR);
|
||||
|
||||
have = file->buf_size - zs->avail_out;
|
||||
|
||||
if (gitfo_write(file->fd, file->z_buf, have) < GIT_SUCCESS)
|
||||
return GIT_EOSERR;
|
||||
|
||||
} while (zs->avail_out == 0);
|
||||
|
||||
assert(zs->avail_in == 0);
|
||||
|
||||
if (file->digest)
|
||||
git_hash_update(file->digest, source, len);
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
||||
{
|
||||
int error;
|
||||
size_t path_len;
|
||||
|
||||
if (file == NULL || path == NULL)
|
||||
if (file == NULL)
|
||||
return GIT_ERROR;
|
||||
|
||||
memset(file, 0x0, sizeof(git_filebuf));
|
||||
@ -122,37 +160,14 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
||||
file->buf_pos = 0;
|
||||
file->fd = -1;
|
||||
|
||||
path_len = strlen(path);
|
||||
|
||||
file->path_original = git__strdup(path);
|
||||
if (file->path_original == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);
|
||||
if (file->path_lock == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(file->path_lock, file->path_original, path_len);
|
||||
memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH);
|
||||
|
||||
/* Allocate the main cache buffer */
|
||||
file->buffer = git__malloc(file->buf_size);
|
||||
if (file->buffer == NULL){
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef GIT_FILEBUF_THREADS
|
||||
file->buffer_back = git__malloc(file->buf_size);
|
||||
if (file->buffer_back == NULL){
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we are hashing on-write, allocate a new hash context */
|
||||
if (flags & GIT_FILEBUF_HASH_CONTENTS) {
|
||||
if ((file->digest = git_hash_new_ctx()) == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
@ -160,8 +175,78 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = lock_file(file, flags)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
/* If we are deflating on-write, */
|
||||
if (flags & GIT_FILEBUF_DEFLATE_CONTENTS) {
|
||||
|
||||
/* Initialize the ZLib stream */
|
||||
if (deflateInit(&file->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
|
||||
error = GIT_EZLIB;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate the Zlib cache buffer */
|
||||
file->z_buf = git__malloc(file->buf_size);
|
||||
if (file->z_buf == NULL){
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Never flush */
|
||||
file->flush_mode = Z_NO_FLUSH;
|
||||
file->write = &write_deflate;
|
||||
} else {
|
||||
file->write = &write_normal;
|
||||
}
|
||||
|
||||
/* If we are writing to a temp file */
|
||||
if (flags & GIT_FILEBUF_TEMPORARY) {
|
||||
char tmp_path[GIT_PATH_MAX];
|
||||
|
||||
/* Open the file as temporary for locking */
|
||||
file->fd = gitfo_creat_tmp(tmp_path, "_filebuf_");
|
||||
if (file->fd < 0) {
|
||||
error = GIT_EOSERR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* No original path */
|
||||
file->path_original = NULL;
|
||||
file->path_lock = git__strdup(tmp_path);
|
||||
|
||||
if (file->path_lock == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
/* If the file is not temporary, make sure we have a path */
|
||||
if (path == NULL) {
|
||||
error = GIT_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
path_len = strlen(path);
|
||||
|
||||
/* Save the original path of the file */
|
||||
file->path_original = git__strdup(path);
|
||||
if (file->path_original == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* create the locking path by appending ".lock" to the original */
|
||||
file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);
|
||||
if (file->path_lock == NULL) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(file->path_lock, file->path_original, path_len);
|
||||
memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH);
|
||||
|
||||
/* open the file for locking */
|
||||
if ((error = lock_file(file, flags)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
|
||||
@ -187,10 +272,25 @@ int git_filebuf_hash(git_oid *oid, git_filebuf *file)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_filebuf_commit_at(git_filebuf *file, const char *path)
|
||||
{
|
||||
free(file->path_original);
|
||||
file->path_original = git__strdup(path);
|
||||
if (file->path_original == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
return git_filebuf_commit(file);
|
||||
}
|
||||
|
||||
int git_filebuf_commit(git_filebuf *file)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* tmp file cannot be commited */
|
||||
if (file->path_original == NULL)
|
||||
return GIT_EOSERR;
|
||||
|
||||
file->flush_mode = Z_FINISH;
|
||||
if ((error = flush_buffer(file)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
@ -204,16 +304,16 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
GIT_INLINE(void) add_to_cache(git_filebuf *file, void *buf, size_t len)
|
||||
GIT_INLINE(void) add_to_cache(git_filebuf *file, const void *buf, size_t len)
|
||||
{
|
||||
memcpy(file->buffer + file->buf_pos, buf, len);
|
||||
file->buf_pos += len;
|
||||
}
|
||||
|
||||
int git_filebuf_write(git_filebuf *file, void *buff, size_t len)
|
||||
int git_filebuf_write(git_filebuf *file, const void *buff, size_t len)
|
||||
{
|
||||
int error;
|
||||
unsigned char *buf = buff;
|
||||
const unsigned char *buf = buff;
|
||||
|
||||
for (;;) {
|
||||
size_t space_left = file->buf_size - file->buf_pos;
|
||||
@ -237,9 +337,9 @@ int git_filebuf_write(git_filebuf *file, void *buff, size_t len)
|
||||
|
||||
/* write too-large chunks immediately */
|
||||
if (len > file->buf_size) {
|
||||
error = gitfo_write(file->fd, buf, len);
|
||||
if (file->digest)
|
||||
git_hash_update(file->digest, buf, len);
|
||||
error = file->write(file, buf, len);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,17 @@
|
||||
|
||||
#include "fileops.h"
|
||||
#include "hash.h"
|
||||
#include "git2/zlib.h"
|
||||
|
||||
#ifdef GIT_THREADS
|
||||
# define GIT_FILEBUF_THREADS
|
||||
#endif
|
||||
|
||||
#define GIT_FILEBUF_HASH_CONTENTS 0x1
|
||||
#define GIT_FILEBUF_APPEND 0x2
|
||||
#define GIT_FILEBUF_FORCE 0x4
|
||||
#define GIT_FILEBUF_HASH_CONTENTS (1 << 0)
|
||||
#define GIT_FILEBUF_APPEND (1 << 2)
|
||||
#define GIT_FILEBUF_FORCE (1 << 3)
|
||||
#define GIT_FILEBUF_TEMPORARY (1 << 4)
|
||||
#define GIT_FILEBUF_DEFLATE_CONTENTS (1 << 5)
|
||||
|
||||
#define GIT_FILELOCK_EXTENSION ".lock\0"
|
||||
#define GIT_FILELOCK_EXTLENGTH 6
|
||||
@ -19,12 +22,16 @@ struct git_filebuf {
|
||||
char *path_original;
|
||||
char *path_lock;
|
||||
|
||||
int (*write)(struct git_filebuf *file,
|
||||
const void *source, size_t len);
|
||||
|
||||
git_hash_ctx *digest;
|
||||
|
||||
unsigned char *buffer;
|
||||
#ifdef GIT_FILEBUF_THREADS
|
||||
unsigned char *buffer_back;
|
||||
#endif
|
||||
unsigned char *z_buf;
|
||||
|
||||
z_stream zs;
|
||||
int flush_mode;
|
||||
|
||||
size_t buf_size, buf_pos;
|
||||
git_file fd;
|
||||
@ -32,12 +39,13 @@ struct git_filebuf {
|
||||
|
||||
typedef struct git_filebuf git_filebuf;
|
||||
|
||||
int git_filebuf_write(git_filebuf *lock, void *buff, size_t len);
|
||||
int git_filebuf_write(git_filebuf *lock, const void *buff, size_t len);
|
||||
int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len);
|
||||
int git_filebuf_printf(git_filebuf *file, const char *format, ...);
|
||||
|
||||
int git_filebuf_open(git_filebuf *lock, const char *path, int flags);
|
||||
int git_filebuf_commit(git_filebuf *lock);
|
||||
int git_filebuf_commit_at(git_filebuf *lock, const char *path);
|
||||
void git_filebuf_cleanup(git_filebuf *lock);
|
||||
int git_filebuf_hash(git_oid *oid, git_filebuf *file);
|
||||
|
||||
|
@ -2,13 +2,13 @@
|
||||
#include "fileops.h"
|
||||
#include <ctype.h>
|
||||
|
||||
static int force_path(const char *to)
|
||||
int gitfo_mkdir_2file(const char *file_path)
|
||||
{
|
||||
const int mode = 0755; /* or 0777 ? */
|
||||
int error = GIT_SUCCESS;
|
||||
char target_folder_path[GIT_PATH_MAX];
|
||||
|
||||
error = git__dirname_r(target_folder_path, sizeof(target_folder_path), to);
|
||||
error = git__dirname_r(target_folder_path, sizeof(target_folder_path), file_path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
@ -25,6 +25,87 @@ static int force_path(const char *to)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int creat_tempfile(char *path_out, const char *tmp_dir, const char *filename)
|
||||
{
|
||||
int fd;
|
||||
|
||||
git__joinpath(path_out, tmp_dir, filename);
|
||||
strcat(path_out, "_git2_XXXXXX");
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
/* FIXME: there may be race conditions when multi-threading
|
||||
* with the library */
|
||||
if (_mktemp_s(path_out, GIT_PATH_MAX) != 0)
|
||||
return GIT_EOSERR;
|
||||
|
||||
fd = gitfo_creat(path_out, 0744);
|
||||
#else
|
||||
fd = mkstemp(path_out);
|
||||
#endif
|
||||
|
||||
return fd >= 0 ? fd : GIT_EOSERR;
|
||||
}
|
||||
|
||||
static const char *find_tmpdir(void)
|
||||
{
|
||||
static int tmpdir_not_found = 0;
|
||||
static char temp_dir[GIT_PATH_MAX];
|
||||
static const char *env_vars[] = {
|
||||
"TEMP", "TMP", "TMPDIR"
|
||||
};
|
||||
|
||||
unsigned int i, j;
|
||||
char test_file[GIT_PATH_MAX];
|
||||
|
||||
if (tmpdir_not_found)
|
||||
return NULL;
|
||||
|
||||
if (temp_dir[0] != '\0')
|
||||
return temp_dir;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(env_vars); ++i) {
|
||||
char *env_path;
|
||||
|
||||
env_path = getenv(env_vars[i]);
|
||||
if (env_path == NULL)
|
||||
continue;
|
||||
|
||||
strcpy(temp_dir, env_path);
|
||||
|
||||
/* Fix backslashes because Windows environment vars
|
||||
* are probably fucked up */
|
||||
for (j = 0; j < strlen(temp_dir); ++j)
|
||||
if (temp_dir[j] == '\\')
|
||||
temp_dir[j] = '/';
|
||||
|
||||
if (creat_tempfile(test_file, temp_dir, "writetest") >= 0) {
|
||||
gitfo_unlink(test_file);
|
||||
return temp_dir;
|
||||
}
|
||||
}
|
||||
|
||||
/* last resort: current folder. */
|
||||
strcpy(temp_dir, "./");
|
||||
if (creat_tempfile(test_file, temp_dir, "writetest") >= 0) {
|
||||
gitfo_unlink(test_file);
|
||||
return temp_dir;
|
||||
}
|
||||
|
||||
tmpdir_not_found = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int gitfo_creat_tmp(char *path_out, const char *filename)
|
||||
{
|
||||
const char *tmp_dir;
|
||||
|
||||
tmp_dir = find_tmpdir();
|
||||
if (tmp_dir == NULL)
|
||||
return GIT_EOSERR;
|
||||
|
||||
return creat_tempfile(path_out, tmp_dir, filename);
|
||||
}
|
||||
|
||||
int gitfo_open(const char *path, int flags)
|
||||
{
|
||||
int fd = open(path, flags | O_BINARY);
|
||||
@ -39,7 +120,7 @@ int gitfo_creat(const char *path, int mode)
|
||||
|
||||
int gitfo_creat_force(const char *path, int mode)
|
||||
{
|
||||
if (force_path(path) < GIT_SUCCESS)
|
||||
if (gitfo_mkdir_2file(path) < GIT_SUCCESS)
|
||||
return GIT_EOSERR;
|
||||
|
||||
return gitfo_creat(path, mode);
|
||||
@ -117,6 +198,7 @@ int gitfo_isdir(const char *path)
|
||||
|
||||
int gitfo_exists(const char *path)
|
||||
{
|
||||
assert(path);
|
||||
return access(path, F_OK);
|
||||
}
|
||||
|
||||
@ -198,7 +280,7 @@ int gitfo_mv(const char *from, const char *to)
|
||||
|
||||
int gitfo_mv_force(const char *from, const char *to)
|
||||
{
|
||||
if (force_path(to) < GIT_SUCCESS)
|
||||
if (gitfo_mkdir_2file(to) < GIT_SUCCESS)
|
||||
return GIT_EOSERR;
|
||||
|
||||
return gitfo_mv(from, to);
|
||||
|
@ -58,8 +58,10 @@ extern int gitfo_exists(const char *path);
|
||||
extern int gitfo_open(const char *path, int flags);
|
||||
extern int gitfo_creat(const char *path, int mode);
|
||||
extern int gitfo_creat_force(const char *path, int mode);
|
||||
extern int gitfo_creat_tmp(char *path_out, const char *filename);
|
||||
extern int gitfo_isdir(const char *path);
|
||||
extern int gitfo_mkdir_recurs(const char *path, int mode);
|
||||
extern int gitfo_mkdir_2file(const char *path);
|
||||
#define gitfo_close(fd) close(fd)
|
||||
|
||||
extern int gitfo_read(git_file fd, void *buf, size_t cnt);
|
||||
|
@ -324,7 +324,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage)
|
||||
entry.file_size = st.st_size;
|
||||
|
||||
/* write the blob to disk and get the oid */
|
||||
if ((error = git_blob_writefile(&entry.oid, index->repository, full_path)) < GIT_SUCCESS)
|
||||
if ((error = git_blob_create_fromfile(&entry.oid, index->repository, rel_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
entry.flags |= (stage << GIT_IDXENTRY_STAGESHIFT);
|
||||
|
276
src/object.c
276
src/object.c
@ -66,153 +66,6 @@ static struct {
|
||||
{ "REF_DELTA", 0, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Object source methods
|
||||
*
|
||||
* Abstract buffer methods that allow the writeback system
|
||||
* to prepare the contents of any git file in-memory before
|
||||
* writing them to disk.
|
||||
*/
|
||||
static int source_resize(git_odb_source *src)
|
||||
{
|
||||
size_t write_offset, new_size;
|
||||
void *new_data;
|
||||
|
||||
write_offset = (size_t)((char *)src->write_ptr - (char *)src->raw.data);
|
||||
|
||||
new_size = src->raw.len * 2;
|
||||
if ((new_data = git__malloc(new_size)) == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
memcpy(new_data, src->raw.data, src->written_bytes);
|
||||
free(src->raw.data);
|
||||
|
||||
src->raw.data = new_data;
|
||||
src->raw.len = new_size;
|
||||
src->write_ptr = (char *)new_data + write_offset;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git__source_printf(git_odb_source *source, const char *format, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
int len;
|
||||
|
||||
assert(source->open && source->write_ptr);
|
||||
|
||||
va_start(arglist, format);
|
||||
|
||||
len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
|
||||
|
||||
while (source->written_bytes + len >= source->raw.len) {
|
||||
if (source_resize(source) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
|
||||
}
|
||||
|
||||
source->write_ptr = (char *)source->write_ptr + len;
|
||||
source->written_bytes += len;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git__source_write(git_odb_source *source, const void *bytes, size_t len)
|
||||
{
|
||||
assert(source);
|
||||
|
||||
assert(source->open && source->write_ptr);
|
||||
|
||||
while (source->written_bytes + len >= source->raw.len) {
|
||||
if (source_resize(source) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(source->write_ptr, bytes, len);
|
||||
source->write_ptr = (char *)source->write_ptr + len;
|
||||
source->written_bytes += len;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void prepare_write(git_object *object)
|
||||
{
|
||||
if (object->source.write_ptr != NULL || object->source.open)
|
||||
git_object__source_close(object);
|
||||
|
||||
/* TODO: proper size calculation */
|
||||
object->source.raw.data = git__malloc(OBJECT_BASE_SIZE);
|
||||
object->source.raw.len = OBJECT_BASE_SIZE;
|
||||
|
||||
object->source.write_ptr = object->source.raw.data;
|
||||
object->source.written_bytes = 0;
|
||||
|
||||
object->source.open = 1;
|
||||
}
|
||||
|
||||
static int write_back(git_object *object)
|
||||
{
|
||||
int error;
|
||||
git_oid new_id;
|
||||
|
||||
assert(object);
|
||||
|
||||
assert(object->source.open);
|
||||
assert(object->modified);
|
||||
|
||||
object->source.raw.len = object->source.written_bytes;
|
||||
|
||||
if ((error = git_odb_write(&new_id, object->repo->db, &object->source.raw)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (object->in_memory) {
|
||||
int idx = git_vector_search(&object->repo->memory_objects, object);
|
||||
git_vector_remove(&object->repo->memory_objects, idx);
|
||||
} else {
|
||||
git_hashtable_remove(object->repo->objects, &object->id);
|
||||
}
|
||||
|
||||
git_oid_cpy(&object->id, &new_id);
|
||||
git_hashtable_insert(object->repo->objects, &object->id, object);
|
||||
|
||||
object->source.write_ptr = NULL;
|
||||
object->source.written_bytes = 0;
|
||||
|
||||
object->modified = 0;
|
||||
object->in_memory = 0;
|
||||
|
||||
git_object__source_close(object);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_object__source_open(git_object *object)
|
||||
{
|
||||
int error;
|
||||
|
||||
assert(object && !object->in_memory);
|
||||
|
||||
if (object->source.open)
|
||||
git_object__source_close(object);
|
||||
|
||||
error = git_odb_read(&object->source.raw, object->repo->db, &object->id);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
object->source.open = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_object__source_close(git_object *object)
|
||||
{
|
||||
assert(object);
|
||||
|
||||
if (object->source.open) {
|
||||
git_rawobj_close(&object->source.raw);
|
||||
object->source.open = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int create_object(git_object **object_out, git_otype type)
|
||||
{
|
||||
git_object *object = NULL;
|
||||
@ -225,43 +78,19 @@ static int create_object(git_object **object_out, git_otype type)
|
||||
case GIT_OBJ_COMMIT:
|
||||
case GIT_OBJ_TAG:
|
||||
case GIT_OBJ_BLOB:
|
||||
case GIT_OBJ_TREE:
|
||||
object = git__malloc(git_object__size(type));
|
||||
if (object == NULL)
|
||||
return GIT_ENOMEM;
|
||||
memset(object, 0x0, git_object__size(type));
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TREE:
|
||||
object = (git_object *)git_tree__new();
|
||||
if (object == NULL)
|
||||
return GIT_ENOMEM;
|
||||
break;
|
||||
|
||||
default:
|
||||
return GIT_EINVALIDTYPE;
|
||||
}
|
||||
|
||||
*object_out = object;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
object->type = type;
|
||||
|
||||
int git_object_new(git_object **object_out, git_repository *repo, git_otype type)
|
||||
{
|
||||
git_object *object = NULL;
|
||||
int error;
|
||||
|
||||
assert(object_out && repo);
|
||||
|
||||
if ((error = create_object(&object, type)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
object->repo = repo;
|
||||
object->in_memory = 1;
|
||||
object->modified = 1;
|
||||
|
||||
object->source.raw.type = type;
|
||||
|
||||
object->lru = ++repo->lru_counter;
|
||||
*object_out = object;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
@ -269,126 +98,77 @@ int git_object_new(git_object **object_out, git_repository *repo, git_otype type
|
||||
int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type)
|
||||
{
|
||||
git_object *object = NULL;
|
||||
git_rawobj obj_file;
|
||||
git_odb_object *odb_obj;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
assert(repo && object_out && id);
|
||||
|
||||
object = git_hashtable_lookup(repo->objects, id);
|
||||
object = git_cache_get(&repo->objects, id);
|
||||
if (object != NULL) {
|
||||
if (type != GIT_OBJ_ANY && type != object->source.raw.type)
|
||||
if (type != GIT_OBJ_ANY && type != object->type)
|
||||
return GIT_EINVALIDTYPE;
|
||||
|
||||
*object_out = object;
|
||||
object->lru = ++repo->lru_counter;
|
||||
object->can_free = 0;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
error = git_odb_read(&obj_file, repo->db, id);
|
||||
error = git_odb_read(&odb_obj, repo->db, id);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (type != GIT_OBJ_ANY && type != obj_file.type) {
|
||||
git_rawobj_close(&obj_file);
|
||||
if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) {
|
||||
git_odb_object_close(odb_obj);
|
||||
return GIT_EINVALIDTYPE;
|
||||
}
|
||||
|
||||
type = obj_file.type;
|
||||
type = odb_obj->raw.type;
|
||||
|
||||
if ((error = create_object(&object, type)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
/* Initialize parent object */
|
||||
git_oid_cpy(&object->id, id);
|
||||
git_oid_cpy(&object->cached.oid, id);
|
||||
object->repo = repo;
|
||||
memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj));
|
||||
object->source.open = 1;
|
||||
|
||||
switch (type) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
error = git_commit__parse((git_commit *)object);
|
||||
error = git_commit__parse((git_commit *)object, odb_obj);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TREE:
|
||||
error = git_tree__parse((git_tree *)object);
|
||||
error = git_tree__parse((git_tree *)object, odb_obj);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TAG:
|
||||
error = git_tag__parse((git_tag *)object);
|
||||
error = git_tag__parse((git_tag *)object, odb_obj);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_BLOB:
|
||||
error = git_blob__parse((git_blob *)object);
|
||||
error = git_blob__parse((git_blob *)object, odb_obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
git_odb_object_close(odb_obj);
|
||||
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_object__free(object);
|
||||
return error;
|
||||
}
|
||||
|
||||
git_object__source_close(object);
|
||||
git_hashtable_insert(repo->objects, &object->id, object);
|
||||
|
||||
object->lru = ++repo->lru_counter;
|
||||
*object_out = object;
|
||||
*object_out = git_cache_try_store(&repo->objects, object);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_object_write(git_object *object)
|
||||
void git_object__free(void *_obj)
|
||||
{
|
||||
int error;
|
||||
git_odb_source *source;
|
||||
git_object *object = (git_object *)_obj;
|
||||
|
||||
assert(object);
|
||||
|
||||
if (object->modified == 0)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
prepare_write(object);
|
||||
source = &object->source;
|
||||
|
||||
switch (source->raw.type) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
error = git_commit__writeback((git_commit *)object, source);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TREE:
|
||||
error = git_tree__writeback((git_tree *)object, source);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_TAG:
|
||||
error = git_tag__writeback((git_tag *)object, source);
|
||||
break;
|
||||
|
||||
case GIT_OBJ_BLOB:
|
||||
error = git_blob__writeback((git_blob *)object, source);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = GIT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_object__source_close(object);
|
||||
return error;
|
||||
}
|
||||
|
||||
return write_back(object);
|
||||
}
|
||||
|
||||
void git_object__free(git_object *object)
|
||||
{
|
||||
assert(object);
|
||||
|
||||
git_object__source_close(object);
|
||||
|
||||
switch (object->source.raw.type) {
|
||||
switch (object->type) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
git_commit__free((git_commit *)object);
|
||||
break;
|
||||
@ -416,29 +196,19 @@ void git_object_close(git_object *object)
|
||||
if (object == NULL)
|
||||
return;
|
||||
|
||||
if (object->in_memory) {
|
||||
int idx = git_vector_search(&object->repo->memory_objects, object);
|
||||
git_vector_remove(&object->repo->memory_objects, idx);
|
||||
git_object__free(object);
|
||||
} else {
|
||||
object->can_free = 1;
|
||||
}
|
||||
git_cached_obj_decref((git_cached_obj *)object, git_object__free);
|
||||
}
|
||||
|
||||
const git_oid *git_object_id(const git_object *obj)
|
||||
{
|
||||
assert(obj);
|
||||
|
||||
if (obj->in_memory)
|
||||
return NULL;
|
||||
|
||||
return &obj->id;
|
||||
return &obj->cached.oid;
|
||||
}
|
||||
|
||||
git_otype git_object_type(const git_object *obj)
|
||||
{
|
||||
assert(obj);
|
||||
return obj->source.raw.type;
|
||||
return obj->type;
|
||||
}
|
||||
|
||||
git_repository *git_object_owner(const git_object *obj)
|
||||
|
143
src/odb.c
143
src/odb.c
@ -87,55 +87,48 @@ int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *ob
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_rawobj_close(git_rawobj *obj)
|
||||
|
||||
static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source)
|
||||
{
|
||||
free(obj->data);
|
||||
obj->data = NULL;
|
||||
git_odb_object *object = git__malloc(sizeof(git_odb_object));
|
||||
memset(object, 0x0, sizeof(git_odb_object));
|
||||
|
||||
git_oid_cpy(&object->cached.oid, oid);
|
||||
memcpy(&object->raw, source, sizeof(git_rawobj));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
int git_rawobj_hash(git_oid *id, git_rawobj *obj)
|
||||
static void free_odb_object(void *o)
|
||||
{
|
||||
git_odb_object *object = (git_odb_object *)o;
|
||||
|
||||
if (object != NULL) {
|
||||
free(object->raw.data);
|
||||
free(object);
|
||||
}
|
||||
}
|
||||
|
||||
void git_odb_object_close(git_odb_object *object)
|
||||
{
|
||||
git_cached_obj_decref((git_cached_obj *)object, &free_odb_object);
|
||||
}
|
||||
|
||||
int git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type)
|
||||
{
|
||||
char hdr[64];
|
||||
int hdrlen;
|
||||
git_rawobj raw;
|
||||
|
||||
assert(id && obj);
|
||||
assert(id);
|
||||
|
||||
return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj);
|
||||
raw.data = (void *)data;
|
||||
raw.len = len;
|
||||
raw.type = type;
|
||||
|
||||
return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, &raw);
|
||||
}
|
||||
|
||||
int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
|
||||
{
|
||||
z_stream zs;
|
||||
int status = Z_OK;
|
||||
|
||||
memset(&zs, 0x0, sizeof(zs));
|
||||
|
||||
zs.next_out = out;
|
||||
zs.avail_out = outlen;
|
||||
|
||||
zs.next_in = in;
|
||||
zs.avail_in = inlen;
|
||||
|
||||
if (inflateInit(&zs) < Z_OK)
|
||||
return GIT_ERROR;
|
||||
|
||||
while (status == Z_OK)
|
||||
status = inflate(&zs, Z_FINISH);
|
||||
|
||||
inflateEnd(&zs);
|
||||
|
||||
if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
|
||||
return GIT_ERROR;
|
||||
|
||||
if (zs.total_out != outlen)
|
||||
return GIT_ERROR;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
*
|
||||
@ -162,6 +155,8 @@ int git_odb_new(git_odb **out)
|
||||
if (!db)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object);
|
||||
|
||||
if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
|
||||
free(db);
|
||||
return GIT_ENOMEM;
|
||||
@ -306,16 +301,23 @@ void git_odb_close(git_odb *db)
|
||||
}
|
||||
|
||||
git_vector_free(&db->backends);
|
||||
git_cache_free(&db->cache);
|
||||
free(db);
|
||||
}
|
||||
|
||||
int git_odb_exists(git_odb *db, const git_oid *id)
|
||||
{
|
||||
git_odb_object *object;
|
||||
unsigned int i;
|
||||
int found = 0;
|
||||
|
||||
assert(db && id);
|
||||
|
||||
if ((object = git_cache_get(&db->cache, id)) != NULL) {
|
||||
git_odb_object_close(object);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < db->backends.length && !found; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
@ -327,19 +329,27 @@ int git_odb_exists(git_odb *db, const git_oid *id)
|
||||
return found;
|
||||
}
|
||||
|
||||
int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id)
|
||||
int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ENOTFOUND;
|
||||
git_odb_object *object;
|
||||
|
||||
assert(out && db && id);
|
||||
assert(db && id);
|
||||
|
||||
if ((object = git_cache_get(&db->cache, id)) != NULL) {
|
||||
*len_p = object->raw.len;
|
||||
*type_p = object->raw.type;
|
||||
git_odb_object_close(object);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
|
||||
if (b->read_header != NULL)
|
||||
error = b->read_header(out, b, id);
|
||||
error = b->read_header(len_p, type_p, b, id);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -347,37 +357,50 @@ int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id)
|
||||
* try reading the whole object and freeing the contents
|
||||
*/
|
||||
if (error < 0) {
|
||||
error = git_odb_read(out, db, id);
|
||||
git_rawobj_close(out);
|
||||
if ((error = git_odb_read(&object, db, id)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
*len_p = object->raw.len;
|
||||
*type_p = object->raw.len;
|
||||
git_odb_object_close(object);
|
||||
}
|
||||
|
||||
return error;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id)
|
||||
int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ENOTFOUND;
|
||||
git_rawobj raw;
|
||||
|
||||
assert(out && db && id);
|
||||
|
||||
*out = git_cache_get(&db->cache, id);
|
||||
if (*out != NULL)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
|
||||
if (b->read != NULL)
|
||||
error = b->read(out, b, id);
|
||||
error = b->read(&raw.data, &raw.len, &raw.type, b, id);
|
||||
}
|
||||
|
||||
if (error == GIT_SUCCESS) {
|
||||
*out = git_cache_try_store(&db->cache, new_odb_object(id, &raw));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)
|
||||
int git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_otype type)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ERROR;
|
||||
|
||||
assert(obj && db && id);
|
||||
assert(stream && db);
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
@ -387,8 +410,26 @@ int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)
|
||||
if (internal->is_alternate)
|
||||
continue;
|
||||
|
||||
if (b->write != NULL)
|
||||
error = b->write(id, b, obj);
|
||||
if (b->writestream != NULL)
|
||||
error = b->writestream(stream, b, size, type);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid)
|
||||
{
|
||||
unsigned int i;
|
||||
int error = GIT_ERROR;
|
||||
|
||||
assert(stream && db);
|
||||
|
||||
for (i = 0; i < db->backends.length && error < 0; ++i) {
|
||||
backend_internal *internal = git_vector_get(&db->backends, i);
|
||||
git_odb_backend *b = internal->backend;
|
||||
|
||||
if (b->readstream != NULL)
|
||||
error = b->readstream(stream, b, oid);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
18
src/odb.h
18
src/odb.h
@ -3,15 +3,31 @@
|
||||
|
||||
#include "git2/odb.h"
|
||||
#include "git2/oid.h"
|
||||
#include "git2/types.h"
|
||||
|
||||
#include "vector.h"
|
||||
#include "cache.h"
|
||||
|
||||
/* DO NOT EXPORT */
|
||||
typedef struct {
|
||||
void *data; /**< Raw, decompressed object data. */
|
||||
size_t len; /**< Total number of bytes in data. */
|
||||
git_otype type; /**< Type of this object. */
|
||||
} git_rawobj;
|
||||
|
||||
/* EXPORT */
|
||||
struct git_odb_object {
|
||||
git_cached_obj cached;
|
||||
git_rawobj raw;
|
||||
};
|
||||
|
||||
/* EXPORT */
|
||||
struct git_odb {
|
||||
void *_internal;
|
||||
git_vector backends;
|
||||
git_cache cache;
|
||||
};
|
||||
|
||||
int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *obj);
|
||||
int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen);
|
||||
|
||||
#endif
|
||||
|
292
src/odb_loose.c
292
src/odb_loose.c
@ -30,14 +30,22 @@
|
||||
#include "hash.h"
|
||||
#include "odb.h"
|
||||
#include "delta-apply.h"
|
||||
#include "filebuf.h"
|
||||
|
||||
#include "git2/odb_backend.h"
|
||||
#include "git2/types.h"
|
||||
|
||||
typedef struct { /* object header data */
|
||||
git_otype type; /* object type */
|
||||
size_t size; /* object size */
|
||||
} obj_hdr;
|
||||
|
||||
typedef struct {
|
||||
git_odb_stream stream;
|
||||
git_filebuf fbuf;
|
||||
int finished;
|
||||
} loose_writestream;
|
||||
|
||||
typedef struct loose_backend {
|
||||
git_odb_backend parent;
|
||||
|
||||
@ -53,38 +61,6 @@ typedef struct loose_backend {
|
||||
*
|
||||
***********************************************************/
|
||||
|
||||
static int make_temp_file(git_file *fd, char *tmp, size_t n, char *file)
|
||||
{
|
||||
char *template = "/tmp_obj_XXXXXX";
|
||||
size_t tmplen = strlen(template);
|
||||
int dirlen;
|
||||
|
||||
if ((dirlen = git__dirname_r(tmp, n, file)) < 0)
|
||||
return GIT_ERROR;
|
||||
|
||||
if ((dirlen + tmplen) >= n)
|
||||
return GIT_ERROR;
|
||||
|
||||
strcpy(tmp + dirlen, (dirlen) ? template : template + 1);
|
||||
|
||||
*fd = gitfo_mkstemp(tmp);
|
||||
if (*fd < 0 && dirlen) {
|
||||
/* create directory if it doesn't exist */
|
||||
tmp[dirlen] = '\0';
|
||||
if ((gitfo_exists(tmp) < 0) && gitfo_mkdir(tmp, 0755))
|
||||
return GIT_ERROR;
|
||||
/* try again */
|
||||
strcpy(tmp + dirlen, template);
|
||||
*fd = gitfo_mkstemp(tmp);
|
||||
}
|
||||
if (*fd < 0)
|
||||
return GIT_ERROR;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id)
|
||||
{
|
||||
size_t len = strlen(dir);
|
||||
@ -236,64 +212,6 @@ static int finish_inflate(z_stream *s)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int deflate_buf(z_stream *s, void *in, size_t len, int flush)
|
||||
{
|
||||
int status = Z_OK;
|
||||
|
||||
set_stream_input(s, in, len);
|
||||
while (status == Z_OK) {
|
||||
status = deflate(s, flush);
|
||||
if (s->avail_in == 0)
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int deflate_obj(gitfo_buf *buf, char *hdr, int hdrlen, git_rawobj *obj, int level)
|
||||
{
|
||||
z_stream zs;
|
||||
int status;
|
||||
size_t size;
|
||||
|
||||
assert(buf && !buf->data && hdr && obj);
|
||||
assert(level == Z_DEFAULT_COMPRESSION || (level >= 0 && level <= 9));
|
||||
|
||||
buf->data = NULL;
|
||||
buf->len = 0;
|
||||
init_stream(&zs, NULL, 0);
|
||||
|
||||
if (deflateInit(&zs, level) < Z_OK)
|
||||
return GIT_ERROR;
|
||||
|
||||
size = deflateBound(&zs, hdrlen + obj->len);
|
||||
|
||||
if ((buf->data = git__malloc(size)) == NULL) {
|
||||
deflateEnd(&zs);
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
set_stream_output(&zs, buf->data, size);
|
||||
|
||||
/* compress the header */
|
||||
status = deflate_buf(&zs, hdr, hdrlen, Z_NO_FLUSH);
|
||||
|
||||
/* if header compressed OK, compress the object */
|
||||
if (status == Z_OK)
|
||||
status = deflate_buf(&zs, obj->data, obj->len, Z_FINISH);
|
||||
|
||||
if (status != Z_STREAM_END) {
|
||||
deflateEnd(&zs);
|
||||
free(buf->data);
|
||||
buf->data = NULL;
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
buf->len = zs.total_out;
|
||||
deflateEnd(&zs);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int is_zlib_compressed_data(unsigned char *data)
|
||||
{
|
||||
unsigned int w;
|
||||
@ -302,6 +220,36 @@ static int is_zlib_compressed_data(unsigned char *data)
|
||||
return data[0] == 0x78 && !(w % 31);
|
||||
}
|
||||
|
||||
static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
|
||||
{
|
||||
z_stream zs;
|
||||
int status = Z_OK;
|
||||
|
||||
memset(&zs, 0x0, sizeof(zs));
|
||||
|
||||
zs.next_out = out;
|
||||
zs.avail_out = outlen;
|
||||
|
||||
zs.next_in = in;
|
||||
zs.avail_in = inlen;
|
||||
|
||||
if (inflateInit(&zs) < Z_OK)
|
||||
return GIT_ERROR;
|
||||
|
||||
while (status == Z_OK)
|
||||
status = inflate(&zs, Z_FINISH);
|
||||
|
||||
inflateEnd(&zs);
|
||||
|
||||
if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
|
||||
return GIT_ERROR;
|
||||
|
||||
if (zs.total_out != outlen)
|
||||
return GIT_ERROR;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
|
||||
{
|
||||
unsigned char *buf, *head = hb;
|
||||
@ -371,7 +319,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, gitfo_buf *obj)
|
||||
|
||||
in = ((unsigned char *)obj->data) + used;
|
||||
len = obj->len - used;
|
||||
if (git_odb__inflate_buffer(in, len, buf, hdr.size)) {
|
||||
if (inflate_buffer(in, len, buf, hdr.size)) {
|
||||
free(buf);
|
||||
return GIT_ERROR;
|
||||
}
|
||||
@ -505,37 +453,6 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int write_obj(gitfo_buf *buf, git_oid *id, loose_backend *backend)
|
||||
{
|
||||
char file[GIT_PATH_MAX];
|
||||
char temp[GIT_PATH_MAX];
|
||||
git_file fd;
|
||||
|
||||
if (object_file_name(file, sizeof(file), backend->objects_dir, id))
|
||||
return GIT_EOSERR;
|
||||
|
||||
if (make_temp_file(&fd, temp, sizeof(temp), file) < 0)
|
||||
return GIT_EOSERR;
|
||||
|
||||
if (gitfo_write(fd, buf->data, buf->len) < 0) {
|
||||
gitfo_close(fd);
|
||||
gitfo_unlink(temp);
|
||||
return GIT_EOSERR;
|
||||
}
|
||||
|
||||
if (backend->fsync_object_files)
|
||||
gitfo_fsync(fd);
|
||||
gitfo_close(fd);
|
||||
gitfo_chmod(temp, 0444);
|
||||
|
||||
if (gitfo_mv(temp, file) < 0) {
|
||||
gitfo_unlink(temp);
|
||||
return GIT_EOSERR;
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int locate_object(char *object_location, loose_backend *backend, const git_oid *oid)
|
||||
{
|
||||
object_file_name(object_location, GIT_PATH_MAX, backend->objects_dir, oid);
|
||||
@ -558,29 +475,44 @@ static int locate_object(char *object_location, loose_backend *backend, const gi
|
||||
*
|
||||
***********************************************************/
|
||||
|
||||
int loose_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
|
||||
int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
|
||||
{
|
||||
char object_path[GIT_PATH_MAX];
|
||||
git_rawobj raw;
|
||||
int error;
|
||||
|
||||
assert(obj && backend && oid);
|
||||
assert(backend && oid);
|
||||
|
||||
if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return read_header_loose(obj, object_path);
|
||||
if ((error = read_header_loose(&raw, object_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
*len_p = raw.len;
|
||||
*type_p = raw.type;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int loose_backend__read(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
|
||||
int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
|
||||
{
|
||||
char object_path[GIT_PATH_MAX];
|
||||
git_rawobj raw;
|
||||
int error;
|
||||
|
||||
assert(obj && backend && oid);
|
||||
assert(backend && oid);
|
||||
|
||||
if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return read_loose(obj, object_path);
|
||||
if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
*buffer_p = raw.data;
|
||||
*len_p = raw.len;
|
||||
*type_p = raw.type;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
|
||||
@ -592,32 +524,104 @@ int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
|
||||
return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int loose_backend__write(git_oid *id, git_odb_backend *_backend, git_rawobj *obj)
|
||||
int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
|
||||
{
|
||||
loose_writestream *stream = (loose_writestream *)_stream;
|
||||
loose_backend *backend = (loose_backend *)_stream->backend;
|
||||
|
||||
int error;
|
||||
char final_path[GIT_PATH_MAX];
|
||||
|
||||
if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid))
|
||||
return GIT_ENOMEM;
|
||||
|
||||
if ((error = gitfo_mkdir_2file(final_path)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
stream->finished = 1;
|
||||
return git_filebuf_commit_at(&stream->fbuf, final_path);
|
||||
}
|
||||
|
||||
int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
|
||||
{
|
||||
loose_writestream *stream = (loose_writestream *)_stream;
|
||||
return git_filebuf_write(&stream->fbuf, data, len);
|
||||
}
|
||||
|
||||
void loose_backend__stream_free(git_odb_stream *_stream)
|
||||
{
|
||||
loose_writestream *stream = (loose_writestream *)_stream;
|
||||
|
||||
if (!stream->finished)
|
||||
git_filebuf_cleanup(&stream->fbuf);
|
||||
|
||||
free(stream);
|
||||
}
|
||||
|
||||
static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
|
||||
{
|
||||
const char *type_str = git_object_type2string(obj_type);
|
||||
int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len);
|
||||
|
||||
assert(len > 0); /* otherwise snprintf() is broken */
|
||||
assert(((size_t) len) < n); /* otherwise the caller is broken! */
|
||||
|
||||
if (len < 0 || ((size_t) len) >= n)
|
||||
return GIT_ERROR;
|
||||
return len+1;
|
||||
}
|
||||
|
||||
int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type)
|
||||
{
|
||||
loose_backend *backend;
|
||||
loose_writestream *stream;
|
||||
|
||||
char hdr[64];
|
||||
int hdrlen;
|
||||
gitfo_buf buf = GITFO_BUF_INIT;
|
||||
int error;
|
||||
loose_backend *backend;
|
||||
|
||||
assert(id && _backend && obj);
|
||||
assert(_backend);
|
||||
|
||||
backend = (loose_backend *)_backend;
|
||||
*stream_out = NULL;
|
||||
|
||||
if ((error = git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj)) < 0)
|
||||
hdrlen = format_object_header(hdr, sizeof(hdr), length, type);
|
||||
if (hdrlen < GIT_SUCCESS)
|
||||
return GIT_EOBJCORRUPTED;
|
||||
|
||||
stream = git__calloc(1, sizeof(loose_writestream));
|
||||
if (stream == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
stream->stream.backend = _backend;
|
||||
stream->stream.read = NULL; /* read only */
|
||||
stream->stream.write = &loose_backend__stream_write;
|
||||
stream->stream.finalize_write = &loose_backend__stream_fwrite;
|
||||
stream->stream.free = &loose_backend__stream_free;
|
||||
stream->stream.mode = GIT_STREAM_WRONLY;
|
||||
|
||||
error = git_filebuf_open(&stream->fbuf, NULL,
|
||||
GIT_FILEBUF_HASH_CONTENTS |
|
||||
GIT_FILEBUF_DEFLATE_CONTENTS |
|
||||
GIT_FILEBUF_TEMPORARY);
|
||||
|
||||
if (error < GIT_SUCCESS) {
|
||||
free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (git_odb_exists(_backend->odb, id))
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if ((error = deflate_obj(&buf, hdr, hdrlen, obj, backend->object_zlib_level)) < 0)
|
||||
error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_filebuf_cleanup(&stream->fbuf);
|
||||
free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = write_obj(&buf, id, backend);
|
||||
|
||||
gitfo_free_buf(&buf);
|
||||
return error;
|
||||
*stream_out = (git_odb_stream *)stream;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void loose_backend__free(git_odb_backend *_backend)
|
||||
@ -649,7 +653,7 @@ int git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir
|
||||
|
||||
backend->parent.read = &loose_backend__read;
|
||||
backend->parent.read_header = &loose_backend__read_header;
|
||||
backend->parent.write = &loose_backend__write;
|
||||
backend->parent.writestream = &loose_backend__stream;
|
||||
backend->parent.exists = &loose_backend__exists;
|
||||
backend->parent.free = &loose_backend__free;
|
||||
|
||||
|
@ -1243,7 +1243,7 @@ static int packfile_unpack_delta(
|
||||
|
||||
error = packfile_unpack_compressed(&delta, backend, p, w_curs, curpos, delta_size, delta_type);
|
||||
if (error < GIT_SUCCESS) {
|
||||
git_rawobj_close(&base);
|
||||
free(base.data);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1252,8 +1252,8 @@ static int packfile_unpack_delta(
|
||||
base.data, base.len,
|
||||
delta.data, delta.len);
|
||||
|
||||
git_rawobj_close(&base);
|
||||
git_rawobj_close(&delta);
|
||||
free(base.data);
|
||||
free(delta.data);
|
||||
|
||||
/* TODO: we might want to cache this shit. eventually */
|
||||
//add_delta_base_cache(p, base_offset, base, base_size, *type);
|
||||
@ -1337,15 +1337,23 @@ int pack_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const g
|
||||
}
|
||||
*/
|
||||
|
||||
int pack_backend__read(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
|
||||
int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
|
||||
{
|
||||
struct pack_entry e;
|
||||
git_rawobj raw;
|
||||
int error;
|
||||
|
||||
if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
return packfile_unpack(obj, (struct pack_backend *)backend, e.p, e.offset);
|
||||
if ((error = packfile_unpack(&raw, (struct pack_backend *)backend, e.p, e.offset)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
*buffer_p = raw.data;
|
||||
*len_p = raw.len;
|
||||
*type_p = raw.type;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
|
||||
@ -1397,7 +1405,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
|
||||
|
||||
backend->parent.read = &pack_backend__read;
|
||||
backend->parent.read_header = NULL;
|
||||
backend->parent.write = NULL;
|
||||
backend->parent.exists = &pack_backend__exists;
|
||||
backend->parent.free = &pack_backend__free;
|
||||
|
||||
|
14
src/oid.c
14
src/oid.c
@ -143,14 +143,18 @@ int git__parse_oid(git_oid *oid, char **buffer_out,
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid)
|
||||
int git__write_oid(git_odb_stream *stream, const char *header, const git_oid *oid)
|
||||
{
|
||||
char hex_oid[41];
|
||||
char hex_oid[42];
|
||||
|
||||
git_oid_fmt(hex_oid, oid);
|
||||
hex_oid[40] = 0;
|
||||
git_oid_fmt(hex_oid + 1, oid);
|
||||
|
||||
return git__source_printf(src, "%s %s\n", header, hex_oid);
|
||||
hex_oid[0] = ' ';
|
||||
hex_oid[41] = '\n';
|
||||
|
||||
stream->write(stream, header, strlen(header));
|
||||
stream->write(stream, hex_oid, 42);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_oid_mkraw(git_oid *out, const unsigned char *raw)
|
||||
|
@ -40,29 +40,11 @@
|
||||
|
||||
#define GIT_BRANCH_MASTER "master"
|
||||
|
||||
static const int OBJECT_TABLE_SIZE = 32;
|
||||
|
||||
typedef struct {
|
||||
char *path_repository;
|
||||
unsigned is_bare:1, has_been_reinit:1;
|
||||
} repo_init;
|
||||
|
||||
/*
|
||||
* Hash table methods
|
||||
*
|
||||
* Callbacks for the ODB cache, implemented
|
||||
* as a hash table
|
||||
*/
|
||||
static uint32_t object_table_hash(const void *key, int hash_id)
|
||||
{
|
||||
uint32_t r;
|
||||
git_oid *id;
|
||||
|
||||
id = (git_oid *)key;
|
||||
memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Git repository open methods
|
||||
*
|
||||
@ -186,25 +168,9 @@ static git_repository *repository_alloc()
|
||||
|
||||
memset(repo, 0x0, sizeof(git_repository));
|
||||
|
||||
repo->objects = git_hashtable_alloc(
|
||||
OBJECT_TABLE_SIZE,
|
||||
object_table_hash,
|
||||
(git_hash_keyeq_ptr)git_oid_cmp);
|
||||
|
||||
if (repo->objects == NULL) {
|
||||
free(repo);
|
||||
return NULL;
|
||||
}
|
||||
git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
|
||||
|
||||
if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
|
||||
git_hashtable_free(repo->objects);
|
||||
free(repo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (git_vector_init(&repo->memory_objects, 16, NULL) < GIT_SUCCESS) {
|
||||
git_hashtable_free(repo->objects);
|
||||
git_repository__refcache_free(&repo->references);
|
||||
free(repo);
|
||||
return NULL;
|
||||
}
|
||||
@ -330,51 +296,19 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_repository_gc(git_repository *repo)
|
||||
{
|
||||
int collected = 0;
|
||||
git_object *object;
|
||||
const void *_unused;
|
||||
|
||||
GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
|
||||
if (object->can_free) {
|
||||
git_object__free(object);
|
||||
collected++;
|
||||
}
|
||||
);
|
||||
|
||||
return collected;
|
||||
}
|
||||
|
||||
void git_repository_free(git_repository *repo)
|
||||
{
|
||||
git_object *object;
|
||||
const void *_unused;
|
||||
unsigned int i;
|
||||
|
||||
if (repo == NULL)
|
||||
return;
|
||||
|
||||
/* force free all the objects */
|
||||
GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
|
||||
git_object__free(object);
|
||||
);
|
||||
|
||||
for (i = 0; i < repo->memory_objects.length; ++i) {
|
||||
object = git_vector_get(&repo->memory_objects, i);
|
||||
git_object__free(object);
|
||||
}
|
||||
git_cache_free(&repo->objects);
|
||||
git_repository__refcache_free(&repo->references);
|
||||
|
||||
free(repo->path_workdir);
|
||||
free(repo->path_index);
|
||||
free(repo->path_repository);
|
||||
free(repo->path_odb);
|
||||
|
||||
git_hashtable_free(repo->objects);
|
||||
git_vector_free(&repo->memory_objects);
|
||||
|
||||
git_repository__refcache_free(&repo->references);
|
||||
|
||||
if (repo->db != NULL)
|
||||
git_odb_close(repo->db);
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "hashtable.h"
|
||||
#include "index.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
|
||||
#define DOT_GIT ".git"
|
||||
@ -16,28 +17,17 @@
|
||||
#define GIT_OBJECTS_DIR "objects/"
|
||||
#define GIT_INDEX_FILE "index"
|
||||
|
||||
typedef struct {
|
||||
git_rawobj raw;
|
||||
void *write_ptr;
|
||||
size_t written_bytes;
|
||||
int open:1;
|
||||
} git_odb_source;
|
||||
|
||||
struct git_object {
|
||||
git_oid id;
|
||||
git_cached_obj cached;
|
||||
git_repository *repo;
|
||||
git_odb_source source;
|
||||
unsigned int lru;
|
||||
unsigned char in_memory, modified, can_free, _pad;
|
||||
git_otype type;
|
||||
};
|
||||
|
||||
struct git_repository {
|
||||
git_odb *db;
|
||||
git_index *index;
|
||||
|
||||
git_hashtable *objects;
|
||||
git_vector memory_objects;
|
||||
|
||||
git_cache objects;
|
||||
git_refcache references;
|
||||
|
||||
char *path_repository;
|
||||
@ -49,17 +39,11 @@ struct git_repository {
|
||||
unsigned int lru_counter;
|
||||
};
|
||||
|
||||
int git_object__source_open(git_object *object);
|
||||
void git_object__source_close(git_object *object);
|
||||
|
||||
/* fully free the object; internal method, do not
|
||||
* export */
|
||||
void git_object__free(git_object *object);
|
||||
|
||||
int git__source_printf(git_odb_source *source, const char *format, ...);
|
||||
int git__source_write(git_odb_source *source, const void *bytes, size_t len);
|
||||
void git_object__free(void *object);
|
||||
|
||||
int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);
|
||||
int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid);
|
||||
int git__write_oid(git_odb_stream *src, const char *header, const git_oid *oid);
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "commit.h"
|
||||
#include "odb.h"
|
||||
#include "hashtable.h"
|
||||
#include "pqueue.h"
|
||||
|
||||
@ -236,22 +237,22 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
|
||||
|
||||
static int commit_parse(git_revwalk *walk, commit_object *commit)
|
||||
{
|
||||
git_rawobj data;
|
||||
git_odb_object *obj;
|
||||
int error;
|
||||
|
||||
if (commit->parsed)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if ((error = git_odb_read(&data, walk->repo->db, &commit->oid)) < GIT_SUCCESS)
|
||||
if ((error = git_odb_read(&obj, walk->repo->db, &commit->oid)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (data.type != GIT_OBJ_COMMIT) {
|
||||
git_rawobj_close(&data);
|
||||
if (obj->raw.type != GIT_OBJ_COMMIT) {
|
||||
git_odb_object_close(obj);
|
||||
return GIT_EOBJTYPE;
|
||||
}
|
||||
|
||||
error = commit_quick_parse(walk, commit, &data);
|
||||
git_rawobj_close(&data);
|
||||
error = commit_quick_parse(walk, commit, &obj->raw);
|
||||
git_odb_object_close(obj);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -46,13 +46,7 @@ git_signature *git_signature_new(const char *name, const char *email, time_t tim
|
||||
goto cleanup;
|
||||
|
||||
p->name = git__strdup(name);
|
||||
if (p->name == NULL)
|
||||
goto cleanup;
|
||||
|
||||
p->email = git__strdup(email);
|
||||
if (p->email == NULL)
|
||||
goto cleanup;
|
||||
|
||||
p->when.time = time;
|
||||
p->when.offset = offset;
|
||||
|
||||
@ -179,10 +173,12 @@ int git_signature__parse(git_signature *sig, char **buffer_out,
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_signature__write(git_odb_source *src, const char *header, const git_signature *sig)
|
||||
int git_signature__write(char **signature, const char *header, const git_signature *sig)
|
||||
{
|
||||
char sign;
|
||||
int offset, hours, mins;
|
||||
char sig_buffer[2048];
|
||||
int sig_buffer_len;
|
||||
char sign;
|
||||
|
||||
offset = sig->when.offset;
|
||||
sign = (sig->when.offset < 0) ? '-' : '+';
|
||||
@ -193,7 +189,16 @@ int git_signature__write(git_odb_source *src, const char *header, const git_sign
|
||||
hours = offset / 60;
|
||||
mins = offset % 60;
|
||||
|
||||
return git__source_printf(src, "%s %s <%s> %u %c%02d%02d\n", header, sig->name, sig->email, (unsigned)sig->when.time, sign, hours, mins);
|
||||
sig_buffer_len = snprintf(sig_buffer, sizeof(sig_buffer),
|
||||
"%s %s <%s> %u %c%02d%02d\n",
|
||||
header, sig->name, sig->email,
|
||||
(unsigned)sig->when.time, sign, hours, mins);
|
||||
|
||||
if (sig_buffer_len < 0 || (size_t)sig_buffer_len > sizeof(sig_buffer))
|
||||
return GIT_ENOMEM;
|
||||
|
||||
*signature = git__strdup(sig_buffer);
|
||||
return sig_buffer_len;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,6 +7,6 @@
|
||||
#include <time.h>
|
||||
|
||||
int git_signature__parse(git_signature *sig, char **buffer_out, const char *buffer_end, const char *header);
|
||||
int git_signature__write(git_odb_source *src, const char *header, const git_signature *sig);
|
||||
int git_signature__write(char **signature, const char *header, const git_signature *sig);
|
||||
|
||||
#endif
|
||||
|
144
src/tag.c
144
src/tag.c
@ -56,21 +56,6 @@ const git_oid *git_tag_target_oid(git_tag *t)
|
||||
return &t->target;
|
||||
}
|
||||
|
||||
int git_tag_set_target(git_tag *tag, git_object *target)
|
||||
{
|
||||
const git_oid *oid;
|
||||
|
||||
assert(tag && target);
|
||||
|
||||
if ((oid = git_object_id(target)) == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
tag->object.modified = 1;
|
||||
git_oid_cpy(&tag->target, oid);
|
||||
tag->type = git_object_type(target);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
git_otype git_tag_type(git_tag *t)
|
||||
{
|
||||
assert(t);
|
||||
@ -83,50 +68,17 @@ const char *git_tag_name(git_tag *t)
|
||||
return t->tag_name;
|
||||
}
|
||||
|
||||
void git_tag_set_name(git_tag *tag, const char *name)
|
||||
{
|
||||
assert(tag && name);
|
||||
|
||||
tag->object.modified = 1;
|
||||
|
||||
if (tag->tag_name)
|
||||
free(tag->tag_name);
|
||||
|
||||
tag->tag_name = git__strdup(name);
|
||||
}
|
||||
|
||||
const git_signature *git_tag_tagger(git_tag *t)
|
||||
{
|
||||
return t->tagger;
|
||||
}
|
||||
|
||||
void git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig)
|
||||
{
|
||||
assert(tag && tagger_sig);
|
||||
tag->object.modified = 1;
|
||||
|
||||
git_signature_free(tag->tagger);
|
||||
tag->tagger = git_signature_dup(tagger_sig);
|
||||
}
|
||||
|
||||
const char *git_tag_message(git_tag *t)
|
||||
{
|
||||
assert(t);
|
||||
return t->message;
|
||||
}
|
||||
|
||||
void git_tag_set_message(git_tag *tag, const char *message)
|
||||
{
|
||||
assert(tag && message);
|
||||
|
||||
tag->object.modified = 1;
|
||||
|
||||
if (tag->message)
|
||||
free(tag->message);
|
||||
|
||||
tag->message = git__strdup(message);
|
||||
}
|
||||
|
||||
static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
{
|
||||
static const char *tag_types[] = {
|
||||
@ -187,9 +139,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
|
||||
buffer = search + 1;
|
||||
|
||||
if (tag->tagger != NULL)
|
||||
git_signature_free(tag->tagger);
|
||||
|
||||
tag->tagger = git__malloc(sizeof(git_signature));
|
||||
|
||||
if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0)
|
||||
@ -197,9 +146,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
|
||||
text_len = buffer_end - ++buffer;
|
||||
|
||||
if (tag->message != NULL)
|
||||
free(tag->message);
|
||||
|
||||
tag->message = git__malloc(text_len + 1);
|
||||
memcpy(tag->message, buffer, text_len);
|
||||
tag->message[text_len] = '\0';
|
||||
@ -207,26 +153,90 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_tag__writeback(git_tag *tag, git_odb_source *src)
|
||||
int git_tag_create_o(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *tag_name,
|
||||
const git_object *target,
|
||||
const git_signature *tagger,
|
||||
const char *message)
|
||||
{
|
||||
if (tag->tag_name == NULL || tag->tagger == NULL)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
return git_tag_create(
|
||||
oid, repo, tag_name,
|
||||
git_object_id(target),
|
||||
git_object_type(target),
|
||||
tagger, message);
|
||||
}
|
||||
|
||||
git__write_oid(src, "object", &tag->target);
|
||||
git__source_printf(src, "type %s\n", git_object_type2string(tag->type));
|
||||
git__source_printf(src, "tag %s\n", tag->tag_name);
|
||||
git_signature__write(src, "tagger", tag->tagger);
|
||||
int git_tag_create(
|
||||
git_oid *oid,
|
||||
git_repository *repo,
|
||||
const char *tag_name,
|
||||
const git_oid *target,
|
||||
git_otype target_type,
|
||||
const git_signature *tagger,
|
||||
const char *message)
|
||||
{
|
||||
size_t final_size = 0;
|
||||
git_odb_stream *stream;
|
||||
|
||||
if (tag->message != NULL)
|
||||
git__source_printf(src, "\n%s", tag->message);
|
||||
const char *type_str;
|
||||
char *tagger_str;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
int type_str_len, tag_name_len, tagger_str_len, message_len;
|
||||
int error;
|
||||
|
||||
|
||||
type_str = git_object_type2string(target_type);
|
||||
|
||||
tagger_str_len = git_signature__write(&tagger_str, "tagger", tagger);
|
||||
|
||||
type_str_len = strlen(type_str);
|
||||
tag_name_len = strlen(tag_name);
|
||||
message_len = strlen(message);
|
||||
|
||||
final_size += GIT_OID_LINE_LENGTH("object");
|
||||
final_size += STRLEN("type ") + type_str_len + 1;
|
||||
final_size += STRLEN("tag ") + tag_name_len + 1;
|
||||
final_size += tagger_str_len;
|
||||
final_size += 1 + message_len;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_TAG)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
git__write_oid(stream, "object", target);
|
||||
|
||||
stream->write(stream, "type ", STRLEN("type "));
|
||||
stream->write(stream, type_str, type_str_len);
|
||||
|
||||
stream->write(stream, "\ntag ", STRLEN("\ntag "));
|
||||
stream->write(stream, tag_name, tag_name_len);
|
||||
stream->write(stream, "\n", 1);
|
||||
|
||||
stream->write(stream, tagger_str, tagger_str_len);
|
||||
free(tagger_str);
|
||||
|
||||
stream->write(stream, "\n", 1);
|
||||
stream->write(stream, message, message_len);
|
||||
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
if (error == GIT_SUCCESS) {
|
||||
char ref_name[512];
|
||||
git_reference *new_ref;
|
||||
git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
|
||||
error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int git_tag__parse(git_tag *tag)
|
||||
int git_tag__parse(git_tag *tag, git_odb_object *obj)
|
||||
{
|
||||
assert(tag && tag->object.source.open);
|
||||
return parse_tag_buffer(tag, tag->object.source.raw.data, (char *)tag->object.source.raw.data + tag->object.source.raw.len);
|
||||
assert(tag);
|
||||
return parse_tag_buffer(tag, obj->raw.data, (char *)obj->raw.data + obj->raw.len);
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "git2/tag.h"
|
||||
#include "repository.h"
|
||||
#include "odb.h"
|
||||
|
||||
struct git_tag {
|
||||
git_object object;
|
||||
@ -16,7 +17,6 @@ struct git_tag {
|
||||
};
|
||||
|
||||
void git_tag__free(git_tag *tag);
|
||||
int git_tag__parse(git_tag *tag);
|
||||
int git_tag__writeback(git_tag *tag, git_odb_source *src);
|
||||
int git_tag__parse(git_tag *tag, git_odb_object *obj);
|
||||
|
||||
#endif
|
||||
|
@ -8,7 +8,7 @@ typedef struct {
|
||||
volatile int val;
|
||||
} git_atomic;
|
||||
|
||||
static inline void git_atomic_set(git_atomic *a, int val)
|
||||
GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
|
||||
{
|
||||
a->val = val;
|
||||
}
|
||||
@ -36,7 +36,7 @@ static inline void git_atomic_set(git_atomic *a, int val)
|
||||
#define git_cond_signal(c) (void)0 //pthread_cond_signal(c)
|
||||
#define git_cond_broadcast(c) (void)0 //pthread_cond_broadcast(c)
|
||||
|
||||
static inline int git_atomic_inc(git_atomic *a)
|
||||
GIT_INLINE(int) git_atomic_inc(git_atomic *a)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
return __sync_add_and_fetch(&a->val, 1);
|
||||
@ -47,7 +47,7 @@ static inline int git_atomic_inc(git_atomic *a)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int git_atomic_dec(git_atomic *a)
|
||||
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
return __sync_sub_and_fetch(&a->val, 1);
|
||||
@ -81,12 +81,12 @@ static inline int git_atomic_dec(git_atomic *a)
|
||||
#define git_cond_signal(c) (void)0
|
||||
#define git_cond_broadcast(c) (void)0
|
||||
|
||||
static inline int git_atomic_inc(git_atomic *a)
|
||||
GIT_INLINE(int) git_atomic_inc(git_atomic *a)
|
||||
{
|
||||
return ++a->val;
|
||||
}
|
||||
|
||||
static inline int git_atomic_dec(git_atomic *a)
|
||||
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
|
||||
{
|
||||
return --a->val;
|
||||
}
|
||||
|
191
src/tree.c
191
src/tree.c
@ -41,9 +41,11 @@ int entry_search_cmp(const void *key, const void *array_member)
|
||||
return strcmp(filename, entry->filename);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int valid_attributes(const int attributes) {
|
||||
return attributes >= 0 && attributes <= MAX_FILEMODE;
|
||||
}
|
||||
#endif
|
||||
|
||||
int entry_sort_cmp(const void *a, const void *b)
|
||||
{
|
||||
@ -56,13 +58,10 @@ int entry_sort_cmp(const void *a, const void *b)
|
||||
entry_b->attr & 040000);
|
||||
}
|
||||
|
||||
void git_tree_clear_entries(git_tree *tree)
|
||||
void git_tree__free(git_tree *tree)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (tree == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < tree->entries.length; ++i) {
|
||||
git_tree_entry *e;
|
||||
e = git_vector_get(&tree->entries, i);
|
||||
@ -71,32 +70,6 @@ void git_tree_clear_entries(git_tree *tree)
|
||||
free(e);
|
||||
}
|
||||
|
||||
git_vector_clear(&tree->entries);
|
||||
tree->object.modified = 1;
|
||||
}
|
||||
|
||||
|
||||
git_tree *git_tree__new(void)
|
||||
{
|
||||
git_tree *tree;
|
||||
|
||||
tree = git__malloc(sizeof(struct git_tree));
|
||||
if (tree == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(tree, 0x0, sizeof(struct git_tree));
|
||||
|
||||
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) {
|
||||
free(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void git_tree__free(git_tree *tree)
|
||||
{
|
||||
git_tree_clear_entries(tree);
|
||||
git_vector_free(&tree->entries);
|
||||
free(tree);
|
||||
}
|
||||
@ -106,37 +79,6 @@ const git_oid *git_tree_id(git_tree *c)
|
||||
return git_object_id((git_object *)c);
|
||||
}
|
||||
|
||||
int git_tree_entry_set_attributes(git_tree_entry *entry, unsigned int attr)
|
||||
{
|
||||
assert(entry && entry->owner);
|
||||
|
||||
if (!valid_attributes(attr)) {
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
entry->attr = attr;
|
||||
entry->owner->object.modified = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_tree_entry_set_name(git_tree_entry *entry, const char *name)
|
||||
{
|
||||
assert(entry && entry->owner);
|
||||
|
||||
free(entry->filename);
|
||||
entry->filename = git__strdup(name);
|
||||
git_vector_sort(&entry->owner->entries);
|
||||
entry->owner->object.modified = 1;
|
||||
}
|
||||
|
||||
void git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid)
|
||||
{
|
||||
assert(entry && entry->owner);
|
||||
|
||||
git_oid_cpy(&entry->oid, oid);
|
||||
entry->owner->object.modified = 1;
|
||||
}
|
||||
|
||||
unsigned int git_tree_entry_attributes(git_tree_entry *entry)
|
||||
{
|
||||
return entry->attr;
|
||||
@ -154,15 +96,10 @@ const git_oid *git_tree_entry_id(git_tree_entry *entry)
|
||||
return &entry->oid;
|
||||
}
|
||||
|
||||
int git_tree_entry_2object(git_object **object_out, git_tree_entry *entry)
|
||||
int git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry)
|
||||
{
|
||||
assert(entry && object_out);
|
||||
return git_object_lookup(object_out, entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY);
|
||||
}
|
||||
|
||||
static void sort_entries(git_tree *tree)
|
||||
{
|
||||
git_vector_sort(&tree->entries);
|
||||
return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY);
|
||||
}
|
||||
|
||||
git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
|
||||
@ -171,8 +108,6 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
|
||||
|
||||
assert(tree && filename);
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
|
||||
if (idx == GIT_ENOTFOUND)
|
||||
return NULL;
|
||||
@ -183,9 +118,6 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
|
||||
git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
|
||||
{
|
||||
assert(tree);
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
return git_vector_get(&tree->entries, (unsigned int)idx);
|
||||
}
|
||||
|
||||
@ -195,107 +127,12 @@ size_t git_tree_entrycount(git_tree *tree)
|
||||
return tree->entries.length;
|
||||
}
|
||||
|
||||
int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes)
|
||||
{
|
||||
git_tree_entry *entry;
|
||||
|
||||
assert(tree && id && filename);
|
||||
if (!valid_attributes(attributes)) {
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
memset(entry, 0x0, sizeof(git_tree_entry));
|
||||
|
||||
entry->filename = git__strdup(filename);
|
||||
git_oid_cpy(&entry->oid, id);
|
||||
entry->attr = attributes;
|
||||
entry->owner = tree;
|
||||
|
||||
if (git_vector_insert(&tree->entries, entry) < 0)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
if (entry_out != NULL)
|
||||
*entry_out = entry;
|
||||
|
||||
tree->object.modified = 1;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_tree_remove_entry_byindex(git_tree *tree, int idx)
|
||||
{
|
||||
git_tree_entry *remove_ptr;
|
||||
|
||||
assert(tree);
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
remove_ptr = git_vector_get(&tree->entries, (unsigned int)idx);
|
||||
if (remove_ptr == NULL)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
free(remove_ptr->filename);
|
||||
free(remove_ptr);
|
||||
|
||||
tree->object.modified = 1;
|
||||
|
||||
return git_vector_remove(&tree->entries, (unsigned int)idx);
|
||||
}
|
||||
|
||||
int git_tree_remove_entry_byname(git_tree *tree, const char *filename)
|
||||
{
|
||||
int idx;
|
||||
|
||||
assert(tree && filename);
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
|
||||
if (idx == GIT_ENOTFOUND)
|
||||
return GIT_ENOTFOUND;
|
||||
|
||||
return git_tree_remove_entry_byindex(tree, idx);
|
||||
}
|
||||
|
||||
int git_tree__writeback(git_tree *tree, git_odb_source *src)
|
||||
{
|
||||
size_t i;
|
||||
char filemode[MAX_FILEMODE_BYTES + 1 + 1];
|
||||
|
||||
assert(tree && src);
|
||||
|
||||
if (tree->entries.length == 0)
|
||||
return GIT_EMISSINGOBJDATA;
|
||||
|
||||
sort_entries(tree);
|
||||
|
||||
for (i = 0; i < tree->entries.length; ++i) {
|
||||
git_tree_entry *entry;
|
||||
|
||||
entry = git_vector_get(&tree->entries, i);
|
||||
|
||||
snprintf(filemode, sizeof(filemode), "%o ", entry->attr);
|
||||
|
||||
git__source_write(src, filemode, strlen(filemode));
|
||||
git__source_write(src, entry->filename, strlen(entry->filename) + 1);
|
||||
git__source_write(src, entry->oid.id, GIT_OID_RAWSZ);
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
|
||||
{
|
||||
static const size_t avg_entry_size = 40;
|
||||
unsigned int expected_size;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
expected_size = (tree->object.source.raw.len / avg_entry_size) + 1;
|
||||
|
||||
git_tree_clear_entries(tree);
|
||||
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
while (buffer < buffer_end) {
|
||||
git_tree_entry *entry;
|
||||
@ -309,7 +146,6 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
|
||||
if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
entry->owner = tree;
|
||||
entry->attr = strtol(buffer, &buffer, 8);
|
||||
|
||||
if (*buffer++ != ' ') {
|
||||
@ -336,16 +172,9 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_tree__parse(git_tree *tree)
|
||||
int git_tree__parse(git_tree *tree, git_odb_object *obj)
|
||||
{
|
||||
char *buffer, *buffer_end;
|
||||
|
||||
assert(tree && tree->object.source.open);
|
||||
assert(!tree->object.in_memory);
|
||||
|
||||
buffer = tree->object.source.raw.data;
|
||||
buffer_end = buffer + tree->object.source.raw.len;
|
||||
|
||||
return tree_parse_buffer(tree, buffer, buffer_end);
|
||||
assert(tree);
|
||||
return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len);
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,13 @@
|
||||
|
||||
#include "git2/tree.h"
|
||||
#include "repository.h"
|
||||
#include "odb.h"
|
||||
#include "vector.h"
|
||||
|
||||
struct git_tree_entry {
|
||||
unsigned int attr;
|
||||
char *filename;
|
||||
git_oid oid;
|
||||
|
||||
git_tree *owner;
|
||||
};
|
||||
|
||||
struct git_tree {
|
||||
@ -19,8 +18,6 @@ struct git_tree {
|
||||
};
|
||||
|
||||
void git_tree__free(git_tree *tree);
|
||||
git_tree *git_tree__new(void);
|
||||
int git_tree__parse(git_tree *tree);
|
||||
int git_tree__writeback(git_tree *tree, git_odb_source *src);
|
||||
int git_tree__parse(git_tree *tree, git_odb_object *obj);
|
||||
|
||||
#endif
|
||||
|
@ -97,6 +97,8 @@ extern char *git__strtok_keep(char *output, char *src, char *delimit);
|
||||
|
||||
#define STRLEN(str) (sizeof(str) - 1)
|
||||
|
||||
#define GIT_OID_LINE_LENGTH(header) (STRLEN(header) + 1 + GIT_OID_HEXSZ + 1)
|
||||
|
||||
/*
|
||||
* Realloc the buffer pointed at by variable 'x' so that it can hold
|
||||
* at least 'nr' entries; the number of entries currently allocated
|
||||
|
@ -23,9 +23,16 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "test_lib.h"
|
||||
|
||||
#include "odb.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include "t01-data.h"
|
||||
|
||||
#include "hash.h"
|
||||
static int hash_object(git_oid *oid, git_rawobj *obj)
|
||||
{
|
||||
return git_odb_hash(oid, obj->data, obj->len, obj->type);
|
||||
}
|
||||
|
||||
BEGIN_TEST(oid0, "validate size of oid objects")
|
||||
git_oid out;
|
||||
@ -497,28 +504,28 @@ BEGIN_TEST(objhash0, "hash junk data")
|
||||
|
||||
/* invalid types: */
|
||||
junk_obj.data = some_data;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
junk_obj.type = GIT_OBJ__EXT1;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
junk_obj.type = GIT_OBJ__EXT2;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
junk_obj.type = GIT_OBJ_OFS_DELTA;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
junk_obj.type = GIT_OBJ_REF_DELTA;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
|
||||
/* data can be NULL only if len is zero: */
|
||||
junk_obj.type = GIT_OBJ_BLOB;
|
||||
junk_obj.data = NULL;
|
||||
must_pass(git_rawobj_hash(&id, &junk_obj));
|
||||
must_pass(hash_object(&id, &junk_obj));
|
||||
must_be_true(git_oid_cmp(&id, &id_zero) == 0);
|
||||
|
||||
junk_obj.len = 1;
|
||||
must_fail(git_rawobj_hash(&id, &junk_obj));
|
||||
must_fail(hash_object(&id, &junk_obj));
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(objhash1, "hash a commit object")
|
||||
@ -526,7 +533,7 @@ BEGIN_TEST(objhash1, "hash a commit object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, commit_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &commit_obj));
|
||||
must_pass(hash_object(&id2, &commit_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -536,7 +543,7 @@ BEGIN_TEST(objhash2, "hash a tree object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, tree_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &tree_obj));
|
||||
must_pass(hash_object(&id2, &tree_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -546,7 +553,7 @@ BEGIN_TEST(objhash3, "hash a tag object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, tag_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &tag_obj));
|
||||
must_pass(hash_object(&id2, &tag_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -556,7 +563,7 @@ BEGIN_TEST(objhash4, "hash a zero-length object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, zero_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &zero_obj));
|
||||
must_pass(hash_object(&id2, &zero_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -566,7 +573,7 @@ BEGIN_TEST(objhash5, "hash an one-byte long object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, one_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &one_obj));
|
||||
must_pass(hash_object(&id2, &one_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -576,7 +583,7 @@ BEGIN_TEST(objhash6, "hash a two-byte long object")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, two_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &two_obj));
|
||||
must_pass(hash_object(&id2, &two_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
@ -586,7 +593,7 @@ BEGIN_TEST(objhash7, "hash an object several bytes long")
|
||||
|
||||
must_pass(git_oid_mkstr(&id1, some_id));
|
||||
|
||||
must_pass(git_rawobj_hash(&id2, &some_obj));
|
||||
must_pass(hash_object(&id2, &some_obj));
|
||||
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
END_TEST
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
#include "test_lib.h"
|
||||
#include "test_helpers.h"
|
||||
#include "odb.h"
|
||||
|
||||
#include "t02-data.h"
|
||||
#include "t02-oids.h"
|
||||
@ -50,16 +51,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose0, "read a loose commit")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &commit));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, commit.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &commit));
|
||||
must_pass(cmp_objects((git_rawobj *)&obj->raw, &commit));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &commit));
|
||||
END_TEST
|
||||
@ -67,16 +68,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose1, "read a loose tree")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &tree));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, tree.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &tree));
|
||||
must_pass(cmp_objects((git_rawobj *)&obj->raw, &tree));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &tree));
|
||||
END_TEST
|
||||
@ -84,16 +85,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose2, "read a loose tag")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &tag));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, tag.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &tag));
|
||||
must_pass(cmp_objects((git_rawobj *)&obj->raw, &tag));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &tag));
|
||||
END_TEST
|
||||
@ -101,16 +102,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose3, "read a loose zero-bytes object")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &zero));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, zero.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &zero));
|
||||
must_pass(cmp_objects((git_rawobj *)&obj->raw, &zero));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &zero));
|
||||
END_TEST
|
||||
@ -118,16 +119,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose4, "read a one-byte long loose object")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &one));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, one.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &one));
|
||||
must_pass(cmp_objects(&obj->raw, &one));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &one));
|
||||
END_TEST
|
||||
@ -135,16 +136,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose5, "read a two-bytes long loose object")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &two));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, two.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &two));
|
||||
must_pass(cmp_objects(&obj->raw, &two));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &two));
|
||||
END_TEST
|
||||
@ -152,16 +153,16 @@ END_TEST
|
||||
BEGIN_TEST(readloose6, "read a loose object which is several bytes long")
|
||||
git_odb *db;
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(write_object_files(odb_dir, &some));
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id, some.id));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(cmp_objects(&obj, &some));
|
||||
must_pass(cmp_objects(&obj->raw, &some));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(odb_dir, &some));
|
||||
END_TEST
|
||||
@ -174,13 +175,13 @@ BEGIN_TEST(readpack0, "read several packed objects")
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) {
|
||||
git_oid id;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(git_oid_mkstr(&id, packed_objects[i]));
|
||||
must_be_true(git_odb_exists(db, &id) == 1);
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
}
|
||||
|
||||
git_odb_close(db);
|
||||
@ -194,17 +195,19 @@ BEGIN_TEST(readheader0, "read only the header of several packed objects")
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) {
|
||||
git_oid id;
|
||||
git_rawobj obj, header;
|
||||
git_odb_object *obj;
|
||||
size_t len;
|
||||
git_otype type;
|
||||
|
||||
must_pass(git_oid_mkstr(&id, packed_objects[i]));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(git_odb_read_header(&header, db, &id));
|
||||
must_pass(git_odb_read_header(&len, &type, db, &id));
|
||||
|
||||
must_be_true(obj.len == header.len);
|
||||
must_be_true(obj.type == header.type);
|
||||
must_be_true(obj->raw.len == len);
|
||||
must_be_true(obj->raw.type == type);
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
}
|
||||
|
||||
git_odb_close(db);
|
||||
@ -218,19 +221,21 @@ BEGIN_TEST(readheader1, "read only the header of several loose objects")
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(loose_objects); ++i) {
|
||||
git_oid id;
|
||||
git_rawobj obj, header;
|
||||
git_odb_object *obj;
|
||||
size_t len;
|
||||
git_otype type;
|
||||
|
||||
must_pass(git_oid_mkstr(&id, loose_objects[i]));
|
||||
|
||||
must_be_true(git_odb_exists(db, &id) == 1);
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id));
|
||||
must_pass(git_odb_read_header(&header, db, &id));
|
||||
must_pass(git_odb_read_header(&len, &type, db, &id));
|
||||
|
||||
must_be_true(obj.len == header.len);
|
||||
must_be_true(obj.type == header.type);
|
||||
must_be_true(obj->raw.len == len);
|
||||
must_be_true(obj->raw.type == type);
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
}
|
||||
|
||||
git_odb_close(db);
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
#include "test_lib.h"
|
||||
#include "fileops.h"
|
||||
#include "odb.h"
|
||||
|
||||
static char *odb_dir = "test-objects";
|
||||
#include "t03-data.h"
|
||||
@ -80,23 +81,39 @@ static int remove_object_files(object_data *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int streaming_write(git_oid *oid, git_odb *odb, git_rawobj *raw)
|
||||
{
|
||||
git_odb_stream *stream;
|
||||
int error;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, odb, raw->len, raw->type)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
stream->write(stream, raw->data, raw->len);
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
stream->free(stream);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
BEGIN_TEST(write0, "write loose commit object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, commit.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &commit_obj));
|
||||
must_pass(streaming_write(&id2, db, &commit_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&commit));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &commit_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &commit_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&commit));
|
||||
END_TEST
|
||||
@ -104,20 +121,20 @@ END_TEST
|
||||
BEGIN_TEST(write1, "write loose tree object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, tree.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &tree_obj));
|
||||
must_pass(streaming_write(&id2, db, &tree_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&tree));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &tree_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &tree_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&tree));
|
||||
END_TEST
|
||||
@ -125,20 +142,20 @@ END_TEST
|
||||
BEGIN_TEST(write2, "write loose tag object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, tag.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &tag_obj));
|
||||
must_pass(streaming_write(&id2, db, &tag_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&tag));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &tag_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &tag_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&tag));
|
||||
END_TEST
|
||||
@ -146,20 +163,20 @@ END_TEST
|
||||
BEGIN_TEST(write3, "write zero-length object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, zero.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &zero_obj));
|
||||
must_pass(streaming_write(&id2, db, &zero_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&zero));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &zero_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &zero_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&zero));
|
||||
END_TEST
|
||||
@ -167,20 +184,20 @@ END_TEST
|
||||
BEGIN_TEST(write4, "write one-byte long object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, one.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &one_obj));
|
||||
must_pass(streaming_write(&id2, db, &one_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&one));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &one_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &one_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&one));
|
||||
END_TEST
|
||||
@ -188,20 +205,20 @@ END_TEST
|
||||
BEGIN_TEST(write5, "write two-byte long object")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, two.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &two_obj));
|
||||
must_pass(streaming_write(&id2, db, &two_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&two));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &two_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &two_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&two));
|
||||
END_TEST
|
||||
@ -209,20 +226,20 @@ END_TEST
|
||||
BEGIN_TEST(write6, "write an object which is several bytes long")
|
||||
git_odb *db;
|
||||
git_oid id1, id2;
|
||||
git_rawobj obj;
|
||||
git_odb_object *obj;
|
||||
|
||||
must_pass(make_odb_dir());
|
||||
must_pass(git_odb_open(&db, odb_dir));
|
||||
must_pass(git_oid_mkstr(&id1, some.id));
|
||||
|
||||
must_pass(git_odb_write(&id2, db, &some_obj));
|
||||
must_pass(streaming_write(&id2, db, &some_obj));
|
||||
must_be_true(git_oid_cmp(&id1, &id2) == 0);
|
||||
must_pass(check_object_files(&some));
|
||||
|
||||
must_pass(git_odb_read(&obj, db, &id1));
|
||||
must_pass(cmp_objects(&obj, &some_obj));
|
||||
must_pass(cmp_objects(&obj->raw, &some_obj));
|
||||
|
||||
git_rawobj_close(&obj);
|
||||
git_odb_object_close(obj);
|
||||
git_odb_close(db);
|
||||
must_pass(remove_object_files(&some));
|
||||
END_TEST
|
||||
|
@ -407,39 +407,42 @@ This is a commit created in memory and it will be written back to disk\n"
|
||||
|
||||
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
|
||||
|
||||
|
||||
BEGIN_TEST(write0, "write a new commit object from memory to disk")
|
||||
git_repository *repo;
|
||||
git_commit *commit, *parent;
|
||||
git_tree *tree;
|
||||
git_oid id;
|
||||
git_commit *commit;
|
||||
git_oid tree_id, parent_id, commit_id;
|
||||
const git_signature *author, *committer;
|
||||
/* char hex_oid[41]; */
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
/* Create commit in memory */
|
||||
must_pass(git_commit_new(&commit, repo));
|
||||
|
||||
/* Add new parent */
|
||||
git_oid_mkstr(&id, commit_ids[4]);
|
||||
must_pass(git_commit_lookup(&parent, repo, &id));
|
||||
git_oid_mkstr(&tree_id, tree_oid);
|
||||
git_oid_mkstr(&parent_id, commit_ids[4]);
|
||||
|
||||
git_commit_add_parent(commit, parent);
|
||||
|
||||
/* Set other attributes */
|
||||
/* create signatures */
|
||||
committer = git_signature_new(COMMITTER_NAME, COMMITTER_EMAIL, 123456789, 60);
|
||||
must_be_true(committer != NULL);
|
||||
|
||||
author = git_signature_new(COMMITTER_NAME, COMMITTER_EMAIL, 987654321, 90);
|
||||
must_be_true(author != NULL);
|
||||
|
||||
git_commit_set_committer(commit, committer);
|
||||
git_commit_set_author(commit, author);
|
||||
git_commit_set_message(commit, COMMIT_MESSAGE);
|
||||
must_pass(git_commit_create_v(
|
||||
&commit_id, /* out id */
|
||||
repo,
|
||||
NULL, /* do not update the HEAD */
|
||||
author,
|
||||
committer,
|
||||
COMMIT_MESSAGE,
|
||||
&tree_id,
|
||||
1, &parent_id));
|
||||
|
||||
git_signature_free((git_signature *)committer);
|
||||
git_signature_free((git_signature *)author);
|
||||
|
||||
must_pass(git_commit_lookup(&commit, repo, &commit_id));
|
||||
|
||||
/* Check attributes were set correctly */
|
||||
author = git_commit_author(commit);
|
||||
must_be_true(author != NULL);
|
||||
@ -457,47 +460,6 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk")
|
||||
|
||||
must_be_true(strcmp(git_commit_message(commit), COMMIT_MESSAGE) == 0);
|
||||
|
||||
/* add new tree */
|
||||
git_oid_mkstr(&id, tree_oid);
|
||||
must_pass(git_tree_lookup(&tree, repo, &id));
|
||||
|
||||
git_commit_set_tree(commit, tree);
|
||||
|
||||
/* Test it has no OID */
|
||||
must_be_true(git_commit_id(commit) == NULL);
|
||||
|
||||
/* Write to disk */
|
||||
must_pass(git_object_write((git_object *)commit));
|
||||
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit));
|
||||
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(write1, "load a commit object, modify it and write it back")
|
||||
git_repository *repo;
|
||||
git_oid id;
|
||||
git_commit *commit, *parent;
|
||||
const char *message;
|
||||
/* char hex_oid[41]; */
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
git_oid_mkstr(&id, commit_ids[0]);
|
||||
|
||||
must_pass(git_commit_lookup(&commit, repo, &id));
|
||||
|
||||
message = git_commit_message(commit);
|
||||
|
||||
git_commit_set_message(commit, "This is a new test message. Cool!\n");
|
||||
|
||||
git_oid_mkstr(&id, commit_ids[4]);
|
||||
must_pass(git_commit_lookup(&parent, repo, &id));
|
||||
|
||||
git_commit_add_parent(commit, parent);
|
||||
|
||||
must_pass(git_object_write((git_object *)commit));
|
||||
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit));
|
||||
|
||||
git_repository_free(repo);
|
||||
@ -509,6 +471,7 @@ BEGIN_SUITE(commit)
|
||||
ADD_TEST(parse1);
|
||||
ADD_TEST(parse2);
|
||||
ADD_TEST(details0);
|
||||
|
||||
ADD_TEST(write0);
|
||||
ADD_TEST(write1);
|
||||
//ADD_TEST(write1);
|
||||
END_SUITE
|
||||
|
@ -61,27 +61,62 @@ BEGIN_TEST(read0, "read and parse a tag from the repository")
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(write0, "write back a tag to the repository")
|
||||
git_oid id;
|
||||
|
||||
#define TAGGER_NAME "Vicent Marti"
|
||||
#define TAGGER_EMAIL "vicent@github.com"
|
||||
#define TAGGER_MESSAGE "This is my tag.\n\nThere are many tags, but this one is mine\n"
|
||||
|
||||
BEGIN_TEST(write0, "write a tag to the repository and read it again")
|
||||
git_repository *repo;
|
||||
git_tag *tag;
|
||||
git_oid target_id, tag_id;
|
||||
const git_signature *tagger;
|
||||
git_reference *ref_tag;
|
||||
/* char hex_oid[41]; */
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
git_oid_mkstr(&id, tag1_id);
|
||||
git_oid_mkstr(&target_id, tagged_commit);
|
||||
|
||||
must_pass(git_tag_lookup(&tag, repo, &id));
|
||||
/* create signatures */
|
||||
tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
|
||||
must_be_true(tagger != NULL);
|
||||
|
||||
git_tag_set_name(tag, "This is a different tag LOL");
|
||||
must_pass(git_tag_create(
|
||||
&tag_id, /* out id */
|
||||
repo,
|
||||
"the-tag", /* do not update the HEAD */
|
||||
&target_id,
|
||||
GIT_OBJ_COMMIT,
|
||||
tagger,
|
||||
TAGGER_MESSAGE));
|
||||
|
||||
git_signature_free((git_signature *)tagger);
|
||||
|
||||
must_pass(git_tag_lookup(&tag, repo, &tag_id));
|
||||
|
||||
/* Check attributes were set correctly */
|
||||
tagger = git_tag_tagger(tag);
|
||||
must_be_true(tagger != NULL);
|
||||
must_be_true(strcmp(tagger->name, TAGGER_NAME) == 0);
|
||||
must_be_true(strcmp(tagger->email, TAGGER_EMAIL) == 0);
|
||||
must_be_true(tagger->when.time == 123456789);
|
||||
must_be_true(tagger->when.offset == 60);
|
||||
|
||||
must_be_true(strcmp(git_tag_message(tag), TAGGER_MESSAGE) == 0);
|
||||
|
||||
must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/the-tag"));
|
||||
must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &tag_id) == 0);
|
||||
must_pass(git_reference_delete(ref_tag));
|
||||
|
||||
must_pass(git_object_write((git_object *)tag));
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag));
|
||||
|
||||
git_repository_free(repo);
|
||||
|
||||
END_TEST
|
||||
|
||||
|
||||
BEGIN_SUITE(tag)
|
||||
ADD_TEST(read0);
|
||||
ADD_TEST(write0);
|
||||
ADD_TEST(write0);
|
||||
END_SUITE
|
||||
|
@ -75,93 +75,15 @@ BEGIN_TEST(read1, "read a tree from the repository")
|
||||
|
||||
must_be_true(strcmp(git_tree_entry_name(entry), "README") == 0);
|
||||
|
||||
must_pass(git_tree_entry_2object(&obj, entry));
|
||||
must_pass(git_tree_entry_2object(&obj, repo, entry));
|
||||
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(write0, "add a new entry to a tree and write it back to disk")
|
||||
const unsigned int entry_count = 128;
|
||||
|
||||
git_repository *repo;
|
||||
git_tree *tree;
|
||||
unsigned int i;
|
||||
git_oid entry_id;
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
must_pass(git_tree_new(&tree, repo));
|
||||
|
||||
git_oid_mkstr(&entry_id, tree_oid);
|
||||
for (i = 0; i < entry_count; ++i) {
|
||||
char filename[32];
|
||||
git_tree_entry *ent = NULL;
|
||||
|
||||
sprintf(filename, "file%d.txt", i);
|
||||
must_pass(git_tree_add_entry(&ent, tree, &entry_id, filename, 040000));
|
||||
must_be_true(ent != NULL);
|
||||
}
|
||||
|
||||
must_be_true(git_tree_entrycount(tree) == entry_count);
|
||||
must_pass(git_object_write((git_object *)tree));
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tree));
|
||||
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
BEGIN_TEST(write1, "add several entries in-memory and validate that they exist; write back to disk")
|
||||
git_oid id;
|
||||
git_repository *repo;
|
||||
git_tree *tree;
|
||||
git_tree_entry *entry;
|
||||
unsigned int i;
|
||||
/* char hex_oid[41]; */
|
||||
|
||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||
|
||||
git_oid_mkstr(&id, tree_oid);
|
||||
|
||||
must_pass(git_tree_lookup(&tree, repo, &id));
|
||||
|
||||
must_be_true(git_tree_entrycount(tree) == 3);
|
||||
|
||||
/* check there is NP if we don't want the
|
||||
* created entry back */
|
||||
git_tree_add_entry(NULL, tree, &id, "zzz_test_entry.dat", 0);
|
||||
git_tree_add_entry(NULL, tree, &id, "01_test_entry.txt", 0);
|
||||
|
||||
must_be_true(git_tree_entrycount(tree) == 5);
|
||||
|
||||
entry = git_tree_entry_byindex(tree, 0);
|
||||
must_be_true(strcmp(git_tree_entry_name(entry), "01_test_entry.txt") == 0);
|
||||
|
||||
entry = git_tree_entry_byindex(tree, 4);
|
||||
must_be_true(strcmp(git_tree_entry_name(entry), "zzz_test_entry.dat") == 0);
|
||||
|
||||
must_pass(git_tree_remove_entry_byname(tree, "README"));
|
||||
must_be_true(git_tree_entrycount(tree) == 4);
|
||||
|
||||
for (i = 0; i < git_tree_entrycount(tree); ++i) {
|
||||
entry = git_tree_entry_byindex(tree, i);
|
||||
must_be_true(strcmp(git_tree_entry_name(entry), "README") != 0);
|
||||
}
|
||||
|
||||
must_pass(git_object_write((git_object *)tree));
|
||||
|
||||
/*
|
||||
git_oid_fmt(hex_oid, git_tree_id(tree));
|
||||
hex_oid[40] = 0;
|
||||
printf("TREE New SHA1: %s\n", hex_oid);
|
||||
*/
|
||||
|
||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tree));
|
||||
git_repository_free(repo);
|
||||
END_TEST
|
||||
|
||||
|
||||
BEGIN_SUITE(tree)
|
||||
ADD_TEST(read0);
|
||||
ADD_TEST(read1);
|
||||
ADD_TEST(write0);
|
||||
ADD_TEST(write1);
|
||||
// ADD_TEST(write0); /* TODO THREADSAFE */
|
||||
// ADD_TEST(write1);
|
||||
END_SUITE
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "git2/odb_backend.h"
|
||||
|
||||
|
||||
static int cmp_objects(git_rawobj *o1, git_rawobj *o2)
|
||||
static int cmp_objects(raw_object *o1, raw_object *o2)
|
||||
{
|
||||
if (o1->type != o2->type)
|
||||
return -1;
|
||||
@ -62,7 +62,7 @@ static git_odb *open_sqlite_odb(void)
|
||||
#define TEST_WRITE(PTR) {\
|
||||
git_odb *db; \
|
||||
git_oid id1, id2; \
|
||||
git_rawobj obj; \
|
||||
raw_object obj; \
|
||||
db = open_sqlite_odb(); \
|
||||
must_be_true(db != NULL); \
|
||||
must_pass(git_oid_mkstr(&id1, PTR.id)); \
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include "test_lib.h"
|
||||
#include <git2.h>
|
||||
|
||||
#include "odb.h"
|
||||
|
||||
#define TEST_REPOSITORY_NAME "testrepo.git"
|
||||
#define REPOSITORY_FOLDER TEST_RESOURCES "/" TEST_REPOSITORY_NAME "/"
|
||||
#define ODB_FOLDER (REPOSITORY_FOLDER "objects/")
|
||||
|
Loading…
Reference in New Issue
Block a user