Skip to content

Commit 7fac7b5

Browse files
committed
Merge branch 'js/safe-directory-plus'
Platform-specific code that determines if a directory is OK to use as a repository has been taught to report more details, especially on Windows. * js/safe-directory-plus: mingw: handle a file owned by the Administrators group correctly mingw: be more informative when ownership check fails on FAT32 mingw: provide details about unsafe directories' ownership setup: prepare for more detailed "dubious ownership" messages setup: fix some formatting
2 parents 7d0a1c8 + 3f7207e commit 7fac7b5

File tree

4 files changed

+81
-15
lines changed

4 files changed

+81
-15
lines changed

compat/mingw.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "../git-compat-util.h"
22
#include "win32.h"
33
#include <aclapi.h>
4+
#include <sddl.h>
45
#include <conio.h>
56
#include <wchar.h>
67
#include "../strbuf.h"
@@ -2670,7 +2671,22 @@ static PSID get_current_user_sid(void)
26702671
return result;
26712672
}
26722673

2673-
int is_path_owned_by_current_sid(const char *path)
2674+
static int acls_supported(const char *path)
2675+
{
2676+
size_t offset = offset_1st_component(path);
2677+
WCHAR wroot[MAX_PATH];
2678+
DWORD file_system_flags;
2679+
2680+
if (offset &&
2681+
xutftowcsn(wroot, path, MAX_PATH, offset) > 0 &&
2682+
GetVolumeInformationW(wroot, NULL, 0, NULL, NULL,
2683+
&file_system_flags, NULL, 0))
2684+
return !!(file_system_flags & FILE_PERSISTENT_ACLS);
2685+
2686+
return 0;
2687+
}
2688+
2689+
int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
26742690
{
26752691
WCHAR wpath[MAX_PATH];
26762692
PSID sid = NULL;
@@ -2709,6 +2725,7 @@ int is_path_owned_by_current_sid(const char *path)
27092725
else if (sid && IsValidSid(sid)) {
27102726
/* Now, verify that the SID matches the current user's */
27112727
static PSID current_user_sid;
2728+
BOOL is_member;
27122729

27132730
if (!current_user_sid)
27142731
current_user_sid = get_current_user_sid();
@@ -2717,6 +2734,46 @@ int is_path_owned_by_current_sid(const char *path)
27172734
IsValidSid(current_user_sid) &&
27182735
EqualSid(sid, current_user_sid))
27192736
result = 1;
2737+
else if (IsWellKnownSid(sid, WinBuiltinAdministratorsSid) &&
2738+
CheckTokenMembership(NULL, sid, &is_member) &&
2739+
is_member)
2740+
/*
2741+
* If owned by the Administrators group, and the
2742+
* current user is an administrator, we consider that
2743+
* okay, too.
2744+
*/
2745+
result = 1;
2746+
else if (report &&
2747+
IsWellKnownSid(sid, WinWorldSid) &&
2748+
!acls_supported(path)) {
2749+
/*
2750+
* On FAT32 volumes, ownership is not actually recorded.
2751+
*/
2752+
strbuf_addf(report, "'%s' is on a file system that does"
2753+
"not record ownership\n", path);
2754+
} else if (report) {
2755+
LPSTR str1, str2, to_free1 = NULL, to_free2 = NULL;
2756+
2757+
if (ConvertSidToStringSidA(sid, &str1))
2758+
to_free1 = str1;
2759+
else
2760+
str1 = "(inconvertible)";
2761+
2762+
if (!current_user_sid)
2763+
str2 = "(none)";
2764+
else if (!IsValidSid(current_user_sid))
2765+
str2 = "(invalid)";
2766+
else if (ConvertSidToStringSidA(current_user_sid, &str2))
2767+
to_free2 = str2;
2768+
else
2769+
str2 = "(inconvertible)";
2770+
strbuf_addf(report,
2771+
"'%s' is owned by:\n"
2772+
"\t'%s'\nbut the current user is:\n"
2773+
"\t'%s'\n", path, str1, str2);
2774+
LocalFree(to_free1);
2775+
LocalFree(to_free2);
2776+
}
27202777
}
27212778

27222779
/*

compat/mingw.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ char *mingw_query_user_email(void);
463463
* Verifies that the specified path is owned by the user running the
464464
* current process.
465465
*/
466-
int is_path_owned_by_current_sid(const char *path);
466+
int is_path_owned_by_current_sid(const char *path, struct strbuf *report);
467467
#define is_path_owned_by_current_user is_path_owned_by_current_sid
468468

469469
/**

git-compat-util.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#include <crtdbg.h>
2424
#endif
2525

26+
struct strbuf;
27+
28+
2629
#define _FILE_OFFSET_BITS 64
2730

2831

@@ -487,7 +490,7 @@ static inline void extract_id_from_env(const char *env, uid_t *id)
487490
}
488491
}
489492

490-
static inline int is_path_owned_by_current_uid(const char *path)
493+
static inline int is_path_owned_by_current_uid(const char *path, struct strbuf *report)
491494
{
492495
struct stat st;
493496
uid_t euid;

setup.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,16 +1142,17 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
11421142
* added, for bare ones their git directory.
11431143
*/
11441144
static int ensure_valid_ownership(const char *gitfile,
1145-
const char *worktree, const char *gitdir)
1145+
const char *worktree, const char *gitdir,
1146+
struct strbuf *report)
11461147
{
11471148
struct safe_directory_data data = {
11481149
.path = worktree ? worktree : gitdir
11491150
};
11501151

11511152
if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
1152-
(!gitfile || is_path_owned_by_current_user(gitfile)) &&
1153-
(!worktree || is_path_owned_by_current_user(worktree)) &&
1154-
(!gitdir || is_path_owned_by_current_user(gitdir)))
1153+
(!gitfile || is_path_owned_by_current_user(gitfile, report)) &&
1154+
(!worktree || is_path_owned_by_current_user(worktree, report)) &&
1155+
(!gitdir || is_path_owned_by_current_user(gitdir, report)))
11551156
return 1;
11561157

11571158
/*
@@ -1232,6 +1233,7 @@ enum discovery_result {
12321233
*/
12331234
static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
12341235
struct strbuf *gitdir,
1236+
struct strbuf *report,
12351237
int die_on_error)
12361238
{
12371239
const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
@@ -1316,10 +1318,11 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
13161318
strbuf_setlen(dir, offset);
13171319
if (gitdirenv) {
13181320
enum discovery_result ret;
1321+
const char *gitdir_candidate =
1322+
gitdir_path ? gitdir_path : gitdirenv;
13191323

1320-
if (ensure_valid_ownership(gitfile,
1321-
dir->buf,
1322-
(gitdir_path ? gitdir_path : gitdirenv))) {
1324+
if (ensure_valid_ownership(gitfile, dir->buf,
1325+
gitdir_candidate, report)) {
13231326
strbuf_addstr(gitdir, gitdirenv);
13241327
ret = GIT_DIR_DISCOVERED;
13251328
} else
@@ -1344,7 +1347,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
13441347
if (is_git_directory(dir->buf)) {
13451348
if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT)
13461349
return GIT_DIR_DISALLOWED_BARE;
1347-
if (!ensure_valid_ownership(NULL, NULL, dir->buf))
1350+
if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
13481351
return GIT_DIR_INVALID_OWNERSHIP;
13491352
strbuf_addstr(gitdir, ".");
13501353
return GIT_DIR_BARE;
@@ -1377,7 +1380,7 @@ int discover_git_directory(struct strbuf *commondir,
13771380
return -1;
13781381

13791382
cwd_len = dir.len;
1380-
if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
1383+
if (setup_git_directory_gently_1(&dir, gitdir, NULL, 0) <= 0) {
13811384
strbuf_release(&dir);
13821385
return -1;
13831386
}
@@ -1424,7 +1427,7 @@ int discover_git_directory(struct strbuf *commondir,
14241427
const char *setup_git_directory_gently(int *nongit_ok)
14251428
{
14261429
static struct strbuf cwd = STRBUF_INIT;
1427-
struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
1430+
struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT, report = STRBUF_INIT;
14281431
const char *prefix = NULL;
14291432
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
14301433

@@ -1449,7 +1452,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
14491452
die_errno(_("Unable to read current working directory"));
14501453
strbuf_addbuf(&dir, &cwd);
14511454

1452-
switch (setup_git_directory_gently_1(&dir, &gitdir, 1)) {
1455+
switch (setup_git_directory_gently_1(&dir, &gitdir, &report, 1)) {
14531456
case GIT_DIR_EXPLICIT:
14541457
prefix = setup_explicit_git_dir(gitdir.buf, &cwd, &repo_fmt, nongit_ok);
14551458
break;
@@ -1481,12 +1484,14 @@ const char *setup_git_directory_gently(int *nongit_ok)
14811484
if (!nongit_ok) {
14821485
struct strbuf quoted = STRBUF_INIT;
14831486

1487+
strbuf_complete(&report, '\n');
14841488
sq_quote_buf_pretty(&quoted, dir.buf);
14851489
die(_("detected dubious ownership in repository at '%s'\n"
1490+
"%s"
14861491
"To add an exception for this directory, call:\n"
14871492
"\n"
14881493
"\tgit config --global --add safe.directory %s"),
1489-
dir.buf, quoted.buf);
1494+
dir.buf, report.buf, quoted.buf);
14901495
}
14911496
*nongit_ok = 1;
14921497
break;
@@ -1573,6 +1578,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
15731578

15741579
strbuf_release(&dir);
15751580
strbuf_release(&gitdir);
1581+
strbuf_release(&report);
15761582
clear_repository_format(&repo_fmt);
15771583

15781584
return prefix;

0 commit comments

Comments
 (0)