storage_processing.c 17 KB

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