Skip to content

Commit a7168b4

Browse files
committed
path: reject .gitmodules as a symlink
Any part of the library which asks the question can pass in the mode to have it checked against `.gitmodules` being a symlink. This is particularly relevant for adding entries to the index from the worktree and for checking out files.
1 parent 58ff913 commit a7168b4

File tree

9 files changed

+232
-215
lines changed

9 files changed

+232
-215
lines changed

src/checkout.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,14 +1276,14 @@ static int checkout_verify_paths(
12761276
unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
12771277

12781278
if (action & CHECKOUT_ACTION__REMOVE) {
1279-
if (!git_path_isvalid(repo, delta->old_file.path, flags)) {
1279+
if (!git_path_isvalid(repo, delta->old_file.path, delta->old_file.mode, flags)) {
12801280
giterr_set(GITERR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path);
12811281
return -1;
12821282
}
12831283
}
12841284

12851285
if (action & ~CHECKOUT_ACTION__REMOVE) {
1286-
if (!git_path_isvalid(repo, delta->new_file.path, flags)) {
1286+
if (!git_path_isvalid(repo, delta->new_file.path, delta->new_file.mode, flags)) {
12871287
giterr_set(GITERR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path);
12881288
return -1;
12891289
}

src/index.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -890,17 +890,18 @@ static int index_entry_create(
890890
size_t pathlen = strlen(path), alloclen;
891891
struct entry_internal *entry;
892892
unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
893-
894-
GIT_UNUSED(st);
893+
uint16_t mode = 0;
895894

896895
/* always reject placing `.git` in the index and directory traversal.
897896
* when requested, disallow platform-specific filenames and upgrade to
898897
* the platform-specific `.git` tests (eg, `git~1`, etc).
899898
*/
900899
if (from_workdir)
901900
path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS;
901+
if (st)
902+
mode = st->st_mode;
902903

903-
if (!git_path_isvalid(repo, path, path_valid_flags)) {
904+
if (!git_path_isvalid(repo, path, mode, path_valid_flags)) {
904905
giterr_set(GITERR_INDEX, "invalid path: '%s'", path);
905906
return -1;
906907
}
@@ -925,7 +926,7 @@ static int index_entry_init(
925926
{
926927
int error = 0;
927928
git_index_entry *entry = NULL;
928-
git_buf path;
929+
git_buf path = GIT_BUF_INIT;
929930
struct stat st;
930931
git_oid oid;
931932
git_repository *repo;

src/path.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,7 @@ static bool verify_component(
17121712
git_repository *repo,
17131713
const char *component,
17141714
size_t len,
1715+
uint16_t mode,
17151716
unsigned int flags)
17161717
{
17171718
if (len == 0)
@@ -1744,13 +1745,19 @@ static bool verify_component(
17441745
return false;
17451746
}
17461747

1747-
if (flags & GIT_PATH_REJECT_DOT_GIT_HFS &&
1748-
!verify_dotgit_hfs(component, len))
1749-
return false;
1748+
if (flags & GIT_PATH_REJECT_DOT_GIT_HFS) {
1749+
if (!verify_dotgit_hfs(component, len))
1750+
return false;
1751+
if (S_ISLNK(mode) && git_path_is_hfs_dotgit_modules(component, len))
1752+
return false;
1753+
}
17501754

1751-
if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS &&
1752-
!verify_dotgit_ntfs(repo, component, len))
1753-
return false;
1755+
if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) {
1756+
if (!verify_dotgit_ntfs(repo, component, len))
1757+
return false;
1758+
if (S_ISLNK(mode) && git_path_is_ntfs_dotgit_modules(component, len))
1759+
return false;
1760+
}
17541761

17551762
/* don't bother rerunning the `.git` test if we ran the HFS or NTFS
17561763
* specific tests, they would have already rejected `.git`.
@@ -1801,6 +1808,7 @@ GIT_INLINE(unsigned int) dotgit_flags(
18011808
bool git_path_isvalid(
18021809
git_repository *repo,
18031810
const char *path,
1811+
uint16_t mode,
18041812
unsigned int flags)
18051813
{
18061814
const char *start, *c;
@@ -1814,14 +1822,14 @@ bool git_path_isvalid(
18141822
return false;
18151823

18161824
if (*c == '/') {
1817-
if (!verify_component(repo, start, (c - start), flags))
1825+
if (!verify_component(repo, start, (c - start), mode, flags))
18181826
return false;
18191827

18201828
start = c+1;
18211829
}
18221830
}
18231831

1824-
return verify_component(repo, start, (c - start), flags);
1832+
return verify_component(repo, start, (c - start), mode, flags);
18251833
}
18261834

18271835
int git_path_normalize_slashes(git_buf *out, const char *path)

src/path.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
637637
extern bool git_path_isvalid(
638638
git_repository *repo,
639639
const char *path,
640+
uint16_t mode,
640641
unsigned int flags);
641642

642643
/**

src/refdb_fs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
744744

745745
assert(file && backend && name);
746746

747-
if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
747+
if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
748748
giterr_set(GITERR_INVALID, "invalid reference name '%s'", name);
749749
return GIT_EINVALIDSPEC;
750750
}
@@ -1742,7 +1742,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
17421742

17431743
repo = backend->repo;
17441744

1745-
if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
1745+
if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
17461746
giterr_set(GITERR_INVALID, "invalid reference name '%s'", refname);
17471747
return GIT_EINVALIDSPEC;
17481748
}

src/submodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ int git_submodule_name_is_valid(const git_repository *repo, const char *name, in
382382
}
383383

384384
/* FIXME: Un-consting it to reduce the amount of diff */
385-
isvalid = git_path_isvalid((git_repository *)repo, buf.ptr, flags);
385+
isvalid = git_path_isvalid((git_repository *)repo, buf.ptr, 0, flags);
386386
git_buf_free(&buf);
387387

388388
return isvalid;

src/tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode)
5454
static int valid_entry_name(git_repository *repo, const char *filename)
5555
{
5656
return *filename != '\0' &&
57-
git_path_isvalid(repo, filename,
57+
git_path_isvalid(repo, filename, 0,
5858
GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH);
5959
}
6060

0 commit comments

Comments
 (0)