Filesystem/Archives: Implemented the SaveData archive
The savedata for each game is stored in /savedata/<ProgramID> for NCCH files. ELF files and 3DSX files use the folder 0 because they have no ID information Got rid of the code duplication in File and Directory Files that deal with the host machine's file system now live in DiskFile, similarly for directories and DiskDirectory and archives with DiskArchive. FS_U: Use the correct error code when a file wasn't foundmaster
parent
e6f440ea7f
commit
ea9ce0fba7
@ -0,0 +1,33 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
|
||||
#include "core/file_sys/archive_savedata.h"
|
||||
#include "core/file_sys/disk_archive.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id)
|
||||
: DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) {
|
||||
LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
|
||||
}
|
||||
|
||||
bool Archive_SaveData::Initialize() {
|
||||
if (!FileUtil::CreateFullPath(mount_point)) {
|
||||
LOG_ERROR(Service_FS, "Unable to create SaveData path.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
@ -0,0 +1,32 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/file_sys/disk_archive.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
/// File system interface to the SaveData archive
|
||||
class Archive_SaveData final : public DiskArchive {
|
||||
public:
|
||||
Archive_SaveData(const std::string& mount_point, u64 program_id);
|
||||
|
||||
/**
|
||||
* Initialize the archive.
|
||||
* @return CreateSaveDataResult AlreadyExists if the SaveData folder already exists,
|
||||
* Success if it was created properly and Failure if there was any error
|
||||
*/
|
||||
bool Initialize();
|
||||
|
||||
std::string GetName() const override { return "SaveData"; }
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
@ -1,88 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
|
||||
#include "core/file_sys/directory_sdmc.h"
|
||||
#include "core/file_sys/archive_sdmc.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) {
|
||||
// TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
|
||||
// the root directory we set while opening the archive.
|
||||
// For example, opening /../../usr/bin can give the emulated program your installed programs.
|
||||
this->path = archive->GetMountPoint() + path.AsString();
|
||||
|
||||
}
|
||||
|
||||
Directory_SDMC::~Directory_SDMC() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool Directory_SDMC::Open() {
|
||||
if (!FileUtil::IsDirectory(path))
|
||||
return false;
|
||||
FileUtil::ScanDirectoryTree(path, directory);
|
||||
children_iterator = directory.children.begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* List files contained in the directory
|
||||
* @param count Number of entries to return at once in entries
|
||||
* @param entries Buffer to read data into
|
||||
* @return Number of entries listed
|
||||
*/
|
||||
u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
|
||||
u32 entries_read = 0;
|
||||
|
||||
while (entries_read < count && children_iterator != directory.children.cend()) {
|
||||
const FileUtil::FSTEntry& file = *children_iterator;
|
||||
const std::string& filename = file.virtualName;
|
||||
Entry& entry = entries[entries_read];
|
||||
|
||||
LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
|
||||
|
||||
// TODO(Link Mauve): use a proper conversion to UTF-16.
|
||||
for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
|
||||
entry.filename[j] = filename[j];
|
||||
if (!filename[j])
|
||||
break;
|
||||
}
|
||||
|
||||
FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
|
||||
|
||||
entry.is_directory = file.isDirectory;
|
||||
entry.is_hidden = (filename[0] == '.');
|
||||
entry.is_read_only = 0;
|
||||
entry.file_size = file.size;
|
||||
|
||||
// We emulate a SD card where the archive bit has never been cleared, as it would be on
|
||||
// most user SD cards.
|
||||
// Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
|
||||
// file bit.
|
||||
entry.is_archive = !file.isDirectory;
|
||||
|
||||
++entries_read;
|
||||
++children_iterator;
|
||||
}
|
||||
return entries_read;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the directory
|
||||
* @return true if the directory closed correctly
|
||||
*/
|
||||
bool Directory_SDMC::Close() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
@ -1,55 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
|
||||
#include "core/file_sys/directory_backend.h"
|
||||
#include "core/file_sys/archive_sdmc.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class Directory_SDMC final : public DirectoryBackend {
|
||||
public:
|
||||
Directory_SDMC();
|
||||
Directory_SDMC(const Archive_SDMC* archive, const Path& path);
|
||||
~Directory_SDMC() override;
|
||||
|
||||
/**
|
||||
* Open the directory
|
||||
* @return true if the directory opened correctly
|
||||
*/
|
||||
bool Open() override;
|
||||
|
||||
/**
|
||||
* List files contained in the directory
|
||||
* @param count Number of entries to return at once in entries
|
||||
* @param entries Buffer to read data into
|
||||
* @return Number of entries listed
|
||||
*/
|
||||
u32 Read(const u32 count, Entry* entries) override;
|
||||
|
||||
/**
|
||||
* Close the directory
|
||||
* @return true if the directory closed correctly
|
||||
*/
|
||||
bool Close() const override;
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
u32 total_entries_in_directory;
|
||||
FileUtil::FSTEntry directory;
|
||||
|
||||
// We need to remember the last entry we returned, so a subsequent call to Read will continue
|
||||
// from the next one. This iterator will always point to the next unread entry.
|
||||
std::vector<FileUtil::FSTEntry>::iterator children_iterator;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
@ -0,0 +1,101 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
/**
|
||||
* Helper which implements a backend accessing the host machine's filesystem.
|
||||
* This should be subclassed by concrete archive types, which will provide the
|
||||
* base directory on the host filesystem and override any required functionality.
|
||||
*/
|
||||
class DiskArchive : public ArchiveBackend {
|
||||
public:
|
||||
DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
|
||||
|
||||
virtual std::string GetName() const = 0;
|
||||
std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
|
||||
bool DeleteFile(const FileSys::Path& path) const override;
|
||||
bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
|
||||
bool DeleteDirectory(const FileSys::Path& path) const override;
|
||||
bool CreateDirectory(const Path& path) const override;
|
||||
bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
|
||||
std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
|
||||
|
||||
/**
|
||||
* Getter for the path used for this Archive
|
||||
* @return Mount point of that passthrough archive
|
||||
*/
|
||||
const std::string& GetMountPoint() const {
|
||||
return mount_point;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string mount_point;
|
||||
};
|
||||
|
||||
class DiskFile : public FileBackend {
|
||||
public:
|
||||
DiskFile();
|
||||
DiskFile(const DiskArchive* archive, const Path& path, const Mode mode);
|
||||
|
||||
~DiskFile() override {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool Open() override;
|
||||
size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
|
||||
size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
|
||||
size_t GetSize() const override;
|
||||
bool SetSize(const u64 size) const override;
|
||||
bool Close() const override;
|
||||
|
||||
void Flush() const override {
|
||||
file->Flush();
|
||||
}
|
||||
|
||||
protected:
|
||||
const DiskArchive* archive;
|
||||
std::string path;
|
||||
Mode mode;
|
||||
FileUtil::IOFile* file;
|
||||
};
|
||||
|
||||
class DiskDirectory : public DirectoryBackend {
|
||||
public:
|
||||
DiskDirectory();
|
||||
DiskDirectory(const DiskArchive* archive, const Path& path);
|
||||
|
||||
~DiskDirectory() override {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool Open() override;
|
||||
u32 Read(const u32 count, Entry* entries) override;
|
||||
|
||||
bool Close() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
const DiskArchive* archive;
|
||||
std::string path;
|
||||
u32 total_entries_in_directory;
|
||||
FileUtil::FSTEntry directory;
|
||||
|
||||
// We need to remember the last entry we returned, so a subsequent call to Read will continue
|
||||
// from the next one. This iterator will always point to the next unread entry.
|
||||
std::vector<FileUtil::FSTEntry>::iterator children_iterator;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
@ -1,75 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
|
||||
#include "core/file_sys/file_backend.h"
|
||||
#include "core/file_sys/archive_sdmc.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class File_SDMC final : public FileBackend {
|
||||
public:
|
||||
File_SDMC();
|
||||
File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode);
|
||||
~File_SDMC() override;
|
||||
|
||||
/**
|
||||
* Open the file
|
||||
* @return true if the file opened correctly
|
||||
*/
|
||||
bool Open() override;
|
||||
|
||||
/**
|
||||
* Read data from the file
|
||||
* @param offset Offset in bytes to start reading data from
|
||||
* @param length Length in bytes of data to read from file
|
||||
* @param buffer Buffer to read data into
|
||||
* @return Number of bytes read
|
||||
*/
|
||||
size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
|
||||
|
||||
/**
|
||||
* Write data to the file
|
||||
* @param offset Offset in bytes to start writing data to
|
||||
* @param length Length in bytes of data to write to file
|
||||
* @param flush The flush parameters (0 == do not flush)
|
||||
* @param buffer Buffer to read data from
|
||||
* @return Number of bytes written
|
||||
*/
|
||||
size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
|
||||
|
||||
/**
|
||||
* Get the size of the file in bytes
|
||||
* @return Size of the file in bytes
|
||||
*/
|
||||
size_t GetSize() const override;
|
||||
|
||||
/**
|
||||
* Set the size of the file in bytes
|
||||
* @param size New size of the file
|
||||
* @return true if successful
|
||||
*/
|
||||
bool SetSize(const u64 size) const override;
|
||||
|
||||
/**
|
||||
* Close the file
|
||||
* @return true if the file closed correctly
|
||||
*/
|
||||
bool Close() const override;
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
Mode mode;
|
||||
FileUtil::IOFile* file;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
Loading…
Reference in New Issue