Skip to content
GitLab
Explore
Sign in
Commits on Source (2)
some comments and gkfs init
· bc835b43
sevenuz
authored
Jul 25, 2025
bc835b43
first draft for gkfs
· 9936cd50
sevenuz
authored
Jul 29, 2025
9936cd50
Show whitespace changes
Inline
Side-by-side
include/client/fuse/fuse_client.hpp
View file @
9936cd50
/*
Copyright 2018-2025, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2025, 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.
This software was partially supported by the
the European Union’s Horizon 2020 JTI-EuroHPC research and
innovation programme, by the project ADMIRE (Project ID: 956748,
admire-eurohpc.eu)
This project was partially promoted by the Ministry for Digital Transformation
and the Civil Service, within the framework of the Recovery,
Transformation and Resilience Plan - Funded by the European Union
-NextGenerationEU.
This file is part of GekkoFS' POSIX interface.
GekkoFS' POSIX interface is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GekkoFS' POSIX interface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GekkoFS' POSIX interface. If not, see
<https://www.gnu.org/licenses/>.
SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef GKFS_CLIENT_FUSE_CONTEXT_HPP
#ifndef GKFS_CLIENT_FUSE_CONTEXT_HPP
#define GKFS_CLIENT_FUSE_CONTEXT_HPP
#define GKFS_CLIENT_FUSE_CONTEXT_HPP
#include
"fuse_log.h"
#include
<utility>
extern
"C"
{
extern
"C"
{
#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
#include
<fuse3/fuse_lowlevel.h>
#include
<fuse3/fuse_lowlevel.h>
...
@@ -37,42 +78,32 @@ struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
...
@@ -37,42 +78,32 @@ struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
};
};
#endif
#endif
/*
* FUSE: Filesystem in Userspace
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE
*/
#include
<errno.h>
#include
<errno.h>
#include
<fcntl.h>
#include
<fcntl.h>
#include
<string.h>
#include
<string.h>
#include
<sys/stat.h>
#include
<sys/stat.h>
#include
<unistd.h>
#include
<unistd.h>
#include
<filesystem>
#include
<unordered_map>
#include
<string>
#include
<mutex>
#ifdef __FreeBSD__
#ifdef __FreeBSD__
#include
<sys/socket.h>
#include
<sys/socket.h>
#include
<sys/un.h>
#include
<sys/un.h>
#endif
#endif
// GekkoFS Project Headers
#include
<common/path_util.hpp>
#include
<client/hooks.hpp>
#include
<client/logging.hpp>
// Assumed to provide LOG and CTX
#include
<client/open_dir.hpp>
#include
<client/open_file_map.hpp>
#include
<client/preload.hpp>
#include
<client/preload_context.hpp>
#include
<client/user_functions.hpp>
#include
<client/gkfs_libc.hpp>
static
inline
int
static
inline
int
do_fallocate
(
int
fd
,
int
mode
,
off_t
offset
,
off_t
length
)
{
do_fallocate
(
int
fd
,
int
mode
,
off_t
offset
,
off_t
length
)
{
#ifdef HAVE_FALLOCATE
#ifdef HAVE_FALLOCATE
...
@@ -103,6 +134,142 @@ do_fallocate(int fd, int mode, off_t offset, off_t length) {
...
@@ -103,6 +134,142 @@ do_fallocate(int fd, int mode, off_t offset, off_t length) {
#endif // HAVE_FALLOCATE
#endif // HAVE_FALLOCATE
}
}
// all from the gkfs_libc
enum
class
PathStatus
{
External
,
Internal
,
Error
};
/**
* @brief Resolves a path in the context of GekkoFS.
* (Details as in original comment)
*/
static
inline
PathStatus
resolve_gkfs_path
(
int
dirfd
,
const
char
*
path
,
std
::
string
&
resolved
,
int
flags
=
0
,
bool
resolve_last_link
=
true
)
{
const
auto
status
=
CTX
->
relativize_fd_path
(
dirfd
,
path
,
resolved
,
flags
,
resolve_last_link
);
switch
(
status
)
{
case
gkfs
::
preload
::
RelativizeStatus
::
internal
:
return
PathStatus
::
Internal
;
case
gkfs
::
preload
::
RelativizeStatus
::
fd_not_a_dir
:
errno
=
ENOTDIR
;
return
PathStatus
::
Error
;
case
gkfs
::
preload
::
RelativizeStatus
::
fd_unknown
:
errno
=
EBADF
;
return
PathStatus
::
Error
;
default:
// Assuming other statuses mean external or not applicable
return
PathStatus
::
External
;
}
}
#define DEBUG_INFO(...) \
do { \
if(CTX->interception_enabled()) \
LOG(DEBUG, __VA_ARGS__); \
} while(0)
#define GKFS_PATH_OPERATION(name, dirfd, path, ...) \
if(CTX->interception_enabled()) { \
std::string resolved; \
switch(resolve_gkfs_path(dirfd, path, resolved)) { \
case PathStatus::Internal: \
fuse_log(FUSE_LOG_DEBUG, "[GKFS] {}(path='{}')\n", #name, \
resolved.c_str()); \
return gkfs::syscall::gkfs_##name(resolved, __VA_ARGS__); \
case PathStatus::Error: \
return -1; \
default:
/* External */
\
break; \
} \
}
#define GKFS_PATH_OPERATION1(name, dirfd, path) \
if(CTX->interception_enabled()) { \
std::string resolved; \
switch(resolve_gkfs_path(dirfd, path, resolved)) { \
case PathStatus::Internal: \
fuse_log(FUSE_LOG_DEBUG, "[GKFS] {}(path='{}')\n", #name, \
resolved.c_str()); \
gkfs::syscall::gkfs_##name(resolved); \
case PathStatus::Error: \
fuse_reply_err(req, -1); \
default:
/* External */
\
fuse_reply_err(req, -1); \
} \
}
struct
GkfsDir
{
// Hypothetical structure that might be used if DIR is cast
int
fd
;
long
int
tell_pos
;
// for telldir/seekdir
char
*
path
;
// other members libc DIR might have
};
static
inline
std
::
pair
<
int
,
std
::
string
>
lol_path
(
int
dfd
,
const
char
*
path
,
int
flags
)
{
std
::
string
resolved
=
""
;
int
err
=
0
;
if
(
CTX
->
interception_enabled
())
{
// AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
bool
follow_link
=
!
(
flags
&
AT_SYMLINK_NOFOLLOW
);
// Path resolution needs to know if it's for lstat or stat context for
// the final component. resolve_gkfs_path's `resolve_last_link`
// parameter handles this.
switch
(
resolve_gkfs_path
(
dfd
,
path
,
resolved
,
flags
,
follow_link
))
{
case
PathStatus
::
Internal
:
break
;
case
PathStatus
::
Error
:
err
=
-
1
;
break
;
default:
// External
break
;
}
}
return
std
::
make_pair
(
err
,
resolved
);
}
static
inline
int
lol_fstatat
(
int
dfd
,
const
char
*
path
,
struct
stat
*
buf
,
int
flags
)
{
if
(
CTX
->
interception_enabled
())
{
std
::
string
resolved
;
// AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
bool
follow_link
=
!
(
flags
&
AT_SYMLINK_NOFOLLOW
);
// Path resolution needs to know if it's for lstat or stat context for
// the final component. resolve_gkfs_path's `resolve_last_link`
// parameter handles this.
switch
(
resolve_gkfs_path
(
dfd
,
path
,
resolved
,
flags
,
follow_link
))
{
case
PathStatus
::
Internal
:
return
gkfs
::
syscall
::
gkfs_stat
(
resolved
,
buf
,
follow_link
);
case
PathStatus
::
Error
:
return
-
1
;
// errno set
default:
// External
break
;
}
}
return
-
1
;
}
static
inline
int
lol_openat
(
int
dfd
,
const
char
*
path
,
mode_t
mode
,
int
flags
)
{
if
(
CTX
->
interception_enabled
())
{
std
::
string
resolved
;
// AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
bool
follow_link
=
!
(
flags
&
AT_SYMLINK_NOFOLLOW
);
// Path resolution needs to know if it's for lstat or stat context for
// the final component. resolve_gkfs_path's `resolve_last_link`
// parameter handles this.
switch
(
resolve_gkfs_path
(
dfd
,
path
,
resolved
,
flags
,
follow_link
))
{
case
PathStatus
::
Internal
:
fuse_log
(
FUSE_LOG_DEBUG
,
"lol_openat internal
\n
"
);
return
gkfs
::
syscall
::
gkfs_open
(
resolved
,
mode
,
follow_link
);
case
PathStatus
::
Error
:
return
-
1
;
// errno set
default:
// External
break
;
}
}
return
-
1
;
}
/*
/*
* Creates files on the underlying file system in response to a FUSE_MKNOD
* Creates files on the underlying file system in response to a FUSE_MKNOD
* operation
* operation
...
@@ -110,18 +277,28 @@ do_fallocate(int fd, int mode, off_t offset, off_t length) {
...
@@ -110,18 +277,28 @@ do_fallocate(int fd, int mode, off_t offset, off_t length) {
static
inline
int
static
inline
int
mknod_wrapper
(
int
dirfd
,
const
char
*
path
,
const
char
*
link
,
int
mode
,
mknod_wrapper
(
int
dirfd
,
const
char
*
path
,
const
char
*
link
,
int
mode
,
dev_t
rdev
)
{
dev_t
rdev
)
{
int
res
;
fuse_log
(
FUSE_LOG_DEBUG
,
"mknod_wrapper
\n
"
);
int
res
=
-
1
;
if
(
S_ISREG
(
mode
))
{
if
(
S_ISREG
(
mode
))
{
res
=
openat
(
dirfd
,
path
,
O_CREAT
|
O_EXCL
|
O_WRONLY
,
mode
);
res
=
lol_openat
(
dirfd
,
path
,
mode
,
O_CREAT
|
O_EXCL
|
O_WRONLY
);
fuse_log
(
FUSE_LOG_DEBUG
,
"lol_openat internal %s
\n
"
,
res
);
if
(
res
>=
0
)
if
(
res
>=
0
)
res
=
close
(
res
);
res
=
gkfs
::
syscall
::
gkfs_
close
(
res
);
}
else
if
(
S_ISDIR
(
mode
))
{
}
else
if
(
S_ISDIR
(
mode
))
{
res
=
mkdirat
(
dirfd
,
path
,
mode
);
GKFS_PATH_OPERATION
(
create
,
dirfd
,
path
,
mode
|
S_IFDIR
)
// res = gkfs::syscall::gkfs_create(resolved, mode | S_IFDIR);
// res = mkdirat(dirfd, path, mode);
}
else
if
(
S_ISLNK
(
mode
)
&&
link
!=
NULL
)
{
}
else
if
(
S_ISLNK
(
mode
)
&&
link
!=
NULL
)
{
res
=
symlinkat
(
link
,
dirfd
,
path
);
fuse_log
(
FUSE_LOG_ERR
,
"fifo in mknod_wrapper not supported
\n
"
);
errno
=
ENOTSUP
;
return
-
1
;
// res = symlinkat(link, dirfd, path);
}
else
if
(
S_ISFIFO
(
mode
))
{
}
else
if
(
S_ISFIFO
(
mode
))
{
res
=
mkfifoat
(
dirfd
,
path
,
mode
);
fuse_log
(
FUSE_LOG_ERR
,
"fifo in mknod_wrapper not supported
\n
"
);
errno
=
ENOTSUP
;
return
-
1
;
// res = mkfifoat(dirfd, path, mode);
#ifdef __FreeBSD__
#ifdef __FreeBSD__
}
else
if
(
S_ISSOCK
(
mode
))
{
}
else
if
(
S_ISSOCK
(
mode
))
{
struct
sockaddr_un
su
;
struct
sockaddr_un
su
;
...
@@ -148,7 +325,10 @@ mknod_wrapper(int dirfd, const char* path, const char* link, int mode,
...
@@ -148,7 +325,10 @@ mknod_wrapper(int dirfd, const char* path, const char* link, int mode,
}
}
#endif
#endif
}
else
{
}
else
{
res
=
mknodat
(
dirfd
,
path
,
mode
,
rdev
);
fuse_log
(
FUSE_LOG_ERR
,
"mknodat in mknod_wrapper not supported
\n
"
);
errno
=
ENOTSUP
;
return
-
1
;
// res = mknodat(dirfd, path, mode, rdev);
}
}
return
res
;
return
res
;
...
...
src/client/CMakeLists.txt
View file @
9936cd50
...
@@ -118,8 +118,10 @@ target_sources(fuse_client
...
@@ -118,8 +118,10 @@ target_sources(fuse_client
)
)
target_link_libraries
(
fuse_client
target_link_libraries
(
fuse_client
PRIVATE gkfs_common metadata distributor env_util arithmetic path_util rpc_utils
${
FUSE3_LIBRARIES
}
${
FUSE3_LIBRARIES
}
gkfs_user_lib
gkfs_user_lib
gkfs_libc_intercept
)
)
target_include_directories
(
fuse_client
target_include_directories
(
fuse_client
...
...
src/client/fuse/fuse_client.cpp
View file @
9936cd50
/*
Copyright 2018-2025, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2025, 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.
This software was partially supported by the
the European Union’s Horizon 2020 JTI-EuroHPC research and
innovation programme, by the project ADMIRE (Project ID: 956748,
admire-eurohpc.eu)
This project was partially promoted by the Ministry for Digital Transformation
and the Civil Service, within the framework of the Recovery,
Transformation and Resilience Plan - Funded by the European Union
-NextGenerationEU.
This file is part of GekkoFS' POSIX interface.
GekkoFS' POSIX interface is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GekkoFS' POSIX interface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GekkoFS' POSIX interface. If not, see
<https://www.gnu.org/licenses/>.
SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include
"client/env.hpp"
#include
"common/env_util.hpp"
#include
<cerrno>
#include
<client/fuse/fuse_client.hpp>
#include
<client/fuse/fuse_client.hpp>
#include
<cstdio>
#include
<cstdlib>
#include
<dirent.h>
#include
<iostream>
struct
lo_inode
{
struct
lo_inode
{
struct
lo_inode
*
next
;
/* protected by lo->mutex */
struct
lo_inode
*
next
;
/* protected by lo->mutex */
...
@@ -85,6 +131,7 @@ lo_debug(fuse_req_t req) {
...
@@ -85,6 +131,7 @@ lo_debug(fuse_req_t req) {
static
void
static
void
lo_init
(
void
*
userdata
,
struct
fuse_conn_info
*
conn
)
{
lo_init
(
void
*
userdata
,
struct
fuse_conn_info
*
conn
)
{
// TODO init gkfs
struct
lo_data
*
lo
=
(
struct
lo_data
*
)
userdata
;
struct
lo_data
*
lo
=
(
struct
lo_data
*
)
userdata
;
bool
has_flag
;
bool
has_flag
;
...
@@ -103,1095 +150,368 @@ lo_init(void* userdata, struct fuse_conn_info* conn) {
...
@@ -103,1095 +150,368 @@ lo_init(void* userdata, struct fuse_conn_info* conn) {
conn
->
no_interrupt
=
1
;
conn
->
no_interrupt
=
1
;
}
}
static
void
// Simplified inode structure
lo_destroy
(
void
*
userdata
)
{
struct
Inode
{
struct
lo_data
*
lo
=
(
struct
lo_data
*
)
userdata
;
std
::
string
path
;
struct
stat
st
;
while
(
lo
->
root
.
next
!=
&
lo
->
root
)
{
uint64_t
lookup_count
;
struct
lo_inode
*
next
=
lo
->
root
.
next
;
};
lo
->
root
.
next
=
next
->
next
;
static
std
::
mutex
ino_mutex
;
close
(
next
->
fd
);
static
std
::
unordered_map
<
fuse_ino_t
,
Inode
>
ino_map
;
free
(
next
);
static
fuse_ino_t
next_ino
=
2
;
// reserve 1 for root
}
}
static
fuse_ino_t
alloc_inode
(
const
std
::
string
&
path
)
{
static
void
std
::
lock_guard
<
std
::
mutex
>
lk
(
ino_mutex
);
lo_getattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
fuse_ino_t
ino
=
next_ino
++
;
int
res
;
ino_map
[
ino
]
=
{
path
,
{},
1
};
struct
stat
buf
;
return
ino
;
struct
lo_data
*
lo
=
lo_data
(
req
);
}
int
fd
=
fi
?
fi
->
fh
:
lo_fd
(
req
,
ino
);
static
Inode
*
get_inode
(
fuse_ino_t
ino
)
{
(
void
)
fi
;
std
::
lock_guard
<
std
::
mutex
>
lk
(
ino_mutex
);
auto
it
=
ino_map
.
find
(
ino
);
res
=
fstatat
(
fd
,
""
,
&
buf
,
AT_EMPTY_PATH
|
AT_SYMLINK_NOFOLLOW
);
return
it
!=
ino_map
.
end
()
?
&
it
->
second
:
nullptr
;
if
(
res
==
-
1
)
}
return
(
void
)
fuse_reply_err
(
req
,
errno
);
static
void
fuse_reply_attr
(
req
,
&
buf
,
lo
->
timeout
);
lookup_handler
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
)
{
}
fuse_log
(
FUSE_LOG_DEBUG
,
"lookup handler ino %u
\n
"
,
parent
);
auto
*
parent_inode
=
get_inode
(
parent
);
static
void
if
(
!
parent_inode
)
{
lo_setattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
stat
*
attr
,
int
valid
,
fuse_log
(
FUSE_LOG_DEBUG
,
"this error 1
\n
"
,
parent
);
struct
fuse_file_info
*
fi
)
{
fuse_reply_err
(
req
,
ENOENT
);
int
saverr
;
return
;
char
procname
[
64
];
struct
lo_inode
*
inode
=
lo_inode
(
req
,
ino
);
int
ifd
=
inode
->
fd
;
int
res
;
if
(
valid
&
FUSE_SET_ATTR_MODE
)
{
if
(
fi
)
{
res
=
fchmod
(
fi
->
fh
,
attr
->
st_mode
);
}
else
{
sprintf
(
procname
,
"/proc/self/fd/%i"
,
ifd
);
res
=
chmod
(
procname
,
attr
->
st_mode
);
}
if
(
res
==
-
1
)
goto
out_err
;
}
if
(
valid
&
(
FUSE_SET_ATTR_UID
|
FUSE_SET_ATTR_GID
))
{
uid_t
uid
=
(
valid
&
FUSE_SET_ATTR_UID
)
?
attr
->
st_uid
:
(
uid_t
)
-
1
;
gid_t
gid
=
(
valid
&
FUSE_SET_ATTR_GID
)
?
attr
->
st_gid
:
(
gid_t
)
-
1
;
res
=
fchownat
(
ifd
,
""
,
uid
,
gid
,
AT_EMPTY_PATH
|
AT_SYMLINK_NOFOLLOW
);
if
(
res
==
-
1
)
goto
out_err
;
}
if
(
valid
&
FUSE_SET_ATTR_SIZE
)
{
if
(
fi
)
{
res
=
ftruncate
(
fi
->
fh
,
attr
->
st_size
);
}
else
{
sprintf
(
procname
,
"/proc/self/fd/%i"
,
ifd
);
res
=
truncate
(
procname
,
attr
->
st_size
);
}
if
(
res
==
-
1
)
goto
out_err
;
}
if
(
valid
&
(
FUSE_SET_ATTR_ATIME
|
FUSE_SET_ATTR_MTIME
))
{
struct
timespec
tv
[
2
];
tv
[
0
].
tv_sec
=
0
;
tv
[
1
].
tv_sec
=
0
;
tv
[
0
].
tv_nsec
=
UTIME_OMIT
;
tv
[
1
].
tv_nsec
=
UTIME_OMIT
;
if
(
valid
&
FUSE_SET_ATTR_ATIME_NOW
)
tv
[
0
].
tv_nsec
=
UTIME_NOW
;
else
if
(
valid
&
FUSE_SET_ATTR_ATIME
)
tv
[
0
]
=
attr
->
st_atim
;
if
(
valid
&
FUSE_SET_ATTR_MTIME_NOW
)
tv
[
1
].
tv_nsec
=
UTIME_NOW
;
else
if
(
valid
&
FUSE_SET_ATTR_MTIME
)
tv
[
1
]
=
attr
->
st_mtim
;
if
(
fi
)
res
=
futimens
(
fi
->
fh
,
tv
);
else
{
sprintf
(
procname
,
"/proc/self/fd/%i"
,
ifd
);
res
=
utimensat
(
AT_FDCWD
,
procname
,
tv
,
0
);
}
if
(
res
==
-
1
)
goto
out_err
;
}
return
lo_getattr
(
req
,
ino
,
fi
);
out_err
:
saverr
=
errno
;
fuse_reply_err
(
req
,
saverr
);
}
static
struct
lo_inode
*
lo_find
(
struct
lo_data
*
lo
,
struct
stat
*
st
)
{
struct
lo_inode
*
p
;
struct
lo_inode
*
ret
=
NULL
;
pthread_mutex_lock
(
&
lo
->
mutex
);
for
(
p
=
lo
->
root
.
next
;
p
!=
&
lo
->
root
;
p
=
p
->
next
)
{
if
(
p
->
ino
==
st
->
st_ino
&&
p
->
dev
==
st
->
st_dev
)
{
assert
(
p
->
refcount
>
0
);
ret
=
p
;
ret
->
refcount
++
;
break
;
}
}
pthread_mutex_unlock
(
&
lo
->
mutex
);
return
ret
;
}
static
struct
lo_inode
*
create_new_inode
(
int
fd
,
struct
fuse_entry_param
*
e
,
struct
lo_data
*
lo
)
{
struct
lo_inode
*
inode
=
NULL
;
struct
lo_inode
*
prev
,
*
next
;
inode
=
(
struct
lo_inode
*
)
calloc
(
1
,
sizeof
(
struct
lo_inode
));
if
(
!
inode
)
return
NULL
;
inode
->
refcount
=
1
;
inode
->
fd
=
fd
;
inode
->
ino
=
e
->
attr
.
st_ino
;
inode
->
dev
=
e
->
attr
.
st_dev
;
pthread_mutex_lock
(
&
lo
->
mutex
);
prev
=
&
lo
->
root
;
next
=
prev
->
next
;
next
->
prev
=
inode
;
inode
->
next
=
next
;
inode
->
prev
=
prev
;
prev
->
next
=
inode
;
pthread_mutex_unlock
(
&
lo
->
mutex
);
return
inode
;
}
static
int
fill_entry_param_new_inode
(
fuse_req_t
req
,
fuse_ino_t
parent
,
int
fd
,
struct
fuse_entry_param
*
e
)
{
int
res
;
struct
lo_data
*
lo
=
lo_data
(
req
);
memset
(
e
,
0
,
sizeof
(
*
e
));
e
->
attr_timeout
=
lo
->
timeout
;
e
->
entry_timeout
=
lo
->
timeout
;
res
=
fstatat
(
fd
,
""
,
&
e
->
attr
,
AT_EMPTY_PATH
|
AT_SYMLINK_NOFOLLOW
);
if
(
res
==
-
1
)
return
errno
;
e
->
ino
=
(
uintptr_t
)
create_new_inode
(
dup
(
fd
),
e
,
lo
);
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
" %lli/%lli -> %lli
\n
"
,
(
unsigned
long
long
)
parent
,
fd
,
(
unsigned
long
long
)
e
->
ino
);
return
0
;
}
static
int
lo_do_lookup
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
struct
fuse_entry_param
*
e
)
{
int
newfd
;
int
res
;
int
saverr
;
struct
lo_data
*
lo
=
lo_data
(
req
);
struct
lo_inode
*
inode
;
memset
(
e
,
0
,
sizeof
(
*
e
));
e
->
attr_timeout
=
lo
->
timeout
;
e
->
entry_timeout
=
lo
->
timeout
;
newfd
=
openat
(
lo_fd
(
req
,
parent
),
name
,
O_PATH
|
O_NOFOLLOW
);
if
(
newfd
==
-
1
)
goto
out_err
;
res
=
fstatat
(
newfd
,
""
,
&
e
->
attr
,
AT_EMPTY_PATH
|
AT_SYMLINK_NOFOLLOW
);
if
(
res
==
-
1
)
goto
out_err
;
inode
=
lo_find
(
lo_data
(
req
),
&
e
->
attr
);
if
(
inode
)
{
close
(
newfd
);
newfd
=
-
1
;
}
else
{
inode
=
create_new_inode
(
newfd
,
e
,
lo
);
if
(
!
inode
)
goto
out_err
;
}
}
e
->
ino
=
(
uintptr_t
)
inode
;
std
::
string
child
=
parent_inode
->
path
+
name
;
fuse_log
(
FUSE_LOG_DEBUG
,
"lookup %s
\n
"
,
child
.
c_str
());
if
(
lo_debug
(
req
))
struct
stat
st
;
fuse_log
(
FUSE_LOG_DEBUG
,
" %lli/%s -> %lli
\n
"
,
int
rc
=
gkfs
::
syscall
::
gkfs_stat
(
child
,
&
st
);
(
unsigned
long
long
)
parent
,
name
,
if
(
rc
<
0
)
{
(
unsigned
long
long
)
e
->
ino
);
fuse_log
(
FUSE_LOG_DEBUG
,
"that error 2
\n
"
,
parent
);
fuse_reply_err
(
req
,
ENOENT
);
return
0
;
return
;
out_err
:
saverr
=
errno
;
if
(
newfd
!=
-
1
)
close
(
newfd
);
return
saverr
;
}
}
fuse_ino_t
ino
=
alloc_inode
(
child
);
static
void
ino_map
[
ino
].
st
=
st
;
lo_lookup
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
)
{
fuse_entry_param
e
=
{};
struct
fuse_entry_param
e
;
e
.
ino
=
ino
;
int
err
;
e
.
attr
=
st
;
e
.
attr_timeout
=
1.0
;
if
(
lo_debug
(
req
))
e
.
entry_timeout
=
1.0
;
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_lookup(parent=%"
PRIu64
", name=%s)
\n
"
,
parent
,
name
);
err
=
lo_do_lookup
(
req
,
parent
,
name
,
&
e
);
if
(
err
)
fuse_reply_err
(
req
,
err
);
else
fuse_reply_entry
(
req
,
&
e
);
fuse_reply_entry
(
req
,
&
e
);
}
}
static
void
static
void
lo_mknod_symlink
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
getattr_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
mode_t
mode
,
dev_t
rdev
,
const
char
*
link
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"getattr handler
\n
"
);
int
res
;
auto
*
inode
=
get_inode
(
ino
);
int
saverr
;
if
(
!
inode
)
{
struct
lo_inode
*
dir
=
lo_inode
(
req
,
parent
);
fuse_reply_err
(
req
,
ENOENT
);
struct
fuse_entry_param
e
;
res
=
mknod_wrapper
(
dir
->
fd
,
name
,
link
,
mode
,
rdev
);
saverr
=
errno
;
if
(
res
==
-
1
)
goto
out
;
saverr
=
lo_do_lookup
(
req
,
parent
,
name
,
&
e
);
if
(
saverr
)
goto
out
;
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
" %lli/%s -> %lli
\n
"
,
(
unsigned
long
long
)
parent
,
name
,
(
unsigned
long
long
)
e
.
ino
);
fuse_reply_entry
(
req
,
&
e
);
return
;
return
;
out:
fuse_reply_err
(
req
,
saverr
);
}
static
void
lo_mknod
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
mode_t
mode
,
dev_t
rdev
)
{
lo_mknod_symlink
(
req
,
parent
,
name
,
mode
,
rdev
,
NULL
);
}
}
// query GekkoFS for latest attr
static
void
struct
stat
st
;
lo_mkdir
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
mode_t
mode
)
{
int
rc
=
gkfs
::
syscall
::
gkfs_stat
(
inode
->
path
,
&
st
);
lo_mknod_symlink
(
req
,
parent
,
name
,
S_IFDIR
|
mode
,
0
,
NULL
);
if
(
rc
)
{
}
fuse_log
(
FUSE_LOG_DEBUG
,
"getattr error %u
\n
"
,
rc
);
fuse_reply_err
(
req
,
ENOENT
);
static
void
lo_symlink
(
fuse_req_t
req
,
const
char
*
link
,
fuse_ino_t
parent
,
const
char
*
name
)
{
lo_mknod_symlink
(
req
,
parent
,
name
,
S_IFLNK
,
0
,
link
);
}
static
void
lo_link
(
fuse_req_t
req
,
fuse_ino_t
ino
,
fuse_ino_t
parent
,
const
char
*
name
)
{
int
res
;
struct
lo_data
*
lo
=
lo_data
(
req
);
struct
lo_inode
*
inode
=
lo_inode
(
req
,
ino
);
struct
fuse_entry_param
e
;
char
procname
[
64
];
int
saverr
;
memset
(
&
e
,
0
,
sizeof
(
struct
fuse_entry_param
));
e
.
attr_timeout
=
lo
->
timeout
;
e
.
entry_timeout
=
lo
->
timeout
;
sprintf
(
procname
,
"/proc/self/fd/%i"
,
inode
->
fd
);
res
=
linkat
(
AT_FDCWD
,
procname
,
lo_fd
(
req
,
parent
),
name
,
AT_SYMLINK_FOLLOW
);
if
(
res
==
-
1
)
goto
out_err
;
res
=
fstatat
(
inode
->
fd
,
""
,
&
e
.
attr
,
AT_EMPTY_PATH
|
AT_SYMLINK_NOFOLLOW
);
if
(
res
==
-
1
)
goto
out_err
;
pthread_mutex_lock
(
&
lo
->
mutex
);
inode
->
refcount
++
;
pthread_mutex_unlock
(
&
lo
->
mutex
);
e
.
ino
=
(
uintptr_t
)
inode
;
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
" %lli/%s -> %lli
\n
"
,
(
unsigned
long
long
)
parent
,
name
,
(
unsigned
long
long
)
e
.
ino
);
fuse_reply_entry
(
req
,
&
e
);
return
;
return
;
out_err:
saverr
=
errno
;
fuse_reply_err
(
req
,
saverr
);
}
}
inode
->
st
=
st
;
static
void
fuse_reply_attr
(
req
,
&
st
,
1.0
);
lo_rmdir
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
)
{
int
res
;
res
=
unlinkat
(
lo_fd
(
req
,
parent
),
name
,
AT_REMOVEDIR
);
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
}
}
static
void
static
void
lo_rename
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
setattr_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
stat
*
attr
,
int
to_set
,
fuse_ino_t
newparent
,
const
char
*
newname
,
unsigned
int
flags
)
{
struct
fuse_file_info
*
fi
)
{
int
res
;
fuse_log
(
FUSE_LOG_DEBUG
,
"setattr handler
\n
"
)
;
auto
*
inode
=
get_inode
(
ino
);
if
(
flags
)
{
if
(
!
inode
)
{
fuse_reply_err
(
req
,
E
INVAL
);
fuse_reply_err
(
req
,
E
NOENT
);
return
;
return
;
}
}
// TODO how to change attr?
res
=
renameat
(
lo_fd
(
req
,
parent
),
name
,
lo_fd
(
req
,
newparent
),
newname
);
int
rc
=
0
;
if
(
rc
)
{
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
fuse_reply_err
(
req
,
rc
);
}
static
void
lo_unlink
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
)
{
int
res
;
res
=
unlinkat
(
lo_fd
(
req
,
parent
),
name
,
0
);
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
}
static
void
unref_inode
(
struct
lo_data
*
lo
,
struct
lo_inode
*
inode
,
uint64_t
n
)
{
if
(
!
inode
)
return
;
return
;
pthread_mutex_lock
(
&
lo
->
mutex
);
assert
(
inode
->
refcount
>=
n
);
inode
->
refcount
-=
n
;
if
(
!
inode
->
refcount
)
{
struct
lo_inode
*
prev
,
*
next
;
prev
=
inode
->
prev
;
next
=
inode
->
next
;
next
->
prev
=
prev
;
prev
->
next
=
next
;
pthread_mutex_unlock
(
&
lo
->
mutex
);
close
(
inode
->
fd
);
free
(
inode
);
}
else
{
pthread_mutex_unlock
(
&
lo
->
mutex
);
}
}
// TODO thats not in gkfs!!!
inode
->
st
.
st_atim
=
attr
->
st_atim
;
inode
->
st
.
st_blksize
=
attr
->
st_blksize
;
inode
->
st
.
st_blocks
=
attr
->
st_blocks
;
inode
->
st
.
st_ctim
=
attr
->
st_ctim
;
inode
->
st
.
st_dev
=
attr
->
st_dev
;
inode
->
st
.
st_gid
=
attr
->
st_gid
;
inode
->
st
.
st_ino
=
attr
->
st_ino
;
inode
->
st
.
st_mode
=
attr
->
st_mode
;
inode
->
st
.
st_mtim
=
attr
->
st_mtim
;
inode
->
st
.
st_nlink
=
attr
->
st_nlink
;
inode
->
st
.
st_rdev
=
attr
->
st_rdev
;
inode
->
st
.
st_size
=
attr
->
st_size
;
inode
->
st
.
st_uid
=
attr
->
st_uid
;
fuse_reply_attr
(
req
,
&
inode
->
st
,
1.0
);
}
static
void
open_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"open handler
\n
"
);
auto
*
inode
=
get_inode
(
ino
);
if
(
!
inode
)
{
fuse_reply_err
(
req
,
ENOENT
);
return
;
}
}
const
int
mode
=
0644
;
// -rw-r--r-- I think that doesnt matter anyway
static
void
int
fd
=
gkfs
::
syscall
::
gkfs_open
(
inode
->
path
,
mode
,
lo_forget_one
(
fuse_req_t
req
,
fuse_ino_t
ino
,
uint64_t
nlookup
)
{
fi
->
flags
);
// TODO mode!
struct
lo_data
*
lo
=
lo_data
(
req
);
if
(
fd
<
0
)
{
struct
lo_inode
*
inode
=
lo_inode
(
req
,
ino
);
fuse_reply_err
(
req
,
ENOENT
);
return
;
if
(
lo_debug
(
req
))
{
fuse_log
(
FUSE_LOG_DEBUG
,
" forget %lli %lli -%lli
\n
"
,
(
unsigned
long
long
)
ino
,
(
unsigned
long
long
)
inode
->
refcount
,
(
unsigned
long
long
)
nlookup
);
}
unref_inode
(
lo
,
inode
,
nlookup
);
}
static
void
lo_forget
(
fuse_req_t
req
,
fuse_ino_t
ino
,
uint64_t
nlookup
)
{
lo_forget_one
(
req
,
ino
,
nlookup
);
fuse_reply_none
(
req
);
}
}
fi
->
fh
=
fd
;
// TODO file handle == file descriptor?
static
void
fuse_reply_open
(
req
,
fi
);
lo_forget_multi
(
fuse_req_t
req
,
size_t
count
,
struct
fuse_forget_data
*
forgets
)
{
int
i
;
for
(
i
=
0
;
i
<
count
;
i
++
)
lo_forget_one
(
req
,
forgets
[
i
].
ino
,
forgets
[
i
].
nlookup
);
fuse_reply_none
(
req
);
}
}
static
void
static
void
lo_readlink
(
fuse_req_t
req
,
fuse_ino_t
ino
)
{
read_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
,
off_t
off
,
char
buf
[
PATH_MAX
+
1
];
struct
fuse_file_info
*
fi
)
{
int
res
;
fuse_log
(
FUSE_LOG_DEBUG
,
"read handler
\n
"
);
auto
*
inode
=
get_inode
(
ino
);
res
=
readlinkat
(
lo_fd
(
req
,
ino
),
""
,
buf
,
sizeof
(
buf
));
if
(
!
inode
)
{
if
(
res
==
-
1
)
fuse_reply_err
(
req
,
ENOENT
);
return
(
void
)
fuse_reply_err
(
req
,
errno
);
return
;
if
(
res
==
sizeof
(
buf
))
return
(
void
)
fuse_reply_err
(
req
,
ENAMETOOLONG
);
buf
[
res
]
=
'\0'
;
fuse_reply_readlink
(
req
,
buf
);
}
}
std
::
vector
<
char
>
buf
(
size
);
struct
lo_dirp
{
int
lc
=
gkfs
::
syscall
::
gkfs_lseek
(
fi
->
fh
,
off
,
SEEK_SET
);
DIR
*
dp
;
if
(
lc
<
0
)
{
struct
dirent
*
entry
;
fuse_reply_err
(
req
,
1
);
off_t
offset
;
return
;
};
static
struct
lo_dirp
*
lo_dirp
(
struct
fuse_file_info
*
fi
)
{
return
(
struct
lo_dirp
*
)
(
uintptr_t
)
fi
->
fh
;
}
}
int
rc
=
gkfs
::
syscall
::
gkfs_read
(
fi
->
fh
,
buf
.
data
(),
size
);
static
void
if
(
rc
<
0
)
{
lo_opendir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
fuse_reply_err
(
req
,
1
);
int
error
=
ENOMEM
;
struct
lo_data
*
lo
=
lo_data
(
req
);
struct
lo_dirp
*
d
;
int
fd
=
-
1
;
d
=
(
struct
lo_dirp
*
)
calloc
(
1
,
sizeof
(
struct
lo_dirp
));
if
(
d
==
NULL
)
goto
out_err
;
fd
=
openat
(
lo_fd
(
req
,
ino
),
"."
,
O_RDONLY
);
if
(
fd
==
-
1
)
goto
out_errno
;
d
->
dp
=
fdopendir
(
fd
);
if
(
d
->
dp
==
NULL
)
goto
out_errno
;
d
->
offset
=
0
;
d
->
entry
=
NULL
;
fi
->
fh
=
(
uintptr_t
)
d
;
if
(
lo
->
cache
!=
CACHE_NEVER
)
fi
->
cache_readdir
=
1
;
if
(
lo
->
cache
==
CACHE_ALWAYS
)
fi
->
keep_cache
=
1
;
fuse_reply_open
(
req
,
fi
);
return
;
return
;
out_errno:
error
=
errno
;
out_err:
if
(
d
)
{
if
(
fd
!=
-
1
)
close
(
fd
);
free
(
d
);
}
}
fuse_reply_err
(
req
,
error
);
fuse_reply_buf
(
req
,
buf
.
data
(),
rc
);
}
static
int
is_dot_or_dotdot
(
const
char
*
name
)
{
return
name
[
0
]
==
'.'
&&
(
name
[
1
]
==
'\0'
||
(
name
[
1
]
==
'.'
&&
name
[
2
]
==
'\0'
));
}
}
static
void
static
void
lo_do_readdir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
,
off_t
offset
,
write_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
const
char
*
buf
,
size_t
size
,
struct
fuse_file_info
*
fi
,
int
plus
)
{
off_t
off
,
struct
fuse_file_info
*
fi
)
{
struct
lo_dirp
*
d
=
lo_dirp
(
fi
);
fuse_log
(
FUSE_LOG_DEBUG
,
"write handler
\n
"
);
char
*
buf
;
auto
*
inode
=
get_inode
(
ino
);
char
*
p
;
if
(
!
inode
)
{
size_t
rem
=
size
;
fuse_reply_err
(
req
,
ENOENT
);
int
err
;
return
;
(
void
)
ino
;
buf
=
(
char
*
)
calloc
(
1
,
size
);
if
(
!
buf
)
{
err
=
ENOMEM
;
goto
error
;
}
p
=
buf
;
if
(
offset
!=
d
->
offset
)
{
seekdir
(
d
->
dp
,
offset
);
d
->
entry
=
NULL
;
d
->
offset
=
offset
;
}
while
(
1
)
{
size_t
entsize
;
off_t
nextoff
;
const
char
*
name
;
if
(
!
d
->
entry
)
{
errno
=
0
;
d
->
entry
=
readdir
(
d
->
dp
);
if
(
!
d
->
entry
)
{
if
(
errno
)
{
// Error
err
=
errno
;
goto
error
;
}
else
{
// End of stream
break
;
}
}
}
nextoff
=
d
->
entry
->
d_off
;
name
=
d
->
entry
->
d_name
;
fuse_ino_t
entry_ino
=
0
;
if
(
plus
)
{
struct
fuse_entry_param
e
;
if
(
is_dot_or_dotdot
(
name
))
{
struct
fuse_entry_param
e
=
{};
e
.
attr
.
st_ino
=
d
->
entry
->
d_ino
;
e
.
attr
.
st_mode
=
static_cast
<
__mode_t
>
(
d
->
entry
->
d_type
<<
12
);
}
else
{
err
=
lo_do_lookup
(
req
,
ino
,
name
,
&
e
);
if
(
err
)
goto
error
;
entry_ino
=
e
.
ino
;
}
entsize
=
fuse_add_direntry_plus
(
req
,
p
,
rem
,
name
,
&
e
,
nextoff
);
}
else
{
struct
stat
st
=
{
.
st_ino
=
d
->
entry
->
d_ino
,
.
st_mode
=
static_cast
<
__mode_t
>
(
d
->
entry
->
d_type
<<
12
),
};
entsize
=
fuse_add_direntry
(
req
,
p
,
rem
,
name
,
&
st
,
nextoff
);
}
}
if
(
entsize
>
rem
)
{
int
lc
=
gkfs
::
syscall
::
gkfs_lseek
(
fi
->
fh
,
off
,
SEEK_SET
);
if
(
entry_ino
!=
0
)
if
(
lc
<
0
)
{
lo_forget_one
(
req
,
entry_ino
,
1
);
fuse_reply_err
(
req
,
1
);
break
;
return
;
}
}
int
rc
=
gkfs
::
syscall
::
gkfs_write
(
fi
->
fh
,
buf
,
size
);
p
+=
entsize
;
if
(
rc
<
0
)
{
rem
-=
entsize
;
fuse_reply_err
(
req
,
1
);
return
;
d
->
entry
=
NULL
;
d
->
offset
=
nextoff
;
}
}
if
(
rc
<
0
)
{
err
=
0
;
fuse_reply_err
(
req
,
1
);
error
:
return
;
// If there's an error, we can only signal it if we haven't stored
// any entries yet - otherwise we'd end up with wrong lookup
// counts for the entries that are already in the buffer. So we
// return what we've collected until that point.
if
(
err
&&
rem
==
size
)
fuse_reply_err
(
req
,
err
);
else
fuse_reply_buf
(
req
,
buf
,
size
-
rem
);
free
(
buf
);
}
}
fuse_reply_write
(
req
,
rc
);
static
void
lo_readdir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
,
off_t
offset
,
struct
fuse_file_info
*
fi
)
{
lo_do_readdir
(
req
,
ino
,
size
,
offset
,
fi
,
0
);
}
}
static
void
static
void
lo_readdirplus
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
,
off_t
offset
,
create_handler
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
mode_t
mode
,
struct
fuse_file_info
*
fi
)
{
struct
fuse_file_info
*
fi
)
{
lo_do_readdir
(
req
,
ino
,
size
,
offset
,
fi
,
1
);
fuse_log
(
FUSE_LOG_DEBUG
,
"create handler
\n
"
);
auto
*
parent_inode
=
get_inode
(
parent
);
if
(
!
parent_inode
)
{
fuse_reply_err
(
req
,
ENOENT
);
return
;
}
}
std
::
string
path
=
parent_inode
->
path
+
name
;
static
void
int
rc
=
gkfs
::
syscall
::
gkfs_create
(
path
,
mode
);
lo_releasedir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
if
(
rc
==
-
1
)
{
struct
lo_dirp
*
d
=
lo_dirp
(
fi
);
fuse_log
(
FUSE_LOG_DEBUG
,
"here here mode %i flags %i
\n
"
,
mode
,
fi
->
flags
);
(
void
)
ino
;
fuse_reply_err
(
req
,
1
);
closedir
(
d
->
dp
);
return
;
free
(
d
);
fuse_reply_err
(
req
,
0
);
}
}
struct
stat
st
;
static
void
int
sc
=
gkfs
::
syscall
::
gkfs_stat
(
path
,
&
st
);
lo_tmpfile
(
fuse_req_t
req
,
fuse_ino_t
parent
,
mode_t
mode
,
if
(
sc
==
-
1
)
{
struct
fuse_file_info
*
fi
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"thats why its not allowed
\n
"
);
int
fd
;
fuse_reply_err
(
req
,
1
);
struct
lo_data
*
lo
=
lo_data
(
req
);
return
;
struct
fuse_entry_param
e
;
int
err
;
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_tmpfile(parent=%"
PRIu64
")
\n
"
,
parent
);
fd
=
openat
(
lo_fd
(
req
,
parent
),
"."
,
(
fi
->
flags
|
O_TMPFILE
)
&
~
O_NOFOLLOW
,
mode
);
if
(
fd
==
-
1
)
return
(
void
)
fuse_reply_err
(
req
,
errno
);
fi
->
fh
=
fd
;
if
(
lo
->
cache
==
CACHE_NEVER
)
fi
->
direct_io
=
1
;
else
if
(
lo
->
cache
==
CACHE_ALWAYS
)
fi
->
keep_cache
=
1
;
/* parallel_direct_writes feature depends on direct_io features.
To make parallel_direct_writes valid, need set fi->direct_io
in current function. */
fi
->
parallel_direct_writes
=
1
;
err
=
fill_entry_param_new_inode
(
req
,
parent
,
fd
,
&
e
);
if
(
err
)
fuse_reply_err
(
req
,
err
);
else
fuse_reply_create
(
req
,
&
e
,
fi
);
}
}
fuse_ino_t
ino
=
alloc_inode
(
path
);
static
void
ino_map
[
ino
].
st
=
st
;
lo_create
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
mode_t
mode
,
fuse_entry_param
e
=
{};
struct
fuse_file_info
*
fi
)
{
e
.
ino
=
ino
;
int
fd
;
e
.
attr
=
st
;
struct
lo_data
*
lo
=
lo_data
(
req
);
e
.
attr_timeout
=
1.0
;
struct
fuse_entry_param
e
;
e
.
entry_timeout
=
1.0
;
int
err
;
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_create(parent=%"
PRIu64
", name=%s)
\n
"
,
parent
,
name
);
fd
=
openat
(
lo_fd
(
req
,
parent
),
name
,
(
fi
->
flags
|
O_CREAT
)
&
~
O_NOFOLLOW
,
mode
);
if
(
fd
==
-
1
)
return
(
void
)
fuse_reply_err
(
req
,
errno
);
fi
->
fh
=
fd
;
if
(
lo
->
cache
==
CACHE_NEVER
)
fi
->
direct_io
=
1
;
else
if
(
lo
->
cache
==
CACHE_ALWAYS
)
fi
->
keep_cache
=
1
;
/* parallel_direct_writes feature depends on direct_io features.
To make parallel_direct_writes valid, need set fi->direct_io
in current function. */
fi
->
parallel_direct_writes
=
1
;
err
=
lo_do_lookup
(
req
,
parent
,
name
,
&
e
);
if
(
err
)
fuse_reply_err
(
req
,
err
);
else
fuse_reply_create
(
req
,
&
e
,
fi
);
fuse_reply_create
(
req
,
&
e
,
fi
);
}
}
static
void
static
void
lo_fsyncdir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
int
datasync
,
opendir_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
struct
fuse_file_info
*
fi
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"opendir handler
\n
"
);
int
res
;
auto
*
inode
=
get_inode
(
ino
);
int
fd
=
dirfd
(
lo_dirp
(
fi
)
->
dp
);
if
(
!
inode
)
{
(
void
)
ino
;
fuse_reply_err
(
req
,
ENOTDIR
);
if
(
datasync
)
return
;
res
=
fdatasync
(
fd
);
else
res
=
fsync
(
fd
);
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
}
}
struct
stat
st
;
static
void
fuse_log
(
FUSE_LOG_DEBUG
,
"open dir %s
\n
"
,
inode
->
path
.
c_str
());
lo_open
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
if
(
gkfs
::
syscall
::
gkfs_stat
(
inode
->
path
,
&
st
)
!=
0
||
S_ISREG
(
st
.
st_mode
))
{
int
fd
;
fuse_reply_err
(
req
,
ENOTDIR
);
char
buf
[
64
];
return
;
struct
lo_data
*
lo
=
lo_data
(
req
);
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_open(ino=%"
PRIu64
", flags=%d)
\n
"
,
ino
,
fi
->
flags
);
/* With writeback cache, kernel may send read requests even
when userspace opened write-only */
if
(
lo
->
writeback
&&
(
fi
->
flags
&
O_ACCMODE
)
==
O_WRONLY
)
{
fi
->
flags
&=
~
O_ACCMODE
;
fi
->
flags
|=
O_RDWR
;
}
}
/* With writeback cache, O_APPEND is handled by the kernel.
const
int
fd
=
gkfs
::
syscall
::
gkfs_opendir
(
inode
->
path
);
This breaks atomicity (since the file may change in the
if
(
fd
<
0
)
{
underlying filesystem, so that the kernel's idea of the
fuse_reply_err
(
req
,
ENOTDIR
);
end of the file isn't accurate anymore). In this example,
return
;
we just accept that. A more rigorous filesystem may want
to return an error here */
if
(
lo
->
writeback
&&
(
fi
->
flags
&
O_APPEND
))
fi
->
flags
&=
~
O_APPEND
;
sprintf
(
buf
,
"/proc/self/fd/%i"
,
lo_fd
(
req
,
ino
));
fd
=
open
(
buf
,
fi
->
flags
&
~
O_NOFOLLOW
);
if
(
fd
==
-
1
)
return
(
void
)
fuse_reply_err
(
req
,
errno
);
fi
->
fh
=
fd
;
if
(
lo
->
cache
==
CACHE_NEVER
)
fi
->
direct_io
=
1
;
else
if
(
lo
->
cache
==
CACHE_ALWAYS
)
fi
->
keep_cache
=
1
;
/* Enable direct_io when open has flags O_DIRECT to enjoy the feature
parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
for writes to the same file in the kernel). */
if
(
fi
->
flags
&
O_DIRECT
)
fi
->
direct_io
=
1
;
/* parallel_direct_writes feature depends on direct_io features.
To make parallel_direct_writes valid, need set fi->direct_io
in current function. */
fi
->
parallel_direct_writes
=
1
;
fuse_reply_open
(
req
,
fi
);
}
}
static
void
// Simulate DIR structure for GekkoFS
lo_release
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
DIR
*
dirp
=
(
void
)
ino
;
static_cast
<
DIR
*>
(
malloc
(
sizeof
(
DIR
)
+
inode
->
path
.
length
()
+
1
));
// Approximate size for DIR and path
close
(
fi
->
fh
);
if
(
dirp
==
nullptr
)
{
fuse_reply_err
(
req
,
0
);
gkfs
::
syscall
::
gkfs_close
(
fd
);
// Clean up opened GekkoFS fd
fuse_reply_err
(
req
,
ENOMEM
);
return
;
}
}
static
void
GkfsDir
*
gkfs_dir
=
reinterpret_cast
<
GkfsDir
*>
(
dirp
);
lo_flush
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
gkfs_dir
->
fd
=
fd
;
int
res
;
gkfs_dir
->
path
=
strdup
(
inode
->
path
.
c_str
());
// strdup allocates memory
(
void
)
ino
;
if
(
!
gkfs_dir
->
path
)
{
res
=
close
(
dup
(
fi
->
fh
));
free
(
dirp
);
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
gkfs
::
syscall
::
gkfs_close
(
fd
);
fuse_reply_err
(
req
,
ENOMEM
);
return
;
}
}
static
void
fi
->
fh
=
(
uint64_t
)
dirp
;
// pointer trick
lo_fsync
(
fuse_req_t
req
,
fuse_ino_t
ino
,
int
datasync
,
fuse_reply_open
(
req
,
fi
);
struct
fuse_file_info
*
fi
)
{
int
res
;
(
void
)
ino
;
if
(
datasync
)
res
=
fdatasync
(
fi
->
fh
);
else
res
=
fsync
(
fi
->
fh
);
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
}
}
static
void
static
void
lo_
read
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
,
off_t
off
set
,
read
dir_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
,
off_t
off
,
struct
fuse_file_info
*
fi
)
{
struct
fuse_file_info
*
fi
)
{
struct
fuse_bufvec
buf
=
FUSE_BUFVEC_INIT
(
size
);
fuse_log
(
FUSE_LOG_DEBUG
,
"readdir handler
\n
"
);
auto
*
dir_ptr
=
reinterpret_cast
<
GkfsDir
*>
(
fi
->
fh
);
if
(
lo_debug
(
req
))
if
(
!
dir_ptr
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
fuse_reply_err
(
req
,
EBADF
);
"lo_read(ino=%"
PRIu64
", size=%zd, "
"off=%lu)
\n
"
,
ino
,
size
,
(
unsigned
long
)
offset
);
buf
.
buf
[
0
].
flags
=
(
enum
fuse_buf_flags
)(
FUSE_BUF_IS_FD
|
FUSE_BUF_FD_SEEK
);
buf
.
buf
[
0
].
fd
=
fi
->
fh
;
buf
.
buf
[
0
].
pos
=
offset
;
fuse_reply_data
(
req
,
&
buf
,
FUSE_BUF_SPLICE_MOVE
);
}
static
void
lo_write_buf
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_bufvec
*
in_buf
,
off_t
off
,
struct
fuse_file_info
*
fi
)
{
(
void
)
ino
;
ssize_t
res
;
struct
fuse_bufvec
out_buf
=
FUSE_BUFVEC_INIT
(
fuse_buf_size
(
in_buf
));
out_buf
.
buf
[
0
].
flags
=
(
enum
fuse_buf_flags
)(
FUSE_BUF_IS_FD
|
FUSE_BUF_FD_SEEK
);
out_buf
.
buf
[
0
].
fd
=
fi
->
fh
;
out_buf
.
buf
[
0
].
pos
=
off
;
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_write(ino=%"
PRIu64
", size=%zd, off=%lu)
\n
"
,
ino
,
out_buf
.
buf
[
0
].
size
,
(
unsigned
long
)
off
);
res
=
(
ssize_t
)
fuse_buf_copy
(
&
out_buf
,
in_buf
,
(
enum
fuse_buf_copy_flags
)
0
);
if
(
res
<
0
)
fuse_reply_err
(
req
,
-
res
);
else
fuse_reply_write
(
req
,
(
size_t
)
res
);
}
static
void
lo_statfs
(
fuse_req_t
req
,
fuse_ino_t
ino
)
{
int
res
;
struct
statvfs
stbuf
;
res
=
fstatvfs
(
lo_fd
(
req
,
ino
),
&
stbuf
);
if
(
res
==
-
1
)
fuse_reply_err
(
req
,
errno
);
else
fuse_reply_statfs
(
req
,
&
stbuf
);
}
static
void
lo_fallocate
(
fuse_req_t
req
,
fuse_ino_t
ino
,
int
mode
,
off_t
offset
,
off_t
length
,
struct
fuse_file_info
*
fi
)
{
int
err
;
(
void
)
ino
;
err
=
-
do_fallocate
(
fi
->
fh
,
mode
,
offset
,
length
);
fuse_reply_err
(
req
,
err
);
}
static
void
lo_flock
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
,
int
op
)
{
int
res
;
(
void
)
ino
;
res
=
flock
(
fi
->
fh
,
op
);
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
}
static
void
lo_getxattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
const
char
*
name
,
size_t
size
)
{
char
*
value
=
NULL
;
char
procname
[
64
];
struct
lo_inode
*
inode
=
lo_inode
(
req
,
ino
);
ssize_t
ret
;
int
saverr
;
saverr
=
ENOSYS
;
if
(
!
lo_data
(
req
)
->
xattr
)
goto
out
;
if
(
lo_debug
(
req
))
{
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_getxattr(ino=%"
PRIu64
", name=%s size=%zd)
\n
"
,
ino
,
name
,
size
);
}
sprintf
(
procname
,
"/proc/self/fd/%i"
,
inode
->
fd
);
if
(
size
)
{
value
=
(
char
*
)
malloc
(
size
);
if
(
!
value
)
goto
out_err
;
ret
=
getxattr
(
procname
,
name
,
value
,
size
);
if
(
ret
==
-
1
)
goto
out_err
;
saverr
=
0
;
if
(
ret
==
0
)
goto
out
;
fuse_reply_buf
(
req
,
value
,
ret
);
}
else
{
ret
=
getxattr
(
procname
,
name
,
NULL
,
0
);
if
(
ret
==
-
1
)
goto
out_err
;
fuse_reply_xattr
(
req
,
ret
);
}
out_free
:
free
(
value
);
return
;
return
;
out_err
:
saverr
=
errno
;
out
:
fuse_reply_err
(
req
,
saverr
);
goto
out_free
;
}
static
void
lo_listxattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
)
{
char
*
value
=
NULL
;
char
procname
[
64
];
struct
lo_inode
*
inode
=
lo_inode
(
req
,
ino
);
ssize_t
ret
;
int
saverr
;
saverr
=
ENOSYS
;
if
(
!
lo_data
(
req
)
->
xattr
)
goto
out
;
if
(
lo_debug
(
req
))
{
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_listxattr(ino=%"
PRIu64
", size=%zd)
\n
"
,
ino
,
size
);
}
}
sprintf
(
procname
,
"/proc/self/fd/%i"
,
inode
->
fd
);
auto
open_dir
=
CTX
->
file_map
()
->
get_dir
(
dir_ptr
->
fd
);
if
(
size
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"read dir %s
\n
"
,
open_dir
->
path
().
c_str
());
value
=
(
char
*
)
malloc
(
size
);
if
(
!
value
)
goto
out_err
;
ret
=
listxattr
(
procname
,
value
,
size
);
if
(
open_dir
==
nullptr
)
{
if
(
ret
==
-
1
)
fuse_reply_err
(
req
,
EBADF
);
goto
out_err
;
saverr
=
0
;
if
(
ret
==
0
)
goto
out
;
fuse_reply_buf
(
req
,
value
,
ret
);
}
else
{
ret
=
listxattr
(
procname
,
NULL
,
0
);
if
(
ret
==
-
1
)
goto
out_err
;
fuse_reply_xattr
(
req
,
ret
);
}
out_free
:
free
(
value
);
return
;
return
;
out_err
:
saverr
=
errno
;
out
:
fuse_reply_err
(
req
,
saverr
);
goto
out_free
;
}
}
static
void
// Allocate a buffer to accumulate entries
lo_setxattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
const
char
*
name
,
const
char
*
value
,
char
*
buf
=
static_cast
<
char
*>
(
malloc
(
size
));
size_t
size
,
int
flags
)
{
if
(
!
buf
)
{
char
procname
[
64
];
fuse_reply_err
(
req
,
ENOMEM
);
struct
lo_inode
*
inode
=
lo_inode
(
req
,
ino
);
return
;
ssize_t
ret
;
int
saverr
;
saverr
=
ENOSYS
;
if
(
!
lo_data
(
req
)
->
xattr
)
goto
out
;
if
(
lo_debug
(
req
))
{
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_setxattr(ino=%"
PRIu64
", name=%s value=%s size=%zd)
\n
"
,
ino
,
name
,
value
,
size
);
}
}
sprintf
(
procname
,
"/proc/self/fd/%i"
,
inode
->
fd
);
size_t
bytes_filled
=
0
;
off_t
pos
=
off
;
ret
=
setxattr
(
procname
,
name
,
value
,
size
,
flags
);
saverr
=
ret
==
-
1
?
errno
:
0
;
out
:
while
(
pos
<
open_dir
->
size
())
{
fuse_reply_err
(
req
,
saverr
);
auto
de
=
open_dir
->
getdent
(
pos
);
}
static
void
struct
stat
st
{};
lo_removexattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
const
char
*
name
)
{
// TODO cannot be right, right?
char
procname
[
64
];
st
.
st_ino
=
struct
lo_inode
*
inode
=
lo_inode
(
req
,
ino
);
std
::
hash
<
std
::
string
>
()(
open_dir
->
path
()
+
"/"
+
de
.
name
());
ssize_t
ret
;
st
.
st_mode
=
(
de
.
type
()
==
gkfs
::
filemap
::
FileType
::
regular
)
?
S_IFREG
int
saverr
;
:
S_IFDIR
;
saverr
=
ENOSYS
;
if
(
!
lo_data
(
req
)
->
xattr
)
goto
out
;
if
(
lo_debug
(
req
))
{
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_removexattr(ino=%"
PRIu64
", name=%s)
\n
"
,
ino
,
name
);
}
sprintf
(
procname
,
"/proc/self/fd/%i"
,
inode
->
fd
);
size_t
entry_size
=
fuse_add_direntry
(
req
,
buf
+
bytes_filled
,
size
-
bytes_filled
,
de
.
name
().
c_str
(),
&
st
,
pos
+
1
);
ret
=
removexattr
(
procname
,
name
);
if
(
entry_size
>
size
-
bytes_filled
)
saverr
=
ret
==
-
1
?
errno
:
0
;
break
;
// not enough space left
out
:
bytes_filled
+=
entry_size
;
fuse_reply_err
(
req
,
saverr
)
;
pos
+=
1
;
}
}
#ifdef HAVE_COPY_FILE_RANGE
open_dir
->
pos
(
pos
);
// update internal position if needed
static
void
lo_copy_file_range
(
fuse_req_t
req
,
fuse_ino_t
ino_in
,
off_t
off_in
,
struct
fuse_file_info
*
fi_in
,
fuse_ino_t
ino_out
,
off_t
off_out
,
struct
fuse_file_info
*
fi_out
,
size_t
len
,
int
flags
)
{
ssize_t
res
;
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
"lo_copy_file_range(ino=%"
PRIu64
"/fd=%lu, "
"off=%lu, ino=%"
PRIu64
"/fd=%lu, "
"off=%lu, size=%zd, flags=0x%x)
\n
"
,
ino_in
,
fi_in
->
fh
,
off_in
,
ino_out
,
fi_out
->
fh
,
off_out
,
len
,
flags
);
res
=
copy_file_range
(
fi_in
->
fh
,
&
off_in
,
fi_out
->
fh
,
&
off_out
,
len
,
flags
);
if
(
res
<
0
)
fuse_reply_err
(
req
,
errno
);
else
fuse_reply_write
(
req
,
res
);
}
#endif
static
void
fuse_reply_buf
(
req
,
buf
,
bytes_filled
);
lo_lseek
(
fuse_req_t
req
,
fuse_ino_t
ino
,
off_t
off
,
int
whence
,
free
(
buf
);
struct
fuse_file_info
*
fi
)
{
off_t
res
;
(
void
)
ino
;
res
=
lseek
(
fi
->
fh
,
off
,
whence
);
if
(
res
!=
-
1
)
fuse_reply_lseek
(
req
,
res
);
else
fuse_reply_err
(
req
,
errno
);
}
}
#ifdef HAVE_STATX
static
void
static
void
lo_statx
(
fuse_req_t
req
,
fuse_ino_t
ino
,
int
flags
,
int
mask
,
init_handler
(
void
*
userdata
,
struct
fuse_conn_info
*
conn
)
{
struct
fuse_file_info
*
fi
)
{
// userdata is GekkoFuse* if passed
struct
lo_data
*
lo
=
lo_data
(
req
);
// optional: adjust conn->max_write, enable writeback etc.
struct
statx
buf
;
int
res
;
int
fd
;
if
(
fi
)
fd
=
fi
->
fh
;
else
fd
=
lo_fd
(
req
,
ino
);
res
=
statx
(
fd
,
""
,
flags
|
AT_EMPTY_PATH
|
AT_SYMLINK_NOFOLLOW
,
mask
,
&
buf
);
if
(
res
==
-
1
)
fuse_reply_err
(
req
,
errno
);
else
fuse_reply_statx
(
req
,
0
,
&
buf
,
lo
->
timeout
);
}
}
#endif
static
const
struct
fuse_lowlevel_ops
lo_oper
=
{
static
const
struct
fuse_lowlevel_ops
lo_oper
=
{
.
init
=
lo_init
,
.
init
=
init_handler
,
//
lo_init,
.
destroy
=
lo_destroy
,
//
.destroy = lo_destroy,
.
lookup
=
lo_
lookup
,
.
lookup
=
lookup
_handler
,
.
forget
=
lo_forget
,
//
.forget = lo_forget,
.
getattr
=
lo_
getattr
,
.
getattr
=
getattr
_handler
,
.
setattr
=
lo_
setattr
,
.
setattr
=
setattr
_handler
,
.
readlink
=
lo_readlink
,
//
.readlink = lo_readlink,
.
mknod
=
lo_mknod
,
//
.mknod = lo_mknod,
.
mkdir
=
lo_mkdir
,
//
.mkdir = lo_mkdir,
.
unlink
=
lo_unlink
,
//
.unlink = lo_unlink,
.
rmdir
=
lo_rmdir
,
//
.rmdir = lo_rmdir,
.
symlink
=
lo_symlink
,
//
.symlink = lo_symlink,
.
rename
=
lo_rename
,
//
.rename = lo_rename,
.
link
=
lo_link
,
//
.link = lo_link,
.
open
=
lo_
open
,
.
open
=
open
_handler
,
.
read
=
lo_
read
,
.
read
=
read
_handler
,
// write
.
write
=
write_handler
,
.
flush
=
lo_flush
,
//
.flush = lo_flush,
.
release
=
lo_release
,
//
.release = lo_release,
.
fsync
=
lo_fsync
,
//
.fsync = lo_fsync,
.
opendir
=
lo_
opendir
,
.
opendir
=
opendir
_handler
,
.
readdir
=
lo_
readdir
,
.
readdir
=
readdir
_handler
,
.
releasedir
=
lo_releasedir
,
//
.releasedir = lo_releasedir,
.
fsyncdir
=
lo_fsyncdir
,
//
.fsyncdir = lo_fsyncdir,
.
statfs
=
lo_statfs
,
//
.statfs = lo_statfs,
.
setxattr
=
lo_setxattr
,
//
.setxattr = lo_setxattr,
.
getxattr
=
lo_getxattr
,
//
.getxattr = lo_getxattr,
.
listxattr
=
lo_listxattr
,
//
.listxattr = lo_listxattr,
.
removexattr
=
lo_removexattr
,
//
.removexattr = lo_removexattr,
// access
// access
.
create
=
lo_
create
,
.
create
=
create
_handler
,
// getlk
// getlk
// setlk
// setlk
// bmap
// bmap
// ioctl
// ioctl
.
write_buf
=
lo_write_buf
,
//
.write_buf = lo_write_buf,
// poll
// poll
// retrive_reply
// retrive_reply
.
forget_multi
=
lo_forget_multi
,
//
.forget_multi = lo_forget_multi,
.
flock
=
lo_flock
,
//
.flock = lo_flock,
.
fallocate
=
lo_fallocate
,
//
.fallocate = lo_fallocate,
.
readdirplus
=
lo_readdirplus
,
//
.readdirplus = lo_readdirplus,
#ifdef HAVE_COPY_FILE_RANGE
#ifdef HAVE_COPY_FILE_RANGE
.
copy_file_range
=
lo_copy_file_range
,
//
.copy_file_range = lo_copy_file_range,
#endif
#endif
.
lseek
=
lo_lseek
,
//
.lseek = lo_lseek,
.
tmpfile
=
lo_tmpfile
,
//
.tmpfile = lo_tmpfile,
#ifdef HAVE_STATX
#ifdef HAVE_STATX
.
statx
=
lo_statx
,
//
.statx = lo_statx,
#endif
#endif
};
};
...
@@ -1212,6 +532,32 @@ main(int argc, char* argv[]) {
...
@@ -1212,6 +532,32 @@ main(int argc, char* argv[]) {
lo
.
root
.
fd
=
-
1
;
lo
.
root
.
fd
=
-
1
;
lo
.
cache
=
CACHE_NORMAL
;
lo
.
cache
=
CACHE_NORMAL
;
// init gekkofs
// TODO how to handle mount point
int
res
=
gkfs_init
();
if
(
res
!=
0
)
{
printf
(
"FUSE client failed to connect to gkfs daemon. Exit."
);
exit
(
1
);
}
auto
fl
=
gkfs
::
syscall
::
gkfs_get_file_list
(
"/"
);
for
(
std
::
string
s
:
fl
)
{
std
::
cout
<<
s
<<
std
::
endl
;
}
std
::
string
root_path
=
"/"
;
struct
stat
st
;
int
rc
=
gkfs
::
syscall
::
gkfs_stat
(
root_path
,
&
st
);
if
(
rc
<
0
)
{
fuse_log
(
FUSE_LOG_ERR
,
"failed to open root
\n
"
);
exit
(
1
);
}
ino_map
[
FUSE_ROOT_ID
]
=
{
root_path
,
{},
1
};
ino_map
[
FUSE_ROOT_ID
].
st
=
st
;
std
::
cout
<<
"root node allocated"
<<
std
::
endl
;
if
(
fuse_parse_cmdline
(
&
args
,
&
opts
)
!=
0
)
if
(
fuse_parse_cmdline
(
&
args
,
&
opts
)
!=
0
)
return
1
;
return
1
;
if
(
opts
.
show_help
)
{
if
(
opts
.
show_help
)
{
...
@@ -1281,12 +627,14 @@ main(int argc, char* argv[]) {
...
@@ -1281,12 +627,14 @@ main(int argc, char* argv[]) {
exit
(
1
);
exit
(
1
);
}
}
lo
.
root
.
fd
=
open
(
lo
.
source
,
O_PATH
);
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 1
\n
"
);
lo
.
root
.
fd
=
gkfs
::
syscall
::
gkfs_open
(
lo
.
source
,
755
,
O_PATH
);
if
(
lo
.
root
.
fd
==
-
1
)
{
if
(
lo
.
root
.
fd
==
-
1
)
{
fuse_log
(
FUSE_LOG_ERR
,
"open(
\"
%s
\"
, O_PATH): %m
\n
"
,
lo
.
source
);
fuse_log
(
FUSE_LOG_ERR
,
"open(
\"
%s
\"
, O_PATH): %m
\n
"
,
lo
.
source
);
exit
(
1
);
exit
(
1
);
}
}
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 2
\n
"
);
se
=
fuse_session_new
(
&
args
,
&
lo_oper
,
sizeof
(
lo_oper
),
&
lo
);
se
=
fuse_session_new
(
&
args
,
&
lo_oper
,
sizeof
(
lo_oper
),
&
lo
);
if
(
se
==
NULL
)
if
(
se
==
NULL
)
goto
err_out1
;
goto
err_out1
;
...
@@ -1313,10 +661,13 @@ main(int argc, char* argv[]) {
...
@@ -1313,10 +661,13 @@ main(int argc, char* argv[]) {
fuse_session_unmount
(
se
);
fuse_session_unmount
(
se
);
err_out3
:
err_out3
:
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 3
\n
"
);
fuse_remove_signal_handlers
(
se
);
fuse_remove_signal_handlers
(
se
);
err_out2
:
err_out2
:
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 4
\n
"
);
fuse_session_destroy
(
se
);
fuse_session_destroy
(
se
);
err_out1
:
err_out1
:
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 5
\n
"
);
free
(
opts
.
mountpoint
);
free
(
opts
.
mountpoint
);
fuse_opt_free_args
(
&
args
);
fuse_opt_free_args
(
&
args
);
...
...
src/client/gkfs_functions.cpp
View file @
9936cd50
...
@@ -185,7 +185,7 @@ test_lock_file(const std::string& path) {
...
@@ -185,7 +185,7 @@ test_lock_file(const std::string& path) {
* @param path
* @param path
* @param mode
* @param mode
* @param flags
* @param flags
* @return
0
on success, -1 on failure
* @return
fd
on success, -1 on failure
*/
*/
int
int
gkfs_open
(
const
std
::
string
&
path
,
mode_t
mode
,
int
flags
)
{
gkfs_open
(
const
std
::
string
&
path
,
mode_t
mode
,
int
flags
)
{
...
@@ -1451,7 +1451,7 @@ gkfs_readv(int fd, const struct iovec* iov, int iovcnt) {
...
@@ -1451,7 +1451,7 @@ gkfs_readv(int fd, const struct iovec* iov, int iovcnt) {
* wrapper function for opening directories
* wrapper function for opening directories
* errno may be set
* errno may be set
* @param path
* @param path
* @return
0
on success or -1 on error
* @return
fd
on success or -1 on error
*/
*/
int
int
gkfs_opendir
(
const
std
::
string
&
path
)
{
gkfs_opendir
(
const
std
::
string
&
path
)
{
...
...
src/client/rpc/forward_metadata.cpp
View file @
9936cd50
...
@@ -664,7 +664,7 @@ forward_get_metadentry_size(const std::string& path, const int copy) {
...
@@ -664,7 +664,7 @@ forward_get_metadentry_size(const std::string& path, const int copy) {
/**
/**
* Send an RPC request to receive all entries of a directory.
* Send an RPC request to receive all entries of a directory.
* @param open_dir
* @param open_dir
* @return error code
* @return error code
, OpenDir
*/
*/
pair
<
int
,
shared_ptr
<
gkfs
::
filemap
::
OpenDir
>>
pair
<
int
,
shared_ptr
<
gkfs
::
filemap
::
OpenDir
>>
forward_get_dirents
(
const
string
&
path
)
{
forward_get_dirents
(
const
string
&
path
)
{
...
...