diff --git a/source/gc/fileOps.c b/source/gc/fileOps.c new file mode 100644 index 00000000..ebfbaab8 --- /dev/null +++ b/source/gc/fileOps.c @@ -0,0 +1,268 @@ +/*//////////////////////////////////////////////////////////////////////////////////////// + +fsop contains coomprensive set of function for file and folder handling + +en exposed s_fsop fsop structure can be used by callback to update operation status + +////////////////////////////////////////////////////////////////////////////////////////*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include //for mkdir +#include + +#include "fileOps.h" +#include "memory/mem2.hpp" +#include "utils.h" + +s_fsop fsop; + +// return false if the file doesn't exist +bool fsop_GetFileSizeBytes (char *path, size_t *filesize) // for me stats st_size report always 0 :( +{ + FILE *f; + size_t size = 0; + + f = fopen(path, "rb"); + if (!f) + { + if (filesize) *filesize = size; + return false; + } + + //Get file size + fseek( f, 0, SEEK_END); + size = ftell(f); + if (filesize) *filesize = size; + SAFE_CLOSE(f); + + + return true; +} + +/* +Recursive fsop_GetFolderBytes +*/ +u64 fsop_GetFolderBytes (char *source) +{ + DIR *pdir; + struct dirent *pent; + char newSource[300]; + u64 bytes = 0; + + pdir=opendir(source); + + while ((pent=readdir(pdir)) != NULL) + { + // Skip it + if (strcmp (pent->d_name, ".") == 0 || strcmp (pent->d_name, "..") == 0) + continue; + + sprintf (newSource, "%s/%s", source, pent->d_name); + + // If it is a folder... recurse... + if (fsop_DirExist (newSource)) + { + bytes += fsop_GetFolderBytes (newSource); + } + else // It is a file ! + { + size_t s; + fsop_GetFileSizeBytes (newSource, &s); + bytes += s; + } + } + + closedir(pdir); + + //Debug ("fsop_GetFolderBytes (%s) = %llu", source, bytes); + + return bytes; + } + +u32 fsop_GetFolderKb (char *source) +{ + u32 ret = (u32) round ((double)fsop_GetFolderBytes (source) / 1000.0); + + return ret; +} + +u32 fsop_GetFreeSpaceKb (char *path) // Return free kb on the device passed +{ + struct statvfs s; + + statvfs (path, &s); + + u32 ret = (u32)round( ((double)s.f_bfree / 1000.0) * s.f_bsize); + + return ret ; +} + + +bool fsop_DirExist (char *path) +{ + DIR *dir; + + dir=opendir(path); + if (dir) + { + closedir(dir); + return true; + } + + return false; +} + +bool fsop_CopyFile (char *source, char *target, progress_callback_t spinner, void *spinner_data) +{ + int err = 0; + fsop.breakop = 0; + + u8 *buff = NULL; + u32 size; + u32 bytes, rb,wb; + u32 block = 71680; //70KB + FILE *fs = NULL, *ft = NULL; + + fs = fopen(source, "rb"); + if (!fs) + { + return false; + } + + ft = fopen(target, "wt"); + if (!ft) + { + SAFE_CLOSE(fs); + return false; + } + + //Get file size + fseek (fs, 0, SEEK_END); + size = ftell(fs); + + fsop.size = size; + + if (size == 0) + { + SAFE_CLOSE(fs); + SAFE_CLOSE(ft); + return true; + } + + // Return to beginning.... + fseek(fs, 0, SEEK_SET); + + buff = MEM2_alloc(block); + if (buff == NULL) + { + SAFE_CLOSE(fs); + return false; + } + + bytes = 0; + bool spinnerFlag = false; + if (strstr (source, "game.iso")) { + spinner(bytes, size, spinner_data); + spinnerFlag = true; + } + + do + { + rb = fread(buff, 1, block, fs); + wb = fwrite(buff, 1, rb, ft); + + if (wb != wb) err = 1; + if (rb == 0) err = 1; + bytes += rb; + + if (spinnerFlag) spinner(bytes, size, spinner_data); + + fsop.multy.bytes += rb; + fsop.bytes = bytes; + + if (fsop.breakop) break; + } + while (bytes < size && err == 0); + + SAFE_CLOSE(fs); + SAFE_CLOSE(ft); + MEM2_free(buff); + + if (err) unlink (target); + + if (fsop.breakop || err) return false; + + return true; +} + +/* +Semplified folder make +*/ +int fsop_MakeFolder (char *path) +{ + if (mkdir(path, S_IREAD | S_IWRITE) == 0) return true; + + return false; +} + +/* +Recursive copyfolder +*/ +static bool doCopyFolder (char *source, char *target, progress_callback_t spinner, void *spinner_data) +{ + DIR *pdir; + struct dirent *pent; + char newSource[300], newTarget[300]; + bool ret = true; + + // If target folder doesn't exist, create it ! + if (!fsop_DirExist (target)) + { + fsop_MakeFolder (target); + } + + pdir=opendir(source); + + while ((pent=readdir(pdir)) != NULL && ret == true) + { + // Skip it + if (strcmp (pent->d_name, ".") == 0 || strcmp (pent->d_name, "..") == 0) + continue; + + sprintf (newSource, "%s/%s", source, pent->d_name); + sprintf (newTarget, "%s/%s", target, pent->d_name); + + // If it is a folder... recurse... + if (fsop_DirExist (newSource)) + { + ret = doCopyFolder (newSource, newTarget, spinner, spinner_data); + } + else // It is a file ! + { + strcpy (fsop.op, pent->d_name); + ret = fsop_CopyFile (newSource, newTarget, spinner, spinner_data); + } + } + + closedir(pdir); + + return ret; +} + +bool fsop_CopyFolder (char *source, char *target, progress_callback_t spinner, void *spinner_data) +{ + fsop.breakop = 0; + fsop.multy.startms = ticks_to_millisecs(gettime()); + fsop.multy.bytes = 0; + fsop.multy.size = fsop_GetFolderBytes (source); + + return doCopyFolder (source, target, spinner, spinner_data); +} diff --git a/source/gc/fileOps.h b/source/gc/fileOps.h new file mode 100644 index 00000000..564a91cb --- /dev/null +++ b/source/gc/fileOps.h @@ -0,0 +1,46 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef _FILEOPS +#define _FILEOPS + +typedef void (*progress_callback_t)(int status,int total,void *user_data); + +typedef struct + { + u64 size, bytes; // for operation that uses more than one file + u32 startms; + } +s_fsopmulty; + +typedef struct + { + char op[256]; // Calling process can set filename or any other info that fit + + u32 size, bytes; + + s_fsopmulty multy; + + int flag1; // user defined flag + bool breakop; // allow to stop a long operation + } +s_fsop; + +extern s_fsop fsop; + +bool fsop_GetFileSizeBytes (char *path, size_t *filesize); +u64 fsop_GetFolderBytes (char *source); +u32 fsop_GetFolderKb (char *source); +u32 fsop_GetFreeSpaceKb (char *path); +bool fsop_DirExist (char *path); +bool fsop_CopyFile (char *source, char *target, progress_callback_t spinner, void *spinner_data); +int fsop_MakeFolder (char *path); +bool fsop_CopyFolder (char *source, char *target, progress_callback_t spinner, void *spinner_data); + +#endif + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/source/gc/gc.c b/source/gc/gc.c index 4ef91840..70790316 100644 --- a/source/gc/gc.c +++ b/source/gc/gc.c @@ -4,6 +4,7 @@ #include #include "gc.h" #include "gecko.h" +#include "fileOps.h" #define MAX_FAT_PATH 1024 @@ -94,18 +95,18 @@ void set_language(u8 lang) while(!__SYS_SyncSram()); } -void DML_RemoveGame(const char *discid) +void DML_RemoveGame(const char *discid, const char* partition) { int num = 6; - const char *fl[6] = {"sd:/games/%s/game.iso","sd:/games/%s/sys/boot.bin","sd:/games/%s/sys/bi2.bin", - "sd:/games/%s/sys/apploader.img","sd:/games/%s/sys","sd:/games/%s"}; + const char *fl[6] = {"%s:/games/%s/game.iso","%s:/games/%s/sys/boot.bin","%s:/games/%s/sys/bi2.bin", + "%s:/games/%s/sys/apploader.img","%s:/games/%s/sys","%s:/games/%s"}; char fname[MAX_FAT_PATH]; FILE *f; DIR *dir; int i; for(i = 0; i < num; i++) { - sprintf(fname, fl[i], discid); + sprintf(fname, fl[i], partition, discid); f = fopen((char*)fname, "r"); if(f) { @@ -123,10 +124,10 @@ void DML_RemoveGame(const char *discid) } } -bool DML_GameIsInstalled(char *discid) +bool DML_GameIsInstalled(char *discid, const char* partition) { char filepath[64]; - sprintf(filepath, "sd:/games/%s/game.iso", discid); + sprintf(filepath, "%s:/games/%s/game.iso", partition, discid); gprintf("Filepath on SD: %s\n", filepath); diff --git a/source/gc/gc.h b/source/gc/gc.h index 9578f8d7..2ef50ae4 100644 --- a/source/gc/gc.h +++ b/source/gc/gc.h @@ -7,8 +7,8 @@ extern "C" #define GC_H_ void set_video_mode(int i); void set_language(u8 lang); -void DML_RemoveGame(const char *discid); -bool DML_GameIsInstalled(char *discid); +void DML_RemoveGame(const char *discid, const char* partition); +bool DML_GameIsInstalled(char *discid, const char* partition); #endif //GC_H_ #ifdef __cplusplus diff --git a/source/list/list.cpp b/source/list/list.cpp index 9b6f25f7..3f2e68ac 100644 --- a/source/list/list.cpp +++ b/source/list/list.cpp @@ -131,7 +131,7 @@ void CList::GetHeaders(safe_vector pathlist, safe_vectorIsInserted(SD)) + currentPartition = m_cfg.getInt("DML", "partition", 0); + if(!DeviceHandler::Instance()->IsInserted(currentPartition)) return false; - gprintf("%s\n", DeviceName[SD]); - DeviceHandler::Instance()->Open_WBFS(SD); - m_gameList.Load(sfmt(DML_DIR, DeviceName[SD]), ".iso", m_cfg.getString("DML", "lastlanguage", "EN").c_str()); + gprintf("%s\n", DeviceName[currentPartition]); + DeviceHandler::Instance()->Open_WBFS(currentPartition); + m_gameList.Load(sfmt(DML_DIR, DeviceName[currentPartition]), ".iso", m_cfg.getString("DML", "lastlanguage", "EN").c_str()); m_cfg.setString("DML", "lastlanguage", m_loc.getString(m_curLanguage, "gametdb_code", "EN")); m_cfg.save(); return m_gameList.size() > 0 ? true : false; diff --git a/source/menu/menu.hpp b/source/menu/menu.hpp index 587d30e9..e983eaab 100644 --- a/source/menu/menu.hpp +++ b/source/menu/menu.hpp @@ -634,6 +634,7 @@ private: private: enum WBFS_OP { WO_ADD_GAME, WO_REMOVE_GAME, WO_FORMAT }; + bool copyGameCubeGame; typedef std::pair FontDesc; typedef std::map FontSet; typedef std::map TexSet; @@ -931,6 +932,7 @@ private: static void _addDiscProgress(int status, int total, void *user_data); static int _gameInstaller(void *obj); static int _GCgameInstaller(void *obj); + static int _GCcopyGame(void *obj); wstringEx _optBoolToString(int b); void _stopSounds(void); diff --git a/source/menu/menu_config.cpp b/source/menu/menu_config.cpp index 559df5d4..fb0a1ce1 100644 --- a/source/menu/menu_config.cpp +++ b/source/menu/menu_config.cpp @@ -84,14 +84,12 @@ void CMenu::_showConfig(void) _setBg(m_configBg, m_configBg); m_btnMgr.show(m_configLblTitle); m_btnMgr.show(m_configBtnBack); - if (m_current_view != COVERFLOW_DML && !m_locked) + if (!m_locked) { m_btnMgr.show(m_configLblPartitionName); m_btnMgr.show(m_configLblPartition); m_btnMgr.show(m_configBtnPartitionP); m_btnMgr.show(m_configBtnPartitionM); - } - if (!m_locked) { m_btnMgr.show(m_configLblDownload); m_btnMgr.show(m_configBtnDownload); } diff --git a/source/menu/menu_config_game.cpp b/source/menu/menu_config_game.cpp index be53ab4a..f4502ea0 100644 --- a/source/menu/menu_config_game.cpp +++ b/source/menu/menu_config_game.cpp @@ -161,8 +161,6 @@ void CMenu::_showGameSettings(void) if(m_current_view != COVERFLOW_DML) { - - m_btnMgr.hide(m_gameSettingsBtnCategoryMain); m_btnMgr.hide(m_gameSettingsLblCategoryMain); diff --git a/source/menu/menu_game.cpp b/source/menu/menu_game.cpp index d50768a6..a482260a 100644 --- a/source/menu/menu_game.cpp +++ b/source/menu/menu_game.cpp @@ -424,6 +424,19 @@ void CMenu::_game(bool launch) else if (launch || m_btnMgr.selected(m_gameBtnPlay) || (!WPadIR_Valid(0) && !WPadIR_Valid(1) && !WPadIR_Valid(2) && !WPadIR_Valid(3) && m_btnMgr.selected((u32)-1))) { _hideGame(); + + if(currentPartition != SD && m_current_view == COVERFLOW_DML) + { + copyGameCubeGame = true; + if(!_wbfsOp(CMenu::WO_ADD_GAME)) + { + copyGameCubeGame = false; + break; + } + currentPartition = SD; + } + + copyGameCubeGame = false; dir_discHdr *hdr = m_cf.getHdr(); m_cf.clear(); diff --git a/source/menu/menu_main.cpp b/source/menu/menu_main.cpp index f0bb3d68..e5877d4a 100644 --- a/source/menu/menu_main.cpp +++ b/source/menu/menu_main.cpp @@ -156,13 +156,15 @@ void CMenu::LoadView(void) m_cf.applySettings(); char *mode = (m_current_view == COVERFLOW_CHANNEL && m_cfg.getBool("NAND", "disable", true)) - ? (char *)"NAND" : ((m_current_view == COVERFLOW_DML) ? (char *)"DML" : (char *)DeviceName[currentPartition]); + ? (char *)"NAND" : (char *)DeviceName[currentPartition]; for(u8 i = 0; strncmp((const char *)&mode[i], "\0", 1) != 0; i++) mode[i] = toupper(mode[i]); m_showtimer=60; - m_btnMgr.setText(m_mainLblNotice, (string)mode); + char gui_name[20]; + sprintf(gui_name,"%s [%s]",_domainFromView(),mode); + m_btnMgr.setText(m_mainLblNotice, (string)gui_name); m_btnMgr.show(m_mainLblNotice); } @@ -370,7 +372,7 @@ int CMenu::main(void) { bool block = m_current_view == COVERFLOW_CHANNEL && m_cfg.getBool("NAND", "disable", true); char *partition; - if(!block && (m_current_view != COVERFLOW_DML)) + if(!block) { _showWaitMessage(); _hideMain(); @@ -387,7 +389,7 @@ int CMenu::main(void) (m_current_view == COVERFLOW_CHANNEL && (DeviceHandler::Instance()->GetFSType(currentPartition) != PART_FS_FAT || (!isD2XnewerThanV6 && DeviceHandler::Instance()->PathToDriveType(m_appDir.c_str()) == currentPartition) || (!isD2XnewerThanV6 && DeviceHandler::Instance()->PathToDriveType(m_dataDir.c_str()) == currentPartition))) || - (m_current_view == COVERFLOW_HOMEBREW && DeviceHandler::Instance()->GetFSType(currentPartition) == PART_FS_WBFS)) + ((m_current_view == COVERFLOW_HOMEBREW || m_current_view == COVERFLOW_DML) && DeviceHandler::Instance()->GetFSType(currentPartition) == PART_FS_WBFS)) { currentPartition = loopNum(currentPartition + 1, (int)USB8); if(limiter > 10) break; @@ -399,8 +401,6 @@ int CMenu::main(void) m_cfg.setInt(_domainFromView(), "partition", currentPartition); } - else if (m_current_view == COVERFLOW_DML) - partition = (char *)"DML"; else partition = (char *)"NAND"; @@ -410,10 +410,12 @@ int CMenu::main(void) gprintf("Next item: %s\n", partition); m_showtimer=60; - m_btnMgr.setText(m_mainLblNotice, (string)partition); + char gui_name[20]; + sprintf(gui_name,"%s [%s]",_domainFromView(),partition); + m_btnMgr.setText(m_mainLblNotice, (string)gui_name); m_btnMgr.show(m_mainLblNotice); - if(!block && (m_current_view != COVERFLOW_DML)) + if(!block) { _loadList(); _showMain(); diff --git a/source/menu/menu_wbfs.cpp b/source/menu/menu_wbfs.cpp index f06656d0..53ea8090 100644 --- a/source/menu/menu_wbfs.cpp +++ b/source/menu/menu_wbfs.cpp @@ -4,6 +4,9 @@ #include "lockMutex.hpp" #include "loader/gc_disc.hpp" #include "gc.h" +#include "fileOps.h" +#include "music/SoundHandler.hpp" +#include "channel/nand.hpp" using namespace std; @@ -119,19 +122,21 @@ int CMenu::_GCgameInstaller(void *obj) u32 nretry = m.m_cfg.getUInt("DML", "num_retries", 5); u32 rsize = 32768; - m_gcdump.Init(skip, comp, wexf, alig, nretry, rsize); + m_gcdump.Init(skip, comp, wexf, alig, nretry, rsize,DeviceName[currentPartition]); int ret; - if (!DeviceHandler::Instance()->IsInserted(SD)) + if (!DeviceHandler::Instance()->IsInserted(currentPartition)) { m.m_thrdWorking = false; return -1; } + char partition[strlen(DeviceName[currentPartition])+2]; + sprintf(partition,"%s:/",DeviceName[currentPartition]); struct statvfs stats; memset(&stats, 0, sizeof(stats)); - statvfs("sd:/" , &stats); + statvfs(partition , &stats); u64 free = (u64)stats.f_frsize * (u64)stats.f_bfree; u32 needed = 0; @@ -170,6 +175,45 @@ int CMenu::_GCgameInstaller(void *obj) return ret; } +int CMenu::_GCcopyGame(void *obj) +{ + CMenu &m = *(CMenu *)obj; + char partition[strlen(DeviceName[SD])]; + sprintf(partition,"%s:/",DeviceName[SD]); + if(fsop_GetFreeSpaceKb((char*)DeviceName[SD])path)) + { + LWP_MutexLock(m.m_mutex); + m._setThrdMsg(wfmt(m._fmt("wbfsop11", L"Not enough space: %d blocks needed, %d available"), fsop_GetFolderKb(m.m_cf.getHdr()->path), fsop_GetFreeSpaceKb(partition)), 0.f); + LWP_MutexUnlock(m.m_mutex); + m.m_thrdWorking = false; + return -1; + } + else + { + LWP_MutexLock(m.m_mutex); + m._setThrdMsg(L"", 0); + char folder[10] = "sd:/games"; + if (!fsop_DirExist(folder)) + { + fsop_MakeFolder(folder); + } + char source[64]; + char target[64]; + sprintf(source, "%s:/games/%s", DeviceName[currentPartition], m.m_cf.getHdr()->path); + sprintf(target, "sd:/games/%s", m.m_cf.getHdr()->path); + gprintf("Copying from: \n%s \nto: \n%s\n",source,target); + LWP_MutexUnlock(m.m_mutex); + fsop_CopyFolder(source, target, CMenu::_addDiscProgress, obj); + LWP_MutexLock(m.m_mutex); + m._setThrdMsg(m._t("wbfsop12", L"Game copied"), 1.f); + gprintf("Game copied.\n"); + LWP_MutexUnlock(m.m_mutex); + slotLight(true); + } + m.m_thrdWorking = false; + return 0; +} + bool CMenu::_wbfsOp(CMenu::WBFS_OP op) { lwp_t thread = 0; @@ -188,10 +232,13 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op) switch (op) { case CMenu::WO_ADD_GAME: - m_btnMgr.setText(m_wbfsLblDialog, _t("wbfsadddlg", L"Please insert the disc you want to copy, then click on Go.")); + if(copyGameCubeGame) + m_btnMgr.setText(m_wbfsLblDialog, _t("wbfscpydlg", L"If you are sure you want to copy this game to SD, click on Go.")); + else + m_btnMgr.setText(m_wbfsLblDialog, _t("wbfsadddlg", L"Please insert the disc you want to copy, then click on Go.")); break; case CMenu::WO_REMOVE_GAME: - m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsremdlg", L"To permanently remove the game : %s, click on Go."), m_cf.getTitle().c_str())); + m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsremdlg", L"To permanently remove the game: %s, click on Go."), (u8*)m_cf.getTitle().toUTF8().c_str())); break; case CMenu::WO_FORMAT: break; @@ -202,7 +249,11 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op) { _mainLoopCommon(false, m_thrdWorking); if ((BTN_HOME_PRESSED || BTN_B_PRESSED) && !m_thrdWorking) + { + if (copyGameCubeGame) + return done; break; + } else if (BTN_UP_PRESSED) m_btnMgr.up(); else if (BTN_DOWN_PRESSED) @@ -210,7 +261,11 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op) if (BTN_A_PRESSED && !m_thrdWorking) { if (m_btnMgr.selected(m_wbfsBtnBack)) + { + if (copyGameCubeGame) + return done; break; + } else if (m_btnMgr.selected(m_wbfsBtnGo)) { switch (op) @@ -222,6 +277,34 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op) m_btnMgr.hide(m_wbfsBtnBack); m_btnMgr.show(m_wbfsLblMessage); m_btnMgr.setText(m_wbfsLblMessage, L""); + if (copyGameCubeGame) + { + char gcfolder[64]; + char* title = (char *)m_cf.getTitle().toUTF8().c_str(); + char* gameid = (char *)m_cf.getHdr()->hdr.id; + sprintf(gcfolder, "%s [%s]", title, gameid); + if (DML_GameIsInstalled(gameid, DeviceName[SD]) || DML_GameIsInstalled(gcfolder, DeviceName[SD])) + { + error(_t("wbfsoperr4", L"Game already installed")); + out = true; + break; + } + cfPos = string(gameid); + m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsop10", L"Copying [%s] %s..."), (u8*)gameid, (u8*)m_cf.getTitle().toUTF8().c_str())); + done = true; + m_thrdWorking = true; + m_thrdProgress = 0.f; + m_thrdMessageAdded = false; + m_cf.stopCoverLoader(); + _stopSounds(); + MusicPlayer::DestroyInstance(); + SoundHandler::DestroyInstance(); + soundDeinit(); + Nand::Instance()->Disable_Emu(); + Nand::DestroyInstance(); + LWP_CreateThread(&thread, (void *(*)(void *))CMenu::_GCcopyGame, (void *)this, 0, 8 * 1024, 64); + break; + } Disc_SetUSB(NULL); if (Disc_Wait() < 0) { @@ -260,7 +343,7 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op) char gcfolder[64]; sprintf(gcfolder, "%s [%s]", gcheader.title, (char *)gcheader.id); - if (_searchGamesByID((const char *) gcheader.id).size() != 0 || DML_GameIsInstalled((char *)gcheader.id) || DML_GameIsInstalled(gcfolder)) + if (_searchGamesByID((const char *) gcheader.id).size() != 0 || DML_GameIsInstalled((char *)gcheader.id, DeviceName[currentPartition]) || DML_GameIsInstalled(gcfolder, DeviceName[currentPartition])) { error(_t("wbfsoperr4", L"Game already installed")); out = true; @@ -286,7 +369,7 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op) if(m_current_view == COVERFLOW_USB) WBFS_RemoveGame((u8 *)m_cf.getId().c_str(), (char *) m_cf.getHdr()->path); else - DML_RemoveGame(m_cf.getHdr()->path); + DML_RemoveGame(m_cf.getHdr()->path, DeviceName[currentPartition]); if(m_cfg.getBool("GENERAL", "delete_cover_and_game", true)) RemoveCover((char *)m_cf.getId().c_str()); m_btnMgr.show(m_wbfsPBar); @@ -319,7 +402,7 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op) } } _hideWBFS(); - if (done && (op == CMenu::WO_REMOVE_GAME || op == CMenu::WO_ADD_GAME)) + if (done && !copyGameCubeGame && (op == CMenu::WO_REMOVE_GAME || op == CMenu::WO_ADD_GAME)) { m_gameList.SetLanguage(m_loc.getString(m_curLanguage, "gametdb_code", "EN").c_str()); if( upd_dml )