LCOV - code coverage report
Current view: top level - src/client - hooks.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 339 453 74.8 %
Date: 2024-04-23 00:09:24 Functions: 38 41 92.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain
       3             :   Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany
       4             : 
       5             :   This software was partially supported by the
       6             :   EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
       7             : 
       8             :   This software was partially supported by the
       9             :   ADA-FS project under the SPPEXA project funded by the DFG.
      10             : 
      11             :   This file is part of GekkoFS' POSIX interface.
      12             : 
      13             :   GekkoFS' POSIX interface is free software: you can redistribute it and/or
      14             :   modify it under the terms of the GNU Lesser General Public License as
      15             :   published by the Free Software Foundation, either version 3 of the License,
      16             :   or (at your option) any later version.
      17             : 
      18             :   GekkoFS' POSIX interface is distributed in the hope that it will be useful,
      19             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      20             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21             :   GNU Lesser General Public License for more details.
      22             : 
      23             :   You should have received a copy of the GNU Lesser General Public License
      24             :   along with GekkoFS' POSIX interface.  If not, see
      25             :   <https://www.gnu.org/licenses/>.
      26             : 
      27             :   SPDX-License-Identifier: LGPL-3.0-or-later
      28             : */
      29             : 
      30             : #include <client/hooks.hpp>
      31             : #include <client/preload.hpp>
      32             : #include <client/preload_util.hpp>
      33             : #include <client/logging.hpp>
      34             : #include <client/gkfs_functions.hpp>
      35             : #include <client/path.hpp>
      36             : #include <client/open_dir.hpp>
      37             : 
      38             : #include <common/path_util.hpp>
      39             : 
      40             : #include <memory>
      41             : 
      42             : extern "C" {
      43             : #include <fcntl.h>
      44             : #include <sys/stat.h>
      45             : #include <sys/statfs.h>
      46             : }
      47             : 
      48             : namespace {
      49             : 
      50             : // TODO replace all internal gkfs errno variable usage with LEAF
      51             : inline int
      52        1401 : with_errno(int ret) {
      53          31 :     return (ret < 0) ? -errno : ret;
      54             : }
      55             : 
      56             : } // namespace
      57             : 
      58             : namespace gkfs::hook {
      59             : 
      60             : int
      61        9768 : hook_openat(int dirfd, const char* cpath, int flags, mode_t mode) {
      62             : 
      63        9768 :     LOG(DEBUG, "{}() called with fd: {}, path: \"{}\", flags: {}, mode: {}",
      64        9768 :         __func__, dirfd, cpath, flags, mode);
      65             : 
      66       19536 :     std::string resolved;
      67        9768 :     auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved);
      68        9768 :     switch(rstatus) {
      69           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
      70           0 :             return syscall_no_intercept_wrapper(SYS_openat, dirfd, cpath, flags,
      71           0 :                                                 mode);
      72             : 
      73        8602 :         case gkfs::preload::RelativizeStatus::external:
      74        8602 :             return syscall_no_intercept_wrapper(SYS_openat, dirfd,
      75        8602 :                                                 resolved.c_str(), flags, mode);
      76             : 
      77             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
      78             :             return -ENOTDIR;
      79             : 
      80        1166 :         case gkfs::preload::RelativizeStatus::internal:
      81        9774 :             return with_errno(gkfs::syscall::gkfs_open(resolved, mode, flags));
      82             : 
      83           0 :         default:
      84           0 :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
      85             :             return -EINVAL;
      86             :     }
      87             : }
      88             : 
      89             : int
      90       12724 : hook_close(int fd) {
      91             : 
      92       12724 :     LOG(DEBUG, "{}() called with fd: {}", __func__, fd);
      93             : 
      94       12724 :     auto ret = gkfs::syscall::gkfs_close(fd);
      95             : 
      96       12724 :     if(ret == 0)
      97             :         return 0;
      98             : 
      99        8600 :     return syscall_no_intercept_wrapper(SYS_close, fd);
     100             : }
     101             : #ifdef SYS_stat
     102             : int
     103          46 : hook_stat(const char* path, struct stat* buf) {
     104             : 
     105          46 :     LOG(DEBUG, "{}() called with path: \"{}\", buf: {}", __func__, path,
     106          46 :         fmt::ptr(buf));
     107             : 
     108          92 :     std::string rel_path;
     109          46 :     if(CTX->relativize_path(path, rel_path, false)) {
     110          61 :         return with_errno(gkfs::syscall::gkfs_stat(rel_path, buf));
     111             :     }
     112             : 
     113           1 :     return syscall_no_intercept_wrapper(SYS_stat, rel_path.c_str(), buf);
     114             : }
     115             : #endif
     116             : 
     117             : #ifdef STATX_TYPE
     118             : 
     119             : int
     120           4 : hook_statx(int dirfd, const char* path, int flags, unsigned int mask,
     121             :            struct ::statx* buf) {
     122             : 
     123           4 :     LOG(DEBUG,
     124             :         "{}() called with dirfd: '{}', path: \"{}\", flags: '{}', mask: '{}', buf: '{}'",
     125           4 :         __func__, dirfd, path, flags, mask, fmt::ptr(buf));
     126             : 
     127           8 :     std::string resolved;
     128           4 :     auto rstatus = CTX->relativize_fd_path(dirfd, path, resolved);
     129           4 :     switch(rstatus) {
     130           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     131           0 :             return syscall_no_intercept_wrapper(SYS_statx, dirfd, path, flags,
     132           0 :                                                 mask, buf);
     133             : 
     134           0 :         case gkfs::preload::RelativizeStatus::external:
     135           0 :             return syscall_no_intercept_wrapper(
     136           0 :                     SYS_statx, dirfd, resolved.c_str(), flags, mask, buf);
     137             : 
     138             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     139             :             return -ENOTDIR;
     140             : 
     141           4 :         case gkfs::preload::RelativizeStatus::internal:
     142           5 :             return with_errno(gkfs::syscall::gkfs_statx(dirfd, resolved.c_str(),
     143           8 :                                                         flags, mask, buf));
     144             : 
     145           0 :         default:
     146           0 :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
     147             :             return -EINVAL;
     148             :     }
     149             : 
     150             :     return syscall_no_intercept(SYS_statx, dirfd, path, flags, mask, buf);
     151             : }
     152             : 
     153             : #endif
     154             : 
     155             : #ifdef SYS_lstat
     156             : int
     157           2 : hook_lstat(const char* path, struct stat* buf) {
     158             : 
     159           2 :     LOG(DEBUG, "{}() called with path: \"{}\", buf: {}", __func__, path,
     160           2 :         fmt::ptr(buf));
     161             : 
     162           4 :     std::string rel_path;
     163           2 :     if(CTX->relativize_path(path, rel_path)) {
     164           2 :         return with_errno(gkfs::syscall::gkfs_stat(rel_path, buf));
     165             :     }
     166           1 :     return syscall_no_intercept_wrapper(SYS_lstat, rel_path.c_str(), buf);
     167             : }
     168             : #endif
     169             : 
     170             : int
     171         291 : hook_fstat(unsigned int fd, struct stat* buf) {
     172             : 
     173         291 :     LOG(DEBUG, "{}() called with fd: {}, buf: {}", __func__, fd, fmt::ptr(buf));
     174             : 
     175         291 :     if(CTX->file_map()->exist(fd)) {
     176          44 :         auto path = CTX->file_map()->get(fd)->path();
     177             : #ifdef HAS_RENAME
     178             :         // Special case for fstat and rename, fd points to new file...
     179             :         // We can change file_map and recall
     180          44 :         auto md = gkfs::utils::get_metadata(path, false);
     181          22 :         if(md.has_value() && md.value().blocks() == -1) {
     182           0 :             path = md.value().rename_path();
     183             :         }
     184             : #endif
     185          22 :         return with_errno(gkfs::syscall::gkfs_stat(path, buf));
     186             :     }
     187         269 :     return syscall_no_intercept_wrapper(SYS_fstat, fd, buf);
     188             : }
     189             : 
     190             : int
     191           0 : hook_fstatat(int dirfd, const char* cpath, struct stat* buf, int flags) {
     192             : 
     193           0 :     LOG(DEBUG, "{}() called with path: \"{}\", fd: {}, buf: {}, flags: {}",
     194           0 :         __func__, cpath, dirfd, fmt::ptr(buf), flags);
     195             : 
     196           0 :     std::string resolved;
     197           0 :     auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved, flags);
     198           0 :     switch(rstatus) {
     199           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     200           0 :             return syscall_no_intercept_wrapper(SYS_newfstatat, dirfd, cpath,
     201           0 :                                                 buf, flags);
     202             : 
     203           0 :         case gkfs::preload::RelativizeStatus::external:
     204           0 :             return syscall_no_intercept_wrapper(SYS_newfstatat, dirfd,
     205           0 :                                                 resolved.c_str(), buf, flags);
     206             : 
     207             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     208             :             return -ENOTDIR;
     209             : 
     210           0 :         case gkfs::preload::RelativizeStatus::internal:
     211           0 :             return with_errno(gkfs::syscall::gkfs_stat(resolved, buf));
     212             : 
     213           0 :         default:
     214           0 :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
     215             :             return -EINVAL;
     216             :     }
     217             : }
     218             : 
     219             : int
     220      182329 : hook_read(unsigned int fd, void* buf, size_t count) {
     221             : 
     222      182329 :     LOG(DEBUG, "{}() called with fd: {}, buf: {} count: {}", __func__, fd,
     223      182329 :         fmt::ptr(buf), count);
     224             : 
     225      182329 :     if(CTX->file_map()->exist(fd)) {
     226          28 :         return with_errno(gkfs::syscall::gkfs_read(fd, buf, count));
     227             :     }
     228      182301 :     return syscall_no_intercept_wrapper(SYS_read, fd, buf, count);
     229             : }
     230             : 
     231             : int
     232           2 : hook_pread(unsigned int fd, char* buf, size_t count, loff_t pos) {
     233             : 
     234           2 :     LOG(DEBUG, "{}() called with fd: {}, buf: {}, count: {}, pos: {}", __func__,
     235           2 :         fd, fmt::ptr(buf), count, pos);
     236             : 
     237           2 :     if(CTX->file_map()->exist(fd)) {
     238           1 :         return with_errno(gkfs::syscall::gkfs_pread_ws(fd, buf, count, pos));
     239             :     }
     240             :     /* Since kernel 2.6: pread() became pread64(), and pwrite() became
     241             :      * pwrite64(). */
     242           1 :     return syscall_no_intercept_wrapper(SYS_pread64, fd, buf, count, pos);
     243             : }
     244             : 
     245             : int
     246           1 : hook_readv(unsigned long fd, const struct iovec* iov, unsigned long iovcnt) {
     247             : 
     248           1 :     LOG(DEBUG, "{}() called with fd: {}, iov: {}, iovcnt: {}", __func__, fd,
     249           1 :         fmt::ptr(iov), iovcnt);
     250             : 
     251           1 :     if(CTX->file_map()->exist(fd)) {
     252           1 :         return with_errno(gkfs::syscall::gkfs_readv(fd, iov, iovcnt));
     253             :     }
     254           0 :     return syscall_no_intercept_wrapper(SYS_readv, fd, iov, iovcnt);
     255             : }
     256             : 
     257             : int
     258           1 : hook_preadv(unsigned long fd, const struct iovec* iov, unsigned long iovcnt,
     259             :             unsigned long pos_l, unsigned long pos_h) {
     260             : 
     261           1 :     LOG(DEBUG,
     262             :         "{}() called with fd: {}, iov: {}, iovcnt: {}, "
     263             :         "pos_l: {},"
     264             :         "pos_h: {}",
     265           1 :         __func__, fd, fmt::ptr(iov), iovcnt, pos_l, pos_h);
     266             : 
     267           1 :     if(CTX->file_map()->exist(fd)) {
     268           1 :         return with_errno(gkfs::syscall::gkfs_preadv(fd, iov, iovcnt, pos_l));
     269             :     }
     270           0 :     return syscall_no_intercept_wrapper(SYS_preadv, fd, iov, iovcnt, pos_l);
     271             : }
     272             : 
     273             : int
     274      180426 : hook_write(unsigned int fd, const char* buf, size_t count) {
     275             : 
     276      180426 :     LOG(DEBUG, "{}() called with fd: {}, buf: {}, count {}", __func__, fd,
     277      180426 :         fmt::ptr(buf), count);
     278             : 
     279      180426 :     if(CTX->file_map()->exist(fd)) {
     280          36 :         return with_errno(gkfs::syscall::gkfs_write(fd, buf, count));
     281             :     }
     282      180390 :     return syscall_no_intercept_wrapper(SYS_write, fd, buf, count);
     283             : }
     284             : 
     285             : int
     286           3 : hook_pwrite(unsigned int fd, const char* buf, size_t count, loff_t pos) {
     287             : 
     288           3 :     LOG(DEBUG, "{}() called with fd: {}, buf: {}, count: {}, pos: {}", __func__,
     289           3 :         fd, fmt::ptr(buf), count, pos);
     290             : 
     291           3 :     if(CTX->file_map()->exist(fd)) {
     292           2 :         return with_errno(gkfs::syscall::gkfs_pwrite_ws(fd, buf, count, pos));
     293             :     }
     294             :     /* Since kernel 2.6: pread() became pread64(), and pwrite() became
     295             :      * pwrite64(). */
     296           1 :     return syscall_no_intercept_wrapper(SYS_pwrite64, fd, buf, count, pos);
     297             : }
     298             : 
     299             : int
     300           2 : hook_writev(unsigned long fd, const struct iovec* iov, unsigned long iovcnt) {
     301             : 
     302           2 :     LOG(DEBUG, "{}() called with fd: {}, iov: {}, iovcnt: {}", __func__, fd,
     303           2 :         fmt::ptr(iov), iovcnt);
     304             : 
     305           2 :     if(CTX->file_map()->exist(fd)) {
     306           2 :         return with_errno(gkfs::syscall::gkfs_writev(fd, iov, iovcnt));
     307             :     }
     308           0 :     return syscall_no_intercept_wrapper(SYS_writev, fd, iov, iovcnt);
     309             : }
     310             : 
     311             : int
     312           2 : hook_pwritev(unsigned long fd, const struct iovec* iov, unsigned long iovcnt,
     313             :              unsigned long pos_l, unsigned long pos_h) {
     314             : 
     315           2 :     LOG(DEBUG,
     316             :         "{}() called with fd: {}, iov: {}, iovcnt: {}, "
     317             :         "pos_l: {},"
     318             :         "pos_h: {}",
     319           2 :         __func__, fd, fmt::ptr(iov), iovcnt, pos_l, pos_h);
     320             : 
     321           2 :     if(CTX->file_map()->exist(fd)) {
     322           2 :         return with_errno(gkfs::syscall::gkfs_pwritev(fd, iov, iovcnt, pos_l));
     323             :     }
     324           0 :     return syscall_no_intercept_wrapper(SYS_pwritev, fd, iov, iovcnt, pos_l);
     325             : }
     326             : 
     327             : int
     328          15 : hook_unlinkat(int dirfd, const char* cpath, int flags) {
     329             : 
     330          15 :     LOG(DEBUG, "{}() called with dirfd: {}, path: \"{}\", flags: {}", __func__,
     331          15 :         dirfd, cpath, flags);
     332             : 
     333          15 :     if((flags & ~AT_REMOVEDIR) != 0) {
     334           0 :         LOG(ERROR, "{}() Flags unknown: {}", __func__, flags);
     335           0 :         return -EINVAL;
     336             :     }
     337             : 
     338          30 :     std::string resolved;
     339          15 :     auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved, false);
     340          15 :     switch(rstatus) {
     341           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     342           0 :             return syscall_no_intercept_wrapper(SYS_unlinkat, dirfd, cpath,
     343           0 :                                                 flags);
     344             : 
     345           4 :         case gkfs::preload::RelativizeStatus::external:
     346           4 :             return syscall_no_intercept_wrapper(SYS_unlinkat, dirfd,
     347           4 :                                                 resolved.c_str(), flags);
     348             : 
     349             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     350             :             return -ENOTDIR;
     351             : 
     352          11 :         case gkfs::preload::RelativizeStatus::internal:
     353          11 :             if(flags & AT_REMOVEDIR) {
     354           4 :                 return with_errno(gkfs::syscall::gkfs_rmdir(resolved));
     355             :             } else {
     356          18 :                 return with_errno(gkfs::syscall::gkfs_remove(resolved));
     357             :             }
     358             : 
     359           0 :         default:
     360           0 :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
     361             :             return -EINVAL;
     362             :     }
     363             : }
     364             : 
     365             : int
     366           1 : hook_symlinkat(const char* oldname, int newdfd, const char* newname) {
     367             : 
     368           1 :     LOG(DEBUG, "{}() called with oldname: \"{}\", newfd: {}, newname: \"{}\"",
     369           1 :         __func__, oldname, newdfd, newname);
     370             : 
     371           2 :     std::string oldname_resolved;
     372           1 :     if(CTX->relativize_path(oldname, oldname_resolved)) {
     373           0 :         LOG(WARNING, "{}() operation not supported", __func__);
     374           0 :         return -ENOTSUP;
     375             :     }
     376             : 
     377           2 :     std::string newname_resolved;
     378           1 :     auto rstatus =
     379           1 :             CTX->relativize_fd_path(newdfd, newname, newname_resolved, false);
     380           1 :     switch(rstatus) {
     381           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     382           0 :             return syscall_no_intercept_wrapper(SYS_symlinkat, oldname, newdfd,
     383           0 :                                                 newname);
     384             : 
     385           1 :         case gkfs::preload::RelativizeStatus::external:
     386           1 :             return syscall_no_intercept_wrapper(SYS_symlinkat, oldname, newdfd,
     387           1 :                                                 newname_resolved.c_str());
     388             : 
     389             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     390             :             return -ENOTDIR;
     391             : 
     392           0 :         case gkfs::preload::RelativizeStatus::internal:
     393           0 :             LOG(WARNING, "{}() operation not supported", __func__);
     394             :             return -ENOTSUP;
     395             : 
     396           0 :         default:
     397           0 :             LOG(ERROR, "{}() relativize status unknown", __func__);
     398             :             return -EINVAL;
     399             :     }
     400             : }
     401             : 
     402             : int
     403           0 : hook_flock(unsigned long fd, int flags) {
     404           0 :     LOG(ERROR, "{}() called flock (Not Supported) with fd '{}' flags '{}'",
     405           0 :         __func__, fd, flags);
     406             : 
     407           0 :     if(CTX->file_map()->exist(fd)) {
     408             :         return 0;
     409             :     } else
     410           0 :         return -EBADF;
     411             : }
     412             : 
     413             : #ifdef SYS_access
     414             : int
     415           5 : hook_access(const char* path, int mask) {
     416             : 
     417           5 :     LOG(DEBUG, "{}() called path: \"{}\", mask: {}", __func__, path, mask);
     418             : 
     419          10 :     std::string rel_path;
     420           5 :     if(CTX->relativize_path(path, rel_path)) {
     421           5 :         auto ret = gkfs::syscall::gkfs_access(rel_path, mask);
     422           5 :         if(ret < 0) {
     423           2 :             return -errno;
     424             :         }
     425             :         return ret;
     426             :     }
     427           0 :     return syscall_no_intercept_wrapper(SYS_access, rel_path.c_str(), mask);
     428             : }
     429             : #endif
     430             : 
     431             : int
     432           4 : hook_faccessat(int dirfd, const char* cpath, int mode) {
     433             : 
     434           4 :     LOG(DEBUG, "{}() called with dirfd: {}, path: \"{}\", mode: {}", __func__,
     435           4 :         dirfd, cpath, mode);
     436             : 
     437           8 :     std::string resolved;
     438           4 :     auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved);
     439           4 :     switch(rstatus) {
     440           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     441           0 :             return syscall_no_intercept_wrapper(SYS_faccessat, dirfd, cpath,
     442           0 :                                                 mode);
     443             : 
     444           2 :         case gkfs::preload::RelativizeStatus::external:
     445           2 :             return syscall_no_intercept_wrapper(SYS_faccessat, dirfd,
     446           2 :                                                 resolved.c_str(), mode);
     447             : 
     448             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     449             :             return -ENOTDIR;
     450             : 
     451           2 :         case gkfs::preload::RelativizeStatus::internal:
     452           4 :             return with_errno(gkfs::syscall::gkfs_access(resolved, mode));
     453             : 
     454           0 :         default:
     455           0 :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
     456             :             return -EINVAL;
     457             :     }
     458             : }
     459             : 
     460             : #ifdef SYS_faccessat2
     461             : int
     462             : hook_faccessat2(int dirfd, const char* cpath, int mode, int flags) {
     463             : 
     464             :     LOG(DEBUG,
     465             :         "{}() called with dirfd: '{}', path: '{}', mode: '{}', flags: '{}'",
     466             :         __func__, dirfd, cpath, mode, flags);
     467             : 
     468             :     std::string resolved;
     469             :     auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved);
     470             :     switch(rstatus) {
     471             :         case gkfs::preload::RelativizeStatus::fd_unknown:
     472             :             return syscall_no_intercept_wrapper(SYS_faccessat2, dirfd, cpath,
     473             :                                                 mode, flags);
     474             : 
     475             :         case gkfs::preload::RelativizeStatus::external:
     476             :             return syscall_no_intercept_wrapper(SYS_faccessat2, dirfd,
     477             :                                                 resolved.c_str(), mode, flags);
     478             : 
     479             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     480             :             return -ENOTDIR;
     481             : 
     482             :         case gkfs::preload::RelativizeStatus::internal:
     483             :             // we do not use permissions and therefore do not handle `flags` for
     484             :             // now
     485             :             return with_errno(gkfs::syscall::gkfs_access(resolved, mode));
     486             : 
     487             :         default:
     488             :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
     489             :             return -EINVAL;
     490             :     }
     491             : }
     492             : #endif
     493             : 
     494             : off_t
     495        8589 : hook_lseek(unsigned int fd, off_t offset, unsigned int whence) {
     496             : 
     497        8589 :     LOG(DEBUG, "{}() called with fd: {}, offset: {}, whence: {}", __func__, fd,
     498        8589 :         offset, whence);
     499             : 
     500        8589 :     if(CTX->file_map()->exist(fd)) {
     501          11 :         auto off_ret = gkfs::syscall::gkfs_lseek(
     502          11 :                 fd, static_cast<off64_t>(offset), whence);
     503          11 :         if(off_ret > std::numeric_limits<off_t>::max()) {
     504             :             return -EOVERFLOW;
     505          11 :         } else if(off_ret < 0) {
     506           5 :             return -errno;
     507             :         }
     508           6 :         LOG(DEBUG, "{}() returning {}", __func__, off_ret);
     509           6 :         return off_ret;
     510             :     }
     511        8578 :     return syscall_no_intercept_wrapper(SYS_lseek, fd, offset, whence);
     512             : }
     513             : 
     514             : int
     515           7 : hook_truncate(const char* path, long length) {
     516             : 
     517           7 :     LOG(DEBUG, "{}() called with path: {}, offset: {}", __func__, path, length);
     518             : 
     519          14 :     std::string rel_path;
     520           7 :     if(CTX->relativize_path(path, rel_path)) {
     521           8 :         return with_errno(gkfs::syscall::gkfs_truncate(rel_path, length));
     522             :     }
     523           1 :     return syscall_no_intercept_wrapper(SYS_truncate, rel_path.c_str(), length);
     524             : }
     525             : 
     526             : int
     527           2 : hook_ftruncate(unsigned int fd, unsigned long length) {
     528             : 
     529           2 :     LOG(DEBUG, "{}() called with fd: {}, offset: {}", __func__, fd, length);
     530             : 
     531           2 :     if(CTX->file_map()->exist(fd)) {
     532           2 :         auto path = CTX->file_map()->get(fd)->path();
     533           1 :         return with_errno(gkfs::syscall::gkfs_truncate(path, length));
     534             :     }
     535           1 :     return syscall_no_intercept_wrapper(SYS_ftruncate, fd, length);
     536             : }
     537             : 
     538             : int
     539           2 : hook_dup(unsigned int fd) {
     540             : 
     541           2 :     LOG(DEBUG, "{}() called with oldfd: {}", __func__, fd);
     542             : 
     543           2 :     if(CTX->file_map()->exist(fd)) {
     544           1 :         return with_errno(gkfs::syscall::gkfs_dup(fd));
     545             :     }
     546           1 :     return syscall_no_intercept_wrapper(SYS_dup, fd);
     547             : }
     548             : #ifdef SYS_dup2
     549             : int
     550           2 : hook_dup2(unsigned int oldfd, unsigned int newfd) {
     551             : 
     552           2 :     LOG(DEBUG, "{}() called with oldfd: {}, newfd: {}", __func__, oldfd, newfd);
     553             : 
     554           2 :     if(CTX->file_map()->exist(oldfd)) {
     555           1 :         return with_errno(gkfs::syscall::gkfs_dup2(oldfd, newfd));
     556             :     }
     557           1 :     return syscall_no_intercept_wrapper(SYS_dup2, oldfd, newfd);
     558             : }
     559             : #endif
     560             : int
     561           2 : hook_dup3(unsigned int oldfd, unsigned int newfd, int flags) {
     562             : 
     563           2 :     LOG(DEBUG, "{}() called with oldfd: {}, newfd: {}, flags: {}", __func__,
     564           2 :         oldfd, newfd, flags);
     565             : 
     566           2 :     if(CTX->file_map()->exist(oldfd)) {
     567             :         // TODO implement O_CLOEXEC flag first which is used with fcntl(2)
     568             :         // It is in glibc since kernel 2.9. So maybe not that important :)
     569           1 :         LOG(WARNING, "{}() Not supported", __func__);
     570           1 :         return -ENOTSUP;
     571             :     }
     572           1 :     return syscall_no_intercept_wrapper(SYS_dup3, oldfd, newfd, flags);
     573             : }
     574             : #ifdef SYS_getdents
     575             : int
     576           0 : hook_getdents(unsigned int fd, struct linux_dirent* dirp, unsigned int count) {
     577             : 
     578           0 :     LOG(DEBUG, "{}() called with fd: {}, dirp: {}, count: {}", __func__, fd,
     579           0 :         fmt::ptr(dirp), count);
     580             : 
     581           0 :     if(CTX->file_map()->exist(fd)) {
     582           0 :         return with_errno(gkfs::syscall::gkfs_getdents(fd, dirp, count));
     583             :     }
     584           0 :     return syscall_no_intercept_wrapper(SYS_getdents, fd, dirp, count);
     585             : }
     586             : #endif
     587             : 
     588             : int
     589          36 : hook_getdents64(unsigned int fd, struct linux_dirent64* dirp,
     590             :                 unsigned int count) {
     591             : 
     592          36 :     LOG(DEBUG, "{}() called with fd: {}, dirp: {}, count: {}", __func__, fd,
     593          36 :         fmt::ptr(dirp), count);
     594             : 
     595          36 :     if(CTX->file_map()->exist(fd)) {
     596          36 :         return with_errno(gkfs::syscall::gkfs_getdents64(fd, dirp, count));
     597             :     }
     598           0 :     return syscall_no_intercept_wrapper(SYS_getdents64, fd, dirp, count);
     599             : }
     600             : 
     601             : 
     602             : int
     603          19 : hook_mkdirat(int dirfd, const char* cpath, mode_t mode) {
     604             : 
     605          19 :     LOG(DEBUG, "{}() called with dirfd: {}, path: \"{}\", mode: {}", __func__,
     606          19 :         dirfd, cpath, mode);
     607             : 
     608          38 :     std::string resolved;
     609          19 :     auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved);
     610          19 :     switch(rstatus) {
     611           2 :         case gkfs::preload::RelativizeStatus::external:
     612           2 :             return syscall_no_intercept_wrapper(SYS_mkdirat, dirfd,
     613           2 :                                                 resolved.c_str(), mode);
     614             : 
     615           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     616           0 :             return syscall_no_intercept_wrapper(SYS_mkdirat, dirfd, cpath,
     617           0 :                                                 mode);
     618             : 
     619             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     620             :             return -ENOTDIR;
     621             : 
     622          17 :         case gkfs::preload::RelativizeStatus::internal:
     623          19 :             return with_errno(
     624             :                     gkfs::syscall::gkfs_create(resolved, mode | S_IFDIR));
     625             : 
     626           0 :         default:
     627           0 :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
     628             :             return -EINVAL;
     629             :     }
     630             : }
     631             : 
     632             : int
     633           3 : hook_fchmodat(int dirfd, const char* cpath, mode_t mode) {
     634             : 
     635           3 :     LOG(DEBUG, "{}() called dirfd: {}, path: \"{}\", mode: {}", __func__, dirfd,
     636           3 :         cpath, mode);
     637             : 
     638           6 :     std::string resolved;
     639           3 :     auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved);
     640           3 :     switch(rstatus) {
     641           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     642           0 :             return syscall_no_intercept_wrapper(SYS_fchmodat, dirfd, cpath,
     643           0 :                                                 mode);
     644             : 
     645           1 :         case gkfs::preload::RelativizeStatus::external:
     646           1 :             return syscall_no_intercept_wrapper(SYS_fchmodat, dirfd,
     647           1 :                                                 resolved.c_str(), mode);
     648             : 
     649             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     650             :             return -ENOTDIR;
     651             : 
     652           2 :         case gkfs::preload::RelativizeStatus::internal:
     653           2 :             LOG(WARNING, "{}() operation not supported", __func__);
     654             :             return -ENOTSUP;
     655             : 
     656           0 :         default:
     657           0 :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
     658             :             return -EINVAL;
     659             :     }
     660             : }
     661             : 
     662             : int
     663           2 : hook_fchmod(unsigned int fd, mode_t mode) {
     664             : 
     665           2 :     LOG(DEBUG, "{}() called with fd: {}, mode: {}", __func__, fd, mode);
     666             : 
     667           2 :     if(CTX->file_map()->exist(fd)) {
     668           1 :         LOG(WARNING, "{}() operation not supported", __func__);
     669           1 :         return -ENOTSUP;
     670             :     }
     671           1 :     return syscall_no_intercept_wrapper(SYS_fchmod, fd, mode);
     672             : }
     673             : 
     674             : int
     675           9 : hook_chdir(const char* path) {
     676             : 
     677           9 :     LOG(DEBUG, "{}() called with path: \"{}\"", __func__, path);
     678             : 
     679          18 :     std::string rel_path;
     680           9 :     bool internal = CTX->relativize_path(path, rel_path);
     681           9 :     if(internal) {
     682             :         // path falls in our namespace
     683           8 :         auto md = gkfs::utils::get_metadata(rel_path);
     684           5 :         if(!md) {
     685           1 :             LOG(ERROR, "{}() path {} errno {}", __func__, path, errno);
     686           3 :             return -errno;
     687             :         }
     688             : 
     689           4 :         if(!S_ISDIR(md->mode())) {
     690           1 :             LOG(ERROR, "{}() path is not a directory", __func__);
     691           1 :             return -ENOTDIR;
     692             :         }
     693             :         // TODO get complete path from relativize_path instead of
     694             :         // removing mountdir and then adding again here
     695           3 :         rel_path.insert(0, CTX->mountdir());
     696           3 :         if(gkfs::path::has_trailing_slash(rel_path)) {
     697             :             // open_dir is '/'
     698           0 :             rel_path.pop_back();
     699             :         }
     700             :     }
     701           7 :     try {
     702           7 :         gkfs::path::set_cwd(rel_path, internal);
     703           1 :     } catch(const std::system_error& se) {
     704           1 :         return -(se.code().value());
     705             :     }
     706             :     return 0;
     707             : }
     708             : 
     709             : int
     710           3 : hook_fchdir(unsigned int fd) {
     711             : 
     712           3 :     LOG(DEBUG, "{}() called with fd: {}", __func__, fd);
     713             : 
     714           3 :     if(CTX->file_map()->exist(fd)) {
     715           3 :         auto open_dir = CTX->file_map()->get_dir(fd);
     716           2 :         if(open_dir == nullptr) {
     717             :             // Cast did not succeeded: open_file is a regular file
     718           1 :             LOG(ERROR, "{}() file descriptor refers to a normal file",
     719           1 :                 __func__);
     720           2 :             return -EBADF;
     721             :         }
     722             : 
     723           2 :         std::string new_path = CTX->mountdir() + open_dir->path();
     724           1 :         if(gkfs::path::has_trailing_slash(new_path)) {
     725             :             // open_dir is '/'
     726           1 :             new_path.pop_back();
     727             :         }
     728           1 :         try {
     729           1 :             gkfs::path::set_cwd(new_path, true);
     730           0 :         } catch(const std::system_error& se) {
     731           0 :             return -(se.code().value());
     732             :         }
     733             :     } else {
     734           1 :         long ret = syscall_no_intercept_wrapper(SYS_fchdir, fd);
     735           1 :         if(ret < 0) {
     736           0 :             throw std::system_error(
     737             :                     syscall_error_code(ret), std::system_category(),
     738           0 :                     "Failed to change directory (fchdir syscall)");
     739             :         }
     740           1 :         gkfs::path::unset_env_cwd();
     741           2 :         CTX->cwd(gkfs::path::get_sys_cwd());
     742             :     }
     743             :     return 0;
     744             : }
     745             : 
     746             : int
     747           5 : hook_getcwd(char* buf, unsigned long size) {
     748             : 
     749           5 :     LOG(DEBUG, "{}() called with buf: {}, size: {}", __func__, fmt::ptr(buf),
     750           5 :         size);
     751             : 
     752           5 :     if(CTX->cwd().size() + 1 > size) {
     753           0 :         LOG(ERROR, "{}() buffer too small to host current working dir",
     754           0 :             __func__);
     755           0 :         return -ERANGE;
     756             :     }
     757             : 
     758           5 :     strcpy(buf, CTX->cwd().c_str());
     759           5 :     return (CTX->cwd().size() + 1);
     760             : }
     761             : 
     762             : int
     763           1 : hook_readlinkat(int dirfd, const char* cpath, char* buf, int bufsiz) {
     764             : 
     765           1 :     LOG(DEBUG, "{}() called with dirfd: {}, path \"{}\", buf: {}, bufsize: {}",
     766           1 :         __func__, dirfd, cpath, fmt::ptr(buf), bufsiz);
     767             : 
     768           2 :     std::string resolved;
     769           1 :     auto rstatus = CTX->relativize_fd_path(dirfd, cpath, resolved, false);
     770           1 :     switch(rstatus) {
     771           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     772           0 :             return syscall_no_intercept_wrapper(SYS_readlinkat, dirfd, cpath,
     773           0 :                                                 buf, bufsiz);
     774             : 
     775           0 :         case gkfs::preload::RelativizeStatus::external:
     776           0 :             return syscall_no_intercept_wrapper(SYS_readlinkat, dirfd,
     777           0 :                                                 resolved.c_str(), buf, bufsiz);
     778             : 
     779             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     780             :             return -ENOTDIR;
     781             : 
     782           1 :         case gkfs::preload::RelativizeStatus::internal:
     783           1 :             LOG(WARNING, "{}() not supported", __func__);
     784             :             return -ENOTSUP;
     785             : 
     786           0 :         default:
     787           0 :             LOG(ERROR, "{}() relativize status unknown: {}", __func__);
     788             :             return -EINVAL;
     789             :     }
     790             : }
     791             : 
     792             : int
     793       17160 : hook_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) {
     794             : 
     795       17160 :     LOG(DEBUG, "{}() called with fd: {}, cmd: {}, arg: {}", __func__, fd, cmd,
     796       17160 :         arg);
     797             : 
     798       17160 :     if(!CTX->file_map()->exist(fd)) {
     799       17154 :         return syscall_no_intercept_wrapper(SYS_fcntl, fd, cmd, arg);
     800             :     }
     801           6 :     int ret;
     802           6 :     switch(cmd) {
     803             : 
     804           1 :         case F_DUPFD:
     805           1 :             LOG(DEBUG, "{}() F_DUPFD on fd {}", __func__, fd);
     806       17160 :             return with_errno(gkfs::syscall::gkfs_dup(fd));
     807             : 
     808           1 :         case F_DUPFD_CLOEXEC:
     809           1 :             LOG(DEBUG, "{}() F_DUPFD_CLOEXEC on fd {}", __func__, fd);
     810           1 :             ret = gkfs::syscall::gkfs_dup(fd);
     811           1 :             if(ret == -1) {
     812           0 :                 return -errno;
     813             :             }
     814           1 :             CTX->file_map()->get(fd)->set_flag(
     815             :                     gkfs::filemap::OpenFile_flags::cloexec, true);
     816           1 :             return ret;
     817             : 
     818           1 :         case F_GETFD:
     819           1 :             LOG(DEBUG, "{}() F_GETFD on fd {}", __func__, fd);
     820           2 :             if(CTX->file_map()->get(fd)->get_flag(
     821             :                        gkfs::filemap::OpenFile_flags::cloexec)) {
     822           0 :                 return FD_CLOEXEC;
     823             :             }
     824             :             return 0;
     825             : 
     826           1 :         case F_GETFL:
     827           1 :             LOG(DEBUG, "{}() F_GETFL on fd {}", __func__, fd);
     828           1 :             ret = 0;
     829           1 :             if(CTX->file_map()->get(fd)->get_flag(
     830             :                        gkfs::filemap::OpenFile_flags::rdonly)) {
     831             :                 ret |= O_RDONLY;
     832             :             }
     833           2 :             if(CTX->file_map()->get(fd)->get_flag(
     834             :                        gkfs::filemap::OpenFile_flags::wronly)) {
     835           0 :                 ret |= O_WRONLY;
     836             :             }
     837           2 :             if(CTX->file_map()->get(fd)->get_flag(
     838             :                        gkfs::filemap::OpenFile_flags::rdwr)) {
     839           1 :                 ret |= O_RDWR;
     840             :             }
     841             :             return ret;
     842             : 
     843           1 :         case F_SETFD:
     844           1 :             LOG(DEBUG, "{}() [fd: {}, cmd: F_SETFD, FD_CLOEXEC: {}]", __func__,
     845           1 :                 fd, (arg & FD_CLOEXEC));
     846           1 :             CTX->file_map()->get(fd)->set_flag(
     847           1 :                     gkfs::filemap::OpenFile_flags::cloexec, (arg & FD_CLOEXEC));
     848           1 :             return 0;
     849             : 
     850           0 :         case F_GETLK:
     851           0 :             LOG(ERROR, "{}() F_GETLK on fd (Not Supported) {}", __func__, fd);
     852             :             return 0;
     853             : 
     854           0 :         case F_SETLK:
     855           0 :             LOG(ERROR, "{}() F_SETLK on fd (Not Supported) {}", __func__, fd);
     856             :             return 0;
     857             : 
     858           1 :         default:
     859           1 :             LOG(ERROR, "{}() unrecognized command {} on fd {}", __func__, cmd,
     860             :                 fd);
     861             :             return -ENOTSUP;
     862             :     }
     863             : }
     864             : 
     865             : int
     866          14 : hook_renameat(int olddfd, const char* oldname, int newdfd, const char* newname,
     867             :               unsigned int flags) {
     868             : 
     869          14 :     LOG(DEBUG,
     870             :         "{}() called with olddfd: {}, oldname: \"{}\", newfd: {}, "
     871             :         "newname \"{}\", flags {}",
     872          14 :         __func__, olddfd, oldname, newdfd, newname, flags);
     873             : 
     874          14 :     const char* oldpath_pass = oldname;
     875          28 :     std::string oldpath_resolved;
     876          14 :     auto oldpath_status =
     877          14 :             CTX->relativize_fd_path(olddfd, oldname, oldpath_resolved);
     878          14 :     switch(oldpath_status) {
     879           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     880           0 :             oldpath_pass = oldname;
     881           0 :             break;
     882             : 
     883           2 :         case gkfs::preload::RelativizeStatus::external:
     884           2 :             oldpath_pass = oldpath_resolved.c_str();
     885           2 :             break;
     886             : 
     887             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     888             :             return -ENOTDIR;
     889             : 
     890             :         case gkfs::preload::RelativizeStatus::internal:
     891             :             break;
     892             : 
     893           0 :         default:
     894           0 :             LOG(ERROR, "{}() relativize status unknown", __func__);
     895             :             return -EINVAL;
     896             :     }
     897             : 
     898          14 :     const char* newpath_pass = newname;
     899          28 :     std::string newpath_resolved;
     900          14 :     auto newpath_status =
     901          14 :             CTX->relativize_fd_path(newdfd, newname, newpath_resolved);
     902          14 :     switch(newpath_status) {
     903           0 :         case gkfs::preload::RelativizeStatus::fd_unknown:
     904           0 :             newpath_pass = newname;
     905           0 :             break;
     906             : 
     907           1 :         case gkfs::preload::RelativizeStatus::external:
     908           1 :             newpath_pass = newpath_resolved.c_str();
     909           1 :             break;
     910             : 
     911             :         case gkfs::preload::RelativizeStatus::fd_not_a_dir:
     912             :             return -ENOTDIR;
     913             : 
     914          13 :         case gkfs::preload::RelativizeStatus::internal:
     915             : #ifdef HAS_RENAME
     916          13 :             if(oldpath_status == gkfs::preload::RelativizeStatus::internal) {
     917          15 :                 return with_errno(gkfs::syscall::gkfs_rename(oldpath_resolved,
     918             :                                                              newpath_resolved));
     919             :             } else {
     920             :                 return -ENOTSUP;
     921             :             }
     922             : #else
     923             :             return -ENOTSUP;
     924             : #endif
     925           0 :         default:
     926           0 :             LOG(ERROR, "{}() relativize status unknown", __func__);
     927             :             return -EINVAL;
     928             :     }
     929             : 
     930           1 :     return syscall_no_intercept_wrapper(SYS_renameat2, olddfd, oldpath_pass,
     931           1 :                                         newdfd, newpath_pass, flags);
     932             : }
     933             : 
     934             : int
     935           1 : hook_statfs(const char* path, struct statfs* buf) {
     936             : 
     937           1 :     LOG(DEBUG, "{}() called with path: \"{}\", buf: {}", __func__, path,
     938           1 :         fmt::ptr(buf));
     939             : 
     940           2 :     std::string rel_path;
     941           1 :     if(CTX->relativize_path(path, rel_path)) {
     942           1 :         return with_errno(gkfs::syscall::gkfs_statfs(buf));
     943             :     }
     944           0 :     return syscall_no_intercept_wrapper(SYS_statfs, rel_path.c_str(), buf);
     945             : }
     946             : 
     947             : int
     948           2 : hook_fstatfs(unsigned int fd, struct statfs* buf) {
     949             : 
     950           2 :     LOG(DEBUG, "{}() called with fd: {}, buf: {}", __func__, fd, fmt::ptr(buf));
     951             : 
     952           2 :     if(CTX->file_map()->exist(fd)) {
     953           1 :         return with_errno(gkfs::syscall::gkfs_statfs(buf));
     954             :     }
     955           1 :     return syscall_no_intercept_wrapper(SYS_fstatfs, fd, buf);
     956             : }
     957             : 
     958             : /* The function should broadcast a flush message (pmem_persist i.e.) if the
     959             :  * application needs the capabilities*/
     960             : int
     961           1 : hook_fsync(unsigned int fd) {
     962             : 
     963           1 :     LOG(DEBUG, "{}() called with fd: {}", __func__, fd);
     964             : 
     965           1 :     if(CTX->file_map()->exist(fd)) {
     966           1 :         errno = 0;
     967           1 :         return 0;
     968             :     }
     969             : 
     970           0 :     return syscall_no_intercept_wrapper(SYS_fsync, fd);
     971             : }
     972             : 
     973             : int
     974           1 : hook_getxattr(const char* path, const char* name, void* value, size_t size) {
     975             : 
     976           1 :     LOG(DEBUG, "{}() called with path '{}' name '{}' value '{}' size '{}'",
     977           1 :         __func__, path, name, fmt::ptr(value), size);
     978             : 
     979           2 :     std::string rel_path;
     980           1 :     if(CTX->relativize_path(path, rel_path)) {
     981             :         return -ENOTSUP;
     982             :     }
     983           0 :     return syscall_no_intercept_wrapper(SYS_getxattr, path, name, value, size);
     984             : }
     985             : 
     986             : } // namespace gkfs::hook

Generated by: LCOV version 1.16