Commit eade8c32 authored by Ramon Nou's avatar Ramon Nou
Browse files

try to fix segfault

parent 9239eace
Loading
Loading
Loading
Loading
Loading
+40 −17
Original line number Diff line number Diff line
@@ -33,6 +33,30 @@ struct dirent_extended {
    char d_name[1];
};

static bool
read_entry(const char* buffer, size_t remaining, dirent_extended*& entry,
           string& name) {
    constexpr auto header_size = offsetof(dirent_extended, d_name);
    if(remaining < header_size) {
        return false;
    }

    entry = reinterpret_cast<dirent_extended*>(const_cast<char*>(buffer));
    const auto record_size = static_cast<size_t>(entry->d_reclen);
    if(record_size < header_size + 1 || record_size > remaining) {
        return false;
    }

    const auto name_capacity = record_size - header_size;
    const auto name_length = strnlen(entry->d_name, name_capacity);
    if(name_length == name_capacity) {
        return false;
    }

    name.assign(entry->d_name, name_length);
    return true;
}

/* Function exported from GekkoFS LD_PRELOAD */
extern "C" int
gkfs_getsingleserverdir(const char* path, struct dirent_extended** dirp,
@@ -304,26 +328,27 @@ worker_routine(void* arg) {
                    char* ptr = reinterpret_cast<char*>(entries);
                    size_t bytes_processed = 0;
                    while(bytes_processed < n) {
                        struct dirent_extended* temp =
                                reinterpret_cast<struct dirent_extended*>(ptr);
                        const auto remaining =
                                static_cast<size_t>(n) - bytes_processed;
                        if(temp->d_reclen <
                                   offsetof(struct dirent_extended, d_name) + 1 ||
                           temp->d_reclen > remaining)
                        struct dirent_extended* temp = nullptr;
                        string entry_name;
                        if(!read_entry(ptr, remaining, temp, entry_name))
                            break;

                        local_found++;

                        // Print entry if not just counting
                        if(!data->opt->just_count) {
                            string p_path = (data->workdir->back() == '/') ? *data->workdir : *data->workdir + "/";
                            p_path += temp->d_name;
                            string p_path = data->workdir->empty() ||
                                                     data->workdir->back() != '/'
                                             ? *data->workdir + "/"
                                             : *data->workdir;
                            p_path += entry_name;
                            cout << data->opt->mountdir << p_path << endl;
                        }

                        bytes_processed += temp->d_reclen;
                        ptr += temp->d_reclen;
                        bytes_processed += static_cast<size_t>(temp->d_reclen);
                        ptr += static_cast<size_t>(temp->d_reclen);
                    }
                    free(entries);
                } else {
@@ -366,13 +391,11 @@ worker_routine(void* arg) {
            char* ptr = reinterpret_cast<char*>(entries);
            size_t bytes_processed = 0;
            while(bytes_processed < n) {
                struct dirent_extended* temp =
                        reinterpret_cast<struct dirent_extended*>(ptr);
                const auto remaining =
                        static_cast<size_t>(n) - bytes_processed;
                if(temp->d_reclen <
                           offsetof(struct dirent_extended, d_name) + 1 ||
                   temp->d_reclen > remaining)
                struct dirent_extended* temp = nullptr;
                string entry_name;
                if(!read_entry(ptr, remaining, temp, entry_name))
                    break;

                if(temp->d_type != 1) {
@@ -384,14 +407,14 @@ worker_routine(void* arg) {
                             temp->size == data->opt->size);
                    bool nameOK =
                            data->opt->name_pattern.empty() ||
                            regex_search(temp->d_name, data->opt->name_regex);
                            regex_search(entry_name, data->opt->name_regex);

                    if(timeOK && sizeOK && nameOK)
                        local_found++;
                }
                local_checked++;
                bytes_processed += temp->d_reclen;
                ptr += temp->d_reclen;
                bytes_processed += static_cast<size_t>(temp->d_reclen);
                ptr += static_cast<size_t>(temp->d_reclen);
            }
            free(entries);
        }