Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion bin/fm-pr-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,54 @@ fm_pr_sha256() {
fi
}

# Some filesystems cannot represent POSIX modes at all, so chmod there is a
# silent no-op and any mode assertion is guaranteed to fail: Git Bash mounts
# NTFS with `noacl` by default, where `chmod 0600` leaves stat reporting 644.
# Probe the actual directory rather than guessing from `uname` or mount flags -
# the same host can hold both mode-capable and mode-incapable filesystems.
# A probe that cannot complete reports capable, so an unexplained failure keeps
# the strict assertion instead of silently relaxing it.
FM_PR_MODE_PROBE_DIR=
FM_PR_MODE_PROBE_RESULT=
fm_pr_mode_capable() {
local dir=$1 tmp first second
first=''
second=''
[ "$dir" = "$FM_PR_MODE_PROBE_DIR" ] && return "$FM_PR_MODE_PROBE_RESULT"
tmp=$(mktemp "$dir/.fm-pr-mode-probe.XXXXXX" 2>/dev/null) || return 0
# Probe both directions. A single chmod would be fooled by the caller's umask
# already creating the file at the target mode - callers here run under
# `umask 077`, so a fresh file reads 600 whether or not chmod works.
if chmod 0600 "$tmp" 2>/dev/null; then first=$(fm_pr_file_mode "$tmp"); fi
if chmod 0644 "$tmp" 2>/dev/null; then second=$(fm_pr_file_mode "$tmp"); fi
rm -f -- "$tmp"
# Only a complete, unambiguous observation may relax anything. A capable
# filesystem reports both requested modes. An incapable one reports the same
# unchanged mode twice, which is chmod demonstrably doing nothing. Every other
# outcome - a failed chmod, an unreadable mode, a partial change - is not
# understood, so it reports capable, keeps the strict assertion, and is not
# cached, so a transient failure cannot be remembered as evidence.
if [ "$first" = 600 ] && [ "$second" = 644 ]; then
FM_PR_MODE_PROBE_DIR=$dir
FM_PR_MODE_PROBE_RESULT=0
return 0
fi
if [ -n "$first" ] && [ "$first" = "$second" ]; then
FM_PR_MODE_PROBE_DIR=$dir
FM_PR_MODE_PROBE_RESULT=1
return 1
fi
return 0
}

fm_pr_private_file_valid() {
local path=$1 mode=$2 device=$3
[ -f "$path" ] && [ ! -L "$path" ] || return 1
[ "$(fm_pr_file_mode "$path")" = "$mode" ] || return 1
# The mode assertion is skipped only where the filesystem provably cannot
# express modes; the checks below carry the substantive guarantees there.
if fm_pr_mode_capable "$(dirname "$path")"; then
[ "$(fm_pr_file_mode "$path")" = "$mode" ] || return 1
fi
[ "$(fm_pr_file_device "$path")" = "$device" ] || return 1
[ "$(fm_pr_file_link_count "$path")" = 1 ]
}
Expand Down