Record: the root desktop entry that was a symlink

Outcome

Integrating Audacity 4.0.0 completes instead of failing with “the AppImage has no root desktop entry”. The SquashFS reader follows symbolic links in a payload the way the kernel does, so a root desktop entry that is a link into the AppImage’s own share/applications is read, a path through a directory link resolves, and the payload’s MIME package is found again on AppImages that use the usr -> . layout.

What Happened

The reported failure was appimage-integrate on audacity-linux-4.0.0-x86_64.AppImage:

State:     unknown
    Launcher:  (none yet)
    the AppImage has no root desktop entry

The AppImage is not malformed. Its root holds a link:

lrwxrwxrwx  org.audacityteam.Audacity4portable.desktop -> share/applications/org.audacityteam.Audacity4portable.desktop
    lrwxrwxrwx  .DirIcon -> audacity4portable.png
    lrwxrwxrwx  audacity4portable.png -> share/icons/hicolor/64x64/apps/audacity4portable.png
    lrwxrwxrwx  usr -> .

Linking the root desktop name into share/applications is an ordinary AppImage shape, and the AppImage runtime resolves it. The reader did not:

.DirIcon being a link had the same effect on the icon, though the root fallback found aup4.svg, so the icon was not the visible symptom.

The Fix

Change Where
is_symlink_inode sources/appimage/squashfs_reader.cpp
split_path_components, shared by both resolvers sources/appimage/squashfs_reader.cpp
resolve_path_following_symlinks: follows a link in any position, resolves a relative target against the directory holding the link, steps back out of .. through a stack of the directories walked, and bounds a chain at 16 sources/appimage/squashfs_reader.cpp
read_file and list_directory use it sources/appimage/squashfs_reader.cpp
The root desktop listing takes real files first, then links that resolve to a regular file, skipping an inode already listed sources/appimage/squashfs_reader.cpp
Fixture gains the Audacity shape, a directory link, and a read through a link tests/40-squashfs-payload-reader.sh
Assertions for both, and for the no-duplicate rule tests/squashfs_reader_test.cpp

Decisions

Verification

verified 2026-10-02:

Commits

If It Happens Again

“no root desktop entry” is a claim about the payload, so check it before believing it:

unsquashfs -ll -offset <payload-offset> <AppImage> | grep -E '\.desktop|^l'
    appimage-inspect <AppImage>            # the payload root, with each entry's node type

The offset is the payload-offset that appimage-inspect prints. A root entry that shows as symlink is normal; if the tool ever again says there is none, the reader is the suspect, not the AppImage.