diff --git a/apply.c b/apply.c index 892ede5a318f75..38283788b1772a 100644 --- a/apply.c +++ b/apply.c @@ -4346,7 +4346,7 @@ static int try_create_file(struct apply_state *state, const char *path, /* Although buf:size is counted string, it also is NUL * terminated. */ - return !!symlink(buf, path); + return !!create_symlink(state && state->repo ? state->repo->index : NULL, buf, path); fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666); if (fd < 0) diff --git a/builtin/difftool.c b/builtin/difftool.c index a3ea60ea71428e..a4ee24fb3188e4 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -505,7 +505,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, } add_path(&wtdir, wtdir_len, dst_path); if (symlinks) { - if (symlink(wtdir.buf, rdir.buf)) { + if (create_symlink(lstate.istate, wtdir.buf, rdir.buf)) { ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf); goto finish; } diff --git a/builtin/init-db.c b/builtin/init-db.c index 94df241ad5f24f..1a132596e271f1 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -76,7 +76,7 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template_path, if (strbuf_readlink(&lnk, template_path->buf, st_template.st_size) < 0) die_errno(_("cannot readlink '%s'"), template_path->buf); - if (symlink(lnk.buf, path->buf)) + if (create_symlink(NULL, lnk.buf, path->buf)) die_errno(_("cannot symlink '%s' '%s'"), lnk.buf, path->buf); strbuf_release(&lnk); @@ -278,7 +278,7 @@ static int create_default_files(const char *template_path, path = git_path_buf(&buf, "tXXXXXX"); if (!close(xmkstemp(path)) && !unlink(path) && - !symlink("testing", path) && + !create_symlink(NULL, "testing", path) && !lstat(path, &st1) && S_ISLNK(st1.st_mode)) unlink(path); /* good */ diff --git a/compat/mingw.c b/compat/mingw.c index cf89e770fcf293..85d5a037c6f71d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2388,28 +2388,32 @@ enum symlink_type { SYMLINK_TYPE_DIRECTORY, }; -static enum symlink_type check_symlink_attr(const char *link) +static enum symlink_type check_symlink_attr(struct index_state *index, const char *link) { static struct attr_check *check; const char *value; + if (!index) + return SYMLINK_TYPE_UNSPECIFIED; + if (!check) check = attr_check_initl("symlink", NULL); - git_check_attr(the_repository->index, link, check); + git_check_attr(index, link, check); value = check->items[0].value; - if (value == NULL) - ; - else if (!strcmp(value, "file")) + if (ATTR_UNSET(value)) + return SYMLINK_TYPE_UNSPECIFIED; + if (!strcmp(value, "file")) return SYMLINK_TYPE_FILE; - else if (!strcmp(value, "dir")) + if (!strcmp(value, "dir") || !strcmp(value, "directory")) return SYMLINK_TYPE_DIRECTORY; + warning(_("ignoring invalid symlink type '%s' for '%s'"), value, link); return SYMLINK_TYPE_UNSPECIFIED; } -int symlink(const char *target, const char *link) +int mingw_create_symlink(struct index_state *index, const char *target, const char *link) { wchar_t wtarget[MAX_LONG_PATH], wlink[MAX_LONG_PATH]; int len; @@ -2429,7 +2433,7 @@ int symlink(const char *target, const char *link) if (wtarget[len] == '/') wtarget[len] = '\\'; - switch (check_symlink_attr(link)) { + switch (check_symlink_attr(index, link)) { case SYMLINK_TYPE_UNSPECIFIED: /* Create a phantom symlink: it is initially created as a file * symlink, but may change to a directory symlink later if/when diff --git a/compat/mingw.h b/compat/mingw.h index 17d4746f55f24b..14bd14ad8e8bd7 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -214,8 +214,10 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); int uname(struct utsname *buf); -int symlink(const char *target, const char *link); int readlink(const char *path, char *buf, size_t bufsiz); +struct index_state; +int mingw_create_symlink(struct index_state *index, const char *target, const char *link); +#define create_symlink mingw_create_symlink /* * replacements of existing functions diff --git a/entry.c b/entry.c index 6fd72b30c87686..39750f37450c16 100644 --- a/entry.c +++ b/entry.c @@ -289,7 +289,7 @@ static int write_entry(struct cache_entry *ce, if (!has_symlinks || to_tempfile) goto write_file_entry; - ret = symlink(new_blob, path); + ret = create_symlink(state ? state->istate : NULL, new_blob, path); free(new_blob); if (ret) return error_errno("unable to create symlink %s", path); diff --git a/git-compat-util.h b/git-compat-util.h index fa76c9840efb56..6fd91d1c9e4440 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -405,6 +405,15 @@ static inline char *git_find_last_dir_sep(const char *path) #define find_last_dir_sep git_find_last_dir_sep #endif +#ifndef create_symlink +struct index_state; +static inline int git_create_symlink(struct index_state *index, const char *target, const char *link) +{ + return symlink(target, link); +} +#define create_symlink git_create_symlink +#endif + #ifndef query_user_email #define query_user_email() NULL #endif diff --git a/merge-recursive.c b/merge-recursive.c index 4851825aebf29d..255347d23ed261 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1011,7 +1011,7 @@ static int update_file_flags(struct merge_options *o, char *lnk = xmemdupz(buf, size); safe_create_leading_directories_const(path); unlink(path); - if (symlink(lnk, path)) + if (create_symlink(&o->orig_index, lnk, path)) ret = err(o, _("failed to symlink '%s': %s"), path, strerror(errno)); free(lnk); diff --git a/refs/files-backend.c b/refs/files-backend.c index dd8abe91850802..bf5c7b9e409173 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1786,7 +1786,7 @@ static int create_ref_symlink(struct ref_lock *lock, const char *target) #ifndef NO_SYMLINK_HEAD char *ref_path = get_locked_file_path(&lock->lk); unlink(ref_path); - ret = symlink(target, ref_path); + ret = create_symlink(NULL, target, ref_path); free(ref_path); if (ret)