Skip to content
gkfs_functions.cpp 29.4 KiB
Newer Older
#ifdef HAS_SYMLINKS

/**
 * gkfs wrapper for make symlink() system calls
 * errno may be set
 *
 * * NOTE: Currently unused
 *
 * @param path
 * @param target_path
 * @return 0 on success or -1 on error
 */
int gkfs_mk_symlink(const std::string& path, const std::string& target_path) {
    gkfs::preload::init_ld_env_if_needed();
    /* The following check is not POSIX compliant.
     * In POSIX the target is not checked at all.
    *  Here if the target is a directory we raise a NOTSUP error.
    *  So that application know we don't support link to directory.
    */
    auto target_md = gkfs::util::get_metadata(target_path, false);
    if (target_md != nullptr) {
        auto trg_mode = target_md->mode();
        if (!(S_ISREG(trg_mode) || S_ISLNK(trg_mode))) {
            assert(S_ISDIR(trg_mode));
            LOG(DEBUG, "Target path is a directory. Not supported");
            errno = ENOTSUP;
            return -1;
        }
    }

Alberto Miranda's avatar
Alberto Miranda committed
    if (check_parent_dir(path)) {
    auto link_md = gkfs::util::get_metadata(path, false);
    if (link_md != nullptr) {
Alberto Miranda's avatar
Alberto Miranda committed
        LOG(DEBUG, "Link exists: '{}'", path);
        errno = EEXIST;
        return -1;
    }
Marc Vef's avatar
Marc Vef committed
    auto err = gkfs::rpc::forward_mk_symlink(path, target_path);
    if (err) {
        errno = err;
        return -1;
    }
    return 0;
/**
 * gkfs wrapper for reading symlinks
 * errno may be set
 *
 * NOTE: Currently unused
 *
 * @param path
 * @param buf
 * @param bufsize
 * @return 0 on success or -1 on error
 */
int gkfs_readlink(const std::string& path, char* buf, int bufsize) {
    gkfs::preload::init_ld_env_if_needed();
    auto md = gkfs::util::get_metadata(path, false);
    if (md == nullptr) {
        LOG(DEBUG, "Named link doesn't exist");
        return -1;
    }
    if (!(md->is_link())) {
        LOG(DEBUG, "The named file is not a symbolic link");
        errno = EINVAL;
        return -1;
    }
    int path_size = md->target_path().size() + CTX->mountdir().size();
    if (path_size >= bufsize) {
        LOG(WARNING, "Destination buffer size is too short: {} < {}, {} ", bufsize, path_size, md->target_path());
        errno = ENAMETOOLONG;
        return -1;
    }

    CTX->mountdir().copy(buf, CTX->mountdir().size());
    std::strcpy(buf + CTX->mountdir().size(), md->target_path().c_str());
    return path_size;
}

} // namespace syscall
} // namespace gkfs