summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/checkout.c27
-rw-r--r--src/crlf.c2
-rw-r--r--src/fileops.c11
-rw-r--r--src/fileops.h10
-rw-r--r--src/win32/posix_w32.c7
5 files changed, 48 insertions, 9 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 8ba3cf536..c4e75b67a 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -13,6 +13,7 @@
#include "git2/tree.h"
#include "git2/commit.h"
#include "git2/blob.h"
+#include "git2/config.h"
#include "common.h"
#include "refs.h"
@@ -29,22 +30,26 @@ typedef struct tree_walk_data
git_indexer_stats *stats;
git_repository *repo;
git_odb *odb;
+ bool do_symlinks;
} tree_walk_data;
-static int blob_contents_to_link(git_repository *repo, git_buf *fnbuf,
+static int blob_contents_to_link(tree_walk_data *data, git_buf *fnbuf,
const git_oid *id)
{
int retcode = GIT_ERROR;
git_blob *blob;
/* Get the link target */
- if (!(retcode = git_blob_lookup(&blob, repo, id))) {
+ if (!(retcode = git_blob_lookup(&blob, data->repo, id))) {
git_buf linktarget = GIT_BUF_INIT;
if (!(retcode = git_blob__getbuf(&linktarget, blob))) {
/* Create the link */
- retcode = p_symlink(git_buf_cstr(&linktarget),
- git_buf_cstr(fnbuf));
+ const char *new = git_buf_cstr(&linktarget),
+ *old = git_buf_cstr(fnbuf);
+ retcode = data->do_symlinks
+ ? p_symlink(new, old)
+ : git_futils_fake_symlink(new, old);
}
git_buf_free(&linktarget);
git_blob_free(blob);
@@ -77,7 +82,7 @@ static int blob_contents_to_file(git_repository *repo, git_buf *fnbuf,
return retcode;
}
-static int checkout_walker(const char *path, git_tree_entry *entry, void *payload)
+static int checkout_walker(const char *path, const git_tree_entry *entry, void *payload)
{
int retcode = 0;
tree_walk_data *data = (tree_walk_data*)payload;
@@ -99,7 +104,7 @@ static int checkout_walker(const char *path, git_tree_entry *entry, void *payloa
path,
git_tree_entry_name(entry));
if (S_ISLNK(attr)) {
- retcode = blob_contents_to_link(data->repo, &fnbuf,
+ retcode = blob_contents_to_link(data, &fnbuf,
git_tree_entry_id(entry));
} else {
retcode = blob_contents_to_file(data->repo, &fnbuf,
@@ -125,6 +130,7 @@ int git_checkout_force(git_repository *repo, git_indexer_stats *stats)
git_indexer_stats dummy_stats;
git_tree *tree;
tree_walk_data payload;
+ git_config *cfg;
assert(repo);
if (!stats) stats = &dummy_stats;
@@ -134,6 +140,15 @@ int git_checkout_force(git_repository *repo, git_indexer_stats *stats)
return GIT_ERROR;
}
+ /* Determine if symlinks should be handled */
+ if (!git_repository_config(&cfg, repo)) {
+ int temp = true;
+ if (!git_config_get_bool(&temp, cfg, "core.symlinks")) {
+ payload.do_symlinks = !!temp;
+ }
+ git_config_free(cfg);
+ }
+
stats->total = stats->processed = 0;
payload.stats = stats;
payload.repo = repo;
diff --git a/src/crlf.c b/src/crlf.c
index 888d86c36..f68938e61 100644
--- a/src/crlf.c
+++ b/src/crlf.c
@@ -230,7 +230,7 @@ static int find_and_add_filter(git_vector *filters, git_repository *repo, const
static int crlf_apply_to_workdir(git_filter *self, git_buf *dest, const git_buf *source)
{
/* TODO */
- return 0;
+ return -1;
}
int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const char *path)
diff --git a/src/fileops.c b/src/fileops.c
index 5849b79b2..bc58a0572 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -480,3 +480,14 @@ int git_futils_find_global_file(git_buf *path, const char *filename)
return 0;
#endif
}
+
+int git_futils_fake_symlink(const char *old, const char *new)
+{
+ int retcode = GIT_ERROR;
+ int fd = git_futils_creat_withpath(new, 0755, 0644);
+ if (fd >= 0) {
+ retcode = p_write(fd, old, strlen(old));
+ p_close(fd);
+ }
+ return retcode;
+}
diff --git a/src/fileops.h b/src/fileops.h
index b0c5779e5..594eacbd0 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -179,4 +179,14 @@ extern int git_futils_find_global_file(git_buf *path, const char *filename);
*/
extern int git_futils_find_system_file(git_buf *path, const char *filename);
+
+/**
+ * Create a "fake" symlink (text file containing the target path).
+ *
+ * @param new symlink file to be created
+ * @param old original symlink target
+ * @return 0 on success, -1 on error
+ */
+extern int git_futils_fake_symlink(const char *new, const char *old);
+
#endif /* INCLUDE_fileops_h__ */
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index c0d66c7ff..557760b94 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -7,6 +7,7 @@
#include "../posix.h"
#include "path.h"
#include "utf-conv.h"
+#include "repository.h"
#include <errno.h>
#include <io.h>
#include <fcntl.h>
@@ -219,8 +220,10 @@ int p_readlink(const char *link, char *target, size_t target_len)
int p_symlink(const char *old, const char *new)
{
- /* TODO */
- return -1;
+ /* Real symlinks on NTFS require admin privileges. Until this changes,
+ * libgit2 just creates a text file with the link target in the contents.
+ */
+ return git_futils_fake_symlink(old, new);
}
int p_open(const char *path, int flags, ...)