dir_walk.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "dir_walk.h"
  2. #include <m-list.h>
  3. LIST_DEF(DirIndexList, uint32_t);
  4. struct DirWalk {
  5. File* file;
  6. string_t 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. string_init(dir_walk->path);
  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. string_clear(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. 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 dir_walk_iter(DirWalk* dir_walk, string_t return_path, FileInfo* fileinfo) {
  48. DirWalkResult result = DirWalkError;
  49. char* name = malloc(256); // FIXME: remove magic number
  50. FileInfo info;
  51. bool end = false;
  52. while(!end) {
  53. storage_dir_read(dir_walk->file, &info, name, 255);
  54. if(storage_file_get_error(dir_walk->file) == FSE_OK) {
  55. result = DirWalkOK;
  56. dir_walk->current_index++;
  57. if(dir_walk_filter(dir_walk, name, &info)) {
  58. if(return_path != NULL) {
  59. string_printf(return_path, "%s/%s", string_get_cstr(dir_walk->path), name);
  60. }
  61. if(fileinfo != NULL) {
  62. memcpy(fileinfo, &info, sizeof(FileInfo));
  63. }
  64. end = true;
  65. }
  66. if((info.flags & FSF_DIRECTORY) && dir_walk->recursive) {
  67. // step into
  68. DirIndexList_push_back(dir_walk->index_list, dir_walk->current_index);
  69. dir_walk->current_index = 0;
  70. storage_dir_close(dir_walk->file);
  71. string_cat_printf(dir_walk->path, "/%s", name);
  72. storage_dir_open(dir_walk->file, string_get_cstr(dir_walk->path));
  73. }
  74. } else if(storage_file_get_error(dir_walk->file) == FSE_NOT_EXIST) {
  75. if(DirIndexList_size(dir_walk->index_list) == 0) {
  76. // last
  77. result = DirWalkLast;
  78. end = true;
  79. } else {
  80. // step out
  81. uint32_t index;
  82. DirIndexList_pop_back(&index, dir_walk->index_list);
  83. dir_walk->current_index = 0;
  84. storage_dir_close(dir_walk->file);
  85. size_t last_char = string_search_rchar(dir_walk->path, '/');
  86. if(last_char != STRING_FAILURE) {
  87. string_left(dir_walk->path, last_char);
  88. }
  89. storage_dir_open(dir_walk->file, string_get_cstr(dir_walk->path));
  90. // rewind
  91. while(true) {
  92. if(index == dir_walk->current_index) {
  93. result = DirWalkOK;
  94. break;
  95. }
  96. if(!storage_dir_read(dir_walk->file, &info, name, 255)) {
  97. result = DirWalkError;
  98. end = true;
  99. break;
  100. }
  101. dir_walk->current_index++;
  102. }
  103. }
  104. } else {
  105. result = DirWalkError;
  106. end = true;
  107. }
  108. }
  109. free(name);
  110. return result;
  111. }
  112. FS_Error dir_walk_get_error(DirWalk* dir_walk) {
  113. return storage_file_get_error(dir_walk->file);
  114. }
  115. DirWalkResult dir_walk_read(DirWalk* dir_walk, string_t return_path, FileInfo* fileinfo) {
  116. return dir_walk_iter(dir_walk, return_path, fileinfo);
  117. }
  118. void dir_walk_close(DirWalk* dir_walk) {
  119. if(storage_file_is_open(dir_walk->file)) {
  120. storage_dir_close(dir_walk->file);
  121. }
  122. DirIndexList_reset(dir_walk->index_list);
  123. string_reset(dir_walk->path);
  124. dir_walk->current_index = 0;
  125. }