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; std::va_list args;
va_start(args, format); va_start(args, format);
CheckLength(std::vsnprintf(string.buffer, N, format, args)); CheckLength(std::vsnprintf(string.buffer, N, format, args));
string.buffer[N - 1] = 0;
va_end(args); va_end(args);
return string; return string;
@ -74,6 +75,7 @@ namespace ams::kvdb {
/* Ensure string can fit in our buffer. */ /* Ensure string can fit in our buffer. */
CheckLength(strnlen(s, N)); CheckLength(strnlen(s, N));
std::strncpy(this->buffer, s, N); std::strncpy(this->buffer, s, N);
this->buffer[N - 1] = 0;
} }
void SetFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) { 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 * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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_bounded_string.hpp"
#include "kvdb_file_key_value_store.hpp" #include "kvdb_file_key_value_store.hpp"
@ -39,16 +39,16 @@ namespace ams::kvdb {
public: public:
static Result CreateNewList(const char *path) { static Result CreateNewList(const char *path) {
/* Create new lru_list.dat. */ /* Create new lru_list.dat. */
R_TRY(fsdevCreateFile(path, FileSize, 0)); R_TRY(fs::CreateFile(path, FileSize));
/* Open the file. */ /* Open the file. */
FILE *fp = fopen(path, "r+b"); fs::FileHandle file;
R_UNLESS(fp != nullptr, fsdevGetLastResult()); R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Write));
ON_SCOPE_EXIT { fclose(fp); }; ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Write new header with zero entries to the file. */ /* Write new header with zero entries to the file. */
LruHeader new_header = { .entry_count = 0, }; 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(); return ResultSuccess();
} }
@ -80,36 +80,33 @@ namespace ams::kvdb {
std::memset(this->keys, 0, BufferSize); std::memset(this->keys, 0, BufferSize);
/* Open file. */ /* Open file. */
FILE *fp = fopen(this->file_path, "rb"); fs::FileHandle file;
R_UNLESS(fp != nullptr, fsdevGetLastResult()); R_TRY(fs::OpenFile(std::addressof(file), this->file_path, fs::OpenMode_Read));
ON_SCOPE_EXIT { fclose(fp); }; ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Read header. */ /* 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. */ /* Read entries. */
const size_t count = this->GetCount(); R_TRY(fs::ReadFile(file, sizeof(this->header), this->keys, BufferSize));
if (count > 0) {
R_UNLESS(fread(this->keys, std::min(BufferSize, sizeof(Key) * count), 1, fp) == 1, fsdevGetLastResult());
}
return ResultSuccess(); return ResultSuccess();
} }
Result Save() { Result Save() {
/* Open file. */ /* Open file. */
FILE *fp = fopen(this->file_path, "r+b"); fs::FileHandle file;
R_UNLESS(fp != nullptr, fsdevGetLastResult()); R_TRY(fs::OpenFile(std::addressof(file), this->file_path, fs::OpenMode_Read));
ON_SCOPE_EXIT { fclose(fp); }; ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Write header. */ /* 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. */ /* 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. */ /* Flush. */
fflush(fp); R_TRY(fs::FlushFile(file));
return ResultSuccess(); return ResultSuccess();
} }
@ -209,38 +206,31 @@ namespace ams::kvdb {
return Path::MakeFormat("%s/%s", dir, "kvs"); 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. */ /* Set out to false initially. */
*out = false; *out = false;
/* Check that the path exists, and that our entry type is correct. */ /* Try to get the entry type. */
{ fs::DirectoryEntryType entry_type;
struct stat st; 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) { /* Check that the entry type is correct. */
R_TRY_CATCH(fsdevGetLastResult()) { R_UNLESS(entry_type == type, ResultInvalidFilesystemState());
/* 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());
}
}
/* The entry exists and is the correct type. */
*out = true; *out = true;
return ResultSuccess(); return ResultSuccess();
} }
static Result DirectoryExists(bool *out, const char *path) { 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) { static Result FileExists(bool *out, const char *path) {
return Exists(out, path, false); return Exists(out, path, fs::DirectoryEntryType_File);
} }
public: public:
static Result CreateNewCache(const char *dir) { static Result CreateNewCache(const char *dir) {

View File

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