diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileops.c | 7 | ||||
| -rw-r--r-- | src/fileops.h | 1 | ||||
| -rw-r--r-- | src/git/index.h | 50 | ||||
| -rw-r--r-- | src/git/repository.h | 33 | ||||
| -rw-r--r-- | src/index.c | 18 | ||||
| -rw-r--r-- | src/index.h | 27 | ||||
| -rw-r--r-- | src/repository.c | 101 | ||||
| -rw-r--r-- | src/repository.h | 9 | 
8 files changed, 205 insertions, 41 deletions
diff --git a/src/fileops.c b/src/fileops.c index f101cec32..e0a5ff461 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -53,6 +53,13 @@ int gitfo_write(git_file fd, void *buf, size_t cnt)  	return GIT_SUCCESS;  } +int gitfo_isdir(const char *path) +{ +	struct stat st; +	return (path && gitfo_stat(path, &st) == 0 && S_ISDIR(st.st_mode)) ?  +		GIT_SUCCESS : GIT_ENOTFOUND; +} +  int gitfo_exists(const char *path)  {  	return access(path, F_OK); diff --git a/src/fileops.h b/src/fileops.h index 2da4231d0..618bddd5b 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -57,6 +57,7 @@ typedef struct {  /* file io buffer  */  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_isdir(const char *path);  #define gitfo_close(fd) close(fd)  extern int gitfo_read(git_file fd, void *buf, size_t cnt); diff --git a/src/git/index.h b/src/git/index.h index 46fccbd74..3b262355e 100644 --- a/src/git/index.h +++ b/src/git/index.h @@ -1,6 +1,7 @@  #ifndef INCLUDE_git_index_h__  #define INCLUDE_git_index_h__ +#include <stdint.h>  #include "common.h"  #include "oid.h" @@ -16,18 +17,50 @@ GIT_BEGIN_DECL  /** Memory representation of an index file. */  typedef struct git_index git_index; + +/** Time used in a git index entry */ +typedef struct { +	uint32_t seconds; +	uint32_t nanoseconds; +} git_index_time; +  /** Memory representation of a file entry in the index. */ -typedef struct git_index_entry git_index_entry; +typedef struct git_index_entry { +	git_index_time ctime; +	git_index_time mtime; + +	uint32_t dev; +	uint32_t ino; +	uint32_t mode; +	uint32_t uid; +	uint32_t gid; +	uint32_t file_size; + +	git_oid oid; + +	uint16_t flags; +	uint16_t flags_extended; + +	char *path; +} git_index_entry;  /**   * Create a new Git index object as a memory representation   * of the Git index file in 'index_path'.   * + * The argument 'working_dir' is the root path of the indexed + * files in the index and is used to calculate the relative path + * when inserting new entries from existing files on disk. + * + * If 'working _dir' is NULL (e.g for bare repositories), the + * methods working on on-disk files will fail. + *   * @param index_path the path to the index file in disk + * @param working_dir working dir for the git repository   * @return the index object; NULL if the index could not be created   */ -GIT_EXTERN(git_index *) git_index_alloc(const char *index_path); +GIT_EXTERN(git_index *) git_index_alloc(const char *index_path, const char *working_dir);  /**   * Clear the contents (all the entries) of an index object. @@ -83,6 +116,19 @@ GIT_EXTERN(int) git_index_find(git_index *index, const char *path);   */  GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage); +/** + * Get a pointer to one of the entries in the index + * + * This entry can be modified, and the changes will be written + * back to disk on the next write() call. + * + * @param index an existing index object + * @param n the position of the entry + * @return a pointer to the entry; NULL if out of bounds + */ +GIT_EXTERN(git_index_entry *) git_index_get(git_index *index, int n); + +  /** @} */  GIT_END_DECL  #endif diff --git a/src/git/repository.h b/src/git/repository.h index 0a50fe1ef..058849b7f 100644 --- a/src/git/repository.h +++ b/src/git/repository.h @@ -4,6 +4,7 @@  #include "common.h"  #include "odb.h"  #include "commit.h" +#include "index.h"  /**   * @file git/repository.h @@ -15,15 +16,28 @@  GIT_BEGIN_DECL  /** - * Allocate a new repository object. + * Open a git repository.   * - * TODO: specify the repository's path instead - * of its object database + * The 'path' argument must point to an existing git repository + * folder, e.g.   * - * @param odb an existing object database to back the repo + *		/path/to/my_repo/.git/	(normal repository) + *							objects/ + *							index + *							HEAD + * + *		/path/to/bare_repo/		(bare repository) + *						objects/ + *						index + *						HEAD + * + *	The method will automatically detect if 'path' is a normal + *	or bare repository or fail is 'path' is neither. + * + * @param path the path to the repository   * @return the new repository handle; NULL on error   */ -GIT_EXTERN(git_repository *) git_repository_alloc(git_odb *odb); +GIT_EXTERN(git_repository *) git_repository_open(const char *path);  /** @@ -58,6 +72,15 @@ GIT_EXTERN(git_object *) git_repository_lookup(git_repository *repo, const git_o  GIT_EXTERN(git_odb *) git_repository_database(git_repository *repo);  /** + * Get the Index file of a Git repository + * + * @param repo a repository object + * @return a pointer to the Index object;  + *	NULL if the index cannot be opened + */ +GIT_EXTERN(git_index *) git_repository_index(git_repository *rpeo); + +/**   * Create a new in-memory repository object with   * the given type.   * diff --git a/src/index.c b/src/index.c index 991f1b126..9996c50fe 100644 --- a/src/index.c +++ b/src/index.c @@ -97,7 +97,7 @@ static int read_tree(git_index *index, const char *buffer, size_t buffer_size);  static git_index_tree *read_tree_internal(const char **, const char *, git_index_tree *); -git_index *git_index_alloc(const char *index_path) +git_index *git_index_alloc(const char *index_path, const char *work_dir)  {  	git_index *index; @@ -116,6 +116,9 @@ git_index *git_index_alloc(const char *index_path)  		return NULL;  	} +	if (work_dir != NULL) +		index->working_path = git__strdup(work_dir); +  	/* Check if index file is stored on disk already */  	if (gitfo_exists(index->index_file_path) == 0)  		index->on_disk = 1; @@ -126,6 +129,9 @@ git_index *git_index_alloc(const char *index_path)  void git_index_clear(git_index *index)  {  	unsigned int i; + +	assert(index); +  	for (i = 0; i < index->entry_count; ++i)  		free(index->entries[i].path); @@ -139,6 +145,9 @@ void git_index_clear(git_index *index)  void git_index_free(git_index *index)  { +	if (index == NULL) +		return; +  	git_index_clear(index);  	free(index->entries);  	index->entries = NULL; @@ -213,6 +222,11 @@ int git_index_write(git_index *index)  	return 0;  } +git_index_entry *git_index_get(git_index *index, int n) +{ +	return (n >= 0 && (unsigned int)n < index->entry_count) ? &index->entries[n] : NULL; +} +  int git_index_add(git_index *index, const char *filename, int stage)  {  	git_index_entry entry; @@ -225,7 +239,7 @@ int git_index_add(git_index *index, const char *filename, int stage)  	if (path_length < GIT_IDXENTRY_NAMEMASK)  		entry.flags |= path_length;  	else -		entry.flags |= path_length; +		entry.flags |= GIT_IDXENTRY_NAMEMASK;;  	if (stage < 0 || stage > 3)  		return GIT_ERROR; diff --git a/src/index.h b/src/index.h index 44da78f9b..6a3c11e82 100644 --- a/src/index.h +++ b/src/index.h @@ -12,31 +12,6 @@  #define GIT_IDXENTRY_VALID     (0x8000)  #define GIT_IDXENTRY_STAGESHIFT 12 -typedef struct { -	uint32_t seconds; -	uint32_t nanoseconds; -} git_index_time; - -struct git_index_entry { -	git_index_time ctime; -	git_index_time mtime; - -	uint32_t dev; -	uint32_t ino; -	uint32_t mode; -	uint32_t uid; -	uint32_t gid; -	uint32_t file_size; - -	git_oid oid; - -	uint16_t flags; -	uint16_t flags_extended; - -	char *path; -}; - -  struct git_index_tree {  	char *name; @@ -53,6 +28,8 @@ typedef struct git_index_tree git_index_tree;  struct git_index {  	char *index_file_path; +	char *working_path; +  	time_t last_modified;  	git_index_entry *entries; diff --git a/src/repository.c b/src/repository.c index fe7b870fe..433e72916 100644 --- a/src/repository.c +++ b/src/repository.c @@ -28,6 +28,7 @@  #include "repository.h"  #include "commit.h"  #include "tag.h" +#include "fileops.h"  static const int default_table_size = 32;  static const double max_load_factor = 0.65; @@ -43,7 +44,7 @@ static const size_t object_sizes[] = {  }; -uint32_t git_object_hash(const void *key) +uint32_t git__objtable_hash(const void *key)  {  	uint32_t r;  	git_oid *id; @@ -53,7 +54,7 @@ uint32_t git_object_hash(const void *key)  	return r;  } -int git_object_haskey(void *object, const void *key) +int git__objtable_haskey(void *object, const void *key)  {  	git_object *obj;  	git_oid *oid; @@ -64,7 +65,62 @@ int git_object_haskey(void *object, const void *key)  	return (git_oid_cmp(oid, &obj->id) == 0);  } -git_repository *git_repository_alloc(git_odb *odb) +static int parse_repository_folders(git_repository *repo, const char *repository_path) +{ +	char path_aux[GIT_PATH_MAX]; +	int path_len, i; + +	if (gitfo_isdir(repository_path) < 0) +		return GIT_ERROR; + +	path_len = strlen(repository_path); +	strcpy(path_aux, repository_path); + +	if (path_aux[path_len - 1] != '/') { +		path_aux[path_len] = '/'; +		path_aux[path_len + 1] = 0; + +		path_len = path_len + 1; +	} + +	repo->path_repository = git__strdup(path_aux); + +	/* objects database */ +	strcpy(path_aux + path_len, "objects/"); +	if (gitfo_isdir(path_aux) < 0) +		return GIT_ERROR; +	repo->path_odb = git__strdup(path_aux); + +	/* index file */ +	strcpy(path_aux + path_len, "index"); +	if (gitfo_exists(path_aux) < 0) +		return GIT_ERROR; +	repo->path_index = git__strdup(path_aux); + +	/* HEAD file */ +	strcpy(path_aux + path_len, "HEAD"); +	if (gitfo_exists(path_aux) < 0) +		return GIT_ERROR; + +	i = path_len - 2; +	while (path_aux[i] != '/') +		i--; + +	if (strcmp(path_aux, "/.git/") == 0) { +		repo->is_bare = 0; + +		path_aux[i + 1] = 0; +		repo->path_workdir = git__strdup(path_aux); + +	} else { +		repo->is_bare = 1; +		repo->path_workdir = NULL; +	} + +	return GIT_SUCCESS; +} + +git_repository *git_repository__alloc()  {  	git_repository *repo = git__malloc(sizeof(git_repository));  	if (!repo) @@ -74,15 +130,30 @@ git_repository *git_repository_alloc(git_odb *odb)  	repo->objects = git_hashtable_alloc(  			default_table_size,  -			git_object_hash, -			git_object_haskey); +			git__objtable_hash, +			git__objtable_haskey);  	if (repo->objects == NULL) {  		free(repo);  		return NULL;  	} -	repo->db = odb; /* TODO: create ODB manually! */ +	return repo; +} + +git_repository *git_repository_open(const char *path) +{ +	git_repository *repo; + +	repo = git_repository__alloc(); +	if (repo == NULL) +		return NULL; + +	if (parse_repository_folders(repo, path) < 0 || +		git_odb_open(&repo->db, repo->path_odb) < 0) { +		git_repository_free(repo); +		return NULL; +	}  	return repo;  } @@ -92,6 +163,11 @@ void git_repository_free(git_repository *repo)  	git_hashtable_iterator it;  	git_object *object; +	free(repo->path_workdir); +	free(repo->path_index); +	free(repo->path_repository); +	free(repo->path_odb); +  	git_hashtable_iterator_init(repo->objects, &it);  	while ((object = (git_object *) @@ -99,10 +175,21 @@ void git_repository_free(git_repository *repo)  		git_object_free(object);  	git_hashtable_free(repo->objects); -	/* TODO: free odb */ +	git_odb_close(repo->db); +	git_index_free(repo->index);  	free(repo);  } +git_index *git_repository_index(git_repository *repo) +{ +	if (repo->index == NULL) { +		repo->index = git_index_alloc(repo->path_index, repo->path_workdir); +		assert(repo->index && repo->index->on_disk); +	} + +	return repo->index; +} +  static int source_resize(git_odb_source *src)  {  	size_t write_offset, new_size; diff --git a/src/repository.h b/src/repository.h index 0ccfc5e92..ca76d4558 100644 --- a/src/repository.h +++ b/src/repository.h @@ -7,6 +7,7 @@  #include "git/repository.h"  #include "hashtable.h" +#include "index.h"  typedef struct {  	git_rawobj raw; @@ -24,7 +25,15 @@ struct git_object {  struct git_repository {  	git_odb *db; +	git_index *index;  	git_hashtable *objects; + +	char *path_repository; +	char *path_index; +	char *path_odb; +	char *path_workdir; + +	unsigned is_bare:1;  };  | 
