mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-11-04 03:05:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			287 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * This file is free software; you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU General Public License, version 2,
 | 
						|
 * as published by the Free Software Foundation.
 | 
						|
 *
 | 
						|
 * In addition to the permissions in the GNU General Public License,
 | 
						|
 * the authors give you unlimited permission to link the compiled
 | 
						|
 * version of this file into combinations with other programs,
 | 
						|
 * and to distribute those combinations without any restriction
 | 
						|
 * coming from the use of this file.  (The General Public License
 | 
						|
 * restrictions do apply in other respects; for example, they cover
 | 
						|
 * modification of the file, and distribution when not linked into
 | 
						|
 * a combined executable.)
 | 
						|
 *
 | 
						|
 * This file is distributed in the hope that it will be useful, but
 | 
						|
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program; see the file COPYING.  If not, write to
 | 
						|
 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 | 
						|
 * Boston, MA 02110-1301, USA.
 | 
						|
 */
 | 
						|
 | 
						|
#include "common.h"
 | 
						|
#include "test_helpers.h"
 | 
						|
#include "fileops.h"
 | 
						|
 | 
						|
int write_object_data(char *file, void *data, size_t len)
 | 
						|
{
 | 
						|
	git_file fd;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	if ((fd = gitfo_creat(file, S_IREAD | S_IWRITE)) < 0)
 | 
						|
		return -1;
 | 
						|
	ret = gitfo_write(fd, data, len);
 | 
						|
	gitfo_close(fd);
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
int write_object_files(const char *odb_dir, object_data *d)
 | 
						|
{
 | 
						|
	if (gitfo_mkdir(odb_dir, 0755) < 0) {
 | 
						|
		int err = errno;
 | 
						|
		fprintf(stderr, "can't make directory \"%s\"", odb_dir);
 | 
						|
		if (err == EEXIST)
 | 
						|
			fprintf(stderr, " (already exists)");
 | 
						|
		fprintf(stderr, "\n");
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((gitfo_mkdir(d->dir, 0755) < 0) && (errno != EEXIST)) {
 | 
						|
		fprintf(stderr, "can't make object directory \"%s\"\n", d->dir);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	if (write_object_data(d->file, d->bytes, d->blen) < 0) {
 | 
						|
		fprintf(stderr, "can't write object file \"%s\"\n", d->file);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int remove_object_files(const char *odb_dir, object_data *d)
 | 
						|
{
 | 
						|
	if (gitfo_unlink(d->file) < 0) {
 | 
						|
		fprintf(stderr, "can't delete object file \"%s\"\n", d->file);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	if ((gitfo_rmdir(d->dir) < 0) && (errno != ENOTEMPTY)) {
 | 
						|
		fprintf(stderr, "can't remove object directory \"%s\"\n", d->dir);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (gitfo_rmdir(odb_dir) < 0) {
 | 
						|
		fprintf(stderr, "can't remove directory \"%s\"\n", odb_dir);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int remove_loose_object(const char *repository_folder, git_object *object)
 | 
						|
{
 | 
						|
	static const char *objects_folder = "objects/";
 | 
						|
 | 
						|
	char *ptr, *full_path, *top_folder;
 | 
						|
	int path_length, objects_length;
 | 
						|
 | 
						|
	assert(repository_folder && object);
 | 
						|
 | 
						|
	objects_length = strlen(objects_folder);
 | 
						|
	path_length = strlen(repository_folder);
 | 
						|
	ptr = full_path = git__malloc(path_length + objects_length + GIT_OID_HEXSZ + 3);
 | 
						|
 | 
						|
	strcpy(ptr, repository_folder);
 | 
						|
	strcpy(ptr + path_length, objects_folder);
 | 
						|
 | 
						|
	ptr = top_folder = ptr + path_length + objects_length;
 | 
						|
	*ptr++ = '/';
 | 
						|
	git_oid_pathfmt(ptr, git_object_id(object));
 | 
						|
	ptr += GIT_OID_HEXSZ + 1;
 | 
						|
	*ptr = 0;
 | 
						|
 | 
						|
	if (gitfo_unlink(full_path) < 0) {
 | 
						|
		fprintf(stderr, "can't delete object file \"%s\"\n", full_path);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	*top_folder = 0;
 | 
						|
 | 
						|
	if ((gitfo_rmdir(full_path) < 0) && (errno != ENOTEMPTY)) {
 | 
						|
		fprintf(stderr, "can't remove object directory \"%s\"\n", full_path);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	free(full_path);
 | 
						|
 | 
						|
	return GIT_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int cmp_objects(git_rawobj *o, object_data *d)
 | 
						|
{
 | 
						|
	if (o->type != git_object_string2type(d->type))
 | 
						|
		return -1;
 | 
						|
	if (o->len != d->dlen)
 | 
						|
		return -1;
 | 
						|
	if ((o->len > 0) && (memcmp(o->data, d->data, o->len) != 0))
 | 
						|
		return -1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int copy_file(const char *src, const char *dst)
 | 
						|
{
 | 
						|
	gitfo_buf source_buf;
 | 
						|
	git_file dst_fd;
 | 
						|
	int error = GIT_ERROR;
 | 
						|
 | 
						|
	if (gitfo_read_file(&source_buf, src) < GIT_SUCCESS)
 | 
						|
		return GIT_ENOTFOUND;
 | 
						|
 | 
						|
	dst_fd = gitfo_creat_force(dst, 0644);
 | 
						|
	if (dst_fd < 0)
 | 
						|
		goto cleanup;
 | 
						|
 | 
						|
	error = gitfo_write(dst_fd, source_buf.data, source_buf.len);
 | 
						|
 | 
						|
cleanup:
 | 
						|
	gitfo_free_buf(&source_buf);
 | 
						|
	gitfo_close(dst_fd);
 | 
						|
 | 
						|
	return error;
 | 
						|
}
 | 
						|
 | 
						|
int cmp_files(const char *a, const char *b)
 | 
						|
{
 | 
						|
	gitfo_buf buf_a, buf_b;
 | 
						|
	int error = GIT_ERROR;
 | 
						|
 | 
						|
	if (gitfo_read_file(&buf_a, a) < GIT_SUCCESS)
 | 
						|
		return GIT_ERROR;
 | 
						|
 | 
						|
	if (gitfo_read_file(&buf_b, b) < GIT_SUCCESS) {
 | 
						|
		gitfo_free_buf(&buf_a);
 | 
						|
		return GIT_ERROR;
 | 
						|
	}
 | 
						|
 | 
						|
	if (buf_a.len == buf_b.len && !memcmp(buf_a.data, buf_b.data, buf_a.len))
 | 
						|
		error = GIT_SUCCESS;
 | 
						|
 | 
						|
	gitfo_free_buf(&buf_a);
 | 
						|
	gitfo_free_buf(&buf_b);
 | 
						|
 | 
						|
	return error;
 | 
						|
}
 | 
						|
 | 
						|
static int remove_filesystem_element_recurs(void *GIT_UNUSED(nil), char *path)
 | 
						|
{
 | 
						|
	int error = GIT_SUCCESS;
 | 
						|
 | 
						|
	GIT_UNUSED_ARG(nil);
 | 
						|
 | 
						|
	error = gitfo_isdir(path);
 | 
						|
	if (error == GIT_SUCCESS) {
 | 
						|
		size_t root_size = strlen(path);
 | 
						|
 | 
						|
		error = gitfo_dirent(path, GIT_PATH_MAX, remove_filesystem_element_recurs, NULL);
 | 
						|
		if (error < GIT_SUCCESS)
 | 
						|
			return error;
 | 
						|
 | 
						|
		path[root_size] = 0;
 | 
						|
		return rmdir(path);
 | 
						|
	}
 | 
						|
 | 
						|
	return gitfo_unlink(path);
 | 
						|
}
 | 
						|
 | 
						|
int rmdir_recurs(const char *directory_path)
 | 
						|
{
 | 
						|
	char buffer[GIT_PATH_MAX];
 | 
						|
	strcpy(buffer, directory_path);
 | 
						|
	return remove_filesystem_element_recurs(NULL, buffer);
 | 
						|
}
 | 
						|
 | 
						|
typedef struct {
 | 
						|
	size_t src_len, dst_len;
 | 
						|
	char *dst;
 | 
						|
} copydir_data;
 | 
						|
 | 
						|
static int copy_filesystem_element_recurs(void *_data, char *source)
 | 
						|
{
 | 
						|
	copydir_data *data = (copydir_data *)_data;
 | 
						|
 | 
						|
	data->dst[data->dst_len] = 0;
 | 
						|
	git__joinpath(data->dst, data->dst, source + data->src_len);
 | 
						|
 | 
						|
	if (gitfo_isdir(source) == GIT_SUCCESS)
 | 
						|
		return gitfo_dirent(source, GIT_PATH_MAX, copy_filesystem_element_recurs, _data);
 | 
						|
 | 
						|
	return copy_file(source, data->dst);
 | 
						|
}
 | 
						|
 | 
						|
int copydir_recurs(const char *source_directory_path, const char *destination_directory_path)
 | 
						|
{
 | 
						|
	char source_buffer[GIT_PATH_MAX];
 | 
						|
	char dest_buffer[GIT_PATH_MAX];
 | 
						|
	copydir_data data;
 | 
						|
 | 
						|
	/* Source has to exist, Destination hast to _not_ exist */
 | 
						|
	if (gitfo_isdir(source_directory_path)  || !gitfo_isdir(destination_directory_path))
 | 
						|
		return GIT_EINVALIDPATH;
 | 
						|
 | 
						|
	git__joinpath(source_buffer, source_directory_path, "");
 | 
						|
	data.src_len = strlen(source_buffer);
 | 
						|
 | 
						|
	git__joinpath(dest_buffer, destination_directory_path, "");
 | 
						|
	data.dst = dest_buffer;
 | 
						|
	data.dst_len = strlen(dest_buffer);
 | 
						|
 | 
						|
	return copy_filesystem_element_recurs(&data, source_buffer);
 | 
						|
}
 | 
						|
 | 
						|
int open_temp_repo(git_repository **repo, const char *path)
 | 
						|
{
 | 
						|
	int error;
 | 
						|
	if ((error = copydir_recurs(path, TEMP_REPO_FOLDER)) < GIT_SUCCESS)
 | 
						|
		return error;
 | 
						|
 | 
						|
	return git_repository_open(repo, TEMP_REPO_FOLDER);
 | 
						|
}
 | 
						|
 | 
						|
void close_temp_repo(git_repository *repo)
 | 
						|
{
 | 
						|
	git_repository_free(repo);
 | 
						|
	rmdir_recurs(TEMP_REPO_FOLDER);
 | 
						|
}
 | 
						|
 | 
						|
static int remove_placeholders_recurs(void *filename, char *path)
 | 
						|
{
 | 
						|
	char passed_filename[GIT_PATH_MAX];
 | 
						|
	char *data = (char *)filename;
 | 
						|
 | 
						|
	if (!gitfo_isdir(path))
 | 
						|
		return gitfo_dirent(path, GIT_PATH_MAX, remove_placeholders_recurs, data);
 | 
						|
 | 
						|
	 if (git__basename_r(passed_filename, sizeof(passed_filename), path) < GIT_SUCCESS)
 | 
						|
		 return GIT_EINVALIDPATH;
 | 
						|
 | 
						|
	if (!strcmp(data, passed_filename))
 | 
						|
		return gitfo_unlink(path);
 | 
						|
 | 
						|
	return GIT_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int remove_placeholders(char *directory_path, char *filename)
 | 
						|
{
 | 
						|
	char buffer[GIT_PATH_MAX];
 | 
						|
 | 
						|
	if (gitfo_isdir(directory_path))
 | 
						|
		return GIT_EINVALIDPATH;
 | 
						|
 | 
						|
	strcpy(buffer, directory_path);
 | 
						|
	return remove_placeholders_recurs(filename, buffer);
 | 
						|
}
 |