Skip to content

Commit 1d7e9c4

Browse files
committed
Merge branch 'tb/commit-graph-perm-bits'
Some of the files commit-graph subsystem keeps on disk did not correctly honor the core.sharedRepository settings and some were left read-write. * tb/commit-graph-perm-bits: commit-graph.c: make 'commit-graph-chain's read-only commit-graph.c: ensure graph layers respect core.sharedRepository commit-graph.c: write non-split graphs as read-only lockfile.c: introduce 'hold_lock_file_for_update_mode' tempfile.c: introduce 'create_tempfile_mode'
2 parents b75dc16 + 45a4365 commit 1d7e9c4

File tree

8 files changed

+100
-19
lines changed

8 files changed

+100
-19
lines changed

commit-graph.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,17 +1576,25 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
15761576
if (ctx->split) {
15771577
char *lock_name = get_chain_filename(ctx->odb);
15781578

1579-
hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
1579+
hold_lock_file_for_update_mode(&lk, lock_name,
1580+
LOCK_DIE_ON_ERROR, 0444);
15801581

15811582
fd = git_mkstemp_mode(ctx->graph_name, 0444);
15821583
if (fd < 0) {
15831584
error(_("unable to create temporary graph layer"));
15841585
return -1;
15851586
}
15861587

1588+
if (adjust_shared_perm(ctx->graph_name)) {
1589+
error(_("unable to adjust shared permissions for '%s'"),
1590+
ctx->graph_name);
1591+
return -1;
1592+
}
1593+
15871594
f = hashfd(fd, ctx->graph_name);
15881595
} else {
1589-
hold_lock_file_for_update(&lk, ctx->graph_name, LOCK_DIE_ON_ERROR);
1596+
hold_lock_file_for_update_mode(&lk, ctx->graph_name,
1597+
LOCK_DIE_ON_ERROR, 0444);
15901598
fd = lk.tempfile->fd;
15911599
f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
15921600
}

lockfile.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ static void resolve_symlink(struct strbuf *path)
7070
}
7171

7272
/* Make sure errno contains a meaningful value on error */
73-
static int lock_file(struct lock_file *lk, const char *path, int flags)
73+
static int lock_file(struct lock_file *lk, const char *path, int flags,
74+
int mode)
7475
{
7576
struct strbuf filename = STRBUF_INIT;
7677

@@ -79,7 +80,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
7980
resolve_symlink(&filename);
8081

8182
strbuf_addstr(&filename, LOCK_SUFFIX);
82-
lk->tempfile = create_tempfile(filename.buf);
83+
lk->tempfile = create_tempfile_mode(filename.buf, mode);
8384
strbuf_release(&filename);
8485
return lk->tempfile ? lk->tempfile->fd : -1;
8586
}
@@ -99,15 +100,15 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
99100
* exactly once. If timeout_ms is -1, try indefinitely.
100101
*/
101102
static int lock_file_timeout(struct lock_file *lk, const char *path,
102-
int flags, long timeout_ms)
103+
int flags, long timeout_ms, int mode)
103104
{
104105
int n = 1;
105106
int multiplier = 1;
106107
long remaining_ms = 0;
107108
static int random_initialized = 0;
108109

109110
if (timeout_ms == 0)
110-
return lock_file(lk, path, flags);
111+
return lock_file(lk, path, flags, mode);
111112

112113
if (!random_initialized) {
113114
srand((unsigned int)getpid());
@@ -121,7 +122,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
121122
long backoff_ms, wait_ms;
122123
int fd;
123124

124-
fd = lock_file(lk, path, flags);
125+
fd = lock_file(lk, path, flags, mode);
125126

126127
if (fd >= 0)
127128
return fd; /* success */
@@ -169,10 +170,11 @@ NORETURN void unable_to_lock_die(const char *path, int err)
169170
}
170171

171172
/* This should return a meaningful errno on failure */
172-
int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,
173-
int flags, long timeout_ms)
173+
int hold_lock_file_for_update_timeout_mode(struct lock_file *lk,
174+
const char *path, int flags,
175+
long timeout_ms, int mode)
174176
{
175-
int fd = lock_file_timeout(lk, path, flags, timeout_ms);
177+
int fd = lock_file_timeout(lk, path, flags, timeout_ms, mode);
176178
if (fd < 0) {
177179
if (flags & LOCK_DIE_ON_ERROR)
178180
unable_to_lock_die(path, errno);

lockfile.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@
9090
* functions. In particular, the state diagram and the cleanup
9191
* machinery are all implemented in the tempfile module.
9292
*
93+
* Permission bits
94+
* ---------------
95+
*
96+
* If you call either `hold_lock_file_for_update_mode` or
97+
* `hold_lock_file_for_update_timeout_mode`, you can specify a suggested
98+
* mode for the underlying temporary file. Note that the file isn't
99+
* guaranteed to have this exact mode, since it may be limited by either
100+
* the umask, 'core.sharedRepository', or both. See `adjust_shared_perm`
101+
* for more.
93102
*
94103
* Error handling
95104
* --------------
@@ -156,12 +165,20 @@ struct lock_file {
156165
* file descriptor for writing to it, or -1 on error. If the file is
157166
* currently locked, retry with quadratic backoff for at least
158167
* timeout_ms milliseconds. If timeout_ms is 0, try exactly once; if
159-
* timeout_ms is -1, retry indefinitely. The flags argument and error
160-
* handling are described above.
168+
* timeout_ms is -1, retry indefinitely. The flags argument, error
169+
* handling, and mode are described above.
161170
*/
162-
int hold_lock_file_for_update_timeout(
171+
int hold_lock_file_for_update_timeout_mode(
172+
struct lock_file *lk, const char *path,
173+
int flags, long timeout_ms, int mode);
174+
175+
static inline int hold_lock_file_for_update_timeout(
163176
struct lock_file *lk, const char *path,
164-
int flags, long timeout_ms);
177+
int flags, long timeout_ms)
178+
{
179+
return hold_lock_file_for_update_timeout_mode(lk, path, flags,
180+
timeout_ms, 0666);
181+
}
165182

166183
/*
167184
* Attempt to create a lockfile for the file at `path` and return a
@@ -175,6 +192,13 @@ static inline int hold_lock_file_for_update(
175192
return hold_lock_file_for_update_timeout(lk, path, flags, 0);
176193
}
177194

195+
static inline int hold_lock_file_for_update_mode(
196+
struct lock_file *lk, const char *path,
197+
int flags, int mode)
198+
{
199+
return hold_lock_file_for_update_timeout_mode(lk, path, flags, 0, mode);
200+
}
201+
178202
/*
179203
* Return a nonzero value iff `lk` is currently locked.
180204
*/

t/t5318-commit-graph.sh

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ test_expect_success 'setup full repo' '
1414
test_oid_init
1515
'
1616

17+
test_expect_success POSIXPERM 'tweak umask for modebit tests' '
18+
umask 022
19+
'
20+
1721
test_expect_success 'verify graph with no graph file' '
1822
cd "$TRASH_DIRECTORY/full" &&
1923
git commit-graph verify
@@ -98,6 +102,13 @@ test_expect_success 'write graph' '
98102
graph_read_expect "3"
99103
'
100104

105+
test_expect_success POSIXPERM 'write graph has correct permissions' '
106+
test_path_is_file $objdir/info/commit-graph &&
107+
echo "-r--r--r--" >expect &&
108+
test_modebits $objdir/info/commit-graph >actual &&
109+
test_cmp expect actual
110+
'
111+
101112
graph_git_behavior 'graph exists' full commits/3 commits/1
102113

103114
test_expect_success 'Add more commits' '
@@ -423,7 +434,8 @@ GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES))
423434
corrupt_graph_setup() {
424435
cd "$TRASH_DIRECTORY/full" &&
425436
test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
426-
cp $objdir/info/commit-graph commit-graph-backup
437+
cp $objdir/info/commit-graph commit-graph-backup &&
438+
chmod u+w $objdir/info/commit-graph
427439
}
428440

429441
corrupt_graph_verify() {
@@ -437,6 +449,7 @@ corrupt_graph_verify() {
437449
fi &&
438450
git status --short &&
439451
GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD=true git commit-graph write &&
452+
chmod u+w $objdir/info/commit-graph &&
440453
git commit-graph verify
441454
}
442455

t/t5324-split-commit-graph.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ graph_read_expect() {
3737
test_cmp expect output
3838
}
3939

40+
test_expect_success POSIXPERM 'tweak umask for modebit tests' '
41+
umask 022
42+
'
43+
4044
test_expect_success 'create commits and write commit-graph' '
4145
for i in $(test_seq 3)
4246
do
@@ -401,4 +405,24 @@ test_expect_success ULIMIT_FILE_DESCRIPTORS 'handles file descriptor exhaustion'
401405
)
402406
'
403407

408+
while read mode modebits
409+
do
410+
test_expect_success POSIXPERM "split commit-graph respects core.sharedrepository $mode" '
411+
rm -rf $graphdir $infodir/commit-graph &&
412+
git reset --hard commits/1 &&
413+
test_config core.sharedrepository "$mode" &&
414+
git commit-graph write --split --reachable &&
415+
ls $graphdir/graph-*.graph >graph-files &&
416+
test_line_count = 1 graph-files &&
417+
echo "$modebits" >expect &&
418+
test_modebits $graphdir/graph-*.graph >actual &&
419+
test_cmp expect actual &&
420+
test_modebits $graphdir/commit-graph-chain >actual &&
421+
test_cmp expect actual
422+
'
423+
done <<\EOF
424+
0666 -r--r--r--
425+
0600 -r--------
426+
EOF
427+
404428
test_done

t/t6600-test-reach.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ test_expect_success 'setup' '
5151
done &&
5252
git commit-graph write --reachable &&
5353
mv .git/objects/info/commit-graph commit-graph-full &&
54+
chmod u+w commit-graph-full &&
5455
git show-ref -s commit-5-5 | git commit-graph write --stdin-commits &&
5556
mv .git/objects/info/commit-graph commit-graph-half &&
57+
chmod u+w commit-graph-half &&
5658
git config core.commitGraph true
5759
'
5860

tempfile.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,17 +130,17 @@ static void deactivate_tempfile(struct tempfile *tempfile)
130130
}
131131

132132
/* Make sure errno contains a meaningful value on error */
133-
struct tempfile *create_tempfile(const char *path)
133+
struct tempfile *create_tempfile_mode(const char *path, int mode)
134134
{
135135
struct tempfile *tempfile = new_tempfile();
136136

137137
strbuf_add_absolute_path(&tempfile->filename, path);
138138
tempfile->fd = open(tempfile->filename.buf,
139-
O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
139+
O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, mode);
140140
if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
141141
/* Try again w/o O_CLOEXEC: the kernel might not support it */
142142
tempfile->fd = open(tempfile->filename.buf,
143-
O_RDWR | O_CREAT | O_EXCL, 0666);
143+
O_RDWR | O_CREAT | O_EXCL, mode);
144144
if (tempfile->fd < 0) {
145145
deactivate_tempfile(tempfile);
146146
return NULL;

tempfile.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,16 @@ struct tempfile {
8888
* Attempt to create a temporary file at the specified `path`. Return
8989
* a tempfile (whose "fd" member can be used for writing to it), or
9090
* NULL on error. It is an error if a file already exists at that path.
91+
* Note that `mode` will be further modified by the umask, and possibly
92+
* `core.sharedRepository`, so it is not guaranteed to have the given
93+
* mode.
9194
*/
92-
struct tempfile *create_tempfile(const char *path);
95+
struct tempfile *create_tempfile_mode(const char *path, int mode);
96+
97+
static inline struct tempfile *create_tempfile(const char *path)
98+
{
99+
return create_tempfile_mode(path, 0666);
100+
}
93101

94102
/*
95103
* Register an existing file as a tempfile, meaning that it will be

0 commit comments

Comments
 (0)