storage_processing.c 17 KB

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