Skip to content

Commit 91d6408

Browse files
committed
Check prefix folder is correct before deleting it
1 parent 66702c3 commit 91d6408

File tree

3 files changed

+130
-81
lines changed

3 files changed

+130
-81
lines changed

src/backend/main.ts

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@ import {
2424
import 'backend/updater'
2525
import { autoUpdater } from 'electron-updater'
2626
import { cpus } from 'os'
27-
import {
28-
existsSync,
29-
rmSync,
30-
watch,
31-
readdirSync,
32-
readFileSync
33-
} from 'graceful-fs'
27+
import { existsSync, watch, readdirSync, readFileSync } from 'graceful-fs'
3428
import 'source-map-support/register'
3529

3630
import Backend from 'i18next-fs-backend'
@@ -60,6 +54,7 @@ import {
6054
downloadDefaultWine,
6155
sendGameStatusUpdate
6256
} from './utils'
57+
import { uninstallGameCallback } from './utils/uninstaller'
6358
import {
6459
configStore,
6560
discordLink,
@@ -87,7 +82,6 @@ import {
8782
createNecessaryFolders,
8883
fixAsarPath,
8984
isSnap,
90-
fixesPath,
9185
isWindows,
9286
isMac
9387
} from './constants'
@@ -144,7 +138,6 @@ import {
144138
getGameOverride,
145139
getGameSdl
146140
} from 'backend/storeManagers/legendary/library'
147-
import { storeMap } from 'common/utils'
148141
import { backendEvents } from './backend_events'
149142

150143
app.commandLine?.appendSwitch('ozone-platform-hint', 'auto')
@@ -957,72 +950,7 @@ ipcMain.handle('openDialog', async (e, args) => {
957950

958951
ipcMain.on('showItemInFolder', async (e, item) => showItemInFolder(item))
959952

960-
ipcMain.handle(
961-
'uninstall',
962-
async (event, appName, runner, shouldRemovePrefix, shouldRemoveSetting) => {
963-
sendGameStatusUpdate({
964-
appName,
965-
runner,
966-
status: 'uninstalling'
967-
})
968-
969-
const { title } = gameManagerMap[runner].getGameInfo(appName)
970-
971-
let uninstalled = false
972-
973-
try {
974-
await gameManagerMap[runner].uninstall({ appName, shouldRemovePrefix })
975-
uninstalled = true
976-
} catch (error) {
977-
notify({
978-
title,
979-
body: i18next.t('notify.uninstalled.error', 'Error uninstalling')
980-
})
981-
logError(error, LogPrefix.Backend)
982-
}
983-
984-
if (uninstalled) {
985-
if (shouldRemovePrefix) {
986-
const { winePrefix } = await gameManagerMap[runner].getSettings(appName)
987-
logInfo(`Removing prefix ${winePrefix}`, LogPrefix.Backend)
988-
// remove prefix if exists
989-
if (existsSync(winePrefix)) {
990-
rmSync(winePrefix, { recursive: true })
991-
}
992-
}
993-
if (shouldRemoveSetting) {
994-
const removeIfExists = (filename: string) => {
995-
logInfo(`Removing ${filename}`, LogPrefix.Backend)
996-
const gameSettingsFile = join(gamesConfigPath, filename)
997-
if (existsSync(gameSettingsFile)) {
998-
rmSync(gameSettingsFile)
999-
}
1000-
}
1001-
1002-
removeIfExists(appName.concat('.json'))
1003-
removeIfExists(appName.concat('.log'))
1004-
removeIfExists(appName.concat('-lastPlay.log'))
1005-
}
1006-
1007-
const fixFilePath = path.join(
1008-
fixesPath,
1009-
`${appName}-${storeMap[runner]}.json`
1010-
)
1011-
if (existsSync(fixFilePath)) {
1012-
rmSync(fixFilePath)
1013-
}
1014-
1015-
notify({ title, body: i18next.t('notify.uninstalled') })
1016-
logInfo('Finished uninstalling', LogPrefix.Backend)
1017-
}
1018-
1019-
sendGameStatusUpdate({
1020-
appName,
1021-
runner,
1022-
status: 'done'
1023-
})
1024-
}
1025-
)
953+
ipcMain.handle('uninstall', uninstallGameCallback)
1026954

1027955
ipcMain.handle('repair', async (event, appName, runner) => {
1028956
if (!isOnline()) {

src/backend/storeManagers/sideload/games.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { notify } from '../../dialog/dialog'
2323
import { launchGame } from 'backend/storeManagers/storeManagerCommon/games'
2424
import { GOGCloudSavesLocation } from 'common/types/gog'
2525
import { InstallResult, RemoveArgs } from 'common/types/game_manager'
26+
import { removePrefix } from 'backend/utils/uninstaller'
2627

2728
export function getGameInfo(appName: string): GameInfo {
2829
const store = libraryStore.get('games', [])
@@ -110,14 +111,9 @@ export async function uninstall({
110111
title,
111112
install: { executable }
112113
} = gameInfo
113-
const { winePrefix } = await getSettings(appName)
114114

115115
if (shouldRemovePrefix) {
116-
logInfo(`Removing prefix ${winePrefix}`, LogPrefix.Backend)
117-
if (existsSync(winePrefix)) {
118-
// remove prefix if exists
119-
rmSync(winePrefix, { recursive: true })
120-
}
116+
removePrefix(appName, 'sideload')
121117
}
122118
libraryStore.set('games', current)
123119

src/backend/utils/uninstaller.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { GlobalConfig } from 'backend/config'
2+
import { fixesPath, gamesConfigPath } from 'backend/constants'
3+
import { notify } from 'backend/dialog/dialog'
4+
import { logError, logInfo, LogPrefix } from 'backend/logger/logger'
5+
import { gameManagerMap } from 'backend/storeManagers'
6+
import { sendGameStatusUpdate } from 'backend/utils'
7+
import { Runner } from 'common/types'
8+
import { storeMap } from 'common/utils'
9+
import { Event } from 'electron'
10+
import { existsSync, readdirSync, rmSync } from 'graceful-fs'
11+
import i18next from 'i18next'
12+
import { join } from 'path'
13+
14+
export const removePrefix = async (appName: string, runner: Runner) => {
15+
const { winePrefix } = await gameManagerMap[runner].getSettings(appName)
16+
logInfo(`Removing prefix ${winePrefix}`, LogPrefix.Backend)
17+
18+
if (!existsSync(winePrefix)) {
19+
logInfo(`Prefix folder ${winePrefix} doesn't exist, ignoring removal`)
20+
return
21+
}
22+
23+
// folder exists, do some sanity checks before deleting it
24+
const { defaultInstallPath, defaultWinePrefix } =
25+
GlobalConfig.get().getSettings()
26+
27+
if (winePrefix === defaultInstallPath) {
28+
logInfo(
29+
`Can't delete folder ${winePrefix}, prefix folder is the default install directory ${defaultInstallPath}`
30+
)
31+
return
32+
}
33+
34+
if (winePrefix === defaultWinePrefix) {
35+
logInfo(
36+
`Can't delete folder ${winePrefix}, prefix folder is the default prefix directory ${defaultWinePrefix}`
37+
)
38+
return
39+
}
40+
41+
const dirContent = readdirSync(winePrefix)
42+
43+
if (dirContent.length > 0) {
44+
const driveCPath = join(winePrefix, 'drive_c')
45+
46+
if (!existsSync(driveCPath)) {
47+
logInfo(
48+
`Can't delete folder ${winePrefix}, folder does not contain a drive_c folder. If this is the correct prefix folder, delete it manually.`
49+
)
50+
return
51+
}
52+
}
53+
54+
// if we got here, we are safe to delete this folder
55+
rmSync(winePrefix, { recursive: true })
56+
}
57+
58+
export const removeFixFile = (appName: string, runner: Runner) => {
59+
const fixFilePath = join(fixesPath, `${appName}-${storeMap[runner]}.json`)
60+
if (existsSync(fixFilePath)) {
61+
rmSync(fixFilePath)
62+
}
63+
}
64+
65+
export const removeSettingsAndLogs = (appName: string) => {
66+
const removeIfExists = (filename: string) => {
67+
logInfo(`Removing ${filename}`, LogPrefix.Backend)
68+
const gameSettingsFile = join(gamesConfigPath, filename)
69+
if (existsSync(gameSettingsFile)) {
70+
rmSync(gameSettingsFile)
71+
}
72+
}
73+
74+
removeIfExists(appName.concat('.json'))
75+
removeIfExists(appName.concat('.log'))
76+
removeIfExists(appName.concat('-lastPlay.log'))
77+
}
78+
79+
export const uninstallGameCallback = async (
80+
event: Event,
81+
appName: string,
82+
runner: Runner,
83+
shouldRemovePrefix: boolean,
84+
shouldRemoveSetting: boolean
85+
) => {
86+
sendGameStatusUpdate({
87+
appName,
88+
runner,
89+
status: 'uninstalling'
90+
})
91+
92+
const { title } = gameManagerMap[runner].getGameInfo(appName)
93+
94+
let uninstalled = false
95+
96+
try {
97+
await gameManagerMap[runner].uninstall({ appName, shouldRemovePrefix })
98+
uninstalled = true
99+
} catch (error) {
100+
notify({
101+
title,
102+
body: i18next.t('notify.uninstalled.error', 'Error uninstalling')
103+
})
104+
logError(error, LogPrefix.Backend)
105+
}
106+
107+
if (uninstalled) {
108+
if (shouldRemovePrefix) {
109+
removePrefix(appName, runner)
110+
}
111+
if (shouldRemoveSetting) {
112+
removeSettingsAndLogs(appName)
113+
}
114+
removeFixFile(appName, runner)
115+
116+
notify({ title, body: i18next.t('notify.uninstalled') })
117+
logInfo('Finished uninstalling', LogPrefix.Backend)
118+
}
119+
120+
sendGameStatusUpdate({
121+
appName,
122+
runner,
123+
status: 'done'
124+
})
125+
}

0 commit comments

Comments
 (0)