int musl_scandir(const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) { DIR *directory = opendir(dirp); if (directory == NULL) { return -1; } // Initialize an array of dirent pointers to hold the entries struct dirent **dir_entries = NULL; size_t dir_entries_used = 0; size_t dir_entries_capacity = 0; struct dirent *curr_entry_ptr; while ((curr_entry_ptr = readdir(directory))) { // If we should filter out this entry, skip it if (filter && !filter(curr_entry_ptr)) { continue; } // If we have run out of space, resize our array if (dir_entries_used >= dir_entries_capacity) { dir_entries_capacity = 2 * dir_entries_capacity + 1; // If the new bytes needed > SIZE_MAX, it's invalid if (dir_entries_capacity > SIZE_MAX / sizeof(*dir_entries)) { break; } struct dirent **tmp = realloc(dir_entries, dir_entries_capacity * sizeof(*dir_entries)); if (!tmp) { break; } dir_entries = tmp; } // Make heap space for this entry, and add it to the array dir_entries[dir_entries_used] = malloc(curr_entry_ptr->d_reclen); if (!dir_entries[dir_entries_used]) { break; } memcpy(dir_entries[dir_entries_used++], curr_entry_ptr, curr_entry_ptr->d_reclen); } closedir(directory); // If an error occurred (errno is a global), free memory if (errno) { if (dir_entries) { while (dir_entries_used-- > 0) { free(dir_entries[dir_entries_used]); } } free(dir_entries); return -1; } // If specified, sort the entries based on `compar` if (compar) { qsort(dir_entries, dir_entries_used, sizeof(*dir_entries), (int (*)(const void *, const void *))compar); } *namelist = dir_entries; return dir_entries_used; }