Storage: tree timestamps (#1971)

* Storage: tree timestamps
* Rpc: add storage timestamp
* Storage: correct timestamp owner
* Storage: update timestamp at sd mount

Co-authored-by: SG <who.just.the.doctor@gmail.com>
This commit is contained in:
あく 2022-11-04 14:26:04 +09:00 committed by GitHub
parent e3ea5bca76
commit d68ac50efd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 142 additions and 2 deletions

View File

@ -138,6 +138,41 @@ static void rpc_system_storage_info_process(const PB_Main* request, void* contex
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
} }
static void rpc_system_storage_timestamp_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(context);
furi_assert(request->which_content == PB_Main_storage_timestamp_request_tag);
FURI_LOG_D(TAG, "Timestamp");
RpcStorageSystem* rpc_storage = context;
RpcSession* session = rpc_storage->session;
furi_assert(session);
rpc_system_storage_reset_state(rpc_storage, session, true);
PB_Main* response = malloc(sizeof(PB_Main));
response->command_id = request->command_id;
Storage* fs_api = furi_record_open(RECORD_STORAGE);
const char* path = request->content.storage_timestamp_request.path;
uint32_t timestamp = 0;
FS_Error error = storage_common_timestamp(fs_api, path, &timestamp);
response->command_status = rpc_system_storage_get_error(error);
response->which_content = PB_Main_empty_tag;
if(error == FSE_OK) {
response->which_content = PB_Main_storage_timestamp_response_tag;
response->content.storage_timestamp_response.timestamp = timestamp;
}
rpc_send_and_release(session, response);
free(response);
furi_record_close(RECORD_STORAGE);
}
static void rpc_system_storage_stat_process(const PB_Main* request, void* context) { static void rpc_system_storage_stat_process(const PB_Main* request, void* context) {
furi_assert(request); furi_assert(request);
furi_assert(context); furi_assert(context);
@ -672,6 +707,9 @@ void* rpc_system_storage_alloc(RpcSession* session) {
rpc_handler.message_handler = rpc_system_storage_info_process; rpc_handler.message_handler = rpc_system_storage_info_process;
rpc_add_handler(session, PB_Main_storage_info_request_tag, &rpc_handler); rpc_add_handler(session, PB_Main_storage_info_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_storage_timestamp_process;
rpc_add_handler(session, PB_Main_storage_timestamp_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_storage_stat_process; rpc_handler.message_handler = rpc_system_storage_stat_process;
rpc_add_handler(session, PB_Main_storage_stat_request_tag, &rpc_handler); rpc_add_handler(session, PB_Main_storage_stat_request_tag, &rpc_handler);

View File

@ -39,6 +39,7 @@ Storage* storage_app_alloc() {
for(uint8_t i = 0; i < STORAGE_COUNT; i++) { for(uint8_t i = 0; i < STORAGE_COUNT; i++) {
storage_data_init(&app->storage[i]); storage_data_init(&app->storage[i]);
storage_data_timestamp(&app->storage[i]);
} }
#ifndef FURI_RAM_EXEC #ifndef FURI_RAM_EXEC

View File

@ -177,6 +177,16 @@ bool storage_dir_rewind(File* file);
/******************* Common Functions *******************/ /******************* Common Functions *******************/
/** Retrieves unix timestamp of last access
*
* @param storage The storage instance
* @param path path to file/directory
* @param timestamp the timestamp pointer
*
* @return FS_Error operation result
*/
FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* timestamp);
/** Retrieves information about a file/directory /** Retrieves information about a file/directory
* @param app pointer to the api * @param app pointer to the api
* @param path path to file/directory * @param path path to file/directory

View File

@ -32,6 +32,7 @@ static void storage_cli_print_usage() {
printf("\tmkdir\t - creates a new directory\r\n"); printf("\tmkdir\t - creates a new directory\r\n");
printf("\tmd5\t - md5 hash of the file\r\n"); printf("\tmd5\t - md5 hash of the file\r\n");
printf("\tstat\t - info about file or dir\r\n"); printf("\tstat\t - info about file or dir\r\n");
printf("\ttimestamp\t - last modification timestamp\r\n");
}; };
static void storage_cli_print_error(FS_Error error) { static void storage_cli_print_error(FS_Error error) {
@ -386,6 +387,22 @@ static void storage_cli_stat(Cli* cli, FuriString* path) {
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
} }
static void storage_cli_timestamp(Cli* cli, FuriString* path) {
UNUSED(cli);
Storage* api = furi_record_open(RECORD_STORAGE);
uint32_t timestamp = 0;
FS_Error error = storage_common_timestamp(api, furi_string_get_cstr(path), &timestamp);
if(error != FSE_OK) {
printf("Invalid arguments\r\n");
} else {
printf("Timestamp %lu\r\n", timestamp);
}
furi_record_close(RECORD_STORAGE);
}
static void storage_cli_copy(Cli* cli, FuriString* old_path, FuriString* args) { static void storage_cli_copy(Cli* cli, FuriString* old_path, FuriString* args) {
UNUSED(cli); UNUSED(cli);
Storage* api = furi_record_open(RECORD_STORAGE); Storage* api = furi_record_open(RECORD_STORAGE);
@ -578,6 +595,11 @@ void storage_cli(Cli* cli, FuriString* args, void* context) {
break; break;
} }
if(furi_string_cmp_str(cmd, "timestamp") == 0) {
storage_cli_timestamp(cli, path);
break;
}
storage_cli_print_usage(); storage_cli_print_usage();
} while(false); } while(false);

View File

@ -354,6 +354,16 @@ bool storage_dir_rewind(File* file) {
/****************** COMMON ******************/ /****************** COMMON ******************/
FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* timestamp) {
S_API_PROLOGUE;
SAData data = {.ctimestamp = {.path = path, .timestamp = timestamp}};
S_API_MESSAGE(StorageCommandCommonTimestamp);
S_API_EPILOGUE;
return S_RETURN_ERROR;
}
FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo) { FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo) {
S_API_PROLOGUE; S_API_PROLOGUE;

View File

@ -82,6 +82,14 @@ const char* storage_data_status_text(StorageData* storage) {
return result; return result;
} }
void storage_data_timestamp(StorageData* storage) {
storage->timestamp = furi_hal_rtc_get_timestamp();
}
uint32_t storage_data_get_timestamp(StorageData* storage) {
return storage->timestamp;
}
/****************** storage glue ******************/ /****************** storage glue ******************/
bool storage_has_file(const File* file, StorageData* storage_data) { bool storage_has_file(const File* file, StorageData* storage_data) {

View File

@ -42,6 +42,8 @@ bool storage_data_lock(StorageData* storage);
bool storage_data_unlock(StorageData* storage); bool storage_data_unlock(StorageData* storage);
StorageStatus storage_data_status(StorageData* storage); StorageStatus storage_data_status(StorageData* storage);
const char* storage_data_status_text(StorageData* storage); const char* storage_data_status_text(StorageData* storage);
void storage_data_timestamp(StorageData* storage);
uint32_t storage_data_get_timestamp(StorageData* storage);
LIST_DEF( LIST_DEF(
StorageFileList, StorageFileList,
@ -58,6 +60,7 @@ struct StorageData {
FuriMutex* mutex; FuriMutex* mutex;
StorageStatus status; StorageStatus status;
StorageFileList_t files; StorageFileList_t files;
uint32_t timestamp;
}; };
bool storage_has_file(const File* file, StorageData* storage_data); bool storage_has_file(const File* file, StorageData* storage_data);

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <furi.h> #include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h> #include <gui/gui.h>
#include "storage_glue.h" #include "storage_glue.h"
#include "storage_sd_api.h" #include "storage_sd_api.h"

View File

@ -42,6 +42,11 @@ typedef struct {
uint16_t name_length; uint16_t name_length;
} SADataDRead; } SADataDRead;
typedef struct {
const char* path;
uint32_t* timestamp;
} SADataCTimestamp;
typedef struct { typedef struct {
const char* path; const char* path;
FileInfo* fileinfo; FileInfo* fileinfo;
@ -78,6 +83,7 @@ typedef union {
SADataDOpen dopen; SADataDOpen dopen;
SADataDRead dread; SADataDRead dread;
SADataCTimestamp ctimestamp;
SADataCStat cstat; SADataCStat cstat;
SADataCFSInfo cfsinfo; SADataCFSInfo cfsinfo;
@ -112,6 +118,7 @@ typedef enum {
StorageCommandDirClose, StorageCommandDirClose,
StorageCommandDirRead, StorageCommandDirRead,
StorageCommandDirRewind, StorageCommandDirRewind,
StorageCommandCommonTimestamp,
StorageCommandCommonStat, StorageCommandCommonStat,
StorageCommandCommonRemove, StorageCommandCommonRemove,
StorageCommandCommonMkDir, StorageCommandCommonMkDir,

View File

@ -114,6 +114,9 @@ bool storage_process_file_open(
if(storage_path_already_open(real_path, storage->files)) { if(storage_path_already_open(real_path, storage->files)) {
file->error_id = FSE_ALREADY_OPEN; file->error_id = FSE_ALREADY_OPEN;
} else { } else {
if(access_mode & FSAM_WRITE) {
storage_data_timestamp(storage);
}
storage_push_storage_file(file, real_path, type, storage); storage_push_storage_file(file, real_path, type, storage);
FS_CALL(storage, file.open(storage, file, remove_vfs(path), access_mode, open_mode)); FS_CALL(storage, file.open(storage, file, remove_vfs(path), access_mode, open_mode));
} }
@ -166,6 +169,7 @@ static uint16_t storage_process_file_write(
if(storage == NULL) { if(storage == NULL) {
file->error_id = FSE_INVALID_PARAMETER; file->error_id = FSE_INVALID_PARAMETER;
} else { } else {
storage_data_timestamp(storage);
FS_CALL(storage, file.write(storage, file, buff, bytes_to_write)); FS_CALL(storage, file.write(storage, file, buff, bytes_to_write));
} }
@ -209,6 +213,7 @@ static bool storage_process_file_truncate(Storage* app, File* file) {
if(storage == NULL) { if(storage == NULL) {
file->error_id = FSE_INVALID_PARAMETER; file->error_id = FSE_INVALID_PARAMETER;
} else { } else {
storage_data_timestamp(storage);
FS_CALL(storage, file.truncate(storage, file)); FS_CALL(storage, file.truncate(storage, file));
} }
@ -222,6 +227,7 @@ static bool storage_process_file_sync(Storage* app, File* file) {
if(storage == NULL) { if(storage == NULL) {
file->error_id = FSE_INVALID_PARAMETER; file->error_id = FSE_INVALID_PARAMETER;
} else { } else {
storage_data_timestamp(storage);
FS_CALL(storage, file.sync(storage, file)); FS_CALL(storage, file.sync(storage, file));
} }
@ -332,6 +338,21 @@ bool storage_process_dir_rewind(Storage* app, File* file) {
/******************* Common FS Functions *******************/ /******************* Common FS Functions *******************/
static FS_Error
storage_process_common_timestamp(Storage* app, const char* path, uint32_t* timestamp) {
FS_Error ret = FSE_OK;
StorageType type = storage_get_type_by_path(app, path);
if(storage_type_is_not_valid(type)) {
ret = FSE_INVALID_NAME;
} else {
StorageData* storage = storage_get_storage_by_type(app, type);
*timestamp = storage_data_get_timestamp(storage);
}
return ret;
}
static FS_Error storage_process_common_stat(Storage* app, const char* path, FileInfo* fileinfo) { static FS_Error storage_process_common_stat(Storage* app, const char* path, FileInfo* fileinfo) {
FS_Error ret = FSE_OK; FS_Error ret = FSE_OK;
StorageType type = storage_get_type_by_path(app, path); StorageType type = storage_get_type_by_path(app, path);
@ -366,6 +387,7 @@ static FS_Error storage_process_common_remove(Storage* app, const char* path) {
break; break;
} }
storage_data_timestamp(storage);
FS_CALL(storage, common.remove(storage, remove_vfs(path))); FS_CALL(storage, common.remove(storage, remove_vfs(path)));
} while(false); } while(false);
@ -382,6 +404,7 @@ static FS_Error storage_process_common_mkdir(Storage* app, const char* path) {
ret = FSE_INVALID_NAME; ret = FSE_INVALID_NAME;
} else { } else {
StorageData* storage = storage_get_storage_by_type(app, type); StorageData* storage = storage_get_storage_by_type(app, type);
storage_data_timestamp(storage);
FS_CALL(storage, common.mkdir(storage, remove_vfs(path))); FS_CALL(storage, common.mkdir(storage, remove_vfs(path)));
} }
@ -417,6 +440,7 @@ static FS_Error storage_process_sd_format(Storage* app) {
ret = FSE_NOT_READY; ret = FSE_NOT_READY;
} else { } else {
ret = sd_format_card(&app->storage[ST_EXT]); ret = sd_format_card(&app->storage[ST_EXT]);
storage_data_timestamp(&app->storage[ST_EXT]);
} }
return ret; return ret;
@ -429,6 +453,7 @@ static FS_Error storage_process_sd_unmount(Storage* app) {
ret = FSE_NOT_READY; ret = FSE_NOT_READY;
} else { } else {
sd_unmount_card(&app->storage[ST_EXT]); sd_unmount_card(&app->storage[ST_EXT]);
storage_data_timestamp(&app->storage[ST_EXT]);
} }
return ret; return ret;
@ -541,6 +566,10 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) {
message->return_data->bool_value = message->return_data->bool_value =
storage_process_dir_rewind(app, message->data->file.file); storage_process_dir_rewind(app, message->data->file.file);
break; break;
case StorageCommandCommonTimestamp:
message->return_data->error_value = storage_process_common_timestamp(
app, message->data->ctimestamp.path, message->data->ctimestamp.timestamp);
break;
case StorageCommandCommonStat: case StorageCommandCommonStat:
message->return_data->error_value = storage_process_common_stat( message->return_data->error_value = storage_process_common_stat(
app, message->data->cstat.path, message->data->cstat.fileinfo); app, message->data->cstat.path, message->data->cstat.fileinfo);

View File

@ -90,6 +90,7 @@ static bool sd_mount_card(StorageData* storage, bool notify) {
} }
} }
storage_data_timestamp(storage);
storage_data_unlock(storage); storage_data_unlock(storage);
return result; return result;

@ -1 +1 @@
Subproject commit 6727eaf287db077dcd28719cd764f5804712223e Subproject commit e5af96e08fea8351898f7b8c6d1e34ce5fd6cdef

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,7.2,, Version,+,7.3,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
@ -1251,6 +1251,7 @@ Function,+,furi_hal_rtc_get_fault_data,uint32_t,
Function,+,furi_hal_rtc_get_log_level,uint8_t, Function,+,furi_hal_rtc_get_log_level,uint8_t,
Function,+,furi_hal_rtc_get_pin_fails,uint32_t, Function,+,furi_hal_rtc_get_pin_fails,uint32_t,
Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister
Function,+,furi_hal_rtc_get_timestamp,uint32_t,
Function,-,furi_hal_rtc_init,void, Function,-,furi_hal_rtc_init,void,
Function,-,furi_hal_rtc_init_early,void, Function,-,furi_hal_rtc_init_early,void,
Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag
@ -2235,6 +2236,7 @@ Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*"
Function,+,storage_common_remove,FS_Error,"Storage*, const char*" Function,+,storage_common_remove,FS_Error,"Storage*, const char*"
Function,+,storage_common_rename,FS_Error,"Storage*, const char*, const char*" Function,+,storage_common_rename,FS_Error,"Storage*, const char*, const char*"
Function,+,storage_common_stat,FS_Error,"Storage*, const char*, FileInfo*" Function,+,storage_common_stat,FS_Error,"Storage*, const char*, FileInfo*"
Function,+,storage_common_timestamp,FS_Error,"Storage*, const char*, uint32_t*"
Function,+,storage_dir_close,_Bool,File* Function,+,storage_dir_close,_Bool,File*
Function,+,storage_dir_open,_Bool,"File*, const char*" Function,+,storage_dir_open,_Bool,"File*, const char*"
Function,+,storage_dir_read,_Bool,"File*, FileInfo*, char*, uint16_t" Function,+,storage_dir_read,_Bool,"File*, FileInfo*, char*, uint16_t"

1 entry status name type params
2 Version + 7.2 7.3
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
1251 Function + furi_hal_rtc_get_log_level uint8_t
1252 Function + furi_hal_rtc_get_pin_fails uint32_t
1253 Function + furi_hal_rtc_get_register uint32_t FuriHalRtcRegister
1254 Function + furi_hal_rtc_get_timestamp uint32_t
1255 Function - furi_hal_rtc_init void
1256 Function - furi_hal_rtc_init_early void
1257 Function + furi_hal_rtc_is_flag_set _Bool FuriHalRtcFlag
2236 Function + storage_common_remove FS_Error Storage*, const char*
2237 Function + storage_common_rename FS_Error Storage*, const char*, const char*
2238 Function + storage_common_stat FS_Error Storage*, const char*, FileInfo*
2239 Function + storage_common_timestamp FS_Error Storage*, const char*, uint32_t*
2240 Function + storage_dir_close _Bool File*
2241 Function + storage_dir_open _Bool File*, const char*
2242 Function + storage_dir_read _Bool File*, FileInfo*, char*, uint16_t

View File

@ -318,6 +318,12 @@ uint32_t furi_hal_rtc_get_pin_fails() {
return furi_hal_rtc_get_register(FuriHalRtcRegisterPinFails); return furi_hal_rtc_get_register(FuriHalRtcRegisterPinFails);
} }
uint32_t furi_hal_rtc_get_timestamp() {
FuriHalRtcDateTime datetime = {0};
furi_hal_rtc_get_datetime(&datetime);
return furi_hal_rtc_datetime_to_timestamp(&datetime);
}
uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) { uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) {
uint32_t timestamp = 0; uint32_t timestamp = 0;
uint8_t years = 0; uint8_t years = 0;

View File

@ -93,6 +93,8 @@ void furi_hal_rtc_set_pin_fails(uint32_t value);
uint32_t furi_hal_rtc_get_pin_fails(); uint32_t furi_hal_rtc_get_pin_fails();
uint32_t furi_hal_rtc_get_timestamp();
uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime); uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime);
#ifdef __cplusplus #ifdef __cplusplus