mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-06 03:06:13 +00:00

The idea...sometimes, a filemode is user-specified via an explicit git_index_entry. In this case, believe the user, always. Sometimes, it is instead built up by statting the file system. In those cases, go with the existing logic we have to determine whether the file system supports all filemodes and symlinks, and make the best guess. On file systems which have full filemode and symlink support, this commit should make no difference. On others (most notably Windows), this will fix problems things like: * git_index_add and git_index_add_frombuffer() should be believed. * As a consequence, git_checkout_tree should make the filemodes in the index match the ones in the tree. * And diffs with GIT_DIFF_UPDATE_INDEX don't write the wrong filemodes. * And merges, and probably other downstream stuff now fixed, too. This makes my previous changes to checkout.c unnecessary, so they are now reverted. Also, added a test for index_entry permissions from git_index_add and git_index_add_frombuffer, both of which failed before these changes.
251 lines
7.4 KiB
C
251 lines
7.4 KiB
C
#include "clar_libgit2.h"
|
|
#include "buffer.h"
|
|
#include "posix.h"
|
|
#include "index.h"
|
|
|
|
static git_repository *g_repo = NULL;
|
|
|
|
void test_index_filemodes__initialize(void)
|
|
{
|
|
g_repo = cl_git_sandbox_init("filemodes");
|
|
}
|
|
|
|
void test_index_filemodes__cleanup(void)
|
|
{
|
|
cl_git_sandbox_cleanup();
|
|
}
|
|
|
|
void test_index_filemodes__read(void)
|
|
{
|
|
git_index *index;
|
|
unsigned int i;
|
|
static bool expected[6] = { 0, 1, 0, 1, 0, 1 };
|
|
|
|
cl_git_pass(git_repository_index(&index, g_repo));
|
|
cl_assert_equal_i(6, (int)git_index_entrycount(index));
|
|
|
|
for (i = 0; i < 6; ++i) {
|
|
const git_index_entry *entry = git_index_get_byindex(index, i);
|
|
cl_assert(entry != NULL);
|
|
cl_assert(((entry->mode & 0100) ? 1 : 0) == expected[i]);
|
|
}
|
|
|
|
git_index_free(index);
|
|
}
|
|
|
|
static void replace_file_with_mode(
|
|
const char *filename, const char *backup, unsigned int create_mode)
|
|
{
|
|
git_buf path = GIT_BUF_INIT, content = GIT_BUF_INIT;
|
|
|
|
cl_git_pass(git_buf_joinpath(&path, "filemodes", filename));
|
|
cl_git_pass(git_buf_printf(&content, "%s as %08u (%d)",
|
|
filename, create_mode, rand()));
|
|
|
|
cl_git_pass(p_rename(path.ptr, backup));
|
|
cl_git_write2file(
|
|
path.ptr, content.ptr, content.size,
|
|
O_WRONLY|O_CREAT|O_TRUNC, create_mode);
|
|
|
|
git_buf_free(&path);
|
|
git_buf_free(&content);
|
|
}
|
|
|
|
#define add_and_check_mode(I,F,X) add_and_check_mode_(I,F,X,__FILE__,__LINE__)
|
|
|
|
static void add_and_check_mode_(
|
|
git_index *index, const char *filename, unsigned int expect_mode,
|
|
const char *file, int line)
|
|
{
|
|
size_t pos;
|
|
const git_index_entry *entry;
|
|
|
|
cl_git_pass(git_index_add_bypath(index, filename));
|
|
|
|
clar__assert(!git_index_find(&pos, index, filename),
|
|
file, line, "Cannot find index entry", NULL, 1);
|
|
|
|
entry = git_index_get_byindex(index, pos);
|
|
|
|
clar__assert_equal(file, line, "Expected mode does not match index",
|
|
1, "%07o", (unsigned int)entry->mode, (unsigned int)expect_mode);
|
|
}
|
|
|
|
void test_index_filemodes__untrusted(void)
|
|
{
|
|
git_index *index;
|
|
|
|
cl_repo_set_bool(g_repo, "core.filemode", false);
|
|
|
|
cl_git_pass(git_repository_index(&index, g_repo));
|
|
cl_assert((git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE) != 0);
|
|
|
|
/* 1 - add 0644 over existing 0644 -> expect 0644 */
|
|
replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644);
|
|
add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
|
|
|
|
/* 2 - add 0644 over existing 0755 -> expect 0755 */
|
|
replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644);
|
|
add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
|
|
|
|
/* 3 - add 0755 over existing 0644 -> expect 0644 */
|
|
replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755);
|
|
add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
|
|
|
|
/* 4 - add 0755 over existing 0755 -> expect 0755 */
|
|
replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
|
|
add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
|
|
|
|
/* 5 - add new 0644 -> expect 0644 */
|
|
cl_git_write2file("filemodes/new_off", "blah", 0,
|
|
O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
|
|
|
|
/* 6 - add new 0755 -> expect 0644 if core.filemode == false */
|
|
cl_git_write2file("filemodes/new_on", "blah", 0,
|
|
O_WRONLY | O_CREAT | O_TRUNC, 0755);
|
|
add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB);
|
|
|
|
git_index_free(index);
|
|
}
|
|
|
|
void test_index_filemodes__trusted(void)
|
|
{
|
|
git_index *index;
|
|
|
|
/* Only run these tests on platforms where I can actually
|
|
* chmod a file and get the stat results I expect!
|
|
*/
|
|
if (!cl_is_chmod_supported())
|
|
return;
|
|
|
|
cl_repo_set_bool(g_repo, "core.filemode", true);
|
|
|
|
cl_git_pass(git_repository_index(&index, g_repo));
|
|
cl_assert((git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE) == 0);
|
|
|
|
/* 1 - add 0644 over existing 0644 -> expect 0644 */
|
|
replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644);
|
|
add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
|
|
|
|
/* 2 - add 0644 over existing 0755 -> expect 0644 */
|
|
replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644);
|
|
add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB);
|
|
|
|
/* 3 - add 0755 over existing 0644 -> expect 0755 */
|
|
replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755);
|
|
add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB_EXECUTABLE);
|
|
|
|
/* 4 - add 0755 over existing 0755 -> expect 0755 */
|
|
replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
|
|
add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
|
|
|
|
/* 5 - add new 0644 -> expect 0644 */
|
|
cl_git_write2file("filemodes/new_off", "blah", 0,
|
|
O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
|
|
|
|
/* 6 - add 0755 -> expect 0755 */
|
|
cl_git_write2file("filemodes/new_on", "blah", 0,
|
|
O_WRONLY | O_CREAT | O_TRUNC, 0755);
|
|
add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE);
|
|
|
|
git_index_free(index);
|
|
}
|
|
|
|
#define add_entry_and_check_mode(I,FF,X) add_entry_and_check_mode_(I,FF,X,__FILE__,__LINE__)
|
|
|
|
static void add_entry_and_check_mode_(
|
|
git_index *index, bool from_file, git_filemode_t mode,
|
|
const char *file, int line)
|
|
{
|
|
size_t pos;
|
|
const git_index_entry* entry;
|
|
git_index_entry new_entry;
|
|
|
|
/* If old_filename exists, we copy that to the new file, and test
|
|
* git_index_add(), otherwise create a new entry testing git_index_add_frombuffer
|
|
*/
|
|
if (from_file)
|
|
{
|
|
clar__assert(!git_index_find(&pos, index, "exec_off"),
|
|
file, line, "Cannot find original index entry", NULL, 1);
|
|
|
|
entry = git_index_get_byindex(index, pos);
|
|
|
|
memcpy(&new_entry, entry, sizeof(new_entry));
|
|
}
|
|
else
|
|
memset(&new_entry, 0x0, sizeof(git_index_entry));
|
|
|
|
new_entry.path = "filemodes/explicit_test";
|
|
new_entry.mode = mode;
|
|
|
|
if (from_file)
|
|
{
|
|
clar__assert(!git_index_add(index, &new_entry),
|
|
file, line, "Cannot add index entry", NULL, 1);
|
|
}
|
|
else
|
|
{
|
|
const char *content = "hey there\n";
|
|
clar__assert(!git_index_add_frombuffer(index, &new_entry, content, strlen(content)),
|
|
file, line, "Cannot add index entry from buffer", NULL, 1);
|
|
}
|
|
|
|
clar__assert(!git_index_find(&pos, index, "filemodes/explicit_test"),
|
|
file, line, "Cannot find new index entry", NULL, 1);
|
|
|
|
entry = git_index_get_byindex(index, pos);
|
|
|
|
clar__assert_equal(file, line, "Expected mode does not match index",
|
|
1, "%07o", (unsigned int)entry->mode, (unsigned int)mode);
|
|
}
|
|
|
|
void test_index_filemodes__explicit(void)
|
|
{
|
|
git_index *index;
|
|
|
|
/* These tests should run and work everywhere, as the filemode is
|
|
* given explicitly to git_index_add or git_index_add_frombuffer
|
|
*/
|
|
cl_repo_set_bool(g_repo, "core.filemode", false);
|
|
|
|
cl_git_pass(git_repository_index(&index, g_repo));
|
|
|
|
/* Each of these tests keeps overwriting the same file in the index. */
|
|
/* 1 - add new 0644 entry */
|
|
add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB);
|
|
|
|
/* 2 - add 0755 entry over existing 0644 */
|
|
add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB_EXECUTABLE);
|
|
|
|
/* 3 - add 0644 entry over existing 0755 */
|
|
add_entry_and_check_mode(index, true, GIT_FILEMODE_BLOB);
|
|
|
|
/* 4 - add 0755 buffer entry over existing 0644 */
|
|
add_entry_and_check_mode(index, false, GIT_FILEMODE_BLOB_EXECUTABLE);
|
|
|
|
/* 5 - add 0644 buffer entry over existing 0755 */
|
|
add_entry_and_check_mode(index, false, GIT_FILEMODE_BLOB);
|
|
|
|
git_index_free(index);
|
|
}
|
|
|
|
void test_index_filemodes__invalid(void)
|
|
{
|
|
git_index *index;
|
|
git_index_entry entry;
|
|
|
|
cl_git_pass(git_repository_index(&index, g_repo));
|
|
|
|
entry.path = "foo";
|
|
entry.mode = GIT_OBJ_BLOB;
|
|
cl_git_fail(git_index_add(index, &entry));
|
|
|
|
entry.mode = GIT_FILEMODE_BLOB;
|
|
cl_git_pass(git_index_add(index, &entry));
|
|
|
|
git_index_free(index);
|
|
}
|