storage_processing.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. #include "storage_processing.h"
  2. #include <m-list.h>
  3. #include <m-dict.h>
  4. #include <m-string.h>
  5. #define FS_CALL(_storage, _fn) \
  6. storage_data_lock(_storage); \
  7. ret = _storage->fs_api->_fn; \
  8. storage_data_unlock(_storage);
  9. #define ST_CALL(_storage, _fn) \
  10. storage_data_lock(_storage); \
  11. ret = _storage->api._fn; \
  12. storage_data_unlock(_storage);
  13. static StorageData* storage_get_storage_by_type(Storage* app, StorageType type) {
  14. furi_check(type == ST_EXT || type == ST_INT);
  15. StorageData* storage = &app->storage[type];
  16. return storage;
  17. }
  18. static bool storage_type_is_not_valid(StorageType type) {
  19. #ifdef FURI_RAM_EXEC
  20. return type != ST_EXT;
  21. #else
  22. return type >= ST_ERROR;
  23. #endif
  24. }
  25. static StorageData* get_storage_by_file(File* file, StorageData* storages) {
  26. StorageData* storage_data = NULL;
  27. for(uint8_t i = 0; i < STORAGE_COUNT; i++) {
  28. if(storage_has_file(file, &storages[i])) {
  29. storage_data = &storages[i];
  30. }
  31. }
  32. return storage_data;
  33. }
  34. static const char* remove_vfs(const char* path) {
  35. return path + MIN(4, strlen(path));
  36. }
  37. static const char* ext_path = "/ext";
  38. static const char* int_path = "/int";
  39. static const char* any_path = "/any";
  40. static StorageType storage_get_type_by_path(Storage* app, const char* path) {
  41. StorageType type = ST_ERROR;
  42. if(strlen(path) >= strlen(ext_path) && memcmp(path, ext_path, strlen(ext_path)) == 0) {
  43. type = ST_EXT;
  44. } else if(strlen(path) >= strlen(int_path) && memcmp(path, int_path, strlen(int_path)) == 0) {
  45. type = ST_INT;
  46. } else if(strlen(path) >= strlen(any_path) && memcmp(path, any_path, strlen(any_path)) == 0) {
  47. type = ST_ANY;
  48. }
  49. if(type == ST_ANY) {
  50. type = ST_INT;
  51. if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusOK) {
  52. type = ST_EXT;
  53. }
  54. }
  55. return type;
  56. }
  57. static void storage_path_change_to_real_storage(string_t path, StorageType real_storage) {
  58. if(memcmp(string_get_cstr(path), any_path, strlen(any_path)) == 0) {
  59. switch(real_storage) {
  60. case ST_EXT:
  61. string_set_char(path, 0, ext_path[0]);
  62. string_set_char(path, 1, ext_path[1]);
  63. string_set_char(path, 2, ext_path[2]);
  64. string_set_char(path, 3, ext_path[3]);
  65. break;
  66. case ST_INT:
  67. string_set_char(path, 0, int_path[0]);
  68. string_set_char(path, 1, int_path[1]);
  69. string_set_char(path, 2, int_path[2]);
  70. string_set_char(path, 3, int_path[3]);
  71. break;
  72. default:
  73. break;
  74. }
  75. }
  76. }
  77. /******************* File Functions *******************/
  78. bool storage_process_file_open(
  79. Storage* app,
  80. File* file,
  81. const char* path,
  82. FS_AccessMode access_mode,
  83. FS_OpenMode open_mode) {
  84. bool ret = false;
  85. StorageType type = storage_get_type_by_path(app, path);
  86. StorageData* storage;
  87. file->error_id = FSE_OK;
  88. if(storage_type_is_not_valid(type)) {
  89. file->error_id = FSE_INVALID_NAME;
  90. } else {
  91. storage = storage_get_storage_by_type(app, type);
  92. string_t real_path;
  93. string_init_set(real_path, path);
  94. storage_path_change_to_real_storage(real_path, type);
  95. if(storage_path_already_open(real_path, storage->files)) {
  96. file->error_id = FSE_ALREADY_OPEN;
  97. } else {
  98. storage_push_storage_file(file, real_path, type, storage);
  99. FS_CALL(storage, file.open(storage, file, remove_vfs(path), access_mode, open_mode));
  100. }
  101. string_clear(real_path);
  102. }
  103. return ret;
  104. }
  105. bool storage_process_file_close(Storage* app, File* file) {
  106. bool ret = false;
  107. StorageData* storage = get_storage_by_file(file, app->storage);
  108. if(storage == NULL) {
  109. file->error_id = FSE_INVALID_PARAMETER;
  110. } else {
  111. FS_CALL(storage, file.close(storage, file));
  112. storage_pop_storage_file(file, storage);
  113. StorageEvent event = {.type = StorageEventTypeFileClose};
  114. furi_pubsub_publish(app->pubsub, &event);
  115. }
  116. return ret;
  117. }
  118. static uint16_t
  119. storage_process_file_read(Storage* app, File* file, void* buff, uint16_t const bytes_to_read) {
  120. uint16_t ret = 0;
  121. StorageData* storage = get_storage_by_file(file, app->storage);
  122. if(storage == NULL) {
  123. file->error_id = FSE_INVALID_PARAMETER;
  124. } else {
  125. FS_CALL(storage, file.read(storage, file, buff, bytes_to_read));
  126. }
  127. return ret;
  128. }
  129. static uint16_t storage_process_file_write(
  130. Storage* app,
  131. File* file,
  132. const void* buff,
  133. uint16_t const bytes_to_write) {
  134. uint16_t ret = 0;
  135. StorageData* storage = get_storage_by_file(file, app->storage);
  136. if(storage == NULL) {
  137. file->error_id = FSE_INVALID_PARAMETER;
  138. } else {
  139. FS_CALL(storage, file.write(storage, file, buff, bytes_to_write));
  140. }
  141. return ret;
  142. }
  143. static bool storage_process_file_seek(
  144. Storage* app,
  145. File* file,
  146. const uint32_t offset,
  147. const bool from_start) {
  148. bool ret = false;
  149. StorageData* storage = get_storage_by_file(file, app->storage);
  150. if(storage == NULL) {
  151. file->error_id = FSE_INVALID_PARAMETER;
  152. } else {
  153. FS_CALL(storage, file.seek(storage, file, offset, from_start));
  154. }
  155. return ret;
  156. }
  157. static uint64_t storage_process_file_tell(Storage* app, File* file) {
  158. uint64_t ret = 0;
  159. StorageData* storage = get_storage_by_file(file, app->storage);
  160. if(storage == NULL) {
  161. file->error_id = FSE_INVALID_PARAMETER;
  162. } else {
  163. FS_CALL(storage, file.tell(storage, file));
  164. }
  165. return ret;
  166. }
  167. static bool storage_process_file_truncate(Storage* app, File* file) {
  168. bool ret = false;
  169. StorageData* storage = get_storage_by_file(file, app->storage);
  170. if(storage == NULL) {
  171. file->error_id = FSE_INVALID_PARAMETER;
  172. } else {
  173. FS_CALL(storage, file.truncate(storage, file));
  174. }
  175. return ret;
  176. }
  177. static bool storage_process_file_sync(Storage* app, File* file) {
  178. bool ret = false;
  179. StorageData* storage = get_storage_by_file(file, app->storage);
  180. if(storage == NULL) {
  181. file->error_id = FSE_INVALID_PARAMETER;
  182. } else {
  183. FS_CALL(storage, file.sync(storage, file));
  184. }
  185. return ret;
  186. }
  187. static uint64_t storage_process_file_size(Storage* app, File* file) {
  188. uint64_t ret = 0;
  189. StorageData* storage = get_storage_by_file(file, app->storage);
  190. if(storage == NULL) {
  191. file->error_id = FSE_INVALID_PARAMETER;
  192. } else {
  193. FS_CALL(storage, file.size(storage, file));
  194. }
  195. return ret;
  196. }
  197. static bool storage_process_file_eof(Storage* app, File* file) {
  198. bool ret = false;
  199. StorageData* storage = get_storage_by_file(file, app->storage);
  200. if(storage == NULL) {
  201. file->error_id = FSE_INVALID_PARAMETER;
  202. } else {
  203. FS_CALL(storage, file.eof(storage, file));
  204. }
  205. return ret;
  206. }
  207. /******************* Dir Functions *******************/
  208. bool storage_process_dir_open(Storage* app, File* file, const char* path) {
  209. bool ret = false;
  210. StorageType type = storage_get_type_by_path(app, path);
  211. StorageData* storage;
  212. file->error_id = FSE_OK;
  213. if(storage_type_is_not_valid(type)) {
  214. file->error_id = FSE_INVALID_NAME;
  215. } else {
  216. storage = storage_get_storage_by_type(app, type);
  217. string_t real_path;
  218. string_init_set(real_path, path);
  219. storage_path_change_to_real_storage(real_path, type);
  220. if(storage_path_already_open(real_path, storage->files)) {
  221. file->error_id = FSE_ALREADY_OPEN;
  222. } else {
  223. storage_push_storage_file(file, real_path, type, storage);
  224. FS_CALL(storage, dir.open(storage, file, remove_vfs(path)));
  225. }
  226. string_clear(real_path);
  227. }
  228. return ret;
  229. }
  230. bool storage_process_dir_close(Storage* app, File* file) {
  231. bool ret = false;
  232. StorageData* storage = get_storage_by_file(file, app->storage);
  233. if(storage == NULL) {
  234. file->error_id = FSE_INVALID_PARAMETER;
  235. } else {
  236. FS_CALL(storage, dir.close(storage, file));
  237. storage_pop_storage_file(file, storage);
  238. StorageEvent event = {.type = StorageEventTypeDirClose};
  239. furi_pubsub_publish(app->pubsub, &event);
  240. }
  241. return ret;
  242. }
  243. bool storage_process_dir_read(
  244. Storage* app,
  245. File* file,
  246. FileInfo* fileinfo,
  247. char* name,
  248. const uint16_t name_length) {
  249. bool ret = false;
  250. StorageData* storage = get_storage_by_file(file, app->storage);
  251. if(storage == NULL) {
  252. file->error_id = FSE_INVALID_PARAMETER;
  253. } else {
  254. FS_CALL(storage, dir.read(storage, file, fileinfo, name, name_length));
  255. }
  256. return ret;
  257. }
  258. bool storage_process_dir_rewind(Storage* app, File* file) {
  259. bool ret = false;
  260. StorageData* storage = get_storage_by_file(file, app->storage);
  261. if(storage == NULL) {
  262. file->error_id = FSE_INVALID_PARAMETER;
  263. } else {
  264. FS_CALL(storage, dir.rewind(storage, file));
  265. }
  266. return ret;
  267. }
  268. /******************* Common FS Functions *******************/
  269. static FS_Error storage_process_common_stat(Storage* app, const char* path, FileInfo* fileinfo) {
  270. FS_Error ret = FSE_OK;
  271. StorageType type = storage_get_type_by_path(app, path);
  272. if(storage_type_is_not_valid(type)) {
  273. ret = FSE_INVALID_NAME;
  274. } else {
  275. StorageData* storage = storage_get_storage_by_type(app, type);
  276. FS_CALL(storage, common.stat(storage, remove_vfs(path), fileinfo));
  277. }
  278. return ret;
  279. }
  280. static FS_Error storage_process_common_remove(Storage* app, const char* path) {
  281. FS_Error ret = FSE_OK;
  282. StorageType type = storage_get_type_by_path(app, path);
  283. string_t real_path;
  284. string_init_set(real_path, path);
  285. storage_path_change_to_real_storage(real_path, type);
  286. do {
  287. if(storage_type_is_not_valid(type)) {
  288. ret = FSE_INVALID_NAME;
  289. break;
  290. }
  291. StorageData* storage = storage_get_storage_by_type(app, type);
  292. if(storage_path_already_open(real_path, storage->files)) {
  293. ret = FSE_ALREADY_OPEN;
  294. break;
  295. }
  296. FS_CALL(storage, common.remove(storage, remove_vfs(path)));
  297. } while(false);
  298. string_clear(real_path);
  299. return ret;
  300. }
  301. static FS_Error storage_process_common_mkdir(Storage* app, const char* path) {
  302. FS_Error ret = FSE_OK;
  303. StorageType type = storage_get_type_by_path(app, path);
  304. if(storage_type_is_not_valid(type)) {
  305. ret = FSE_INVALID_NAME;
  306. } else {
  307. StorageData* storage = storage_get_storage_by_type(app, type);
  308. FS_CALL(storage, common.mkdir(storage, remove_vfs(path)));
  309. }
  310. return ret;
  311. }
  312. static FS_Error storage_process_common_fs_info(
  313. Storage* app,
  314. const char* fs_path,
  315. uint64_t* total_space,
  316. uint64_t* free_space) {
  317. FS_Error ret = FSE_OK;
  318. StorageType type = storage_get_type_by_path(app, fs_path);
  319. if(storage_type_is_not_valid(type)) {
  320. ret = FSE_INVALID_NAME;
  321. } else {
  322. StorageData* storage = storage_get_storage_by_type(app, type);
  323. FS_CALL(storage, common.fs_info(storage, remove_vfs(fs_path), total_space, free_space));
  324. }
  325. return ret;
  326. }
  327. /****************** Raw SD API ******************/
  328. // TODO think about implementing a custom storage API to split that kind of api linkage
  329. #include "storages/storage_ext.h"
  330. static FS_Error storage_process_sd_format(Storage* app) {
  331. FS_Error ret = FSE_OK;
  332. if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusNotReady) {
  333. ret = FSE_NOT_READY;
  334. } else {
  335. ret = sd_format_card(&app->storage[ST_EXT]);
  336. }
  337. return ret;
  338. }
  339. static FS_Error storage_process_sd_unmount(Storage* app) {
  340. FS_Error ret = FSE_OK;
  341. if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusNotReady) {
  342. ret = FSE_NOT_READY;
  343. } else {
  344. sd_unmount_card(&app->storage[ST_EXT]);
  345. }
  346. return ret;
  347. }
  348. static FS_Error storage_process_sd_info(Storage* app, SDInfo* info) {
  349. FS_Error ret = FSE_OK;
  350. if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusNotReady) {
  351. ret = FSE_NOT_READY;
  352. } else {
  353. ret = sd_card_info(&app->storage[ST_EXT], info);
  354. }
  355. return ret;
  356. }
  357. static FS_Error storage_process_sd_status(Storage* app) {
  358. FS_Error ret;
  359. StorageStatus status = storage_data_status(&app->storage[ST_EXT]);
  360. switch(status) {
  361. case StorageStatusOK:
  362. ret = FSE_OK;
  363. break;
  364. case StorageStatusNotReady:
  365. ret = FSE_NOT_READY;
  366. break;
  367. default:
  368. ret = FSE_INTERNAL;
  369. break;
  370. }
  371. return ret;
  372. }
  373. /****************** API calls processing ******************/
  374. void storage_process_message_internal(Storage* app, StorageMessage* message) {
  375. switch(message->command) {
  376. case StorageCommandFileOpen:
  377. message->return_data->bool_value = storage_process_file_open(
  378. app,
  379. message->data->fopen.file,
  380. message->data->fopen.path,
  381. message->data->fopen.access_mode,
  382. message->data->fopen.open_mode);
  383. break;
  384. case StorageCommandFileClose:
  385. message->return_data->bool_value =
  386. storage_process_file_close(app, message->data->fopen.file);
  387. break;
  388. case StorageCommandFileRead:
  389. message->return_data->uint16_value = storage_process_file_read(
  390. app,
  391. message->data->fread.file,
  392. message->data->fread.buff,
  393. message->data->fread.bytes_to_read);
  394. break;
  395. case StorageCommandFileWrite:
  396. message->return_data->uint16_value = storage_process_file_write(
  397. app,
  398. message->data->fwrite.file,
  399. message->data->fwrite.buff,
  400. message->data->fwrite.bytes_to_write);
  401. break;
  402. case StorageCommandFileSeek:
  403. message->return_data->bool_value = storage_process_file_seek(
  404. app,
  405. message->data->fseek.file,
  406. message->data->fseek.offset,
  407. message->data->fseek.from_start);
  408. break;
  409. case StorageCommandFileTell:
  410. message->return_data->uint64_value =
  411. storage_process_file_tell(app, message->data->file.file);
  412. break;
  413. case StorageCommandFileTruncate:
  414. message->return_data->bool_value =
  415. storage_process_file_truncate(app, message->data->file.file);
  416. break;
  417. case StorageCommandFileSync:
  418. message->return_data->bool_value =
  419. storage_process_file_sync(app, message->data->file.file);
  420. break;
  421. case StorageCommandFileSize:
  422. message->return_data->uint64_value =
  423. storage_process_file_size(app, message->data->file.file);
  424. break;
  425. case StorageCommandFileEof:
  426. message->return_data->bool_value = storage_process_file_eof(app, message->data->file.file);
  427. break;
  428. case StorageCommandDirOpen:
  429. message->return_data->bool_value =
  430. storage_process_dir_open(app, message->data->dopen.file, message->data->dopen.path);
  431. break;
  432. case StorageCommandDirClose:
  433. message->return_data->bool_value =
  434. storage_process_dir_close(app, message->data->file.file);
  435. break;
  436. case StorageCommandDirRead:
  437. message->return_data->bool_value = storage_process_dir_read(
  438. app,
  439. message->data->dread.file,
  440. message->data->dread.fileinfo,
  441. message->data->dread.name,
  442. message->data->dread.name_length);
  443. break;
  444. case StorageCommandDirRewind:
  445. message->return_data->bool_value =
  446. storage_process_dir_rewind(app, message->data->file.file);
  447. break;
  448. case StorageCommandCommonStat:
  449. message->return_data->error_value = storage_process_common_stat(
  450. app, message->data->cstat.path, message->data->cstat.fileinfo);
  451. break;
  452. case StorageCommandCommonRemove:
  453. message->return_data->error_value =
  454. storage_process_common_remove(app, message->data->path.path);
  455. break;
  456. case StorageCommandCommonMkDir:
  457. message->return_data->error_value =
  458. storage_process_common_mkdir(app, message->data->path.path);
  459. break;
  460. case StorageCommandCommonFSInfo:
  461. message->return_data->error_value = storage_process_common_fs_info(
  462. app,
  463. message->data->cfsinfo.fs_path,
  464. message->data->cfsinfo.total_space,
  465. message->data->cfsinfo.free_space);
  466. break;
  467. case StorageCommandSDFormat:
  468. message->return_data->error_value = storage_process_sd_format(app);
  469. break;
  470. case StorageCommandSDUnmount:
  471. message->return_data->error_value = storage_process_sd_unmount(app);
  472. break;
  473. case StorageCommandSDInfo:
  474. message->return_data->error_value =
  475. storage_process_sd_info(app, message->data->sdinfo.info);
  476. break;
  477. case StorageCommandSDStatus:
  478. message->return_data->error_value = storage_process_sd_status(app);
  479. break;
  480. }
  481. osSemaphoreRelease(message->semaphore);
  482. }
  483. void storage_process_message(Storage* app, StorageMessage* message) {
  484. storage_process_message_internal(app, message);
  485. }