dir_walk.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include "dir_walk.h"
  2. #include <m-list.h>
  3. LIST_DEF(DirIndexList, uint32_t);
  4. struct DirWalk {
  5. File* file;
  6. FuriString* path;
  7. DirIndexList_t index_list;
  8. uint32_t current_index;
  9. bool recursive;
  10. DirWalkFilterCb filter_cb;
  11. void* filter_context;
  12. };
  13. DirWalk* dir_walk_alloc(Storage* storage) {
  14. DirWalk* dir_walk = malloc(sizeof(DirWalk));
  15. dir_walk->path = furi_string_alloc();
  16. dir_walk->file = storage_file_alloc(storage);
  17. DirIndexList_init(dir_walk->index_list);
  18. dir_walk->recursive = true;
  19. dir_walk->filter_cb = NULL;
  20. return dir_walk;
  21. }
  22. void dir_walk_free(DirWalk* dir_walk) {
  23. storage_file_free(dir_walk->file);
  24. furi_string_free(dir_walk->path);
  25. DirIndexList_clear(dir_walk->index_list);
  26. free(dir_walk);
  27. }
  28. void dir_walk_set_recursive(DirWalk* dir_walk, bool recursive) {
  29. dir_walk->recursive = recursive;
  30. }
  31. void dir_walk_set_filter_cb(DirWalk* dir_walk, DirWalkFilterCb cb, void* context) {
  32. dir_walk->filter_cb = cb;
  33. dir_walk->filter_context = context;
  34. }
  35. bool dir_walk_open(DirWalk* dir_walk, const char* path) {
  36. furi_string_set(dir_walk->path, path);
  37. dir_walk->current_index = 0;
  38. return storage_dir_open(dir_walk->file, path);
  39. }
  40. static bool dir_walk_filter(DirWalk* dir_walk, const char* name, FileInfo* fileinfo) {
  41. if(dir_walk->filter_cb) {
  42. return dir_walk->filter_cb(name, fileinfo, dir_walk->filter_context);
  43. } else {
  44. return true;
  45. }
  46. }
  47. static DirWalkResult
  48. dir_walk_iter(DirWalk* dir_walk, FuriString* return_path, FileInfo* fileinfo) {
  49. DirWalkResult result = DirWalkError;
  50. char* name = malloc(256); // FIXME: remove magic number
  51. FileInfo info;
  52. bool end = false;
  53. while(!end) {
  54. storage_dir_read(dir_walk->file, &info, name, 255);
  55. if(storage_file_get_error(dir_walk->file) == FSE_OK) {
  56. result = DirWalkOK;
  57. dir_walk->current_index++;
  58. if(dir_walk_filter(dir_walk, name, &info)) {
  59. if(return_path != NULL) {
  60. furi_string_printf( //-V576
  61. return_path,
  62. "%s/%s",
  63. furi_string_get_cstr(dir_walk->path),
  64. name);
  65. }
  66. if(fileinfo != NULL) {
  67. memcpy(fileinfo, &info, sizeof(FileInfo));
  68. }
  69. end = true;
  70. }
  71. if(file_info_is_dir(&info) && dir_walk->recursive) {
  72. // step into
  73. DirIndexList_push_back(dir_walk->index_list, dir_walk->current_index);
  74. dir_walk->current_index = 0;
  75. storage_dir_close(dir_walk->file);
  76. furi_string_cat_printf(dir_walk->path, "/%s", name);
  77. storage_dir_open(dir_walk->file, furi_string_get_cstr(dir_walk->path));
  78. }
  79. } else if(storage_file_get_error(dir_walk->file) == FSE_NOT_EXIST) {
  80. if(DirIndexList_size(dir_walk->index_list) == 0) {
  81. // last
  82. result = DirWalkLast;
  83. end = true;
  84. } else {
  85. // step out
  86. uint32_t index;
  87. DirIndexList_pop_back(&index, dir_walk->index_list);
  88. dir_walk->current_index = 0;
  89. storage_dir_close(dir_walk->file);
  90. size_t last_char = furi_string_search_rchar(dir_walk->path, '/');
  91. if(last_char != FURI_STRING_FAILURE) {
  92. furi_string_left(dir_walk->path, last_char);
  93. }
  94. storage_dir_open(dir_walk->file, furi_string_get_cstr(dir_walk->path));
  95. // rewind
  96. while(true) {
  97. if(index == dir_walk->current_index) {
  98. result = DirWalkOK;
  99. break;
  100. }
  101. if(!storage_dir_read(dir_walk->file, &info, name, 255)) {
  102. result = DirWalkError;
  103. end = true;
  104. break;
  105. }
  106. dir_walk->current_index++;
  107. }
  108. }
  109. } else {
  110. result = DirWalkError;
  111. end = true;
  112. }
  113. }
  114. free(name);
  115. return result;
  116. }
  117. FS_Error dir_walk_get_error(DirWalk* dir_walk) {
  118. return storage_file_get_error(dir_walk->file);
  119. }
  120. DirWalkResult dir_walk_read(DirWalk* dir_walk, FuriString* return_path, FileInfo* fileinfo) {
  121. return dir_walk_iter(dir_walk, return_path, fileinfo);
  122. }
  123. void dir_walk_close(DirWalk* dir_walk) {
  124. if(storage_file_is_open(dir_walk->file)) {
  125. storage_dir_close(dir_walk->file);
  126. }
  127. DirIndexList_reset(dir_walk->index_list);
  128. furi_string_reset(dir_walk->path);
  129. dir_walk->current_index = 0;
  130. }