fix broken mount on synced apps

This commit is contained in:
olcxja 2026-10-09 19:47:12 +02:00
commit cd0007fc7d
4 changed files with 33 additions and 11 deletions

View file

@ -27,9 +27,23 @@ const XDG_LAYOUT = {
XDG_STATE_HOME: ['state', path.join('.local', 'state')]
}
// Write access goes to the folder the app was imported from and nowhere else
// outside its home: a portable app writes its logs next to itself.
const SYSTEM_DIRS = ['/bin', '/sbin', '/lib', '/lib32', '/lib64', '/libx32', '/usr', '/etc', '/boot', '/proc', '/sys', '/dev', '/run']
// Every folder the app is addressed by - the tree it was imported as, the one
// it runs in, and the one its binary sits in (a bundle may keep that in bin/,
// or start an app from a folder of its own) - each as stated and as it really
// is, since an app imported from the home may sit behind a link of its own.
function appShapes(game) {
const dirs = [game && game.path, game && game.workdir, game && game.exePath && path.dirname(game.exePath)]
const shapes = new Set()
for (const dir of dirs) {
if (!dir) continue
shapes.add(path.resolve(dir))
try {
shapes.add(fs.realpathSync(dir))
} catch {}
}
return [...shapes]
}
function writableAppDir(game) {
const dir = (game && (game.path || (game.exePath && path.dirname(game.exePath)))) || ''
@ -63,7 +77,7 @@ function linuxUser() {
// The names the app owns in its home: the redirected XDG folders and the
// launcher's own folder. The host home never gets to shadow them.
const OWNED_HOME_NAMES = new Set([PLWL_DIR])
const OWNED_HOME_NAMES = new Set([PLWL_DIR, '.config', '.local', '.cache'])
// The host home's own entries - what the desktop can hand an app (a drop from
// the file manager, a file picked in a dialog). A link resolving nowhere is
@ -112,15 +126,22 @@ function clearHomeRedirects(root) {
// view gives exactly those names back, at their real paths; the app's own
// entries are never touched. No other level has a view to point at, so the
// links come off again there - they would only dangle.
function syncHomeRedirects(root, { relaxed }) {
// One name is never linked: the one the app's own folder sits under. A portable
// bundle resolves itself with `readlink -f "$0"`, so a link there answers with
// FS_ROOT - a path under /tmp - and Prism Launcher reads that as "Your instance
// folder is in a temporary folder" on every start (measured in a real profile).
function syncHomeRedirects(root, { relaxed, appDirs = [] }) {
clearHomeRedirects(root)
if (!relaxed) return []
const home = os.homedir()
const made = []
for (const name of hostHomeEntries()) {
const real = path.join(home, name)
if (appDirs.some(dir => dir === real || dir.startsWith(real + path.sep))) continue
const file = path.join(root, 'home', name)
if (fs.existsSync(file)) continue
try {
fs.symlinkSync(path.join(FS_ROOT, os.homedir(), name), file)
fs.symlinkSync(path.join(FS_ROOT, real), file)
made.push(name)
} catch {}
}
@ -446,7 +467,7 @@ function buildLinuxEnv({ game, backend = 'env', fsRoot = false }) {
const prefixName = prefixNameForGame(game)
const root = ensureLinuxPfx(prefixName)
syncDesktopConfig(root)
const homeRedirects = syncHomeRedirects(root, { relaxed: backend === 'bwrap' && fsRoot })
const homeRedirects = syncHomeRedirects(root, { relaxed: backend === 'bwrap' && fsRoot, appDirs: appShapes(game) })
const sandboxed = backend === 'bwrap'
const home = sandboxed ? `/home/${linuxUser()}` : path.join(root, 'home')
const env = { ...process.env }
@ -615,5 +636,6 @@ module.exports = {
resolveLevel,
isolationLine,
handedPathFor,
runLinuxGame
runLinuxGame,
appShapes
}