Unverified Commit 47388a1d authored by Tommaso Tocci's avatar Tommaso Tocci
Browse files

intercept getdents

parent 303c6619
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -65,7 +65,9 @@ ssize_t adafs_read(int fd, void* buf, size_t count);

int adafs_opendir(const std::string& path);

struct dirent * adafs_readdir(int fd);
int getdents(unsigned int fd,
             struct linux_dirent *dirp,
             unsigned int count);

int adafs_rmdir(const std::string& path);

+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ int hook_lseek(unsigned int fd, off_t offset, unsigned int whence);
int hook_dup(unsigned int fd);
int hook_dup2(unsigned int oldfd, unsigned int newfd);
int hook_dup3(unsigned int oldfd, unsigned int newfd, int flags);
int hook_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count);


#endif
+11 −14
Original line number Diff line number Diff line
@@ -23,28 +23,25 @@
#include <client/open_file_map.hpp>


class OpenDir: public OpenFile {
    private:

class DirEntry {
    private:
        std::string name_;
        FileType type_;
    public:
                std::string name;
                FileType type;

        DirEntry(const std::string& name, const FileType type);
        const std::string& name();
        FileType type();
};

class OpenDir: public OpenFile {
    private:
        std::vector<DirEntry> entries;
        struct dirent dirent_;
        bool is_dirent_valid;

        void update_dirent(unsigned int pos);


    public:
        OpenDir(const std::string& path);
        void add(const std::string& name, const FileType& type);
        struct dirent * readdir();
        const DirEntry& getdent(unsigned int pos);
        size_t size();
};

+61 −8
Original line number Diff line number Diff line
@@ -23,6 +23,20 @@
#include <client/rpc/ld_rpc_data_ws.hpp>
#include <client/open_dir.hpp>

#include <dirent.h>


#define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))
#define __ALIGN_KERNEL(x, a)		    __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
#define ALIGN(x, a)                     __ALIGN_KERNEL((x), (a))

struct linux_dirent {
    unsigned long	d_ino;
    unsigned long	d_off;
    unsigned short	d_reclen;
    char		d_name[1];
};

using namespace std;

int adafs_open(const std::string& path, mode_t mode, int flags) {
@@ -506,17 +520,56 @@ int adafs_rmdir(const std::string& path) {
    return rpc_send::rm_node(path, true);
}

struct dirent * adafs_readdir(int fd){
    CTX->log()->trace("{}() called on fd: {}", __func__, fd);
    auto open_file = CTX->file_map()->get(fd);
    assert(open_file != nullptr);
    auto open_dir = static_pointer_cast<OpenDir>(open_file);
    if(!open_dir){

int getdents(unsigned int fd,
             struct linux_dirent *dirp,
             unsigned int count) {
    CTX->log()->trace("{}() called on fd: {}, count {}", __func__, fd, count);
    auto open_dir = CTX->file_map()->get_dir(fd);
    if(open_dir == nullptr){
        //Cast did not succeeded: open_file is a regular file
        errno = EBADF;
        return nullptr;
        return -1;
    }

    auto pos = open_dir->pos();
    if (pos >= open_dir->size()) {
        return 0;
    }
    return open_dir->readdir();

    unsigned int written = 0;
    struct linux_dirent * current_dirp = nullptr;
    while(pos < open_dir->size()) {
        DirEntry de = open_dir->getdent(pos);
        auto total_size = ALIGN(offsetof(struct linux_dirent, d_name) +
                de.name().size() + 3, sizeof(long));
        if (total_size > (count - written)) {
            //no enough space left on user buffer to insert next dirent
            break;
        }
        current_dirp = reinterpret_cast<struct linux_dirent *>(
                        reinterpret_cast<char*>(dirp) + written);
        current_dirp->d_ino = std::hash<std::string>()(
                open_dir->path() + "/" + de.name());

        current_dirp->d_reclen = total_size;

        *(reinterpret_cast<char*>(current_dirp) + total_size - 1) =
            ((de.type() == FileType::regular)? DT_REG : DT_DIR);

        CTX->log()->trace("{}() name {}: {}", __func__, pos, de.name());
        std::strcpy(&(current_dirp->d_name[0]), de.name().c_str());
        ++pos;
        current_dirp->d_off = pos;
        written += total_size;
    }

    if (written == 0) {
        errno = EINVAL;
        return -1;
    }
    open_dir->pos(pos);
    return written;
}

#ifdef HAS_SYMLINKS
+8 −0
Original line number Diff line number Diff line
@@ -181,3 +181,11 @@ int hook_dup3(unsigned int oldfd, unsigned int newfd, int flags) {
    }
    return syscall_no_intercept(SYS_dup3, oldfd, newfd, flags);
}

int hook_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count) {
    CTX->log()->trace("{}() called with fd {}, count {}", __func__, fd, count);
    if (CTX->file_map()->exist(fd)) {
        return with_errno(getdents(fd, dirp, count));
    }
    return syscall_no_intercept(SYS_getdents, fd, dirp, count);
}
Loading