test_helpers.c 8.16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * 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.
 */

26
#include "common.h"
27 28 29 30 31
#include "test_helpers.h"
#include "fileops.h"

int write_object_data(char *file, void *data, size_t len)
{
32 33
	git_file fd;
	int ret;
34

Vicent Marti committed
35
	if ((fd = p_creat(file, S_IREAD | S_IWRITE)) < 0)
36
		return -1;
Vicent Marti committed
37 38
	ret = p_write(fd, data, len);
	p_close(fd);
39

40
	return ret;
41 42 43 44
}

int write_object_files(const char *odb_dir, object_data *d)
{
45
	if (p_mkdir(odb_dir, GIT_OBJECT_DIR_MODE) < 0) {
46 47 48 49 50 51 52
		int err = errno;
		fprintf(stderr, "can't make directory \"%s\"", odb_dir);
		if (err == EEXIST)
			fprintf(stderr, " (already exists)");
		fprintf(stderr, "\n");
		return -1;
	}
53

54
	if ((p_mkdir(d->dir, GIT_OBJECT_DIR_MODE) < 0) && (errno != EEXIST)) {
55 56 57 58 59 60 61
		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;
	}
62

63
	return 0;
64 65 66 67
}

int remove_object_files(const char *odb_dir, object_data *d)
{
Vicent Marti committed
68
	if (p_unlink(d->file) < 0) {
69 70 71
		fprintf(stderr, "can't delete object file \"%s\"\n", d->file);
		return -1;
	}
Vicent Marti committed
72
	if ((p_rmdir(d->dir) < 0) && (errno != ENOTEMPTY)) {
73 74 75
		fprintf(stderr, "can't remove object directory \"%s\"\n", d->dir);
		return -1;
	}
76

Vicent Marti committed
77
	if (p_rmdir(odb_dir) < 0) {
78 79 80
		fprintf(stderr, "can't remove directory \"%s\"\n", odb_dir);
		return -1;
	}
81

82
	return 0;
83 84
}

85
void locate_loose_object(const char *repository_folder, git_object *object, char **out, char **out_folder)
86
{
87 88
	static const char *objects_folder = "objects/";

89
	char *ptr, *full_path, *top_folder;
90 91 92
	int path_length, objects_length;

	assert(repository_folder && object);
93

94 95 96
	objects_length = strlen(objects_folder);
	path_length = strlen(repository_folder);
	ptr = full_path = git__malloc(path_length + objects_length + GIT_OID_HEXSZ + 3);
97

98 99
	strcpy(ptr, repository_folder);
	strcpy(ptr + path_length, objects_folder);
100

101
	ptr = top_folder = ptr + path_length + objects_length;
102 103 104 105 106
	*ptr++ = '/';
	git_oid_pathfmt(ptr, git_object_id(object));
	ptr += GIT_OID_HEXSZ + 1;
	*ptr = 0;

107 108 109 110 111 112
	*out = full_path;

	if (out_folder)
		*out_folder = top_folder;
}

113 114 115 116 117 118
int loose_object_mode(const char *repository_folder, git_object *object)
{
	char *object_path;
	struct stat st;

	locate_loose_object(repository_folder, object, &object_path, NULL);
119 120
	if (p_stat(object_path, &st) < 0)
		return 0;
121 122 123 124 125
	free(object_path);

	return st.st_mode;
}

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
int loose_object_dir_mode(const char *repository_folder, git_object *object)
{
	char *object_path;
	size_t pos;
	struct stat st;

	locate_loose_object(repository_folder, object, &object_path, NULL);

	pos = strlen(object_path);
	while (pos--) {
		if (object_path[pos] == '/') {
			object_path[pos] = 0;
			break;
		}
	}

142 143
	if (p_stat(object_path, &st) < 0)
		return 0;
144 145 146 147 148 149 150 151 152 153 154
	free(object_path);

	return st.st_mode;
}

int remove_loose_object(const char *repository_folder, git_object *object)
{
	char *full_path, *top_folder;

	locate_loose_object(repository_folder, object, &full_path, &top_folder);

Vicent Marti committed
155
	if (p_unlink(full_path) < 0) {
156 157 158 159 160 161
		fprintf(stderr, "can't delete object file \"%s\"\n", full_path);
		return -1;
	}

	*top_folder = 0;

Vicent Marti committed
162
	if ((p_rmdir(full_path) < 0) && (errno != ENOTEMPTY)) {
163 164 165 166
		fprintf(stderr, "can't remove object directory \"%s\"\n", full_path);
		return -1;
	}

167
	git__free(full_path);
168 169 170 171

	return GIT_SUCCESS;
}

172
int cmp_objects(git_rawobj *o, object_data *d)
173
{
174
	if (o->type != git_object_string2type(d->type))
175 176 177 178 179 180
		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;
181
}
182 183 184

int copy_file(const char *src, const char *dst)
{
Vicent Marti committed
185
	git_fbuffer source_buf;
186 187 188
	git_file dst_fd;
	int error = GIT_ERROR;

Vicent Marti committed
189
	if (git_futils_readbuffer(&source_buf, src) < GIT_SUCCESS)
190 191
		return GIT_ENOTFOUND;

192
	dst_fd = git_futils_creat_withpath(dst, 0777, 0666);
193 194 195
	if (dst_fd < 0)
		goto cleanup;

Vicent Marti committed
196
	error = p_write(dst_fd, source_buf.data, source_buf.len);
197 198

cleanup:
Vicent Marti committed
199 200
	git_futils_freebuffer(&source_buf);
	p_close(dst_fd);
201 202 203 204 205 206

	return error;
}

int cmp_files(const char *a, const char *b)
{
Vicent Marti committed
207
	git_fbuffer buf_a, buf_b;
208 209
	int error = GIT_ERROR;

Vicent Marti committed
210
	if (git_futils_readbuffer(&buf_a, a) < GIT_SUCCESS)
211 212
		return GIT_ERROR;

Vicent Marti committed
213 214
	if (git_futils_readbuffer(&buf_b, b) < GIT_SUCCESS) {
		git_futils_freebuffer(&buf_a);
215 216 217 218 219 220
		return GIT_ERROR;
	}

	if (buf_a.len == buf_b.len && !memcmp(buf_a.data, buf_b.data, buf_a.len))
		error = GIT_SUCCESS;

Vicent Marti committed
221 222
	git_futils_freebuffer(&buf_a);
	git_futils_freebuffer(&buf_b);
223 224 225

	return error;
}
226

227
typedef struct {
228 229 230 231
	git_buf src;
	size_t  src_baselen;
	git_buf dst;
	size_t  dst_baselen;
232 233
} copydir_data;

234
static int copy_filesystem_element_recurs(void *_data, git_buf *source)
235 236 237
{
	copydir_data *data = (copydir_data *)_data;

238
	git_buf_truncate(&data->dst, data->dst_baselen);
239
	git_buf_puts(&data->dst, source->ptr + data->src_baselen);
240

241 242 243 244
	if (git_futils_isdir(source->ptr) == GIT_SUCCESS)
		return git_futils_direach(source, copy_filesystem_element_recurs, _data);
	else
		return copy_file(source->ptr, data->dst.ptr);
245 246
}

247 248 249
int copydir_recurs(
	const char *source_directory_path,
	const char *destination_directory_path)
250
{
251 252
	int error;
	copydir_data data = { GIT_BUF_INIT, 0, GIT_BUF_INIT, 0 };
253 254

	/* Source has to exist, Destination hast to _not_ exist */
Vicent Marti committed
255 256
	if (git_futils_isdir(source_directory_path) != GIT_SUCCESS ||
		git_futils_isdir(destination_directory_path) == GIT_SUCCESS)
257 258
		return GIT_EINVALIDPATH;

259 260 261 262 263 264 265
	git_buf_joinpath(&data.src, source_directory_path, "");
	data.src_baselen = data.src.size;

	git_buf_joinpath(&data.dst, destination_directory_path, "");
	data.dst_baselen = data.dst.size;

	error = copy_filesystem_element_recurs(&data, &data.src);
266

267 268
	git_buf_free(&data.src);
	git_buf_free(&data.dst);
269

270
	return error;
271
}
272 273 274

int open_temp_repo(git_repository **repo, const char *path)
{
275 276 277
	int error;
	if ((error = copydir_recurs(path, TEMP_REPO_FOLDER)) < GIT_SUCCESS)
		return error;
278 279 280 281 282 283 284

	return git_repository_open(repo, TEMP_REPO_FOLDER);
}

void close_temp_repo(git_repository *repo)
{
	git_repository_free(repo);
285 286 287 288
	if (git_futils_rmdir_r(TEMP_REPO_FOLDER, 1) < GIT_SUCCESS) {
		printf("\nFailed to remove temporary folder. Aborting test suite.\n");
		exit(-1);
	}
289
}
290

291 292 293 294 295 296
typedef struct {
	const char *filename;
	size_t filename_len;
} remove_data;

static int remove_placeholders_recurs(void *_data, git_buf *path)
297
{
298 299
	remove_data *data = (remove_data *)_data;
	size_t pathlen;
300

301 302
	if (!git_futils_isdir(path->ptr))
		return git_futils_direach(path, remove_placeholders_recurs, data);
303

304
	pathlen = path->size;
305

306 307 308 309 310 311 312 313
	if (pathlen < data->filename_len)
		return GIT_SUCCESS;

	/* if path ends in '/'+filename (or equals filename) */
	if (!strcmp(data->filename, path->ptr + pathlen - data->filename_len) &&
		(pathlen == data->filename_len ||
		 path->ptr[pathlen - data->filename_len - 1] == '/'))
		return p_unlink(path->ptr);
314 315 316 317

	return GIT_SUCCESS;
}

318
int remove_placeholders(const char *directory_path, const char *filename)
319
{
320 321 322
	int error;
	remove_data data;
	git_buf buffer = GIT_BUF_INIT;
323

Vicent Marti committed
324
	if (git_futils_isdir(directory_path))
325 326
		return GIT_EINVALIDPATH;

327 328 329 330 331 332 333 334 335 336 337
	if ((error = git_buf_sets(&buffer, directory_path)) < GIT_SUCCESS)
		return error;

	data.filename = filename;
	data.filename_len = strlen(filename);

	error = remove_placeholders_recurs(&data, &buffer);

	git_buf_free(&buffer);

	return error;
338
}