diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileops.c | 38 | ||||
| -rw-r--r-- | src/fileops.h | 1 | ||||
| -rw-r--r-- | src/path.c | 50 | ||||
| -rw-r--r-- | src/path.h | 5 | ||||
| -rw-r--r-- | src/repository.c | 171 | ||||
| -rw-r--r-- | src/unix/posix.h | 2 | ||||
| -rw-r--r-- | src/win32/posix.c | 11 | ||||
| -rw-r--r-- | src/win32/posix.h | 1 | 
8 files changed, 154 insertions, 125 deletions
diff --git a/src/fileops.c b/src/fileops.c index 486ea3bbe..275934ca1 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -125,18 +125,16 @@ int git_futils_isfile(const char *path)  	struct stat st;  	int stat_error; -	if (!path) -		return git__throw(GIT_ENOTFOUND, "No path given to git_futils_isfile"); - +	assert(path);  	stat_error = p_stat(path, &st);  	if (stat_error < GIT_SUCCESS) -		return git__throw(GIT_ENOTFOUND, "%s does not exist", path); +		return -1;  	if (!S_ISREG(st.st_mode)) -		return git__throw(GIT_ENOTFOUND, "%s is not a file", path); +		return -1; -	return GIT_SUCCESS; +	return 0;  }  int git_futils_exists(const char *path) @@ -149,7 +147,8 @@ git_off_t git_futils_filesize(git_file fd)  {  	struct stat sb;  	if (p_fstat(fd, &sb)) -		return git__throw(GIT_EOSERR, "Failed to get size of file. File missing or corrupted"); +		return GIT_ERROR; +  	return sb.st_size;  } @@ -273,22 +272,6 @@ int git_futils_direach(  	return GIT_SUCCESS;  } -int git_futils_root_offset(const char *path) -{ -	int offset = 0; - -#ifdef GIT_WIN32 -	/* Does the root of the path look like a windows drive ? */ -	if (isalpha(path[0]) && (path[1] == ':')) -		offset += 2; -#endif - -	if (*(path + offset) == '/') -		return offset; - -	return -1;	/* Not a real error. Rather a signal than the path is not rooted */ -} -  int git_futils_mkdir_r(const char *path, int mode)  {  	int error, root_path_offset; @@ -301,7 +284,7 @@ int git_futils_mkdir_r(const char *path, int mode)  	error = GIT_SUCCESS;  	pp = path_copy; -	root_path_offset = git_futils_root_offset(pp); +	root_path_offset = git_path_root(pp);  	if (root_path_offset > 0)  		pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */ @@ -338,7 +321,7 @@ static int retrieve_previous_path_component_start(const char *path)  {  	int offset, len, root_offset, start = 0; -	root_offset = git_futils_root_offset(path); +	root_offset = git_path_root(path);  	if (root_offset > -1)  		start += root_offset; @@ -373,7 +356,7 @@ int git_futils_prettify_dir(char *buffer_out, size_t size, const char *path, con  	buffer_end = path + strlen(path);  	buffer_out_start = buffer_out; -	root_path_offset = git_futils_root_offset(path); +	root_path_offset = git_path_root(path);  	if (root_path_offset < 0) {  		if (base_path == NULL) {  			error = p_getcwd(buffer_out, size); @@ -446,7 +429,6 @@ int git_futils_prettify_dir(char *buffer_out, size_t size, const char *path, con  	}  	*buffer_out = '\0'; -  	return GIT_SUCCESS;  } @@ -472,7 +454,7 @@ int git_futils_prettyify_file(char *buffer_out, size_t size, const char *path, c  		return error;	/* The callee already takes care of setting the correct error message. */  	path_len = strlen(buffer_out); -	root_offset = git_futils_root_offset(buffer_out) + 1; +	root_offset = git_path_root(buffer_out) + 1;  	if (path_len == root_offset)  		return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path); diff --git a/src/fileops.h b/src/fileops.h index 52eb2295c..c9ede4978 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -198,6 +198,5 @@ int git_futils_prettify_dir(char *buffer_out, size_t size, const char *path, con   */  int git_futils_prettyify_file(char *buffer_out, size_t size, const char *path, const char *base_path); -int git_futils_root_offset(const char *path);  #endif /* INCLUDE_fileops_h__ */ diff --git a/src/path.c b/src/path.c index 766f67427..1f7a16679 100644 --- a/src/path.c +++ b/src/path.c @@ -1,4 +1,7 @@  #include "common.h" +#include "path.h" +#include "posix.h" +  #include <stdarg.h>  #include <stdio.h>  #include <ctype.h> @@ -202,3 +205,50 @@ void git_path_join_n(char *buffer_out, int count, ...)  	*buffer_out = '\0';  } +int git_path_root(const char *path) +{ +	int offset = 0; + +#ifdef GIT_WIN32 +	/* Does the root of the path look like a windows drive ? */ +	if (isalpha(path[0]) && (path[1] == ':')) +		offset += 2; +#endif + +	if (*(path + offset) == '/') +		return offset; + +	return -1;	/* Not a real error. Rather a signal than the path is not rooted */ +} + +int git_path_prettify(char *path_out, const char *path, const char *base) +{ +	char *result; + +	if (base == NULL || git_path_root(path) >= 0) { +		result = p_realpath(path, path_out); +	} else { +		char aux_path[GIT_PATH_MAX]; +		git_path_join(aux_path, base, path); +		result = p_realpath(aux_path, path_out); +	} + +	return result ? GIT_SUCCESS : GIT_EOSERR; +} + +int git_path_prettify_dir(char *path_out, const char *path, const char *base) +{ +	size_t end; + +	if (git_path_prettify(path_out, path, base) < GIT_SUCCESS) +		return GIT_EOSERR; + +	end = strlen(path_out); + +	if (end && path_out[end - 1] != '/') { +		path_out[end] = '/'; +		path_out[end + 1] = '\0'; +	} + +	return GIT_SUCCESS; +} diff --git a/src/path.h b/src/path.h index 1bae9dfbe..36e22a768 100644 --- a/src/path.h +++ b/src/path.h @@ -59,6 +59,11 @@ GIT_INLINE(void) git_path_join(char *buffer_out, const char *path_a, const char  	git_path_join_n(buffer_out, 2, path_a, path_b);  } +int git_path_root(const char *path); + +int git_path_prettify(char *path_out, const char *path, const char *base); +int git_path_prettify_dir(char *path_out, const char *path, const char *base); +  #ifdef GIT_WIN32  GIT_INLINE(void) git_path_mkposix(char *path)  { diff --git a/src/repository.c b/src/repository.c index a8ead3a32..48c8e2b7e 100644 --- a/src/repository.c +++ b/src/repository.c @@ -39,7 +39,6 @@  #define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"  #define GIT_FILE_CONTENT_PREFIX "gitdir: " -#define GIT_FILE_CONTENT_PREFIX_LENGTH 8  #define GIT_BRANCH_MASTER "master" @@ -135,7 +134,7 @@ static int check_repository_dirs(git_repository *repo)  	/* Ensure HEAD file exists */  	git_path_join(path_aux, repo->path_repository, GIT_HEAD_FILE); -	if (git_futils_exists(path_aux) < 0) +	if (git_futils_isfile(path_aux) < 0)  		return git__throw(GIT_ENOTAREPO, "HEAD file is missing");  	return GIT_SUCCESS; @@ -160,6 +159,26 @@ static int guess_repository_dirs(git_repository *repo, const char *repository_pa  	return assign_repository_dirs(repo, repository_path, NULL, NULL, path_work_tree);  } +static int quickcheck_repository_dir(const char *repository_path) +{ +	char path_aux[GIT_PATH_MAX]; + +	/* Ensure HEAD file exists */ +	git_path_join(path_aux, repository_path, GIT_HEAD_FILE); +	if (git_futils_isfile(path_aux) < 0) +		return GIT_ERROR; + +	git_path_join(path_aux, repository_path, GIT_OBJECTS_DIR); +	if (git_futils_isdir(path_aux) < 0) +		return GIT_ERROR; + +	git_path_join(path_aux, repository_path, GIT_REFS_DIR); +	if (git_futils_isdir(path_aux) < 0) +		return GIT_ERROR; + +	return GIT_SUCCESS; +} +  static git_repository *repository_alloc()  {  	int error; @@ -352,23 +371,6 @@ cleanup:  	return git__rethrow(error, "Failed to open repository");  } -static int abspath(char *buffer_out, size_t size, const char *path) -{ -	assert(buffer_out && size >= GIT_PATH_MAX); - -	#ifdef GIT_WIN32 -		if (_fullpath(buffer_out, path, size) == NULL) -			return git__throw(GIT_EOSERR, "Failed to retrieve real path: %s causing errors", buffer_out); -	#else -		if (realpath(path, buffer_out) == NULL) -			return git__throw(GIT_EOSERR, "Failed to retrieve real path: %s causing errors", buffer_out); -	#endif - -	git_path_mkposix(buffer_out); - -	return GIT_SUCCESS; -} -  static int retrieve_device(dev_t *device_out, const char *path)  {  	struct stat path_info; @@ -393,7 +395,7 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei  	assert(path); -	min_len = git_futils_root_offset(path) + 1; +	min_len = git_path_root(path) + 1;  	if (ceiling_directories == NULL || min_len == 0)  		return min_len; @@ -402,13 +404,13 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei  		for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);  		len = sep - ceil; -		if (len == 0 || len > GIT_PATH_MAX || git_futils_root_offset(ceil) == -1) +		if (len == 0 || len > GIT_PATH_MAX || git_path_root(ceil) == -1)  			continue;  		strncpy(buf, ceil, len);  		buf[len] = '\0'; -		if (abspath(buf2, sizeof(buf2), buf) < GIT_SUCCESS) +		if (p_realpath(buf, buf2) == NULL)  			continue;  		len = strlen(buf2); @@ -426,13 +428,13 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei  	return max_len <= min_len ? min_len : max_len;  } -static int read_gitfile(char *path_out, size_t size, const char *file_path, const char *base_path) +static int read_gitfile(char *path_out, const char *file_path, const char *base_path)  {  	git_fbuffer file;  	int error, end_offset;  	char *data; -	assert(file_path && path_out && size > 0); +	assert(path_out && file_path && path_out);  	error = git_futils_readbuffer(&file, file_path); @@ -451,22 +453,19 @@ static int read_gitfile(char *path_out, size_t size, const char *file_path, cons  	for (;data[end_offset] == '\r' || data[end_offset] == '\n'; --end_offset);  	data[end_offset + 1] = '\0'; -	if (GIT_FILE_CONTENT_PREFIX_LENGTH == end_offset + 1) { +	if (STRLEN(GIT_FILE_CONTENT_PREFIX) == end_offset + 1) {  		git_futils_freebuffer(&file);  		return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);  	} -	error = git_futils_prettify_dir(path_out, size, data + GIT_FILE_CONTENT_PREFIX_LENGTH, base_path); -	if (error == GIT_SUCCESS) { -		end_offset = strlen(path_out); - -		if (end_offset > 0 && path_out[end_offset - 1] == '/') -			path_out[end_offset - 1 ] = '\0'; -	} - +	data = data + STRLEN(GIT_FILE_CONTENT_PREFIX); +	error = git_path_prettify_dir(path_out, data, base_path);  	git_futils_freebuffer(&file); -	return error; +	if (error == 0 && git_futils_exists(path_out) == 0) +		return GIT_SUCCESS; + +	return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to an inexisting path");  }  static void git_repository__free_dirs(git_repository *repo) @@ -498,7 +497,6 @@ void git_repository_free(git_repository *repo)  int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs)  { -	git_repository repo;  	int error, ceiling_offset;  	char bare_path[GIT_PATH_MAX];  	char normal_path[GIT_PATH_MAX]; @@ -506,80 +504,70 @@ int git_repository_discover(char *repository_path, size_t size, const char *star  	dev_t current_device = 0;  	assert(start_path && repository_path); -	memset(&repo, 0x0, sizeof(git_repository)); - -	error = abspath(bare_path, sizeof(bare_path), start_path); +	error = git_path_prettify_dir(bare_path, start_path, NULL);  	if (error < GIT_SUCCESS) -		goto cleanup; +		return error;  	if (!across_fs) {  		error = retrieve_device(¤t_device, bare_path); -  		if (error < GIT_SUCCESS) -			goto cleanup; +			return error;  	}  	ceiling_offset = retrieve_ceiling_directories_offset(bare_path, ceiling_dirs);  	git_path_join(normal_path, bare_path, DOT_GIT); -	while(1){ -		//look for .git file +	while(1) { +		/** +		 * If the `.git` file is regular instead of +		 * a directory, it should contain the path of the actual git repository +		 */  		if (git_futils_isfile(normal_path) == GIT_SUCCESS) { -			error = read_gitfile(repository_path, size, normal_path, bare_path); - -			if (error < GIT_SUCCESS) { -				git__rethrow(error, "Unable to read git file `%s`", normal_path); -				goto cleanup; -			} +			error = read_gitfile(repository_path, normal_path, bare_path); -			error = discover_repository_dirs(&repo, repository_path);  			if (error < GIT_SUCCESS) -				goto cleanup; +				return git__rethrow(error, "Unable to read git file `%s`", normal_path); -			git_repository__free_dirs(&repo); +			error = quickcheck_repository_dir(repository_path); +			if (error < GIT_SUCCESS) +				return git__throw(GIT_ENOTFOUND, "The `.git` file found at '%s' points" +					"to an inexisting Git folder", normal_path);  			return GIT_SUCCESS;  		} -		//look for .git repository -		error = discover_repository_dirs(&repo, normal_path); -		if (error < GIT_SUCCESS && error != GIT_ENOTAREPO) -			goto cleanup; - -		if (error == GIT_SUCCESS) { -			found_path = normal_path; -			break; +		/** +		 * If the `.git` file is a folder, we check inside of it +		 */ +		if (git_futils_isdir(normal_path) == GIT_SUCCESS) { +			error = quickcheck_repository_dir(normal_path); +			if (error == GIT_SUCCESS) { +				found_path = normal_path; +				break; +			}  		} -		git_repository__free_dirs(&repo); - -		//look for bare repository in current directory -		error = discover_repository_dirs(&repo, bare_path); -		if (error < GIT_SUCCESS && error != GIT_ENOTAREPO) -			goto cleanup; - +		/** +		 * Otherwise, the repository may be bare, let's check +		 * the root anyway +		 */ +		error = quickcheck_repository_dir(bare_path);  		if (error == GIT_SUCCESS) {  			found_path = bare_path;  			break;  		} -		git_repository__free_dirs(&repo); -  		if (git_path_dirname_r(normal_path, sizeof(normal_path), bare_path) < GIT_SUCCESS) -			goto cleanup; +			return git__throw(GIT_EOSERR, "Failed to dirname '%s'", bare_path);  		if (!across_fs) {  			dev_t new_device;  			error = retrieve_device(&new_device, normal_path); -			if (error < GIT_SUCCESS) -				goto cleanup; - -			if (current_device != new_device) { -				error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n" -					"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM_ENVIRONMENT not set).", bare_path); -				goto cleanup; +			if (error < GIT_SUCCESS || current_device != new_device) { +				return git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n" +					"Stopping at filesystem boundary.", bare_path);  			}  			current_device = new_device;  		} @@ -587,27 +575,18 @@ int git_repository_discover(char *repository_path, size_t size, const char *star  		strcpy(bare_path, normal_path);  		git_path_join(normal_path, bare_path, DOT_GIT); -		//nothing has been found, lets try the parent directory +		// nothing has been found, lets try the parent directory  		if (bare_path[ceiling_offset] == '\0') { -			error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path); -			goto cleanup; +			return git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path);  		} -  	} -	if (size < (strlen(found_path) + 1) * sizeof(char)) { -		error = git__throw(GIT_EOVERFLOW, "The repository buffer is not long enough to handle the repository path `%s`", found_path); -		goto cleanup; +	if (size < (strlen(found_path) + 2) * sizeof(char)) { +		return git__throw(GIT_EOVERFLOW, "The repository buffer is not long enough to handle the repository path `%s`", found_path);  	} -	strcpy(repository_path, found_path); -	git_repository__free_dirs(&repo); - +	git_path_join(repository_path, found_path, "");  	return GIT_SUCCESS; - -	cleanup: -		git_repository__free_dirs(&repo); -		return git__rethrow(error, "Failed to discover repository");  }  git_odb *git_repository_database(git_repository *repo) @@ -689,15 +668,17 @@ static int repo_init_structure(repo_init *results)  static int repo_init_find_dir(repo_init *results, const char* path)  {  	char temp_path[GIT_PATH_MAX]; -	int error = GIT_SUCCESS; +	int error;  	error = git_futils_prettify_dir(temp_path, sizeof(temp_path), path, NULL);  	if (error < GIT_SUCCESS) -		return git__rethrow(error, "Failed to find directory to initialize repository"); +		return git__throw(GIT_ENOTFOUND, "Invalid directory to initialize repository"); -	if (!results->is_bare) { +//	if (p_realpath(path, temp_path) == NULL) +//		return git__throw(GIT_ENOTFOUND, "Invalid directory to initialize repository"); + +	if (!results->is_bare)  		git_path_join(temp_path, temp_path, GIT_DIR); -	}  	results->path_repository = git__strdup(temp_path);  	if (results->path_repository == NULL) diff --git a/src/unix/posix.h b/src/unix/posix.h index ab98c451d..079373919 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -9,6 +9,6 @@  #define p_unlink(p) unlink(p)  #define p_mkdir(p,m) mkdir(p, m)  #define p_fsync(fd) fsync(fd) -#define p_realpath(p, r) realpath(p, r) +#define p_realpath(p, po) realpath(p, po)  #endif diff --git a/src/win32/posix.c b/src/win32/posix.c index 003ce1fd6..610a4166c 100644 --- a/src/win32/posix.c +++ b/src/win32/posix.c @@ -1,4 +1,5 @@  #include "posix.h" +#include "path.h"  #include <errno.h>  int p_unlink(const char *path) @@ -189,3 +190,13 @@ int p_hide_directory__w32(const char *path)  	return error;  } +int p_realpath(const char *orig_path, char *buffer) +{ +	int ret = GetFullPathName(orig_path, GIT_PATH_MAX, buffer, NULL); +	if (!ret || ret > GIT_PATH_MAX) +		return GIT_EOSERR; + +	git_path_mkposix(buffer); +	return GIT_SUCCESS; +} + diff --git a/src/win32/posix.h b/src/win32/posix.h index 31ee7201c..3b5bff806 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -21,5 +21,6 @@ extern int p_unlink(const char *path);  extern int p_lstat(const char *file_name, struct stat *buf);  extern int p_readlink(const char *link, char *target, size_t target_len);  extern int p_hide_directory__w32(const char *path); +extern int p_realpath(const char *orig_path, char *buffer);  #endif  | 
