1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-24 01:26:16 +02:00

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'
This commit is contained in:
Junio C Hamano 2020-05-05 14:54:28 -07:00
commit 1d7e9c4c4e
8 changed files with 100 additions and 19 deletions

View File

@ -1576,7 +1576,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
if (ctx->split) { if (ctx->split) {
char *lock_name = get_chain_filename(ctx->odb); char *lock_name = get_chain_filename(ctx->odb);
hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR); hold_lock_file_for_update_mode(&lk, lock_name,
LOCK_DIE_ON_ERROR, 0444);
fd = git_mkstemp_mode(ctx->graph_name, 0444); fd = git_mkstemp_mode(ctx->graph_name, 0444);
if (fd < 0) { if (fd < 0) {
@ -1584,9 +1585,16 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
return -1; return -1;
} }
if (adjust_shared_perm(ctx->graph_name)) {
error(_("unable to adjust shared permissions for '%s'"),
ctx->graph_name);
return -1;
}
f = hashfd(fd, ctx->graph_name); f = hashfd(fd, ctx->graph_name);
} else { } else {
hold_lock_file_for_update(&lk, ctx->graph_name, LOCK_DIE_ON_ERROR); hold_lock_file_for_update_mode(&lk, ctx->graph_name,
LOCK_DIE_ON_ERROR, 0444);
fd = lk.tempfile->fd; fd = lk.tempfile->fd;
f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf); f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
} }

View File

@ -70,7 +70,8 @@ static void resolve_symlink(struct strbuf *path)
} }
/* Make sure errno contains a meaningful value on error */ /* Make sure errno contains a meaningful value on error */
static int lock_file(struct lock_file *lk, const char *path, int flags) static int lock_file(struct lock_file *lk, const char *path, int flags,
int mode)
{ {
struct strbuf filename = STRBUF_INIT; struct strbuf filename = STRBUF_INIT;
@ -79,7 +80,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
resolve_symlink(&filename); resolve_symlink(&filename);
strbuf_addstr(&filename, LOCK_SUFFIX); strbuf_addstr(&filename, LOCK_SUFFIX);
lk->tempfile = create_tempfile(filename.buf); lk->tempfile = create_tempfile_mode(filename.buf, mode);
strbuf_release(&filename); strbuf_release(&filename);
return lk->tempfile ? lk->tempfile->fd : -1; return lk->tempfile ? lk->tempfile->fd : -1;
} }
@ -99,7 +100,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
* exactly once. If timeout_ms is -1, try indefinitely. * exactly once. If timeout_ms is -1, try indefinitely.
*/ */
static int lock_file_timeout(struct lock_file *lk, const char *path, static int lock_file_timeout(struct lock_file *lk, const char *path,
int flags, long timeout_ms) int flags, long timeout_ms, int mode)
{ {
int n = 1; int n = 1;
int multiplier = 1; int multiplier = 1;
@ -107,7 +108,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
static int random_initialized = 0; static int random_initialized = 0;
if (timeout_ms == 0) if (timeout_ms == 0)
return lock_file(lk, path, flags); return lock_file(lk, path, flags, mode);
if (!random_initialized) { if (!random_initialized) {
srand((unsigned int)getpid()); srand((unsigned int)getpid());
@ -121,7 +122,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
long backoff_ms, wait_ms; long backoff_ms, wait_ms;
int fd; int fd;
fd = lock_file(lk, path, flags); fd = lock_file(lk, path, flags, mode);
if (fd >= 0) if (fd >= 0)
return fd; /* success */ return fd; /* success */
@ -169,10 +170,11 @@ NORETURN void unable_to_lock_die(const char *path, int err)
} }
/* This should return a meaningful errno on failure */ /* This should return a meaningful errno on failure */
int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path, int hold_lock_file_for_update_timeout_mode(struct lock_file *lk,
int flags, long timeout_ms) const char *path, int flags,
long timeout_ms, int mode)
{ {
int fd = lock_file_timeout(lk, path, flags, timeout_ms); int fd = lock_file_timeout(lk, path, flags, timeout_ms, mode);
if (fd < 0) { if (fd < 0) {
if (flags & LOCK_DIE_ON_ERROR) if (flags & LOCK_DIE_ON_ERROR)
unable_to_lock_die(path, errno); unable_to_lock_die(path, errno);

View File

@ -90,6 +90,15 @@
* functions. In particular, the state diagram and the cleanup * functions. In particular, the state diagram and the cleanup
* machinery are all implemented in the tempfile module. * machinery are all implemented in the tempfile module.
* *
* Permission bits
* ---------------
*
* If you call either `hold_lock_file_for_update_mode` or
* `hold_lock_file_for_update_timeout_mode`, you can specify a suggested
* mode for the underlying temporary file. Note that the file isn't
* guaranteed to have this exact mode, since it may be limited by either
* the umask, 'core.sharedRepository', or both. See `adjust_shared_perm`
* for more.
* *
* Error handling * Error handling
* -------------- * --------------
@ -156,12 +165,20 @@ struct lock_file {
* file descriptor for writing to it, or -1 on error. If the file is * file descriptor for writing to it, or -1 on error. If the file is
* currently locked, retry with quadratic backoff for at least * currently locked, retry with quadratic backoff for at least
* timeout_ms milliseconds. If timeout_ms is 0, try exactly once; if * timeout_ms milliseconds. If timeout_ms is 0, try exactly once; if
* timeout_ms is -1, retry indefinitely. The flags argument and error * timeout_ms is -1, retry indefinitely. The flags argument, error
* handling are described above. * handling, and mode are described above.
*/ */
int hold_lock_file_for_update_timeout( int hold_lock_file_for_update_timeout_mode(
struct lock_file *lk, const char *path, struct lock_file *lk, const char *path,
int flags, long timeout_ms); int flags, long timeout_ms, int mode);
static inline int hold_lock_file_for_update_timeout(
struct lock_file *lk, const char *path,
int flags, long timeout_ms)
{
return hold_lock_file_for_update_timeout_mode(lk, path, flags,
timeout_ms, 0666);
}
/* /*
* Attempt to create a lockfile for the file at `path` and return a * 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(
return hold_lock_file_for_update_timeout(lk, path, flags, 0); return hold_lock_file_for_update_timeout(lk, path, flags, 0);
} }
static inline int hold_lock_file_for_update_mode(
struct lock_file *lk, const char *path,
int flags, int mode)
{
return hold_lock_file_for_update_timeout_mode(lk, path, flags, 0, mode);
}
/* /*
* Return a nonzero value iff `lk` is currently locked. * Return a nonzero value iff `lk` is currently locked.
*/ */

View File

@ -14,6 +14,10 @@ test_expect_success 'setup full repo' '
test_oid_init test_oid_init
' '
test_expect_success POSIXPERM 'tweak umask for modebit tests' '
umask 022
'
test_expect_success 'verify graph with no graph file' ' test_expect_success 'verify graph with no graph file' '
cd "$TRASH_DIRECTORY/full" && cd "$TRASH_DIRECTORY/full" &&
git commit-graph verify git commit-graph verify
@ -98,6 +102,13 @@ test_expect_success 'write graph' '
graph_read_expect "3" graph_read_expect "3"
' '
test_expect_success POSIXPERM 'write graph has correct permissions' '
test_path_is_file $objdir/info/commit-graph &&
echo "-r--r--r--" >expect &&
test_modebits $objdir/info/commit-graph >actual &&
test_cmp expect actual
'
graph_git_behavior 'graph exists' full commits/3 commits/1 graph_git_behavior 'graph exists' full commits/3 commits/1
test_expect_success 'Add more commits' ' test_expect_success 'Add more commits' '
@ -423,7 +434,8 @@ GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES))
corrupt_graph_setup() { corrupt_graph_setup() {
cd "$TRASH_DIRECTORY/full" && cd "$TRASH_DIRECTORY/full" &&
test_when_finished mv commit-graph-backup $objdir/info/commit-graph && test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
cp $objdir/info/commit-graph commit-graph-backup cp $objdir/info/commit-graph commit-graph-backup &&
chmod u+w $objdir/info/commit-graph
} }
corrupt_graph_verify() { corrupt_graph_verify() {
@ -437,6 +449,7 @@ corrupt_graph_verify() {
fi && fi &&
git status --short && git status --short &&
GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD=true git commit-graph write && GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD=true git commit-graph write &&
chmod u+w $objdir/info/commit-graph &&
git commit-graph verify git commit-graph verify
} }

View File

@ -37,6 +37,10 @@ graph_read_expect() {
test_cmp expect output test_cmp expect output
} }
test_expect_success POSIXPERM 'tweak umask for modebit tests' '
umask 022
'
test_expect_success 'create commits and write commit-graph' ' test_expect_success 'create commits and write commit-graph' '
for i in $(test_seq 3) for i in $(test_seq 3)
do do
@ -401,4 +405,24 @@ test_expect_success ULIMIT_FILE_DESCRIPTORS 'handles file descriptor exhaustion'
) )
' '
while read mode modebits
do
test_expect_success POSIXPERM "split commit-graph respects core.sharedrepository $mode" '
rm -rf $graphdir $infodir/commit-graph &&
git reset --hard commits/1 &&
test_config core.sharedrepository "$mode" &&
git commit-graph write --split --reachable &&
ls $graphdir/graph-*.graph >graph-files &&
test_line_count = 1 graph-files &&
echo "$modebits" >expect &&
test_modebits $graphdir/graph-*.graph >actual &&
test_cmp expect actual &&
test_modebits $graphdir/commit-graph-chain >actual &&
test_cmp expect actual
'
done <<\EOF
0666 -r--r--r--
0600 -r--------
EOF
test_done test_done

View File

@ -51,8 +51,10 @@ test_expect_success 'setup' '
done && done &&
git commit-graph write --reachable && git commit-graph write --reachable &&
mv .git/objects/info/commit-graph commit-graph-full && mv .git/objects/info/commit-graph commit-graph-full &&
chmod u+w commit-graph-full &&
git show-ref -s commit-5-5 | git commit-graph write --stdin-commits && git show-ref -s commit-5-5 | git commit-graph write --stdin-commits &&
mv .git/objects/info/commit-graph commit-graph-half && mv .git/objects/info/commit-graph commit-graph-half &&
chmod u+w commit-graph-half &&
git config core.commitGraph true git config core.commitGraph true
' '

View File

@ -130,17 +130,17 @@ static void deactivate_tempfile(struct tempfile *tempfile)
} }
/* Make sure errno contains a meaningful value on error */ /* Make sure errno contains a meaningful value on error */
struct tempfile *create_tempfile(const char *path) struct tempfile *create_tempfile_mode(const char *path, int mode)
{ {
struct tempfile *tempfile = new_tempfile(); struct tempfile *tempfile = new_tempfile();
strbuf_add_absolute_path(&tempfile->filename, path); strbuf_add_absolute_path(&tempfile->filename, path);
tempfile->fd = open(tempfile->filename.buf, tempfile->fd = open(tempfile->filename.buf,
O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666); O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, mode);
if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL) if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
/* Try again w/o O_CLOEXEC: the kernel might not support it */ /* Try again w/o O_CLOEXEC: the kernel might not support it */
tempfile->fd = open(tempfile->filename.buf, tempfile->fd = open(tempfile->filename.buf,
O_RDWR | O_CREAT | O_EXCL, 0666); O_RDWR | O_CREAT | O_EXCL, mode);
if (tempfile->fd < 0) { if (tempfile->fd < 0) {
deactivate_tempfile(tempfile); deactivate_tempfile(tempfile);
return NULL; return NULL;

View File

@ -88,8 +88,16 @@ struct tempfile {
* Attempt to create a temporary file at the specified `path`. Return * Attempt to create a temporary file at the specified `path`. Return
* a tempfile (whose "fd" member can be used for writing to it), or * a tempfile (whose "fd" member can be used for writing to it), or
* NULL on error. It is an error if a file already exists at that path. * NULL on error. It is an error if a file already exists at that path.
* Note that `mode` will be further modified by the umask, and possibly
* `core.sharedRepository`, so it is not guaranteed to have the given
* mode.
*/ */
struct tempfile *create_tempfile(const char *path); struct tempfile *create_tempfile_mode(const char *path, int mode);
static inline struct tempfile *create_tempfile(const char *path)
{
return create_tempfile_mode(path, 0666);
}
/* /*
* Register an existing file as a tempfile, meaning that it will be * Register an existing file as a tempfile, meaning that it will be