Subject: [PATCH v2 0/4] commit-graph: write non-split graphs as read-only

From: Taylor Blau <[email-masked]>
Date: Mon, 27 Apr 2020 10:27:49 -0600

Hi,

Here's an updated version of my series to resolve a difference between
the permissions that split- and non-split commit-graphs are written
with.

Not much has changed since last time, since the main discussion revolved
around differences between what mode the user passes and how that
interacts with 'adjust_shared_perm' as well as why split-graphs are
always read-only for everybody.

Patches 1-3 remain mostly the same, with only some additional
documentation in the patches and headers about the interaction between
the 'mode' parameter and the umask and 'core.sharedRepository'. The
fourth patch is new, and makes sure that split-graphs are also
respecting 'core.sharedRepository' (and never have permissions above
0444).

The end-state of this is that both split- and non-split graphs have at
most permission 0444, and both respect core.sharedRepository.

Thanks in advance for another look.

Taylor Blau (4):
  tempfile.c: introduce 'create_tempfile_mode'
  lockfile.c: introduce 'hold_lock_file_for_update_mode'
  commit-graph.c: write non-split graphs as read-only
  commit-graph.c: ensure graph layers respect core.sharedRepository

 commit-graph.c                |  9 ++++++++-
 lockfile.c                    | 18 ++++++++++--------
 lockfile.h                    | 32 ++++++++++++++++++++++++++++----
 t/t5318-commit-graph.sh       | 11 ++++++++++-
 t/t5324-split-commit-graph.sh | 18 ++++++++++++++++++
 t/t6600-test-reach.sh         |  2 ++
 tempfile.c                    |  6 +++---
 tempfile.h                    | 10 +++++++++-
 8 files changed, 88 insertions(+), 18 deletions(-)

Range-diff against v1:
1:  aa86e8df40 ! 1:  03c975b0bd tempfile.c: introduce 'create_tempfile_mode'
    @@ Commit message
         creates a temporary file with global read-write permissions, introduce a
         variant here that allows specifying the mode.

    +    Note that the mode given to 'create_tempfile_mode' is not guaranteed to
    +    be written to disk, since it is subject to both the umask and
    +    'core.sharedRepository'.
    +
         Arguably, all temporary files should have permission 0444, since they
         are likely to be renamed into place and then not written to again. This
         is a much larger change than we may want to take on in this otherwise
    @@ tempfile.c: static void deactivate_tempfile(struct tempfile *tempfile)

      ## tempfile.h ##
     @@ tempfile.h: struct tempfile {
    +  * Attempt to create a temporary file at the specified `path`. Return
       * 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.
    ++ * 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);
2:  dad37d4233 ! 2:  c1c84552bc lockfile.c: introduce 'hold_lock_file_for_update_mode'
    @@ Commit message
         functions, and leave the existing functions alone by inlining their
         definitions in terms of the new mode variants.

    -    Note that even though the commit-graph machinery only calls
    +    Note that, like in the previous commit, 'hold_lock_file_for_update_mode'
    +    is not guarenteed to set the given mode, since it may be modified by
    +    both the umask and 'core.sharedRepository'.
    +
    +    Note also that even though the commit-graph machinery only calls
         'hold_lock_file_for_update', that this is defined in terms of
         'hold_lock_file_for_update_timeout', and so both need an additional mode
         parameter here.
    @@ lockfile.c: NORETURN void unable_to_lock_die(const char *path, int err)
      			unable_to_lock_die(path, errno);

      ## lockfile.h ##
    +@@
    +  * functions. In particular, the state diagram and the cleanup
    +  * 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
    +  * --------------
     @@ lockfile.h: struct lock_file {
    -  * timeout_ms is -1, retry indefinitely. The flags argument and error
    -  * handling are described above.
    +  * file descriptor for writing to it, or -1 on error. If the file is
    +  * currently locked, retry with quadratic backoff for at least
    +  * timeout_ms milliseconds. If timeout_ms is 0, try exactly once; if
    +- * timeout_ms is -1, retry indefinitely. The flags argument and error
    +- * handling are described above.
    ++ * timeout_ms is -1, retry indefinitely. The flags argument, error
    ++ * handling, and mode are described above.
       */
     -int hold_lock_file_for_update_timeout(
     +int hold_lock_file_for_update_timeout_mode(
3:  622fd92cee ! 3:  86cf29ce9c commit-graph.c: write non-split graphs as read-only
    @@ Commit message
         commit-graph.c: write non-split graphs as read-only

         In the previous commit, Git learned 'hold_lock_file_for_update_mode' to
    -    allow the caller to specify the permission bits used when acquiring a
    -    temporary file.
    +    allow the caller to specify the permission bits (prior to further
    +    adjustment by the umask and shared repository permissions) used when
    +    acquiring a temporary file.

         Use this in the commit-graph machinery for writing a non-split graph to
         acquire an opened temporary file with permissions read-only permissions
         to match the split behavior. (In the split case, Git uses
    -    'git_mkstemp_mode' for each of the commit-graph layers with permission
    +    git_mkstemp_mode' for each of the commit-graph layers with permission
         bits '0444').

         One can notice this discrepancy when moving a non-split graph to be part
-:  ---------- > 4:  f83437f130 commit-graph.c: ensure graph layers respect core.sharedRepository
--
2.26.0.113.ge9739cdccc