kvdb: use fs::

This commit is contained in:
Michael Scire 2020-03-04 01:46:13 -08:00
parent 674fd8f1e2
commit 797815b838
4 changed files with 104 additions and 110 deletions

View file

@ -51,6 +51,7 @@ namespace ams::kvdb {
std::va_list args;
va_start(args, format);
CheckLength(std::vsnprintf(string.buffer, N, format, args));
string.buffer[N - 1] = 0;
va_end(args);
return string;
@ -74,6 +75,7 @@ namespace ams::kvdb {
/* Ensure string can fit in our buffer. */
CheckLength(strnlen(s, N));
std::strncpy(this->buffer, s, N);
this->buffer[N - 1] = 0;
}
void SetFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) {

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/stat.h>
#include <stratosphere/fs.hpp>
#include "kvdb_bounded_string.hpp"
#include "kvdb_file_key_value_store.hpp"
@ -39,16 +39,16 @@ namespace ams::kvdb {
public:
static Result CreateNewList(const char *path) {
/* Create new lru_list.dat. */
R_TRY(fsdevCreateFile(path, FileSize, 0));
R_TRY(fs::CreateFile(path, FileSize));
/* Open the file. */
FILE *fp = fopen(path, "r+b");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Write new header with zero entries to the file. */
LruHeader new_header = { .entry_count = 0, };
R_UNLESS(fwrite(&new_header, sizeof(new_header), 1, fp) == 1, fsdevGetLastResult());
R_TRY(fs::WriteFile(file, 0, std::addressof(new_header), sizeof(new_header), fs::WriteOption::Flush));
return ResultSuccess();
}
@ -80,36 +80,33 @@ namespace ams::kvdb {
std::memset(this->keys, 0, BufferSize);
/* Open file. */
FILE *fp = fopen(this->file_path, "rb");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), this->file_path, fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Read header. */
R_UNLESS(fread(&this->header, sizeof(this->header), 1, fp) == 1, fsdevGetLastResult());
R_TRY(fs::ReadFile(file, 0, std::addressof(this->header), sizeof(this->header)));
/* Read entries. */
const size_t count = this->GetCount();
if (count > 0) {
R_UNLESS(fread(this->keys, std::min(BufferSize, sizeof(Key) * count), 1, fp) == 1, fsdevGetLastResult());
}
R_TRY(fs::ReadFile(file, sizeof(this->header), this->keys, BufferSize));
return ResultSuccess();
}
Result Save() {
/* Open file. */
FILE *fp = fopen(this->file_path, "r+b");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), this->file_path, fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Write header. */
R_UNLESS(fwrite(&this->header, sizeof(this->header), 1, fp) == 1, fsdevGetLastResult());
R_TRY(fs::WriteFile(file, 0, std::addressof(this->header), sizeof(this->header), fs::WriteOption::None));
/* Write entries. */
R_UNLESS(fwrite(this->keys, BufferSize, 1, fp) == 1, fsdevGetLastResult());
R_TRY(fs::WriteFile(file, sizeof(this->header), this->keys, BufferSize, fs::WriteOption::None));
/* Flush. */
fflush(fp);
R_TRY(fs::FlushFile(file));
return ResultSuccess();
}
@ -209,38 +206,31 @@ namespace ams::kvdb {
return Path::MakeFormat("%s/%s", dir, "kvs");
}
static Result Exists(bool *out, const char *path, bool is_dir) {
static Result Exists(bool *out, const char *path, fs::DirectoryEntryType type) {
/* Set out to false initially. */
*out = false;
/* Check that the path exists, and that our entry type is correct. */
{
struct stat st;
/* Try to get the entry type. */
fs::DirectoryEntryType entry_type;
R_TRY_CATCH(fs::GetEntryType(std::addressof(entry_type), path)) {
/* If the path doesn't exist, nothing has gone wrong. */
R_CONVERT(fs::ResultPathNotFound, ResultSuccess());
} R_END_TRY_CATCH;
if (stat(path, &st) != 0) {
R_TRY_CATCH(fsdevGetLastResult()) {
/* If the path doesn't exist, nothing has gone wrong. */
R_CONVERT(fs::ResultPathNotFound, ResultSuccess());
} R_END_TRY_CATCH;
}
if (is_dir) {
R_UNLESS((S_ISDIR(st.st_mode)), ResultInvalidFilesystemState());
} else {
R_UNLESS((S_ISREG(st.st_mode)), ResultInvalidFilesystemState());
}
}
/* Check that the entry type is correct. */
R_UNLESS(entry_type == type, ResultInvalidFilesystemState());
/* The entry exists and is the correct type. */
*out = true;
return ResultSuccess();
}
static Result DirectoryExists(bool *out, const char *path) {
return Exists(out, path, true);
return Exists(out, path, fs::DirectoryEntryType_Directory);
}
static Result FileExists(bool *out, const char *path) {
return Exists(out, path, false);
return Exists(out, path, fs::DirectoryEntryType_File);
}
public:
static Result CreateNewCache(const char *dir) {

View file

@ -15,7 +15,7 @@
*/
#pragma once
#include <sys/stat.h>
#include <stratosphere/fs.hpp>
#include "kvdb_auto_buffer.hpp"
#include "kvdb_archive.hpp"
#include "kvdb_bounded_string.hpp"
@ -262,11 +262,9 @@ namespace ams::kvdb {
Result Initialize(const char *dir, size_t capacity) {
/* Ensure that the passed path is a directory. */
{
struct stat st;
R_UNLESS(stat(dir, &st) == 0, fs::ResultPathNotFound());
R_UNLESS((S_ISDIR(st.st_mode)), fs::ResultPathNotFound());
}
fs::DirectoryEntryType entry_type;
R_TRY(fs::GetEntryType(std::addressof(entry_type), dir));
R_UNLESS(entry_type == fs::DirectoryEntryType_Directory, fs::ResultPathNotFound());
/* Set paths. */
this->path.SetFormat("%s%s", dir, "/imkvdb.arc");
@ -337,7 +335,7 @@ namespace ams::kvdb {
return ResultSuccess();
}
Result Save() {
Result Save(bool destructive = false) {
/* Create a buffer to hold the archive. */
AutoBuffer buffer;
R_TRY(buffer.Initialize(this->GetArchiveSize()));
@ -353,7 +351,7 @@ namespace ams::kvdb {
}
/* Save the buffer to disk. */
return this->Commit(buffer);
return this->Commit(buffer, destructive);
}
Result Set(const Key &key, const void *value, size_t value_size) {
@ -468,27 +466,38 @@ namespace ams::kvdb {
return this->index.find(key);
}
private:
Result Commit(const AutoBuffer &buffer) {
/* Try to delete temporary archive, but allow deletion failure (it may not exist). */
std::remove(this->temp_path.Get());
Result SaveArchiveToFile(const char *path, const void *buf, size_t size) {
/* Try to delete the archive, but allow deletion failure. */
fs::DeleteFile(path);
/* Create new temporary archive. */
R_TRY(fsdevCreateFile(this->temp_path.Get(), buffer.GetSize(), 0));
/* Create new archive. */
R_TRY(fs::CreateFile(path, size));
/* Write data to the temporary archive. */
/* Write data to the archive. */
{
FILE *f = fopen(this->temp_path, "r+b");
R_UNLESS(f != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(f); };
R_UNLESS(fwrite(buffer.Get(), buffer.GetSize(), 1, f) == 1, fsdevGetLastResult());
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
R_TRY(fs::WriteFile(file, 0, buf, size, fs::WriteOption::Flush));
}
/* Try to delete the saved archive, but allow deletion failure. */
std::remove(this->path.Get());
return ResultSuccess();
}
/* Rename the path. */
R_UNLESS(std::rename(this->temp_path.Get(), this->path.Get()) == 0, fsdevGetLastResult());
Result Commit(const AutoBuffer &buffer, bool destructive) {
if (destructive) {
/* Delete and save to the real archive. */
R_TRY(SaveArchiveToFile(this->path.Get(), buffer.Get(), buffer.GetSize()));
} else {
/* Delete and save to a temporary archive. */
R_TRY(SaveArchiveToFile(this->temp_path.Get(), buffer.Get(), buffer.GetSize()));
/* Try to delete the saved archive, but allow deletion failure. */
fs::DeleteFile(this->path.Get());
/* Rename the path. */
R_TRY(fs::RenameFile(this->temp_path.Get(), this->path.Get()));
}
return ResultSuccess();
}
@ -505,18 +514,17 @@ namespace ams::kvdb {
Result ReadArchiveFile(AutoBuffer *dst) const {
/* Open the file. */
FILE *f = fopen(this->path, "rb");
R_UNLESS(f != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(f); };
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Get the archive file size. */
fseek(f, 0, SEEK_END);
const size_t archive_size = ftell(f);
fseek(f, 0, SEEK_SET);
s64 archive_size;
R_TRY(fs::GetFileSize(std::addressof(archive_size), file));
/* Make a new buffer, read the file. */
R_TRY(dst->Initialize(archive_size));
R_UNLESS(fread(dst->Get(), archive_size, 1, f) == 1, fsdevGetLastResult());
R_TRY(dst->Initialize(static_cast<size_t>(archive_size)));
R_TRY(fs::ReadFile(file, 0, dst->Get(), dst->GetSize()));
return ResultSuccess();
}

View file

@ -180,11 +180,9 @@ namespace ams::kvdb {
Result FileKeyValueStore::InitializeWithCache(const char *dir, void *cache_buffer, size_t cache_buffer_size, size_t cache_capacity) {
/* Ensure that the passed path is a directory. */
{
struct stat st;
R_UNLESS(stat(dir, &st) == 0, fs::ResultPathNotFound());
R_UNLESS((S_ISDIR(st.st_mode)), fs::ResultPathNotFound());
}
fs::DirectoryEntryType entry_type;
R_TRY(fs::GetEntryType(std::addressof(entry_type), dir));
R_UNLESS(entry_type == fs::DirectoryEntryType_Directory, fs::ResultPathNotFound());
/* Set path. */
this->dir_path.Set(dir);
@ -210,24 +208,22 @@ namespace ams::kvdb {
}
/* Open the value file. */
FILE *fp = fopen(this->GetPath(key, key_size), "rb");
if (fp == nullptr) {
R_TRY_CATCH(fsdevGetLastResult()) {
R_CONVERT(fs::ResultPathNotFound, ResultKeyNotFound())
} R_END_TRY_CATCH;
}
ON_SCOPE_EXIT { fclose(fp); };
fs::FileHandle file;
R_TRY_CATCH(fs::OpenFile(std::addressof(file), this->GetPath(key, key_size), fs::OpenMode_Read)) {
R_CONVERT(fs::ResultPathNotFound, ResultKeyNotFound());
} R_END_TRY_CATCH;
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Get the value size. */
fseek(fp, 0, SEEK_END);
const size_t value_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
s64 file_size;
R_TRY(fs::GetFileSize(std::addressof(file_size), file));
/* Ensure there's enough space for the value. */
R_UNLESS(value_size <= max_out_size, ResultBufferInsufficient());
R_UNLESS(file_size <= static_cast<s64>(max_out_size), ResultBufferInsufficient());
/* Read the value. */
R_UNLESS(fread(out_value, value_size, 1, fp) == 1, fsdevGetLastResult());
const size_t value_size = static_cast<size_t>(value_size);
R_TRY(fs::ReadFile(file, 0, out_value, value_size));
*out_size = value_size;
/* Cache the newly read value. */
@ -251,17 +247,17 @@ namespace ams::kvdb {
}
/* Open the value file. */
FILE *fp = fopen(this->GetPath(key, key_size), "rb");
if (fp == nullptr) {
R_TRY_CATCH(fsdevGetLastResult()) {
R_CONVERT(fs::ResultPathNotFound, ResultKeyNotFound())
} R_END_TRY_CATCH;
}
ON_SCOPE_EXIT { fclose(fp); };
fs::FileHandle file;
R_TRY_CATCH(fs::OpenFile(std::addressof(file), this->GetPath(key, key_size), fs::OpenMode_Read)) {
R_CONVERT(fs::ResultPathNotFound, ResultKeyNotFound());
} R_END_TRY_CATCH;
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Get the value size. */
fseek(fp, 0, SEEK_END);
*out_size = ftell(fp);
s64 file_size;
R_TRY(fs::GetFileSize(std::addressof(file_size), file));
*out_size = static_cast<size_t>(file_size);
return ResultSuccess();
}
@ -278,18 +274,18 @@ namespace ams::kvdb {
/* Delete the file, if it exists. Don't check result, since it's okay if it's already deleted. */
auto key_path = this->GetPath(key, key_size);
std::remove(key_path);
fs::DeleteFile(key_path);
/* Create the new value file. */
R_TRY(fs::CreateFile(key_path, value_size));
/* Open the value file. */
FILE *fp = fopen(key_path, "wb");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), key_path, fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Write the value file. */
R_UNLESS(fwrite(value, value_size, 1, fp) == 1, fsdevGetLastResult());
/* Flush the value file. */
fflush(fp);
/* Write the value file and flush. */
R_TRY(fs::WriteFile(file, 0, value, value_size, fs::WriteOption::Flush));
return ResultSuccess();
}
@ -306,11 +302,9 @@ namespace ams::kvdb {
}
/* Remove the file. */
if (std::remove(this->GetPath(key, key_size)) != 0) {
R_TRY_CATCH(fsdevGetLastResult()) {
R_CONVERT(fs::ResultPathNotFound, ResultKeyNotFound())
} R_END_TRY_CATCH;
}
R_TRY_CATCH(fs::DeleteFile(this->GetPath(key, key_size))) {
R_CONVERT(fs::ResultPathNotFound, ResultKeyNotFound())
} R_END_TRY_CATCH;
return ResultSuccess();
}