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:
commit
1d7e9c4c4e
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
18
lockfile.c
18
lockfile.c
|
@ -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);
|
||||||
|
|
32
lockfile.h
32
lockfile.h
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
'
|
'
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
10
tempfile.h
10
tempfile.h
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue