early-access version 3706
This commit is contained in:
parent
b6463d97ba
commit
376f012568
@ -1,7 +1,7 @@
|
|||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3705.
|
This is the source code for early-access 3706.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.yuzu.yuzu_emu.R
|
||||||
|
|
||||||
|
class LongMessageDialogFragment : DialogFragment() {
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val titleId = requireArguments().getInt(TITLE)
|
||||||
|
val description = requireArguments().getString(DESCRIPTION)
|
||||||
|
val helpLinkId = requireArguments().getInt(HELP_LINK)
|
||||||
|
|
||||||
|
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setPositiveButton(R.string.close, null)
|
||||||
|
.setTitle(titleId)
|
||||||
|
.setMessage(description)
|
||||||
|
|
||||||
|
if (helpLinkId != 0) {
|
||||||
|
dialog.setNeutralButton(R.string.learn_more) { _, _ ->
|
||||||
|
openLink(getString(helpLinkId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openLink(link: String) {
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link))
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LongMessageDialogFragment"
|
||||||
|
|
||||||
|
private const val TITLE = "Title"
|
||||||
|
private const val DESCRIPTION = "Description"
|
||||||
|
private const val HELP_LINK = "Link"
|
||||||
|
|
||||||
|
fun newInstance(
|
||||||
|
titleId: Int,
|
||||||
|
description: String,
|
||||||
|
helpLinkId: Int = 0
|
||||||
|
): LongMessageDialogFragment {
|
||||||
|
val dialog = LongMessageDialogFragment()
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.apply {
|
||||||
|
putInt(TITLE, titleId)
|
||||||
|
putString(DESCRIPTION, description)
|
||||||
|
putInt(HELP_LINK, helpLinkId)
|
||||||
|
}
|
||||||
|
dialog.arguments = bundle
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
package org.yuzu.yuzu_emu.ui.main
|
package org.yuzu.yuzu_emu.ui.main
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
@ -42,6 +43,7 @@ import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
|
|||||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
|
||||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
||||||
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
|
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
|
||||||
|
import org.yuzu.yuzu_emu.fragments.LongMessageDialogFragment
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
@ -481,62 +483,110 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val installGameUpdate =
|
val installGameUpdate = registerForActivityResult(
|
||||||
registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
ActivityResultContracts.OpenMultipleDocuments()
|
||||||
if (it == null) {
|
) { documents: List<Uri> ->
|
||||||
return@registerForActivityResult
|
if (documents.isNotEmpty()) {
|
||||||
}
|
|
||||||
|
|
||||||
IndeterminateProgressDialogFragment.newInstance(
|
IndeterminateProgressDialogFragment.newInstance(
|
||||||
this@MainActivity,
|
this@MainActivity,
|
||||||
R.string.install_game_content
|
R.string.install_game_content
|
||||||
) {
|
) {
|
||||||
val result = NativeLibrary.installFileToNand(it.toString())
|
var installSuccess = 0
|
||||||
|
var installOverwrite = 0
|
||||||
|
var errorBaseGame = 0
|
||||||
|
var errorExtension = 0
|
||||||
|
var errorOther = 0
|
||||||
|
var errorTotal = 0
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.Main) {
|
documents.forEach {
|
||||||
when (result) {
|
when (NativeLibrary.installFileToNand(it.toString())) {
|
||||||
NativeLibrary.InstallFileToNandResult.Success -> {
|
NativeLibrary.InstallFileToNandResult.Success -> {
|
||||||
Toast.makeText(
|
installSuccess += 1
|
||||||
applicationContext,
|
|
||||||
R.string.install_game_content_success,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeLibrary.InstallFileToNandResult.SuccessFileOverwritten -> {
|
NativeLibrary.InstallFileToNandResult.SuccessFileOverwritten -> {
|
||||||
Toast.makeText(
|
installOverwrite += 1
|
||||||
applicationContext,
|
|
||||||
R.string.install_game_content_success_overwrite,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeLibrary.InstallFileToNandResult.ErrorBaseGame -> {
|
NativeLibrary.InstallFileToNandResult.ErrorBaseGame -> {
|
||||||
MessageDialogFragment.newInstance(
|
errorBaseGame += 1
|
||||||
R.string.install_game_content_failure,
|
|
||||||
R.string.install_game_content_failure_base
|
|
||||||
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeLibrary.InstallFileToNandResult.ErrorFilenameExtension -> {
|
NativeLibrary.InstallFileToNandResult.ErrorFilenameExtension -> {
|
||||||
MessageDialogFragment.newInstance(
|
errorExtension += 1
|
||||||
R.string.install_game_content_failure,
|
|
||||||
R.string.install_game_content_failure_file_extension,
|
|
||||||
R.string.install_game_content_help_link
|
|
||||||
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
MessageDialogFragment.newInstance(
|
errorOther += 1
|
||||||
R.string.install_game_content_failure,
|
|
||||||
R.string.install_game_content_failure_description,
|
|
||||||
R.string.install_game_content_help_link
|
|
||||||
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
val separator = System.getProperty("line.separator") ?: "\n"
|
||||||
|
val installResult = StringBuilder()
|
||||||
|
if (installSuccess > 0) {
|
||||||
|
installResult.append(
|
||||||
|
getString(
|
||||||
|
R.string.install_game_content_success_install,
|
||||||
|
installSuccess
|
||||||
|
)
|
||||||
|
)
|
||||||
|
installResult.append(separator)
|
||||||
|
}
|
||||||
|
if (installOverwrite > 0) {
|
||||||
|
installResult.append(
|
||||||
|
getString(
|
||||||
|
R.string.install_game_content_success_overwrite,
|
||||||
|
installOverwrite
|
||||||
|
)
|
||||||
|
)
|
||||||
|
installResult.append(separator)
|
||||||
|
}
|
||||||
|
errorTotal = errorBaseGame + errorExtension + errorOther
|
||||||
|
if (errorTotal > 0) {
|
||||||
|
installResult.append(separator)
|
||||||
|
installResult.append(
|
||||||
|
getString(
|
||||||
|
R.string.install_game_content_failed_count,
|
||||||
|
errorTotal
|
||||||
|
)
|
||||||
|
)
|
||||||
|
installResult.append(separator)
|
||||||
|
if (errorBaseGame > 0) {
|
||||||
|
installResult.append(separator)
|
||||||
|
installResult.append(
|
||||||
|
getString(R.string.install_game_content_failure_base)
|
||||||
|
)
|
||||||
|
installResult.append(separator)
|
||||||
|
}
|
||||||
|
if (errorExtension > 0) {
|
||||||
|
installResult.append(separator)
|
||||||
|
installResult.append(
|
||||||
|
getString(R.string.install_game_content_failure_file_extension)
|
||||||
|
)
|
||||||
|
installResult.append(separator)
|
||||||
|
}
|
||||||
|
if (errorOther > 0) {
|
||||||
|
installResult.append(
|
||||||
|
getString(R.string.install_game_content_failure_description)
|
||||||
|
)
|
||||||
|
installResult.append(separator)
|
||||||
|
}
|
||||||
|
LongMessageDialogFragment.newInstance(
|
||||||
|
R.string.install_game_content_failure,
|
||||||
|
installResult.toString().trim(),
|
||||||
|
R.string.install_game_content_help_link
|
||||||
|
).show(supportFragmentManager, LongMessageDialogFragment.TAG)
|
||||||
|
} else {
|
||||||
|
LongMessageDialogFragment.newInstance(
|
||||||
|
R.string.install_game_content_success,
|
||||||
|
installResult.toString().trim()
|
||||||
|
).show(supportFragmentManager, LongMessageDialogFragment.TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return@newInstance result
|
return@newInstance installSuccess + installOverwrite + errorTotal
|
||||||
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,12 +104,14 @@
|
|||||||
<string name="share_log_missing">No log file found</string>
|
<string name="share_log_missing">No log file found</string>
|
||||||
<string name="install_game_content">Install game content</string>
|
<string name="install_game_content">Install game content</string>
|
||||||
<string name="install_game_content_description">Install game updates or DLC</string>
|
<string name="install_game_content_description">Install game updates or DLC</string>
|
||||||
<string name="install_game_content_failure">Error installing file to NAND</string>
|
<string name="install_game_content_failure">Error installing file(s) to NAND</string>
|
||||||
<string name="install_game_content_failure_description">Game content installation failed. Please ensure content is valid and that the prod.keys file is installed.</string>
|
<string name="install_game_content_failure_description">Please ensure content(s) are valid and that the prod.keys file is installed.</string>
|
||||||
<string name="install_game_content_failure_base">Installation of base games isn\'t permitted in order to avoid possible conflicts. Please select an update or DLC instead.</string>
|
<string name="install_game_content_failure_base">Installation of base games isn\'t permitted in order to avoid possible conflicts.</string>
|
||||||
<string name="install_game_content_failure_file_extension">The selected file type is not supported. Only NSP and XCI content is supported for this action. Please verify the game content is valid.</string>
|
<string name="install_game_content_failure_file_extension">Only NSP and XCI content is supported. Please verify the game content(s) are valid.</string>
|
||||||
<string name="install_game_content_success">Game content installed successfully</string>
|
<string name="install_game_content_failed_count">%1$d installation error(s)</string>
|
||||||
<string name="install_game_content_success_overwrite">Game content was overwritten successfully</string>
|
<string name="install_game_content_success">Game content(s) installed successfully</string>
|
||||||
|
<string name="install_game_content_success_install">%1$d installed successfully</string>
|
||||||
|
<string name="install_game_content_success_overwrite">%1$d overwritten successfully</string>
|
||||||
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
|
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
|
||||||
|
|
||||||
<!-- About screen strings -->
|
<!-- About screen strings -->
|
||||||
|
@ -76,6 +76,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
|
|||||||
VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size,
|
VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size,
|
||||||
Mode perms) {
|
Mode perms) {
|
||||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||||
|
std::scoped_lock lk{list_lock};
|
||||||
|
|
||||||
if (auto it = cache.find(path); it != cache.end()) {
|
if (auto it = cache.find(path); it != cache.end()) {
|
||||||
if (auto file = it->second.lock(); file) {
|
if (auto file = it->second.lock(); file) {
|
||||||
@ -88,7 +89,7 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto reference = std::make_unique<FileReference>();
|
auto reference = std::make_unique<FileReference>();
|
||||||
this->InsertReferenceIntoList(*reference);
|
this->InsertReferenceIntoListLocked(*reference);
|
||||||
|
|
||||||
auto file = std::shared_ptr<RealVfsFile>(
|
auto file = std::shared_ptr<RealVfsFile>(
|
||||||
new RealVfsFile(*this, std::move(reference), path, perms, size));
|
new RealVfsFile(*this, std::move(reference), path, perms, size));
|
||||||
@ -103,7 +104,10 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
|
|||||||
|
|
||||||
VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
|
VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
|
||||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||||
cache.erase(path);
|
{
|
||||||
|
std::scoped_lock lk{list_lock};
|
||||||
|
cache.erase(path);
|
||||||
|
}
|
||||||
|
|
||||||
// Current usages of CreateFile expect to delete the contents of an existing file.
|
// Current usages of CreateFile expect to delete the contents of an existing file.
|
||||||
if (FS::IsFile(path)) {
|
if (FS::IsFile(path)) {
|
||||||
@ -133,8 +137,11 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_
|
|||||||
VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
|
VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
|
||||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||||
cache.erase(old_path);
|
{
|
||||||
cache.erase(new_path);
|
std::scoped_lock lk{list_lock};
|
||||||
|
cache.erase(old_path);
|
||||||
|
cache.erase(new_path);
|
||||||
|
}
|
||||||
if (!FS::RenameFile(old_path, new_path)) {
|
if (!FS::RenameFile(old_path, new_path)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -143,7 +150,10 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
|
|||||||
|
|
||||||
bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
|
bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
|
||||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||||
cache.erase(path);
|
{
|
||||||
|
std::scoped_lock lk{list_lock};
|
||||||
|
cache.erase(path);
|
||||||
|
}
|
||||||
return FS::RemoveFile(path);
|
return FS::RemoveFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,14 +192,17 @@ bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
|
|||||||
return FS::RemoveDirRecursively(path);
|
return FS::RemoveDirRecursively(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms,
|
std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path,
|
||||||
FileReference& reference) {
|
Mode perms,
|
||||||
|
FileReference& reference) {
|
||||||
|
std::unique_lock lk{list_lock};
|
||||||
|
|
||||||
// Temporarily remove from list.
|
// Temporarily remove from list.
|
||||||
this->RemoveReferenceFromList(reference);
|
this->RemoveReferenceFromListLocked(reference);
|
||||||
|
|
||||||
// Restore file if needed.
|
// Restore file if needed.
|
||||||
if (!reference.file) {
|
if (!reference.file) {
|
||||||
this->EvictSingleReference();
|
this->EvictSingleReferenceLocked();
|
||||||
|
|
||||||
reference.file =
|
reference.file =
|
||||||
FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile);
|
FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile);
|
||||||
@ -199,12 +212,16 @@ void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reinsert into list.
|
// Reinsert into list.
|
||||||
this->InsertReferenceIntoList(reference);
|
this->InsertReferenceIntoListLocked(reference);
|
||||||
|
|
||||||
|
return lk;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) {
|
void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) {
|
||||||
|
std::scoped_lock lk{list_lock};
|
||||||
|
|
||||||
// Remove from list.
|
// Remove from list.
|
||||||
this->RemoveReferenceFromList(*reference);
|
this->RemoveReferenceFromListLocked(*reference);
|
||||||
|
|
||||||
// Close the file.
|
// Close the file.
|
||||||
if (reference->file) {
|
if (reference->file) {
|
||||||
@ -213,14 +230,14 @@ void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealVfsFilesystem::EvictSingleReference() {
|
void RealVfsFilesystem::EvictSingleReferenceLocked() {
|
||||||
if (num_open_files < MaxOpenFiles || open_references.empty()) {
|
if (num_open_files < MaxOpenFiles || open_references.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get and remove from list.
|
// Get and remove from list.
|
||||||
auto& reference = open_references.back();
|
auto& reference = open_references.back();
|
||||||
this->RemoveReferenceFromList(reference);
|
this->RemoveReferenceFromListLocked(reference);
|
||||||
|
|
||||||
// Close the file.
|
// Close the file.
|
||||||
if (reference.file) {
|
if (reference.file) {
|
||||||
@ -229,10 +246,10 @@ void RealVfsFilesystem::EvictSingleReference() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reinsert into closed list.
|
// Reinsert into closed list.
|
||||||
this->InsertReferenceIntoList(reference);
|
this->InsertReferenceIntoListLocked(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) {
|
void RealVfsFilesystem::InsertReferenceIntoListLocked(FileReference& reference) {
|
||||||
if (reference.file) {
|
if (reference.file) {
|
||||||
open_references.push_front(reference);
|
open_references.push_front(reference);
|
||||||
} else {
|
} else {
|
||||||
@ -240,7 +257,7 @@ void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealVfsFilesystem::RemoveReferenceFromList(FileReference& reference) {
|
void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) {
|
||||||
if (reference.file) {
|
if (reference.file) {
|
||||||
open_references.erase(open_references.iterator_to(reference));
|
open_references.erase(open_references.iterator_to(reference));
|
||||||
} else {
|
} else {
|
||||||
@ -271,7 +288,7 @@ std::size_t RealVfsFile::GetSize() const {
|
|||||||
|
|
||||||
bool RealVfsFile::Resize(std::size_t new_size) {
|
bool RealVfsFile::Resize(std::size_t new_size) {
|
||||||
size.reset();
|
size.reset();
|
||||||
base.RefreshReference(path, perms, *reference);
|
auto lk = base.RefreshReference(path, perms, *reference);
|
||||||
return reference->file ? reference->file->SetSize(new_size) : false;
|
return reference->file ? reference->file->SetSize(new_size) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +305,7 @@ bool RealVfsFile::IsReadable() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
|
std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||||
base.RefreshReference(path, perms, *reference);
|
auto lk = base.RefreshReference(path, perms, *reference);
|
||||||
if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
|
if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -297,7 +314,7 @@ std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset)
|
|||||||
|
|
||||||
std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
|
std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
|
||||||
size.reset();
|
size.reset();
|
||||||
base.RefreshReference(path, perms, *reference);
|
auto lk = base.RefreshReference(path, perms, *reference);
|
||||||
if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
|
if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include "common/intrusive_list.h"
|
#include "common/intrusive_list.h"
|
||||||
@ -48,22 +49,24 @@ private:
|
|||||||
std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache;
|
std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache;
|
||||||
ReferenceListType open_references;
|
ReferenceListType open_references;
|
||||||
ReferenceListType closed_references;
|
ReferenceListType closed_references;
|
||||||
|
std::mutex list_lock;
|
||||||
size_t num_open_files{};
|
size_t num_open_files{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RealVfsFile;
|
friend class RealVfsFile;
|
||||||
void RefreshReference(const std::string& path, Mode perms, FileReference& reference);
|
std::unique_lock<std::mutex> RefreshReference(const std::string& path, Mode perms,
|
||||||
|
FileReference& reference);
|
||||||
void DropReference(std::unique_ptr<FileReference>&& reference);
|
void DropReference(std::unique_ptr<FileReference>&& reference);
|
||||||
void EvictSingleReference();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void InsertReferenceIntoList(FileReference& reference);
|
|
||||||
void RemoveReferenceFromList(FileReference& reference);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RealVfsDirectory;
|
friend class RealVfsDirectory;
|
||||||
VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size,
|
VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size,
|
||||||
Mode perms = Mode::Read);
|
Mode perms = Mode::Read);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void EvictSingleReferenceLocked();
|
||||||
|
void InsertReferenceIntoListLocked(FileReference& reference);
|
||||||
|
void RemoveReferenceFromListLocked(FileReference& reference);
|
||||||
};
|
};
|
||||||
|
|
||||||
// An implementation of VfsFile that represents a file on the user's computer.
|
// An implementation of VfsFile that represents a file on the user's computer.
|
||||||
|
Loading…
Reference in New Issue
Block a user