void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; set_repo_symlink_handling_cap_to(true); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); #ifdef GIT_WIN32 test_file_contents("./testrepo/link_to_new.txt", "new.txt"); #else { char link_data[1024]; size_t link_size = 1024; link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size); link_data[link_size] = '\0'; cl_assert_equal_i(link_size, strlen("new.txt")); cl_assert_equal_s(link_data, "new.txt"); test_file_contents("./testrepo/link_to_new.txt", "my new file\n"); } #endif }
void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; cl_repo_set_bool(g_repo, "core.symlinks", true); opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); #ifdef GIT_WIN32 check_file_contents("./testrepo/link_to_new.txt", "new.txt"); #else { char link_data[1024]; size_t link_size = 1024; link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size); link_data[link_size] = '\0'; cl_assert_equal_i(link_size, strlen("new.txt")); cl_assert_equal_s(link_data, "new.txt"); check_file_contents("./testrepo/link_to_new.txt", "my new file\n"); } #endif }
static int diff_file_content_load_workdir_symlink( git_diff_file_content *fc, git_buf *path) { ssize_t alloc_len, read_len; int symlink_supported, error; if ((error = git_repository__cvar( &symlink_supported, fc->repo, GIT_CVAR_SYMLINKS)) < 0) return -1; if (!symlink_supported) return diff_file_content_load_workdir_symlink_fake(fc, path); /* link path on disk could be UTF-16, so prepare a buffer that is * big enough to handle some UTF-8 data expansion */ alloc_len = (ssize_t)(fc->file->size * 2) + 1; fc->map.data = git__calloc(alloc_len, sizeof(char)); GITERR_CHECK_ALLOC(fc->map.data); fc->flags |= GIT_DIFF_FLAG__FREE_DATA; read_len = p_readlink(git_buf_cstr(path), fc->map.data, alloc_len); if (read_len < 0) { giterr_set(GITERR_OS, "failed to read symlink '%s'", fc->file->path); return -1; } fc->map.len = read_len; return 0; }
void test_checkout_index__honor_coresymlinks_default(void) { git_repository *repo; git_remote *origin; git_object *target; char cwd[GIT_PATH_MAX]; const char *url = git_repository_path(g_repo); cl_assert(getcwd(cwd, sizeof(cwd)) != NULL); cl_assert_equal_i(0, p_mkdir("readonly", 0555)); // Read-only directory cl_assert_equal_i(0, chdir("readonly")); cl_git_pass(git_repository_init(&repo, "../symlink.git", true)); cl_assert_equal_i(0, chdir(cwd)); cl_assert_equal_i(0, p_mkdir("symlink", 0777)); cl_git_pass(git_repository_set_workdir(repo, "symlink", 1)); cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); cl_git_pass(git_remote_fetch(origin, NULL, NULL, NULL)); git_remote_free(origin); cl_git_pass(git_revparse_single(&target, repo, "remotes/origin/master")); cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL)); git_object_free(target); git_repository_free(repo); #ifdef GIT_WIN32 check_file_contents("./symlink/link_to_new.txt", "new.txt"); #else { char link_data[1024]; size_t link_size = 1024; link_size = p_readlink("./symlink/link_to_new.txt", link_data, link_size); link_data[link_size] = '\0'; cl_assert_equal_i(link_size, strlen("new.txt")); cl_assert_equal_s(link_data, "new.txt"); check_file_contents("./symlink/link_to_new.txt", "my new file\n"); } #endif cl_fixture_cleanup("symlink"); }
int git_odb__hashlink(git_oid *out, const char *path) { struct stat st; git_off_t size; int result; if (git_path_lstat(path, &st) < 0) return -1; size = st.st_size; if (!git__is_sizet(size)) { giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); return -1; } if (S_ISLNK(st.st_mode)) { char *link_data; ssize_t read_len; link_data = (char*) git__malloc((size_t)(size + 1)); GITERR_CHECK_ALLOC(link_data); read_len = p_readlink(path, link_data, (size_t)size); link_data[size] = '\0'; if (read_len != (ssize_t)size) { giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", path); git__free(link_data); return -1; } result = git_odb_hash(out, link_data, (size_t)size, GIT_OBJ_BLOB); git__free(link_data); } else { int fd = git_futils_open_ro(path); if (fd < 0) return -1; result = git_odb__hashfd(out, fd, (size_t)size, GIT_OBJ_BLOB); p_close(fd); } return result; }
static int write_symlink( git_oid *id, git_odb *odb, const char *path, size_t link_size) { char *link_data; ssize_t read_len; int error; link_data = git__malloc(link_size); GITERR_CHECK_ALLOC(link_data); read_len = p_readlink(path, link_data, link_size); if (read_len != (ssize_t)link_size) { giterr_set(GITERR_OS, "failed to create blob: cannot read symlink '%s'", path); git__free(link_data); return -1; } error = git_odb_write(id, odb, (void *)link_data, link_size, GIT_OBJECT_BLOB); git__free(link_data); return error; }
void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) { set_repo_symlink_handling_cap_to(true); cl_git_pass(git_checkout_index(g_repo, &g_opts, NULL)); #ifdef GIT_WIN32 test_file_contents("./testrepo/link_to_new.txt", "new.txt"); #else { char link_data[1024]; size_t link_size = 1024; link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size); link_data[link_size] = '\0'; cl_assert_equal_i(link_size, strlen("new.txt")); cl_assert_equal_s(link_data, "new.txt"); test_file_contents("./testrepo/link_to_new.txt", "my new file\n"); } #endif }
static void ensure_workdir_link(const char *path, const char *target) { #ifdef GIT_WIN32 ensure_workdir_contents(path, target); #else git_buf fullpath = GIT_BUF_INIT; char actual[1024]; struct stat st; int len; cl_git_pass( git_buf_joinpath(&fullpath, git_repository_workdir(g_repo), path)); cl_git_pass(p_lstat(git_buf_cstr(&fullpath), &st)); cl_assert(S_ISLNK(st.st_mode)); cl_assert((len = p_readlink(git_buf_cstr(&fullpath), actual, 1024)) > 0); actual[len] = '\0'; cl_assert(strcmp(actual, target) == 0); git_buf_free(&fullpath); #endif }
static int do_lstat( const char *file_name, struct stat *buf, int posix_enotdir) { WIN32_FILE_ATTRIBUTE_DATA fdata; wchar_t fbuf[GIT_WIN_PATH], lastch; int flen; flen = git__utf8_to_16(fbuf, GIT_WIN_PATH, file_name); /* truncate trailing slashes */ for (; flen > 0; --flen) { lastch = fbuf[flen - 1]; if (WIN32_IS_WSEP(lastch)) fbuf[flen - 1] = L'\0'; else if (lastch != L'\0') break; } if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) { int fMode = S_IREAD; if (!buf) return 0; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) fMode |= S_IFDIR; else fMode |= S_IFREG; if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) fMode |= S_IWRITE; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) fMode |= S_IFLNK; buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; buf->st_nlink = 1; buf->st_mode = (mode_t)fMode; buf->st_size = ((git_off_t)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow; buf->st_dev = buf->st_rdev = (_getdrive() - 1); buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); /* Windows symlinks have zero file size, call readlink to determine * the length of the path pointed to, which we expect everywhere else */ if (S_ISLNK(fMode)) { char target[GIT_WIN_PATH]; int readlink_result; readlink_result = p_readlink(file_name, target, GIT_WIN_PATH); if (readlink_result == -1) return -1; buf->st_size = strlen(target); } return 0; } errno = ENOENT; /* We need POSIX behavior, then ENOTDIR must set when any of the folders in the * file path is a regular file,otherwise ENOENT must be set. */ if (posix_enotdir) { /* scan up path until we find an existing item */ while (1) { /* remove last directory component */ for (--flen; flen > 0 && !WIN32_IS_WSEP(fbuf[flen]); --flen); if (flen <= 0) break; fbuf[flen] = L'\0'; if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) { if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) errno = ENOTDIR; break; } } } return -1; }