Skip to content

Commit 06cbe85

Browse files
heikkiorsilagitster
authored andcommitted
Make core.sharedRepository more generic
git init --shared=0xxx, where '0xxx' is an octal number, will create a repository with file modes set to '0xxx'. Users with a safe umask value (0077) can use this option to force file modes. For example, '0640' is a group-readable but not group-writable regardless of user's umask value. Values compatible with old Git versions are written as they were before, for compatibility reasons. That is, "1" for "group" and "2" for "everybody". "git config core.sharedRepository 0xxx" is also handled. Signed-off-by: Heikki Orsila <heikki.orsila@iki.fi> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent a17b1d2 commit 06cbe85

File tree

7 files changed

+149
-38
lines changed

7 files changed

+149
-38
lines changed

Documentation/config.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,12 @@ core.sharedRepository::
261261
group-writable). When 'all' (or 'world' or 'everybody'), the
262262
repository will be readable by all users, additionally to being
263263
group-shareable. When 'umask' (or 'false'), git will use permissions
264-
reported by umask(2). See linkgit:git-init[1]. False by default.
264+
reported by umask(2). When '0xxx', where '0xxx' is an octal number,
265+
files in the repository will have this mode value. '0xxx' will override
266+
user's umask value, and thus, users with a safe umask (0077) can use
267+
this option. Examples: '0660' is equivalent to 'group'. '0640' is a
268+
repository that is group-readable but not group-writable.
269+
See linkgit:git-init[1]. False by default.
265270

266271
core.warnAmbiguousRefs::
267272
If true, git will warn you if the ref name you passed it is ambiguous

Documentation/git-init.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ structure, some suggested "exclude patterns", and copies of non-executing
3131
"hook" files. The suggested patterns and hook files are all modifiable and
3232
extensible.
3333

34-
--shared[={false|true|umask|group|all|world|everybody}]::
34+
--shared[={false|true|umask|group|all|world|everybody|0xxx}]::
3535

3636
Specify that the git repository is to be shared amongst several users. This
3737
allows users belonging to the same group to push into that
@@ -52,6 +52,12 @@ is given:
5252
- 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
5353
readable by all users.
5454

55+
- '0xxx': '0xxx' is an octal number and each file will have mode '0xxx'
56+
Any option except 'umask' can be set using this option. '0xxx' will
57+
override users umask(2) value, and thus, users with a safe umask (0077)
58+
can use this option. '0640' will create a repository which is group-readable
59+
but not writable. '0660' is equivalent to 'group'.
60+
5561
By default, the configuration flag receive.denyNonFastForwards is enabled
5662
in shared repositories, so that you cannot force a non fast-forwarding push
5763
into it.

builtin-init-db.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,16 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
400400
char buf[10];
401401
/* We do not spell "group" and such, so that
402402
* the configuration can be read by older version
403-
* of git.
403+
* of git. Note, we use octal numbers for new share modes,
404+
* and compatibility values for PERM_GROUP and
405+
* PERM_EVERYBODY.
404406
*/
405-
sprintf(buf, "%d", shared_repository);
407+
if (shared_repository == PERM_GROUP)
408+
sprintf(buf, "%d", OLD_PERM_GROUP);
409+
else if (shared_repository == PERM_EVERYBODY)
410+
sprintf(buf, "%d", OLD_PERM_EVERYBODY);
411+
else
412+
sprintf(buf, "0%o", shared_repository);
406413
git_config_set("core.sharedrepository", buf);
407414
git_config_set("receive.denyNonFastforwards", "true");
408415
}

cache.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,10 +474,20 @@ static inline void hashclr(unsigned char *hash)
474474

475475
int git_mkstemp(char *path, size_t n, const char *template);
476476

477+
/*
478+
* NOTE NOTE NOTE!!
479+
*
480+
* PERM_UMASK, OLD_PERM_GROUP and OLD_PERM_EVERYBODY enumerations must
481+
* not be changed. Old repositories have core.sharedrepository written in
482+
* numeric format, and therefore these values are preserved for compatibility
483+
* reasons.
484+
*/
477485
enum sharedrepo {
478-
PERM_UMASK = 0,
479-
PERM_GROUP,
480-
PERM_EVERYBODY
486+
PERM_UMASK = 0,
487+
OLD_PERM_GROUP = 1,
488+
OLD_PERM_EVERYBODY = 2,
489+
PERM_GROUP = 0660,
490+
PERM_EVERYBODY = 0664,
481491
};
482492
int git_config_perm(const char *var, const char *value);
483493
int adjust_shared_perm(const char *path);

path.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -266,24 +266,25 @@ int adjust_shared_perm(const char *path)
266266
if (lstat(path, &st) < 0)
267267
return -1;
268268
mode = st.st_mode;
269-
if (mode & S_IRUSR)
270-
mode |= (shared_repository == PERM_GROUP
271-
? S_IRGRP
272-
: (shared_repository == PERM_EVERYBODY
273-
? (S_IRGRP|S_IROTH)
274-
: 0));
275-
276-
if (mode & S_IWUSR)
277-
mode |= S_IWGRP;
278-
279-
if (mode & S_IXUSR)
280-
mode |= (shared_repository == PERM_GROUP
281-
? S_IXGRP
282-
: (shared_repository == PERM_EVERYBODY
283-
? (S_IXGRP|S_IXOTH)
284-
: 0));
285-
if (S_ISDIR(mode))
269+
270+
if (shared_repository) {
271+
int tweak = shared_repository;
272+
if (!(mode & S_IWUSR))
273+
tweak &= ~0222;
274+
mode = (mode & ~0777) | tweak;
275+
} else {
276+
/* Preserve old PERM_UMASK behaviour */
277+
if (mode & S_IWUSR)
278+
mode |= S_IWGRP;
279+
}
280+
281+
if (S_ISDIR(mode)) {
286282
mode |= FORCE_DIR_SET_GID;
283+
284+
/* Copy read bits to execute bits */
285+
mode |= (shared_repository & 0444) >> 2;
286+
}
287+
287288
if ((mode & st.st_mode) != mode && chmod(path, mode) < 0)
288289
return -2;
289290
return 0;

setup.c

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -428,21 +428,53 @@ const char *setup_git_directory_gently(int *nongit_ok)
428428

429429
int git_config_perm(const char *var, const char *value)
430430
{
431-
if (value) {
432-
int i;
433-
if (!strcmp(value, "umask"))
434-
return PERM_UMASK;
435-
if (!strcmp(value, "group"))
436-
return PERM_GROUP;
437-
if (!strcmp(value, "all") ||
438-
!strcmp(value, "world") ||
439-
!strcmp(value, "everybody"))
440-
return PERM_EVERYBODY;
441-
i = atoi(value);
442-
if (i > 1)
443-
return i;
431+
int i;
432+
char *endptr;
433+
434+
if (value == NULL)
435+
return PERM_GROUP;
436+
437+
if (!strcmp(value, "umask"))
438+
return PERM_UMASK;
439+
if (!strcmp(value, "group"))
440+
return PERM_GROUP;
441+
if (!strcmp(value, "all") ||
442+
!strcmp(value, "world") ||
443+
!strcmp(value, "everybody"))
444+
return PERM_EVERYBODY;
445+
446+
/* Parse octal numbers */
447+
i = strtol(value, &endptr, 8);
448+
449+
/* If not an octal number, maybe true/false? */
450+
if (*endptr != 0)
451+
return git_config_bool(var, value) ? PERM_GROUP : PERM_UMASK;
452+
453+
/*
454+
* Treat values 0, 1 and 2 as compatibility cases, otherwise it is
455+
* a chmod value.
456+
*/
457+
switch (i) {
458+
case PERM_UMASK: /* 0 */
459+
return PERM_UMASK;
460+
case OLD_PERM_GROUP: /* 1 */
461+
return PERM_GROUP;
462+
case OLD_PERM_EVERYBODY: /* 2 */
463+
return PERM_EVERYBODY;
444464
}
445-
return git_config_bool(var, value);
465+
466+
/* A filemode value was given: 0xxx */
467+
468+
if ((i & 0600) != 0600)
469+
die("Problem with core.sharedRepository filemode value "
470+
"(0%.3o).\nThe owner of files must always have "
471+
"read and write permissions.", i);
472+
473+
/*
474+
* Mask filemode value. Others can not get write permission.
475+
* x flags for directories are handled separately.
476+
*/
477+
return i & 0666;
446478
}
447479

448480
int check_repository_format_version(const char *var, const char *value)

t/t1301-shared-repo.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ test_description='Test shared repository initialization'
77

88
. ./test-lib.sh
99

10+
# User must have read permissions to the repo -> failure on --shared=0400
11+
test_expect_success 'shared = 0400 (faulty permission u-w)' '
12+
mkdir sub && (
13+
cd sub && git init --shared=0400
14+
)
15+
ret="$?"
16+
rm -rf sub
17+
test $ret != "0"
18+
'
19+
1020
test_expect_success 'shared=all' '
1121
mkdir sub &&
1222
cd sub &&
@@ -33,4 +43,44 @@ test_expect_success 'update-server-info honors core.sharedRepository' '
3343
esac
3444
'
3545

46+
for u in 0660:rw-rw---- \
47+
0640:rw-r----- \
48+
0600:rw------- \
49+
0666:rw-rw-rw- \
50+
0664:rw-rw-r--
51+
do
52+
x=$(expr "$u" : ".*:\([rw-]*\)") &&
53+
y=$(echo "$x" | sed -e "s/w/-/g") &&
54+
u=$(expr "$u" : "\([0-7]*\)") &&
55+
git config core.sharedrepository "$u" &&
56+
umask 0277 &&
57+
58+
test_expect_success "shared = $u ($y) ro" '
59+
60+
rm -f .git/info/refs &&
61+
git update-server-info &&
62+
actual="$(ls -l .git/info/refs)" &&
63+
actual=${actual%% *} &&
64+
test "x$actual" = "x-$y" || {
65+
ls -lt .git/info
66+
false
67+
}
68+
'
69+
70+
umask 077 &&
71+
test_expect_success "shared = $u ($x) rw" '
72+
73+
rm -f .git/info/refs &&
74+
git update-server-info &&
75+
actual="$(ls -l .git/info/refs)" &&
76+
actual=${actual%% *} &&
77+
test "x$actual" = "x-$x" || {
78+
ls -lt .git/info
79+
false
80+
}
81+
82+
'
83+
84+
done
85+
3686
test_done

0 commit comments

Comments
 (0)