|
|
@ -230,7 +230,6 @@ class EspFileLock : public FileLock { |
|
|
|
const std::string filename_; |
|
|
|
const std::string filename_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EspLogger final : public Logger { |
|
|
|
class EspLogger final : public Logger { |
|
|
|
public: |
|
|
|
public: |
|
|
|
explicit EspLogger(FIL file) : file_(file) {} |
|
|
|
explicit EspLogger(FIL file) : file_(file) {} |
|
|
@ -247,8 +246,8 @@ class EspLogger final : public Logger { |
|
|
|
snprintf(output, bytes_needed, format, args_copy); |
|
|
|
snprintf(output, bytes_needed, format, args_copy); |
|
|
|
#pragma GCC diagnostic pop |
|
|
|
#pragma GCC diagnostic pop |
|
|
|
va_end(args_copy); |
|
|
|
va_end(args_copy); |
|
|
|
ESP_LOGV("LEVELDB", "%s", output); |
|
|
|
ESP_LOGI("LEVELDB", "%s", output); |
|
|
|
//f_puts(output, &file_);
|
|
|
|
// f_puts(output, &file_);
|
|
|
|
free(reinterpret_cast<void*>(output)); |
|
|
|
free(reinterpret_cast<void*>(output)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -256,190 +255,197 @@ class EspLogger final : public Logger { |
|
|
|
FIL file_; |
|
|
|
FIL file_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
EspEnv::~EspEnv() { |
|
|
|
EspEnv::~EspEnv() { |
|
|
|
ESP_LOGE("LEVELDB", "EspEnv singleton destroyed. Unsupported behavior!"); |
|
|
|
ESP_LOGE("LEVELDB", "EspEnv singleton destroyed. Unsupported behavior!"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::NewSequentialFile(const std::string& filename, |
|
|
|
|
|
|
|
SequentialFile** result) { |
|
|
|
|
|
|
|
FIL file; |
|
|
|
|
|
|
|
FRESULT res = f_open(&file, filename.c_str(), FA_READ); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*result = new EspSequentialFile(filename, file); |
|
|
|
Status EspEnv::NewSequentialFile(const std::string& filename, |
|
|
|
return Status::OK(); |
|
|
|
SequentialFile** result) { |
|
|
|
|
|
|
|
FIL file; |
|
|
|
|
|
|
|
FRESULT res = f_open(&file, filename.c_str(), FA_READ); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::NewRandomAccessFile(const std::string& filename, |
|
|
|
*result = new EspSequentialFile(filename, file); |
|
|
|
RandomAccessFile** result) { |
|
|
|
return Status::OK(); |
|
|
|
// EspRandomAccessFile doesn't try to open the file until it's needed, so
|
|
|
|
} |
|
|
|
// we need to first ensure the file exists to handle the NotFound case
|
|
|
|
|
|
|
|
// correctly.
|
|
|
|
|
|
|
|
FILINFO info; |
|
|
|
|
|
|
|
FRESULT res = f_stat(filename.c_str(), &info); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*result = new EspRandomAccessFile(filename); |
|
|
|
Status EspEnv::NewRandomAccessFile(const std::string& filename, |
|
|
|
return Status::OK(); |
|
|
|
RandomAccessFile** result) { |
|
|
|
|
|
|
|
// EspRandomAccessFile doesn't try to open the file until it's needed, so
|
|
|
|
|
|
|
|
// we need to first ensure the file exists to handle the NotFound case
|
|
|
|
|
|
|
|
// correctly.
|
|
|
|
|
|
|
|
FILINFO info; |
|
|
|
|
|
|
|
FRESULT res = f_stat(filename.c_str(), &info); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::NewWritableFile(const std::string& filename, |
|
|
|
*result = new EspRandomAccessFile(filename); |
|
|
|
WritableFile** result) { |
|
|
|
return Status::OK(); |
|
|
|
FIL file; |
|
|
|
} |
|
|
|
FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_CREATE_ALWAYS); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*result = new EspWritableFile(filename, file); |
|
|
|
Status EspEnv::NewWritableFile(const std::string& filename, |
|
|
|
return Status::OK(); |
|
|
|
WritableFile** result) { |
|
|
|
|
|
|
|
FIL file; |
|
|
|
|
|
|
|
FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_CREATE_ALWAYS); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::NewAppendableFile(const std::string& filename, |
|
|
|
*result = new EspWritableFile(filename, file); |
|
|
|
WritableFile** result) { |
|
|
|
return Status::OK(); |
|
|
|
FIL file; |
|
|
|
} |
|
|
|
FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_OPEN_APPEND); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*result = new EspWritableFile(filename, file); |
|
|
|
Status EspEnv::NewAppendableFile(const std::string& filename, |
|
|
|
return Status::OK(); |
|
|
|
WritableFile** result) { |
|
|
|
|
|
|
|
FIL file; |
|
|
|
|
|
|
|
FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_OPEN_APPEND); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool EspEnv::FileExists(const std::string& filename) { |
|
|
|
*result = new EspWritableFile(filename, file); |
|
|
|
FILINFO info; |
|
|
|
return Status::OK(); |
|
|
|
return f_stat(filename.c_str(), &info) == FR_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::GetChildren(const std::string& directory_path, |
|
|
|
bool EspEnv::FileExists(const std::string& filename) { |
|
|
|
std::vector<std::string>* result) { |
|
|
|
FILINFO info; |
|
|
|
result->clear(); |
|
|
|
return f_stat(filename.c_str(), &info) == FR_OK; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
FF_DIR dir; |
|
|
|
Status EspEnv::GetChildren(const std::string& directory_path, |
|
|
|
FRESULT res = f_opendir(&dir, directory_path.c_str()); |
|
|
|
std::vector<std::string>* result) { |
|
|
|
if (res != FR_OK) { |
|
|
|
result->clear(); |
|
|
|
return EspError(directory_path, res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FILINFO info; |
|
|
|
FF_DIR dir; |
|
|
|
for (;;) { |
|
|
|
FRESULT res = f_opendir(&dir, directory_path.c_str()); |
|
|
|
res = f_readdir(&dir, &info); |
|
|
|
if (res != FR_OK) { |
|
|
|
if (res != FR_OK) { |
|
|
|
return EspError(directory_path, res); |
|
|
|
return EspError(directory_path, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (info.fname[0] == 0) { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
result->emplace_back(info.fname); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = f_closedir(&dir); |
|
|
|
FILINFO info; |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
|
|
|
res = f_readdir(&dir, &info); |
|
|
|
if (res != FR_OK) { |
|
|
|
if (res != FR_OK) { |
|
|
|
return EspError(directory_path, res); |
|
|
|
return EspError(directory_path, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (info.fname[0] == 0) { |
|
|
|
return Status::OK(); |
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
result->emplace_back(info.fname); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::RemoveFile(const std::string& filename) { |
|
|
|
res = f_closedir(&dir); |
|
|
|
FRESULT res = f_unlink(filename.c_str()); |
|
|
|
if (res != FR_OK) { |
|
|
|
if (res != FR_OK) { |
|
|
|
return EspError(directory_path, res); |
|
|
|
return EspError(filename, res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return Status::OK(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::CreateDir(const std::string& dirname) { |
|
|
|
return Status::OK(); |
|
|
|
FRESULT res = f_mkdir(dirname.c_str()); |
|
|
|
} |
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
return EspError(dirname, res); |
|
|
|
Status EspEnv::RemoveFile(const std::string& filename) { |
|
|
|
} |
|
|
|
FRESULT res = f_unlink(filename.c_str()); |
|
|
|
return Status::OK(); |
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return Status::OK(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::RemoveDir(const std::string& dirname) { |
|
|
|
Status EspEnv::CreateDir(const std::string& dirname) { |
|
|
|
return RemoveFile(dirname); |
|
|
|
FRESULT res = f_mkdir(dirname.c_str()); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
return EspError(dirname, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return Status::OK(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::GetFileSize(const std::string& filename, uint64_t* size) { |
|
|
|
Status EspEnv::RemoveDir(const std::string& dirname) { |
|
|
|
FILINFO info; |
|
|
|
return RemoveFile(dirname); |
|
|
|
FRESULT res = f_stat(filename.c_str(), &info); |
|
|
|
} |
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*size = 0; |
|
|
|
Status EspEnv::GetFileSize(const std::string& filename, uint64_t* size) { |
|
|
|
return EspError(filename, res); |
|
|
|
FILINFO info; |
|
|
|
} |
|
|
|
FRESULT res = f_stat(filename.c_str(), &info); |
|
|
|
*size = info.fsize; |
|
|
|
if (res != FR_OK) { |
|
|
|
return Status::OK(); |
|
|
|
*size = 0; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
*size = info.fsize; |
|
|
|
|
|
|
|
return Status::OK(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::RenameFile(const std::string& from, const std::string& to) { |
|
|
|
Status EspEnv::RenameFile(const std::string& from, const std::string& to) { |
|
|
|
FRESULT res = f_rename(from.c_str(), to.c_str()); |
|
|
|
// Match the POSIX behaviour of replacing any existing file.
|
|
|
|
if (res != FR_OK) { |
|
|
|
if (FileExists(to)) { |
|
|
|
return EspError(from, res); |
|
|
|
Status s = RemoveFile(to); |
|
|
|
|
|
|
|
if (!s.ok()) { |
|
|
|
|
|
|
|
return s; |
|
|
|
} |
|
|
|
} |
|
|
|
return Status::OK(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
FRESULT res = f_rename(from.c_str(), to.c_str()); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
return EspError(from, res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return Status::OK(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::LockFile(const std::string& filename, FileLock** lock) { |
|
|
|
Status EspEnv::LockFile(const std::string& filename, FileLock** lock) { |
|
|
|
*lock = nullptr; |
|
|
|
*lock = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
if (!locks_.Insert(filename)) { |
|
|
|
|
|
|
|
return Status::IOError("lock " + filename, "already held by process"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*lock = new EspFileLock(filename); |
|
|
|
if (!locks_.Insert(filename)) { |
|
|
|
return Status::OK(); |
|
|
|
return Status::IOError("lock " + filename, "already held by process"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::UnlockFile(FileLock* lock) { |
|
|
|
*lock = new EspFileLock(filename); |
|
|
|
EspFileLock* posix_file_lock = static_cast<EspFileLock*>(lock); |
|
|
|
return Status::OK(); |
|
|
|
locks_.Remove(posix_file_lock->filename()); |
|
|
|
} |
|
|
|
delete posix_file_lock; |
|
|
|
|
|
|
|
return Status::OK(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void EspEnv::StartThread(void (*thread_main)(void* thread_main_arg), |
|
|
|
Status EspEnv::UnlockFile(FileLock* lock) { |
|
|
|
void* thread_main_arg) { |
|
|
|
EspFileLock* posix_file_lock = static_cast<EspFileLock*>(lock); |
|
|
|
std::thread new_thread(thread_main, thread_main_arg); |
|
|
|
locks_.Remove(posix_file_lock->filename()); |
|
|
|
new_thread.detach(); |
|
|
|
delete posix_file_lock; |
|
|
|
} |
|
|
|
return Status::OK(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::GetTestDirectory(std::string* result) { |
|
|
|
void EspEnv::StartThread(void (*thread_main)(void* thread_main_arg), |
|
|
|
CreateDir("/tmp"); |
|
|
|
void* thread_main_arg) { |
|
|
|
*result = "/tmp"; |
|
|
|
std::thread new_thread(thread_main, thread_main_arg); |
|
|
|
return Status::OK(); |
|
|
|
new_thread.detach(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Status EspEnv::NewLogger(const std::string& filename, Logger** result) { |
|
|
|
Status EspEnv::GetTestDirectory(std::string* result) { |
|
|
|
FIL file; |
|
|
|
CreateDir("/tmp"); |
|
|
|
FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_OPEN_APPEND); |
|
|
|
*result = "/tmp"; |
|
|
|
if (res != FR_OK) { |
|
|
|
return Status::OK(); |
|
|
|
*result = nullptr; |
|
|
|
} |
|
|
|
return EspError(filename, res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*result = new EspLogger(file); |
|
|
|
Status EspEnv::NewLogger(const std::string& filename, Logger** result) { |
|
|
|
return Status::OK(); |
|
|
|
FIL file; |
|
|
|
|
|
|
|
FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_OPEN_APPEND); |
|
|
|
|
|
|
|
if (res != FR_OK) { |
|
|
|
|
|
|
|
*result = nullptr; |
|
|
|
|
|
|
|
return EspError(filename, res); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint64_t EspEnv::NowMicros() { |
|
|
|
*result = new EspLogger(file); |
|
|
|
struct timeval tv_now; |
|
|
|
return Status::OK(); |
|
|
|
gettimeofday(&tv_now, NULL); |
|
|
|
} |
|
|
|
return (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void EspEnv::SleepForMicroseconds(int micros) { |
|
|
|
uint64_t EspEnv::NowMicros() { |
|
|
|
vTaskDelay(pdMS_TO_TICKS(micros / 1000)); |
|
|
|
struct timeval tv_now; |
|
|
|
} |
|
|
|
gettimeofday(&tv_now, NULL); |
|
|
|
|
|
|
|
return (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void EspEnv::SleepForMicroseconds(int micros) { |
|
|
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(micros / 1000)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
extern "C" void BackgroundThreadEntryPoint(EspEnv* env) { |
|
|
|
extern "C" void BackgroundThreadEntryPoint(EspEnv* env) { |
|
|
|
env->BackgroundThreadMain(); |
|
|
|
env->BackgroundThreadMain(); |
|
|
|