Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 177 additions & 69 deletions src/posix/handlers/posix_readdir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned long int>(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<unsigned long int>(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);
Expand Down Expand Up @@ -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<unsigned long int>(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<unsigned long int>(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);
Expand Down Expand Up @@ -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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(dirp)).second);
return opened_directory->at(reinterpret_cast<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<unsigned long int>(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<dirent *>(capio_internal_readdir(dirp, pid));

LOG("CAPIO returned a directory entry: %s", entry->d_name);
return 0;
}

#endif // POSIX_READDIR_HPP
Loading