| 931 | } |
| 932 | |
| 933 | static void walk_dir(const char *dir_path, const char *rel_prefix, const cbm_discover_opts_t *opts, |
| 934 | const cbm_gitignore_t *gitignore, const cbm_gitignore_t *global_gi, |
| 935 | const cbm_gitignore_t *cbmignore, file_list_t *out) { |
| 936 | walk_stack_t ws = { |
| 937 | .frames = calloc(WALK_STACK_CAP, sizeof(walk_frame_t)), .top = 0, .cap = WALK_STACK_CAP}; |
| 938 | if (!ws.frames) { |
| 939 | out->failed = true; |
| 940 | return; |
| 941 | } |
| 942 | /* Collect all owned gitignores — freed at the end because child frames |
| 943 | * on the stack hold borrowed pointers to them. */ |
| 944 | cbm_gitignore_t **owned_gis = NULL; |
| 945 | size_t owned_count = 0; |
| 946 | size_t owned_capacity = 0; |
| 947 | |
| 948 | int initial_directory_length = snprintf(ws.frames[0].dir, CBM_SZ_4K, "%s", dir_path); |
| 949 | int initial_prefix_length = snprintf(ws.frames[0].prefix, CBM_SZ_4K, "%s", rel_prefix); |
| 950 | if (initial_directory_length <= 0 || initial_directory_length >= CBM_SZ_4K || |
| 951 | initial_prefix_length < 0 || initial_prefix_length >= CBM_SZ_4K) { |
| 952 | out->failed = true; |
| 953 | free(ws.frames); |
| 954 | return; |
| 955 | } |
| 956 | ws.top++; |
| 957 | |
| 958 | while (ws.top > 0 && !file_list_should_stop(out)) { |
| 959 | walk_frame_t frame = ws.frames[--ws.top]; |
| 960 | |
| 961 | cbm_gitignore_t *loaded = try_load_nested_gitignore(&frame); |
| 962 | if (loaded) { |
| 963 | int local_prefix_length = |
| 964 | snprintf(frame.local_gi_prefix, sizeof(frame.local_gi_prefix), "%s", frame.prefix); |
| 965 | if (local_prefix_length < 0 || |
| 966 | (size_t)local_prefix_length >= sizeof(frame.local_gi_prefix) || |
| 967 | !walk_owned_gitignore_append(&owned_gis, &owned_count, &owned_capacity, loaded)) { |
| 968 | cbm_gitignore_free(loaded); |
| 969 | out->failed = true; |
| 970 | break; |
| 971 | } |
| 972 | frame.local_gi = loaded; |
| 973 | } |
| 974 | |
| 975 | cbm_dir_t *d = cbm_opendir(frame.dir); |
| 976 | if (!d) { |
| 977 | if (out->count_only) { |
| 978 | out->failed = true; |
| 979 | } |
| 980 | continue; |
| 981 | } |
| 982 | |
| 983 | cbm_dirent_t *entry; |
| 984 | while (!file_list_should_stop(out) && (entry = cbm_readdir(d)) != NULL) { |
| 985 | walk_dir_process_entry(entry, &frame, opts, gitignore, global_gi, cbmignore, &ws, out); |
| 986 | } |
| 987 | cbm_closedir(d); |
| 988 | } |
| 989 | for (size_t i = 0; i < owned_count; i++) { |
| 990 | cbm_gitignore_free(owned_gis[i]); |
no test coverage detected