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