fix: patch symlinked entries instead of writing through them

This commit is contained in:
Felitendo committed 2026-09-29 08:15:38 +02:00
1 parent 6f62c7f21c
commit 0234e81811
3 files changed
+43 -8

No files matched your search

+3 -1
View File
@@ -116,7 +116,9 @@ Two ways, chosen per application.
Programs that start themselves at login write their own entry into Programs that start themselves at login write their own entry into
_~/.config/autostart_ pointing straight at their binary, bypassing the menu _~/.config/autostart_ pointing straight at their binary, bypassing the menu
entry entirely. Those are patched in place as well, unless the application is entry entirely. Those are patched in place as well, unless the application is
turned off in the applications list. turned off in the applications list. An entry that is a symlink, often to an
application's entry in _/usr/share/applications_, is replaced by a patched
file rather than written through, and undoing puts the link back.
Shortcuts on the desktop itself are patched in place too. Nothing in the XDG Shortcuts on the desktop itself are patched in place too. Nothing in the XDG
search path looks at that folder, so a shortcut that lives only there would search path looks at that folder, so a shortcut that lives only there would
+7 -1
View File
@@ -343,12 +343,18 @@ mca_backup_name() {
# copy was stored under. Existing backups are never overwritten: the first copy # copy was stored under. Existing backups are never overwritten: the first copy
# is the pristine one, and a second apply must not replace it with an already # is the pristine one, and a second apply must not replace it with an already
# patched version. # patched version.
#
# A symlink is kept as a symlink, so undo can put the link back. It is taken
# again every time: this program never writes a link, so one is always pristine.
mca_backup() { mca_backup() {
local file="$1" name local file="$1" name
name="$(mca_backup_name "$file")" name="$(mca_backup_name "$file")"
mkdir -p "$MCA_BACKUPDIR" 2>/dev/null || return 1 mkdir -p "$MCA_BACKUPDIR" 2>/dev/null || return 1
if [[ ! -e "$MCA_BACKUPDIR/$name" ]]; then if [[ -L $file ]]; then
rm -f -- "$MCA_BACKUPDIR/$name"
cp -P -p -- "$file" "$MCA_BACKUPDIR/$name" 2>/dev/null || return 1
elif [[ ! -e "$MCA_BACKUPDIR/$name" && ! -L "$MCA_BACKUPDIR/$name" ]]; then
cp -p -- "$file" "$MCA_BACKUPDIR/$name" 2>/dev/null || return 1 cp -p -- "$file" "$MCA_BACKUPDIR/$name" 2>/dev/null || return 1
fi fi
printf '%s\n' "$name" printf '%s\n' "$name"
+33 -6
View File
@@ -375,7 +375,7 @@ mca_desktop_apply() {
[[ "$content" == "$(< "$src")" ]] && return 0 [[ "$content" == "$(< "$src")" ]] && return 0
backup="$(mca_backup "$src")" || return 1 backup="$(mca_backup "$src")" || return 1
if mca_write_if_changed "$src" "$content"$'\n'; then if _mca_entry_write "$src" "$content"$'\n'; then
MCA_CHANGES=$(( MCA_CHANGES + 1 )) MCA_CHANGES=$(( MCA_CHANGES + 1 ))
fi fi
mca_ledger_add inplace "$src" "$backup" mca_ledger_add inplace "$src" "$backup"
@@ -418,6 +418,30 @@ mca_desktop_apply() {
# Neither can be shadowed from anywhere, so both are edited where they stand, # Neither can be shadowed from anywhere, so both are edited where they stand,
# with the original kept. # with the original kept.
# _mca_entry_write <file> <content>
# Writes an entry edited in place, like mca_write_if_changed. A symlink is
# replaced by the edited file instead of written through: it usually points at
# a package's entry in /usr, which is not ours to change. Undo puts the link
# back from the backup.
_mca_entry_write() {
local file="$1" content="$2" tmp
[[ -L $file ]] || { mca_write_if_changed "$file" "$content"; return; }
tmp="$(mktemp "$file.XXXXXX")" || return 2
chmod --reference="$file" -- "$tmp" 2>/dev/null || chmod 644 -- "$tmp"
# A link into /usr/share/applications is trusted for where it points. A
# copy on the desktop is only trusted by KDE when it can be run.
chmod u+x -- "$tmp" 2>/dev/null || true
if printf '%s' "$content" > "$tmp" && mv -f -- "$tmp" "$file"; then
return 0
fi
rm -f -- "$tmp"
return 2
}
# _mca_entry_patch_inplace <file> # _mca_entry_patch_inplace <file>
# One desktop entry that lives outside the XDG search path, edited where it is # One desktop entry that lives outside the XDG search path, edited where it is
# because there is nowhere to shadow it from. It follows the applications list # because there is nowhere to shadow it from. It follows the applications list
@@ -482,7 +506,7 @@ _mca_entry_patch_inplace() {
[[ "$content" == "$(< "$file")" ]] && return 0 [[ "$content" == "$(< "$file")" ]] && return 0
backup="$(mca_backup "$file")" || return 0 backup="$(mca_backup "$file")" || return 0
if mca_write_if_changed "$file" "$content"$'\n'; then if _mca_entry_write "$file" "$content"$'\n'; then
MCA_CHANGES=$(( MCA_CHANGES + 1 )) MCA_CHANGES=$(( MCA_CHANGES + 1 ))
fi fi
mca_ledger_add inplace "$file" "$backup" mca_ledger_add inplace "$file" "$backup"
@@ -607,7 +631,7 @@ mca_prune_orphans() {
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
mca_revert_all() { mca_revert_all() {
local kind path detail local kind path detail backup
[[ -f $MCA_LEDGER ]] || return 0 [[ -f $MCA_LEDGER ]] || return 0
@@ -623,12 +647,15 @@ mca_revert_all() {
fi fi
;; ;;
inplace) inplace)
if [[ -n $detail && -f "$MCA_BACKUPDIR/$detail" ]]; then backup="$MCA_BACKUPDIR/$detail"
if [[ -n $detail ]] && [[ -f $backup || -L $backup ]]; then
if [[ -e $path ]] || [[ -d "$(dirname -- "$path")" ]]; then if [[ -e $path ]] || [[ -d "$(dirname -- "$path")" ]]; then
cp -p -- "$MCA_BACKUPDIR/$detail" "$path" 2>/dev/null \ # A link goes back as a link, not written through.
[[ -L $backup ]] && rm -f -- "$path"
cp -P -p -- "$backup" "$path" 2>/dev/null \
&& MCA_CHANGES=$(( MCA_CHANGES + 1 )) && MCA_CHANGES=$(( MCA_CHANGES + 1 ))
fi fi
rm -f -- "$MCA_BACKUPDIR/$detail" rm -f -- "$backup"
elif [[ -f $path ]]; then elif [[ -f $path ]]; then
# No backup: the file did not exist before we wrote it. # No backup: the file did not exist before we wrote it.
rm -f -- "$path" rm -f -- "$path"