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

Generated by: LCOV version 1.16