diff --git a/src/posix/handlers/posix_readdir.hpp b/src/posix/handlers/posix_readdir.hpp index f9adfc026..978a183c7 100644 --- a/src/posix/handlers/posix_readdir.hpp +++ b/src/posix/handlers/posix_readdir.hpp @@ -83,6 +83,75 @@ inline int count_files_in_directory(const char *path) { return count; } +inline struct dirent64 *capio_internal_readdir(DIR *dirp, long pid) { + START_LOG(pid, "call(dirp=%ld)", dirp); + + auto directory_path = + std::get<0>(opened_directory->at(reinterpret_cast(dirp))); + + if (directory_commit_token_path.find(directory_path) == directory_commit_token_path.end()) { + LOG("Commit token path was not found for path %s", directory_path.c_str()); + auto token_path = new char[PATH_MAX]{0}; + posix_directory_committed_request(pid, directory_path, token_path); + LOG("Inserting token path %s", token_path); + directory_commit_token_path.insert({directory_path, token_path}); + } + + const auto token_path = directory_commit_token_path.at(directory_path); + + if (const auto item = opened_directory->find(reinterpret_cast(dirp)); + item != opened_directory->end() || std::filesystem::exists(token_path)) { + LOG("Found dirp."); + const auto dir_path_name = std::get<0>(item->second); + const auto capio_internal_offset = std::get<1>(item->second); + + auto files_in_directory = count_files_in_directory(dir_path_name.c_str()); + LOG("There are %ld files inside %s", files_in_directory, dir_path_name.c_str()); + while (files_in_directory <= capio_internal_offset) { + LOG("Not enough files: expected %ld, got %ld... waiting", files_in_directory, + capio_internal_offset); + LOG("Checking for commit token existence (%s)", token_path.c_str()); + syscall_no_intercept_flag = true; + bool is_committed = std::filesystem::exists(token_path); + syscall_no_intercept_flag = false; + LOG("File %s committed", is_committed ? "is" : "is not"); + if (is_committed) { + LOG("Returning NULL as result"); + errno = 0; + return NULL; + } + + struct timespec req{0}; + req.tv_sec = 0; + req.tv_nsec = 100 * 1000000L; // 100 ms + syscall_no_intercept(SYS_nanosleep, &req, NULL); + files_in_directory = count_files_in_directory(dir_path_name.c_str()); + LOG("There are %ld files inside %s", files_in_directory, dir_path_name.c_str()); + } + + LOG("Returning item %d", std::get<1>(item->second)); + + char real_path[PATH_MAX]; + capio_realpath(dir_path_name.c_str(), real_path); + + LOG("Getting files inside directory %s", real_path); + + const auto return_value = directory_items->at(real_path)->at(std::get<1>(item->second)); + std::get<1>(item->second)++; + + LOG("Returned dirent structure:"); + LOG("dirent.d_name = %s", return_value->d_name); + LOG("dirent.d_type = %d", return_value->d_type); + LOG("dirent.d_ino = %d", return_value->d_ino); + LOG("dirent.d_off = %d", return_value->d_off); + LOG("dirent.d_reclen = %d", return_value->d_reclen); + return return_value; + } + LOG("Reached end of branch... something might be amiss.. returning EOS"); + errno = 0; + return NULL; +} + DIR *opendir(const char *name) { auto tmp = std::string(name); @@ -177,75 +246,6 @@ int closedir(DIR *dirp) { return return_code; } -inline struct dirent64 *capio_internal_readdir(DIR *dirp, long pid) { - START_LOG(pid, "call(dirp=%ld)", dirp); - - auto directory_path = - std::get<0>(opened_directory->at(reinterpret_cast(dirp))); - - if (directory_commit_token_path.find(directory_path) == directory_commit_token_path.end()) { - LOG("Commit token path was not found for path %s", directory_path.c_str()); - auto token_path = new char[PATH_MAX]{0}; - posix_directory_committed_request(pid, directory_path, token_path); - LOG("Inserting token path %s", token_path); - directory_commit_token_path.insert({directory_path, token_path}); - } - - const auto token_path = directory_commit_token_path.at(directory_path); - - if (const auto item = opened_directory->find(reinterpret_cast(dirp)); - item != opened_directory->end() || std::filesystem::exists(token_path)) { - LOG("Found dirp."); - const auto dir_path_name = std::get<0>(item->second); - const auto capio_internal_offset = std::get<1>(item->second); - - auto files_in_directory = count_files_in_directory(dir_path_name.c_str()); - LOG("There are %ld files inside %s", files_in_directory, dir_path_name.c_str()); - while (files_in_directory <= capio_internal_offset) { - LOG("Not enough files: expected %ld, got %ld... waiting", files_in_directory, - capio_internal_offset); - LOG("Checking for commit token existence (%s)", token_path.c_str()); - syscall_no_intercept_flag = true; - bool is_committed = std::filesystem::exists(token_path); - syscall_no_intercept_flag = false; - LOG("File %s committed", is_committed ? "is" : "is not"); - if (is_committed) { - LOG("Returning NULL as result"); - errno = 0; - return NULL; - } - - struct timespec req{0}; - req.tv_sec = 0; - req.tv_nsec = 100 * 1000000L; // 100 ms - syscall_no_intercept(SYS_nanosleep, &req, NULL); - files_in_directory = count_files_in_directory(dir_path_name.c_str()); - LOG("There are %ld files inside %s", files_in_directory, dir_path_name.c_str()); - } - - LOG("Returning item %d", std::get<1>(item->second)); - - char real_path[PATH_MAX]; - capio_realpath(dir_path_name.c_str(), real_path); - - LOG("Getting files inside directory %s", real_path); - - const auto return_value = directory_items->at(real_path)->at(std::get<1>(item->second)); - std::get<1>(item->second)++; - - LOG("Returned dirent structure:"); - LOG("dirent.d_name = %s", return_value->d_name); - LOG("dirent.d_type = %d", return_value->d_type); - LOG("dirent.d_ino = %d", return_value->d_ino); - LOG("dirent.d_off = %d", return_value->d_off); - LOG("dirent.d_reclen = %d", return_value->d_reclen); - return return_value; - } - LOG("Reached end of branch... something might be amiss.. returning EOS"); - errno = 0; - return NULL; -} - struct dirent *readdir(DIR *dirp) { long pid = capio_syscall(SYS_gettid); START_LOG(pid, "call(dir=%ld)", dirp); @@ -300,4 +300,112 @@ struct dirent64 *readdir64(DIR *dirp) { return capio_internal_dirent64; } +void rewinddir(DIR *dirp) { + long pid = capio_syscall(SYS_gettid); + START_LOG(pid, "call(dir=%ld)", dirp); + + static void (*real_rewinddir)(DIR *) = NULL; + if (!real_rewinddir) { + LOG("Loading real glibc method"); + syscall_no_intercept_flag = true; + real_rewinddir = (void (*)(DIR *)) dlsym(RTLD_NEXT, "rewinddir"); + syscall_no_intercept_flag = false; + } + + if (opened_directory->find(reinterpret_cast(dirp)) == + opened_directory->end()) { + LOG("Directory is not handled by CAPIO. Returning false"); + syscall_no_intercept_flag = true; + real_rewinddir(dirp); + syscall_no_intercept_flag = false; + } else { + LOG("File handled by CAPIO. Resetting internal CAPIO offset"); + opened_directory->at(reinterpret_cast(dirp)).second = 0; + } +} + +long int telldir(DIR *dirp) { + long pid = capio_syscall(SYS_gettid); + START_LOG(pid, "call(dir=%ld)", dirp); + + static long int (*real_telldir)(DIR *) = NULL; + if (!real_telldir) { + LOG("Loading real glibc method"); + syscall_no_intercept_flag = true; + real_telldir = (long int (*)(DIR *)) dlsym(RTLD_NEXT, "telldir"); + syscall_no_intercept_flag = false; + } + + if (opened_directory->find(reinterpret_cast(dirp)) == + opened_directory->end()) { + LOG("Directory is not handled by CAPIO. Returning false"); + syscall_no_intercept_flag = true; + auto result = real_telldir(dirp); + syscall_no_intercept_flag = false; + LOG("Telldir returned %ld", result); + return result; + } + + LOG("File handled by CAPIO. Returning internal CAPIO offset (which is %ld)", + opened_directory->at(reinterpret_cast(dirp)).second); + return opened_directory->at(reinterpret_cast(dirp)).second; +} + +void seekdir(DIR *dirp, long int loc) { + long pid = capio_syscall(SYS_gettid); + START_LOG(pid, "call(dir=%ld, loc=%ld)", dirp, loc); + + static void (*real_seekdir)(DIR *, long int) = NULL; + if (!real_seekdir) { + LOG("Loading real glibc method"); + syscall_no_intercept_flag = true; + real_seekdir = (void (*)(DIR *, long int)) dlsym(RTLD_NEXT, "seekdir"); + syscall_no_intercept_flag = false; + } + + if (opened_directory->find(reinterpret_cast(dirp)) == + opened_directory->end()) { + LOG("Directory is not handled by CAPIO. Using real seekdir"); + syscall_no_intercept_flag = true; + real_seekdir(dirp, loc); + syscall_no_intercept_flag = false; + } else { + LOG("Directory is handled by CAPIO. Setting internal offset to %ld", loc); + opened_directory->at(reinterpret_cast(dirp)).second = loc; + } +} + +int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { + + /* + * WARN: I have not yet clear the usage of this function, as such bugs are surely presents + * TODO: implement the correct handling logic for this method + */ + long pid = capio_syscall(SYS_gettid); + START_LOG(pid, "call(dir=%ld)", dirp); + + static int (*real_readdir_r)(DIR *, struct dirent *, struct dirent **) = NULL; + if (!real_readdir_r) { + LOG("Loading real glibc method"); + syscall_no_intercept_flag = true; + real_readdir_r = + (int (*)(DIR *, struct dirent *, struct dirent **)) dlsym(RTLD_NEXT, "readdir_r"); + syscall_no_intercept_flag = false; + } + + if (opened_directory->find(reinterpret_cast(dirp)) == + opened_directory->end()) { + LOG("Directory is not handled by CAPIO. Using real readdir_r"); + syscall_no_intercept_flag = true; + int res = real_readdir_r(dirp, entry, result); + syscall_no_intercept_flag = false; + return res; + } + + *result = reinterpret_cast(capio_internal_readdir(dirp, pid)); + + LOG("CAPIO returned a directory entry: %s", entry->d_name); + return 0; +} + #endif // POSIX_READDIR_HPP