diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3fa828ff82..bfd5e69035 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2276,6 +2276,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Util/AudioFormat.h
Core/Util/GameManager.cpp
Core/Util/GameManager.h
+ Core/Util/MemStick.cpp
+ Core/Util/MemStick.h
Core/Util/GameDB.cpp
Core/Util/GameDB.h
Core/Util/PortManager.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 6a350b693c..c9acd32dc1 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -1079,6 +1079,7 @@
+
@@ -1449,6 +1450,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 1b49e9273d..0918b045f4 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -1303,6 +1303,9 @@
Util
+
+ Util
+
@@ -2082,6 +2085,9 @@
Util
+
+ Util
+
diff --git a/Core/Util/MemStick.cpp b/Core/Util/MemStick.cpp
new file mode 100644
index 0000000000..aa27a2b2ee
--- /dev/null
+++ b/Core/Util/MemStick.cpp
@@ -0,0 +1,205 @@
+#include "Common/File/Path.h"
+#include "Common/File/FileUtil.h"
+#include "Common/File/DirListing.h"
+#include "Common/Log.h"
+#include "Common/StringUtils.h"
+#include "Common/Data/Text/I18n.h"
+#include "Common/Data/Text/Parsers.h"
+
+#include "Core/Util/MemStick.h"
+#include "Core/Config.h"
+#include "Core/System.h"
+#include "Core/Reporting.h"
+
+bool FolderSeemsToBeUsed(const Path &newMemstickFolder) {
+ // Inspect the potential new folder, quickly.
+ if (File::Exists(newMemstickFolder / "PSP/SAVEDATA") || File::Exists(newMemstickFolder / "SAVEDATA")) {
+ // Does seem likely. We could add more criteria like checking for actual savegames or something.
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool SwitchMemstickFolderTo(Path newMemstickFolder) {
+ // Doesn't already exist, create.
+ // Should this ever happen?
+ if (newMemstickFolder.Type() == PathType::NATIVE) {
+ if (!File::Exists(newMemstickFolder)) {
+ File::CreateFullPath(newMemstickFolder);
+ }
+ Path testWriteFile = newMemstickFolder / ".write_verify_file";
+ if (!File::WriteDataToFile(true, "1", 1, testWriteFile)) {
+ return false;
+ }
+ File::Delete(testWriteFile);
+ } else {
+ // TODO: Do the same but with scoped storage? Not really necessary, right? If it came from a browse
+ // for folder, we can assume it exists and is writable, barring wacky race conditions like the user
+ // being connected by USB and deleting it.
+ }
+
+ Path memStickDirFile = g_Config.internalDataDirectory / "memstick_dir.txt";
+#if PPSSPP_PLATFORM(UWP)
+ File::Delete(memStickDirFile);
+ if (newMemstickFolder != g_Config.internalDataDirectory) {
+#endif
+
+ std::string str = newMemstickFolder.ToString();
+ if (!File::WriteDataToFile(true, str.c_str(), (unsigned int)str.size(), memStickDirFile)) {
+ ERROR_LOG(SYSTEM, "Failed to write memstick path '%s' to '%s'", newMemstickFolder.c_str(), memStickDirFile.c_str());
+ // Not sure what to do if this file can't be written. Disk full?
+ }
+
+#if PPSSPP_PLATFORM(UWP)
+ }
+#endif
+
+ // Save so the settings, at least, are transferred.
+ g_Config.memStickDirectory = newMemstickFolder;
+ g_Config.SetSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
+ g_Config.UpdateIniLocation();
+ return true;
+}
+
+
+// Keep the size with the file, so we can skip overly large ones in the move.
+// The user will have to take care of them afterwards, it'll just take too long probably.
+struct FileSuffix {
+ std::string suffix;
+ u64 fileSize;
+};
+
+static bool ListFileSuffixesRecursively(const Path &root, const Path &folder, std::vector &dirSuffixes, std::vector &fileSuffixes) {
+ std::vector files;
+ if (!File::GetFilesInDir(folder, &files)) {
+ return false;
+ }
+
+ for (auto &file : files) {
+ if (file.isDirectory) {
+ std::string dirSuffix;
+ if (root.ComputePathTo(file.fullName, dirSuffix)) {
+ if (!dirSuffix.empty()) {
+ dirSuffixes.push_back(dirSuffix);
+ ListFileSuffixesRecursively(root, folder / file.name, dirSuffixes, fileSuffixes);
+ }
+ } else {
+ ERROR_LOG_REPORT(SYSTEM, "Failed to compute PathTo from '%s' to '%s'", root.c_str(), folder.c_str());
+ }
+ } else {
+ std::string fileSuffix;
+ if (root.ComputePathTo(file.fullName, fileSuffix)) {
+ if (!fileSuffix.empty()) {
+ fileSuffixes.push_back(FileSuffix{ fileSuffix, file.size });
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressReporter &progressReporter) {
+ auto ms = GetI18NCategory(I18NCat::MEMSTICK);
+ if (moveSrc.GetFilename() != "PSP") {
+ moveSrc = moveSrc / "PSP";
+ }
+ if (moveDest.GetFilename() != "PSP") {
+ moveDest = moveDest / "PSP";
+ File::CreateDir(moveDest);
+ }
+
+ INFO_LOG(SYSTEM, "About to move PSP data from '%s' to '%s'", moveSrc.c_str(), moveDest.c_str());
+
+ // Search through recursively, listing the files to move and also summing their sizes.
+ std::vector fileSuffixesToMove;
+ std::vector directorySuffixesToCreate;
+
+ // NOTE: It's correct to pass moveSrc twice here, it's to keep the root in the recursion.
+ if (!ListFileSuffixesRecursively(moveSrc, moveSrc, directorySuffixesToCreate, fileSuffixesToMove)) {
+ // TODO: Handle failure listing files.
+ std::string error = "Failed to read old directory";
+ INFO_LOG(SYSTEM, "%s", error.c_str());
+ progressReporter.Set(ms->T(error.c_str()));
+ return new MoveResult{ false, error };
+ }
+
+ bool dryRun = false; // Useful for debugging.
+
+ size_t failedFiles = 0;
+ size_t skippedFiles = 0;
+
+ // We're not moving huge files like ISOs during this process, unless
+ // they can be directly moved, without rewriting the file.
+ const uint64_t BIG_FILE_THRESHOLD = 24 * 1024 * 1024;
+
+ if (!moveSrc.empty()) {
+ // Better not interrupt the app while this is happening!
+
+ // Create all the necessary directories.
+ for (auto &dirSuffix : directorySuffixesToCreate) {
+ Path dir = moveDest / dirSuffix;
+ if (dryRun) {
+ INFO_LOG(SYSTEM, "dry run: Would have created dir '%s'", dir.c_str());
+ } else {
+ INFO_LOG(SYSTEM, "Creating dir '%s'", dir.c_str());
+ progressReporter.Set(dirSuffix);
+ // Just ignore already-exists errors.
+ File::CreateDir(dir);
+ }
+ }
+
+ for (auto &fileSuffix : fileSuffixesToMove) {
+ progressReporter.Set(StringFromFormat("%s (%s)", fileSuffix.suffix.c_str(), NiceSizeFormat(fileSuffix.fileSize).c_str()));
+
+ Path from = moveSrc / fileSuffix.suffix;
+ Path to = moveDest / fileSuffix.suffix;
+
+ if (fileSuffix.fileSize > BIG_FILE_THRESHOLD) {
+ // We only move big files if it's fast to do so.
+ if (dryRun) {
+ INFO_LOG(SYSTEM, "dry run: Would have moved '%s' to '%s' (%d bytes) if fast", from.c_str(), to.c_str(), (int)fileSuffix.fileSize);
+ } else {
+ if (!File::MoveIfFast(from, to)) {
+ INFO_LOG(SYSTEM, "Skipped moving file '%s' to '%s' (%s)", from.c_str(), to.c_str(), NiceSizeFormat(fileSuffix.fileSize).c_str());
+ skippedFiles++;
+ } else {
+ INFO_LOG(SYSTEM, "Moved file '%s' to '%s'", from.c_str(), to.c_str());
+ }
+ }
+ } else {
+ if (dryRun) {
+ INFO_LOG(SYSTEM, "dry run: Would have moved '%s' to '%s' (%d bytes)", from.c_str(), to.c_str(), (int)fileSuffix.fileSize);
+ } else {
+ // Remove the "from" prefix from the path.
+ // We have to drop down to string operations for this.
+ if (!File::Move(from, to)) {
+ ERROR_LOG(SYSTEM, "Failed to move file '%s' to '%s'", from.c_str(), to.c_str());
+ failedFiles++;
+ // Should probably just bail?
+ } else {
+ INFO_LOG(SYSTEM, "Moved file '%s' to '%s'", from.c_str(), to.c_str());
+ }
+ }
+ }
+ }
+
+ // Delete all the old, now hopefully empty, directories.
+ // Hopefully DeleteDir actually fails if it contains a file...
+ for (auto &dirSuffix : directorySuffixesToCreate) {
+ Path dir = moveSrc / dirSuffix;
+ if (dryRun) {
+ INFO_LOG(SYSTEM, "dry run: Would have deleted dir '%s'", dir.c_str());
+ } else {
+ INFO_LOG(SYSTEM, "Deleting dir '%s'", dir.c_str());
+ progressReporter.Set(dirSuffix);
+ if (File::Exists(dir)) {
+ File::DeleteDir(dir);
+ }
+ }
+ }
+ }
+
+ return new MoveResult{ true, "", failedFiles };
+}
diff --git a/Core/Util/MemStick.h b/Core/Util/MemStick.h
new file mode 100644
index 0000000000..6fdb868768
--- /dev/null
+++ b/Core/Util/MemStick.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "Common/File/Path.h"
+
+#include
+
+// Utility functions moved out from MemstickScreen.
+
+class MoveProgressReporter {
+public:
+ void Set(const std::string &value) {
+ std::lock_guard guard(mutex_);
+ progress_ = value;
+ }
+
+ std::string Get() {
+ std::lock_guard guard(mutex_);
+ return progress_;
+ }
+
+private:
+ std::string progress_;
+ std::mutex mutex_;
+};
+
+struct MoveResult {
+ bool success; // Got through the whole move.
+ std::string errorMessage;
+ size_t failedFiles;
+ size_t skippedFiles;
+};
+
+bool FolderSeemsToBeUsed(const Path &newMemstickFolder);
+bool SwitchMemstickFolderTo(Path newMemstickFolder);
+MoveResult *MoveDirectoryContentsSafe(Path moveSrc, Path moveDest, MoveProgressReporter &progressReporter);
diff --git a/GPU/Common/TextureReplacer.cpp b/GPU/Common/TextureReplacer.cpp
index b0a3709d5b..d85e837221 100644
--- a/GPU/Common/TextureReplacer.cpp
+++ b/GPU/Common/TextureReplacer.cpp
@@ -735,6 +735,7 @@ bool TextureReplacer::WillSave(const ReplacedTextureDecodeInfo &replacedInfo) {
void TextureReplacer::NotifyTextureDecoded(ReplacedTexture *texture, const ReplacedTextureDecodeInfo &replacedInfo, const void *data, int pitch, int level, int origW, int origH, int scaledW, int scaledH) {
_assert_msg_(enabled_, "Replacement not enabled");
+ _assert_(pitch >= 0);
if (!WillSave(replacedInfo)) {
// Ignore.
@@ -798,7 +799,7 @@ void TextureReplacer::NotifyTextureDecoded(ReplacedTexture *texture, const Repla
// while we're at it.
saveBuf.resize(w * h * 4);
for (int y = 0; y < h; y++) {
- memcpy((u8 *)saveBuf.data() + y * w * 4, (const u8 *)data + y * pitch, w * sizeof(u32));
+ memcpy((u8 *)saveBuf.data() + y * w * 4, (const u8 *)data + y * pitch, w * 4);
}
pitch = w * 4;
diff --git a/UI/MemStickScreen.cpp b/UI/MemStickScreen.cpp
index 5e9f0d02bc..8e54b8d4ca 100644
--- a/UI/MemStickScreen.cpp
+++ b/UI/MemStickScreen.cpp
@@ -44,64 +44,13 @@
#include "Core/Reporting.h"
#include "Core/System.h"
#include "Core/Util/GameManager.h"
+#include "Core/Util/MemStick.h"
#include "UI/MemStickScreen.h"
#include "UI/MainScreen.h"
#include "UI/MiscScreens.h"
#include "UI/OnScreenDisplay.h"
-static bool FolderSeemsToBeUsed(const Path &newMemstickFolder) {
- // Inspect the potential new folder, quickly.
- if (File::Exists(newMemstickFolder / "PSP/SAVEDATA") || File::Exists(newMemstickFolder / "SAVEDATA")) {
- // Does seem likely. We could add more criteria like checking for actual savegames or something.
- return true;
- } else {
- return false;
- }
-}
-
-static bool SwitchMemstickFolderTo(Path newMemstickFolder) {
- // Doesn't already exist, create.
- // Should this ever happen?
- if (newMemstickFolder.Type() == PathType::NATIVE) {
- if (!File::Exists(newMemstickFolder)) {
- File::CreateFullPath(newMemstickFolder);
- }
- Path testWriteFile = newMemstickFolder / ".write_verify_file";
- if (!File::WriteDataToFile(true, "1", 1, testWriteFile)) {
- return false;
- }
- File::Delete(testWriteFile);
- } else {
- // TODO: Do the same but with scoped storage? Not really necessary, right? If it came from a browse
- // for folder, we can assume it exists and is writable, barring wacky race conditions like the user
- // being connected by USB and deleting it.
- }
-
- Path memStickDirFile = g_Config.internalDataDirectory / "memstick_dir.txt";
-#if PPSSPP_PLATFORM(UWP)
- File::Delete(memStickDirFile);
- if (newMemstickFolder != g_Config.internalDataDirectory) {
-#endif
-
- std::string str = newMemstickFolder.ToString();
- if (!File::WriteDataToFile(true, str.c_str(), (unsigned int)str.size(), memStickDirFile)) {
- ERROR_LOG(SYSTEM, "Failed to write memstick path '%s' to '%s'", newMemstickFolder.c_str(), memStickDirFile.c_str());
- // Not sure what to do if this file can't be written. Disk full?
- }
-
-#if PPSSPP_PLATFORM(UWP)
- }
-#endif
-
- // Save so the settings, at least, are transferred.
- g_Config.memStickDirectory = newMemstickFolder;
- g_Config.SetSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
- g_Config.UpdateIniLocation();
-
- return true;
-}
-
static std::string FormatSpaceString(int64_t space) {
if (space >= 0) {
char buffer[50];
@@ -506,43 +455,6 @@ void MemStickScreen::update() {
}
}
-// Keep the size with the file, so we can skip overly large ones in the move.
-// The user will have to take care of them afterwards, it'll just take too long probably.
-struct FileSuffix {
- std::string suffix;
- u64 fileSize;
-};
-
-static bool ListFileSuffixesRecursively(const Path &root, const Path &folder, std::vector &dirSuffixes, std::vector &fileSuffixes) {
- std::vector files;
- if (!File::GetFilesInDir(folder, &files)) {
- return false;
- }
-
- for (auto &file : files) {
- if (file.isDirectory) {
- std::string dirSuffix;
- if (root.ComputePathTo(file.fullName, dirSuffix)) {
- if (!dirSuffix.empty()) {
- dirSuffixes.push_back(dirSuffix);
- ListFileSuffixesRecursively(root, folder / file.name, dirSuffixes, fileSuffixes);
- }
- } else {
- ERROR_LOG_REPORT(SYSTEM, "Failed to compute PathTo from '%s' to '%s'", root.c_str(), folder.c_str());
- }
- } else {
- std::string fileSuffix;
- if (root.ComputePathTo(file.fullName, fileSuffix)) {
- if (!fileSuffix.empty()) {
- fileSuffixes.push_back(FileSuffix{ fileSuffix, file.size });
- }
- }
- }
- }
-
- return true;
-}
-
ConfirmMemstickMoveScreen::ConfirmMemstickMoveScreen(Path newMemstickFolder, bool initialSetup)
: newMemstickFolder_(newMemstickFolder), initialSetup_(initialSetup) {
existingFilesInNewFolder_ = FolderSeemsToBeUsed(newMemstickFolder);
@@ -666,109 +578,9 @@ UI::EventReturn ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams ¶ms) {
progressReporter_.Set(T(I18NCat::MEMSTICK, "Starting move..."));
moveDataTask_ = Promise::Spawn(&g_threadManager, [&]() -> MoveResult * {
- auto ms = GetI18NCategory(I18NCat::MEMSTICK);
Path moveSrc = g_Config.memStickDirectory;
Path moveDest = newMemstickFolder_;
- if (moveSrc.GetFilename() != "PSP") {
- moveSrc = moveSrc / "PSP";
- }
- if (moveDest.GetFilename() != "PSP") {
- moveDest = moveDest / "PSP";
- File::CreateDir(moveDest);
- }
-
- INFO_LOG(SYSTEM, "About to move PSP data from '%s' to '%s'", moveSrc.c_str(), moveDest.c_str());
-
- // Search through recursively, listing the files to move and also summing their sizes.
- std::vector fileSuffixesToMove;
- std::vector directorySuffixesToCreate;
-
- // NOTE: It's correct to pass moveSrc twice here, it's to keep the root in the recursion.
- if (!ListFileSuffixesRecursively(moveSrc, moveSrc, directorySuffixesToCreate, fileSuffixesToMove)) {
- // TODO: Handle failure listing files.
- std::string error = "Failed to read old directory";
- INFO_LOG(SYSTEM, "%s", error.c_str());
- progressReporter_.Set(ms->T(error.c_str()));
- return new MoveResult{ false, error };
- }
-
- bool dryRun = false; // Useful for debugging.
-
- size_t failedFiles = 0;
- size_t skippedFiles = 0;
-
- // We're not moving huge files like ISOs during this process, unless
- // they can be directly moved, without rewriting the file.
- const uint64_t BIG_FILE_THRESHOLD = 24 * 1024 * 1024;
-
- if (!moveSrc.empty()) {
- // Better not interrupt the app while this is happening!
-
- // Create all the necessary directories.
- for (auto &dirSuffix : directorySuffixesToCreate) {
- Path dir = moveDest / dirSuffix;
- if (dryRun) {
- INFO_LOG(SYSTEM, "dry run: Would have created dir '%s'", dir.c_str());
- } else {
- INFO_LOG(SYSTEM, "Creating dir '%s'", dir.c_str());
- progressReporter_.Set(dirSuffix);
- // Just ignore already-exists errors.
- File::CreateDir(dir);
- }
- }
-
- for (auto &fileSuffix : fileSuffixesToMove) {
- progressReporter_.Set(StringFromFormat("%s (%s)", fileSuffix.suffix.c_str(), NiceSizeFormat(fileSuffix.fileSize).c_str()));
-
- Path from = moveSrc / fileSuffix.suffix;
- Path to = moveDest / fileSuffix.suffix;
-
- if (fileSuffix.fileSize > BIG_FILE_THRESHOLD) {
- // We only move big files if it's fast to do so.
- if (dryRun) {
- INFO_LOG(SYSTEM, "dry run: Would have moved '%s' to '%s' (%d bytes) if fast", from.c_str(), to.c_str(), (int)fileSuffix.fileSize);
- } else {
- if (!File::MoveIfFast(from, to)) {
- INFO_LOG(SYSTEM, "Skipped moving file '%s' to '%s' (%s)", from.c_str(), to.c_str(), NiceSizeFormat(fileSuffix.fileSize).c_str());
- skippedFiles++;
- } else {
- INFO_LOG(SYSTEM, "Moved file '%s' to '%s'", from.c_str(), to.c_str());
- }
- }
- } else {
- if (dryRun) {
- INFO_LOG(SYSTEM, "dry run: Would have moved '%s' to '%s' (%d bytes)", from.c_str(), to.c_str(), (int)fileSuffix.fileSize);
- } else {
- // Remove the "from" prefix from the path.
- // We have to drop down to string operations for this.
- if (!File::Move(from, to)) {
- ERROR_LOG(SYSTEM, "Failed to move file '%s' to '%s'", from.c_str(), to.c_str());
- failedFiles++;
- // Should probably just bail?
- } else {
- INFO_LOG(SYSTEM, "Moved file '%s' to '%s'", from.c_str(), to.c_str());
- }
- }
- }
- }
-
- // Delete all the old, now hopefully empty, directories.
- // Hopefully DeleteDir actually fails if it contains a file...
- for (auto &dirSuffix : directorySuffixesToCreate) {
- Path dir = moveSrc / dirSuffix;
- if (dryRun) {
- INFO_LOG(SYSTEM, "dry run: Would have deleted dir '%s'", dir.c_str());
- } else {
- INFO_LOG(SYSTEM, "Deleting dir '%s'", dir.c_str());
- progressReporter_.Set(dirSuffix);
- if (File::Exists(dir)) {
- File::DeleteDir(dir);
- }
- }
- }
- }
-
- return new MoveResult{ true, "", failedFiles };
+ return MoveDirectoryContentsSafe(moveSrc, moveDest, progressReporter_);
}, TaskType::IO_BLOCKING, TaskPriority::HIGH);
RecreateViews();
diff --git a/UI/MemStickScreen.h b/UI/MemStickScreen.h
index bf30f6373c..d705aa72ee 100644
--- a/UI/MemStickScreen.h
+++ b/UI/MemStickScreen.h
@@ -27,6 +27,8 @@
#include "Common/UI/UIScreen.h"
#include "Common/Thread/Promise.h"
+#include "Core/Util/MemStick.h"
+
#include "UI/MiscScreens.h"
class NoticeView;
@@ -91,30 +93,6 @@ private:
#endif
};
-class ProgressReporter {
-public:
- void Set(const std::string &value) {
- std::lock_guard guard(mutex_);
- progress_ = value;
- }
-
- std::string Get() {
- std::lock_guard guard(mutex_);
- return progress_;
- }
-
-private:
- std::string progress_;
- std::mutex mutex_;
-};
-
-struct MoveResult {
- bool success; // Got through the whole move.
- std::string errorMessage;
- size_t failedFiles;
- size_t skippedFiles;
-};
-
class ConfirmMemstickMoveScreen : public UIDialogScreenWithBackground {
public:
ConfirmMemstickMoveScreen(Path newMemstickFolder, bool initialSetup);
@@ -141,7 +119,7 @@ private:
#endif
bool initialSetup_;
- ProgressReporter progressReporter_;
+ MoveProgressReporter progressReporter_;
UI::TextView *progressView_ = nullptr;
Promise *moveDataTask_ = nullptr;
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index 3b8737f8c4..207fa9ad79 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -321,6 +321,7 @@
+
@@ -607,6 +608,7 @@
+
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index 0f70f58548..82bf9b68af 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -1192,6 +1192,10 @@
Util
+
+
+ Util
+
@@ -1868,6 +1872,10 @@
Util
+
+
+ Util
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 196a3de1cf..e4e6838e7f 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -676,6 +676,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/MIPS/JitCommon/JitBlockCache.cpp \
$(SRC)/Core/MIPS/JitCommon/JitState.cpp \
$(SRC)/Core/Util/AudioFormat.cpp \
+ $(SRC)/Core/Util/MemStick.cpp \
$(SRC)/Core/Util/PortManager.cpp \
$(SRC)/Core/Util/GameDB.cpp \
$(SRC)/Core/Util/GameManager.cpp \
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index 9538c75fd7..611be9130a 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -742,6 +742,7 @@ SOURCES_CXX += \
$(COREDIR)/System.cpp \
$(COREDIR)/ThreadPools.cpp \
$(COREDIR)/Util/BlockAllocator.cpp \
+ $(COREDIR)/Util/MemStick.cpp \
$(COREDIR)/Util/PPGeDraw.cpp \
$(COREDIR)/Util/AudioFormat.cpp \
$(COREDIR)/Util/PortManager.cpp \