Newer
Older
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
#include <config.hpp>
#include <client/preload_util.hpp>
#include <client/logging.hpp>
#include <client/gkfs_functions.hpp>
#include <client/rpc/forward_metadata.hpp>
#include <client/rpc/forward_data.hpp>
#include <global/path_util.hpp>
extern "C" {
#include <dirent.h> // used for file types in the getdents{,64}() functions
#include <linux/kernel.h> // used for definition of alignment macros
#include <sys/statfs.h>
#include <sys/statvfs.h>
}
using namespace std;
/*
* Macro used within getdents{,64} functions.
* __ALIGN_KERNEL defined in linux/kernel.h
*/
#define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
* linux_dirent is used in getdents() but is privately defined in the linux
* kernel: fs/readdir.c.
*/
struct linux_dirent {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[1];
};
/*
* linux_dirent64 is used in getdents64() and defined in the linux kernel:
* include/linux/dirent.h. However, it is not part of the kernel-headers and
* cannot be imported.
*/
struct linux_dirent64 {
uint64_t d_ino;
int64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[1]; // originally `char d_name[0]` in kernel, but ISO C++
// forbids zero-size array 'd_name'
* Checks if metadata for parent directory exists (can be disabled with
* CREATE_CHECK_PARENTS). errno may be set
* @param path
* @return 0 on success, -1 on failure
*/
int
check_parent_dir(const std::string& path) {
auto p_comp = gkfs::path::dirname(path);
auto md = gkfs::util::get_metadata(p_comp);
if(!md) {
if(errno == ENOENT) {
LOG(DEBUG, "Parent component does not exist: '{}'", p_comp);
} else {
LOG(ERROR, "Failed to get metadata for parent component '{}': {}",
path, strerror(errno));
if(!S_ISDIR(md->mode())) {
LOG(DEBUG, "Parent component is not a directory: '{}'", p_comp);
errno = ENOTDIR;
return -1;
}
#endif // CREATE_CHECK_PARENTS
return 0;
}
namespace gkfs {
namespace syscall {
/**
* gkfs wrapper for open() system calls
* errno may be set
* @param path
* @param mode
* @param flags
* @return 0 on success, -1 on failure
*/
int
gkfs_open(const std::string& path, mode_t mode, int flags) {
LOG(ERROR, "`O_PATH` flag is not supported");
errno = ENOTSUP;
return -1;
}
LOG(ERROR, "`O_APPEND` flag is not supported");
errno = ENOTSUP;
return -1;
}
auto md = gkfs::util::get_metadata(path);
if(!md) {
if(errno == ENOENT) {
LOG(ERROR, "Error while retriving stat to file");
if(!exists) {
if(!(flags & O_CREAT)) {
// file doesn't exists and O_CREAT was not set
errno = ENOENT;
return -1;
}
/*** CREATION ***/
assert(flags & O_CREAT);
if(flags & O_DIRECTORY) {
LOG(ERROR, "O_DIRECTORY use with O_CREAT. NOT SUPPORTED");
// no access check required here. If one is using our FS they have the
// permissions.
if(gkfs_create(path, mode | S_IFREG)) {
LOG(ERROR, "Error creating non-existent file: '{}'",
strerror(errno));
// File exists and O_EXCL was set
errno = EEXIST;
return -1;
if(md->is_link()) {
if(flags & O_NOFOLLOW) {
LOG(WARNING, "Symlink found and O_NOFOLLOW flag was specified");
return gkfs_open(md->target_path(), mode, flags);
if(S_ISDIR(md->mode())) {
return gkfs_opendir(path);
if((flags & O_TRUNC) && ((flags & O_RDWR) || (flags & O_WRONLY))) {
if(gkfs_truncate(path, md->size(), 0)) {
LOG(ERROR, "Error truncating file");
return CTX->file_map()->add(
std::make_shared<gkfs::filemap::OpenFile>(path, flags));
Loading full blame...