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
#define GKFS_CLIENT_FUSE_CONTEXT_HPP
#include
"fuse_log.h"
#include
<utility>
extern
"C"
{
#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
#include
<fuse3/fuse_lowlevel.h>
...
...
@@ -37,42 +78,32 @@ struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
};
#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
<fcntl.h>
#include
<string.h>
#include
<sys/stat.h>
#include
<unistd.h>
#include
<filesystem>
#include
<unordered_map>
#include
<string>
#include
<mutex>
#ifdef __FreeBSD__
#include
<sys/socket.h>
#include
<sys/un.h>
#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
do_fallocate
(
int
fd
,
int
mode
,
off_t
offset
,
off_t
length
)
{
#ifdef HAVE_FALLOCATE
...
...
@@ -103,6 +134,142 @@ do_fallocate(int fd, int mode, off_t offset, off_t length) {
#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
* operation
...
...
@@ -110,18 +277,28 @@ do_fallocate(int fd, int mode, off_t offset, off_t length) {
static
inline
int
mknod_wrapper
(
int
dirfd
,
const
char
*
path
,
const
char
*
link
,
int
mode
,
dev_t
rdev
)
{
int
res
;
fuse_log
(
FUSE_LOG_DEBUG
,
"mknod_wrapper
\n
"
);
int
res
=
-
1
;
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
)
res
=
close
(
res
);
res
=
gkfs
::
syscall
::
gkfs_
close
(
res
);
}
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
)
{
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
))
{
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__
}
else
if
(
S_ISSOCK
(
mode
))
{
struct
sockaddr_un
su
;
...
...
@@ -148,7 +325,10 @@ mknod_wrapper(int dirfd, const char* path, const char* link, int mode,
}
#endif
}
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
;
...
...
src/client/CMakeLists.txt
View file @
9936cd50
...
...
@@ -118,8 +118,10 @@ target_sources(fuse_client
)
target_link_libraries
(
fuse_client
PRIVATE gkfs_common metadata distributor env_util arithmetic path_util rpc_utils
${
FUSE3_LIBRARIES
}
gkfs_user_lib
gkfs_libc_intercept
)
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
<cstdio>
#include
<cstdlib>
#include
<dirent.h>
#include
<iostream>
struct
lo_inode
{
struct
lo_inode
*
next
;
/* protected by lo->mutex */
...
...
@@ -85,6 +131,7 @@ lo_debug(fuse_req_t req) {
static
void
lo_init
(
void
*
userdata
,
struct
fuse_conn_info
*
conn
)
{
// TODO init gkfs
struct
lo_data
*
lo
=
(
struct
lo_data
*
)
userdata
;
bool
has_flag
;
...
...
@@ -103,1095 +150,368 @@ lo_init(void* userdata, struct fuse_conn_info* conn) {
conn
->
no_interrupt
=
1
;
}
static
void
lo_destroy
(
void
*
userdata
)
{
struct
lo_data
*
lo
=
(
struct
lo_data
*
)
userdata
;
while
(
lo
->
root
.
next
!=
&
lo
->
root
)
{
struct
lo_inode
*
next
=
lo
->
root
.
next
;
lo
->
root
.
next
=
next
->
next
;
close
(
next
->
fd
);
free
(
next
);
}
}
static
void
lo_getattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
int
res
;
struct
stat
buf
;
struct
lo_data
*
lo
=
lo_data
(
req
);
int
fd
=
fi
?
fi
->
fh
:
lo_fd
(
req
,
ino
);
(
void
)
fi
;
res
=
fstatat
(
fd
,
""
,
&
buf
,
AT_EMPTY_PATH
|
AT_SYMLINK_NOFOLLOW
);
if
(
res
==
-
1
)
return
(
void
)
fuse_reply_err
(
req
,
errno
);
fuse_reply_attr
(
req
,
&
buf
,
lo
->
timeout
);
}
static
void
lo_setattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
stat
*
attr
,
int
valid
,
struct
fuse_file_info
*
fi
)
{
int
saverr
;
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
;
// Simplified inode structure
struct
Inode
{
std
::
string
path
;
struct
stat
st
;
uint64_t
lookup_count
;
};
static
std
::
mutex
ino_mutex
;
static
std
::
unordered_map
<
fuse_ino_t
,
Inode
>
ino_map
;
static
fuse_ino_t
next_ino
=
2
;
// reserve 1 for root
static
fuse_ino_t
alloc_inode
(
const
std
::
string
&
path
)
{
std
::
lock_guard
<
std
::
mutex
>
lk
(
ino_mutex
);
fuse_ino_t
ino
=
next_ino
++
;
ino_map
[
ino
]
=
{
path
,
{},
1
};
return
ino
;
}
static
Inode
*
get_inode
(
fuse_ino_t
ino
)
{
std
::
lock_guard
<
std
::
mutex
>
lk
(
ino_mutex
);
auto
it
=
ino_map
.
find
(
ino
);
return
it
!=
ino_map
.
end
()
?
&
it
->
second
:
nullptr
;
}
static
void
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
);
if
(
!
parent_inode
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"this error 1
\n
"
,
parent
);
fuse_reply_err
(
req
,
ENOENT
);
return
;
}
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
);
return
0
;
out_err
:
saverr
=
errno
;
if
(
newfd
!=
-
1
)
close
(
newfd
);
return
saverr
;
std
::
string
child
=
parent_inode
->
path
+
name
;
fuse_log
(
FUSE_LOG_DEBUG
,
"lookup %s
\n
"
,
child
.
c_str
());
struct
stat
st
;
int
rc
=
gkfs
::
syscall
::
gkfs_stat
(
child
,
&
st
);
if
(
rc
<
0
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"that error 2
\n
"
,
parent
);
fuse_reply_err
(
req
,
ENOENT
);
return
;
}
static
void
lo_lookup
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
)
{
struct
fuse_entry_param
e
;
int
err
;
if
(
lo_debug
(
req
))
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_ino_t
ino
=
alloc_inode
(
child
);
ino_map
[
ino
].
st
=
st
;
fuse_entry_param
e
=
{};
e
.
ino
=
ino
;
e
.
attr
=
st
;
e
.
attr_timeout
=
1.0
;
e
.
entry_timeout
=
1.0
;
fuse_reply_entry
(
req
,
&
e
);
}
static
void
lo_mknod_symlink
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
mode_t
mode
,
dev_t
rdev
,
const
char
*
link
)
{
int
res
;
int
saverr
;
struct
lo_inode
*
dir
=
lo_inode
(
req
,
parent
);
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
);
getattr_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"getattr handler
\n
"
);
auto
*
inode
=
get_inode
(
ino
);
if
(
!
inode
)
{
fuse_reply_err
(
req
,
ENOENT
);
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
);
}
static
void
lo_mkdir
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
mode_t
mode
)
{
lo_mknod_symlink
(
req
,
parent
,
name
,
S_IFDIR
|
mode
,
0
,
NULL
);
}
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
);
// query GekkoFS for latest attr
struct
stat
st
;
int
rc
=
gkfs
::
syscall
::
gkfs_stat
(
inode
->
path
,
&
st
);
if
(
rc
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"getattr error %u
\n
"
,
rc
);
fuse_reply_err
(
req
,
ENOENT
);
return
;
out_err:
saverr
=
errno
;
fuse_reply_err
(
req
,
saverr
);
}
static
void
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
);
inode
->
st
=
st
;
fuse_reply_attr
(
req
,
&
st
,
1.0
);
}
static
void
lo_rename
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
fuse_ino_t
newparent
,
const
char
*
newname
,
unsigned
int
flags
)
{
int
res
;
if
(
flags
)
{
fuse_reply_err
(
req
,
E
INVAL
);
setattr_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
stat
*
attr
,
int
to_set
,
struct
fuse_file_info
*
fi
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"setattr handler
\n
"
)
;
auto
*
inode
=
get_inode
(
ino
);
if
(
!
inode
)
{
fuse_reply_err
(
req
,
E
NOENT
);
return
;
}
res
=
renameat
(
lo_fd
(
req
,
parent
),
name
,
lo_fd
(
req
,
newparent
),
newname
);
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
}
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
)
// TODO how to change attr?
int
rc
=
0
;
if
(
rc
)
{
fuse_reply_err
(
req
,
rc
);
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
;
}
static
void
lo_forget_one
(
fuse_req_t
req
,
fuse_ino_t
ino
,
uint64_t
nlookup
)
{
struct
lo_data
*
lo
=
lo_data
(
req
);
struct
lo_inode
*
inode
=
lo_inode
(
req
,
ino
);
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
);
const
int
mode
=
0644
;
// -rw-r--r-- I think that doesnt matter anyway
int
fd
=
gkfs
::
syscall
::
gkfs_open
(
inode
->
path
,
mode
,
fi
->
flags
);
// TODO mode!
if
(
fd
<
0
)
{
fuse_reply_err
(
req
,
ENOENT
);
return
;
}
static
void
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
);
fi
->
fh
=
fd
;
// TODO file handle == file descriptor?
fuse_reply_open
(
req
,
fi
);
}
static
void
lo_readlink
(
fuse_req_t
req
,
fuse_ino_t
ino
)
{
char
buf
[
PATH_MAX
+
1
];
int
res
;
res
=
readlinkat
(
lo_fd
(
req
,
ino
),
""
,
buf
,
sizeof
(
buf
));
if
(
res
==
-
1
)
return
(
void
)
fuse_reply_err
(
req
,
errno
);
if
(
res
==
sizeof
(
buf
))
return
(
void
)
fuse_reply_err
(
req
,
ENAMETOOLONG
);
buf
[
res
]
=
'\0'
;
fuse_reply_readlink
(
req
,
buf
);
read_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
,
off_t
off
,
struct
fuse_file_info
*
fi
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"read handler
\n
"
);
auto
*
inode
=
get_inode
(
ino
);
if
(
!
inode
)
{
fuse_reply_err
(
req
,
ENOENT
);
return
;
}
struct
lo_dirp
{
DIR
*
dp
;
struct
dirent
*
entry
;
off_t
offset
;
};
static
struct
lo_dirp
*
lo_dirp
(
struct
fuse_file_info
*
fi
)
{
return
(
struct
lo_dirp
*
)
(
uintptr_t
)
fi
->
fh
;
std
::
vector
<
char
>
buf
(
size
);
int
lc
=
gkfs
::
syscall
::
gkfs_lseek
(
fi
->
fh
,
off
,
SEEK_SET
);
if
(
lc
<
0
)
{
fuse_reply_err
(
req
,
1
);
return
;
}
static
void
lo_opendir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
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
);
int
rc
=
gkfs
::
syscall
::
gkfs_read
(
fi
->
fh
,
buf
.
data
(),
size
);
if
(
rc
<
0
)
{
fuse_reply_err
(
req
,
1
);
return
;
out_errno:
error
=
errno
;
out_err:
if
(
d
)
{
if
(
fd
!=
-
1
)
close
(
fd
);
free
(
d
);
}
fuse_reply_err
(
req
,
error
);
}
static
int
is_dot_or_dotdot
(
const
char
*
name
)
{
return
name
[
0
]
==
'.'
&&
(
name
[
1
]
==
'\0'
||
(
name
[
1
]
==
'.'
&&
name
[
2
]
==
'\0'
));
fuse_reply_buf
(
req
,
buf
.
data
(),
rc
);
}
static
void
lo_do_readdir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
size_t
size
,
off_t
offset
,
struct
fuse_file_info
*
fi
,
int
plus
)
{
struct
lo_dirp
*
d
=
lo_dirp
(
fi
);
char
*
buf
;
char
*
p
;
size_t
rem
=
size
;
int
err
;
(
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
);
write_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
const
char
*
buf
,
size_t
size
,
off_t
off
,
struct
fuse_file_info
*
fi
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"write handler
\n
"
);
auto
*
inode
=
get_inode
(
ino
);
if
(
!
inode
)
{
fuse_reply_err
(
req
,
ENOENT
);
return
;
}
if
(
entsize
>
rem
)
{
if
(
entry_ino
!=
0
)
lo_forget_one
(
req
,
entry_ino
,
1
);
break
;
int
lc
=
gkfs
::
syscall
::
gkfs_lseek
(
fi
->
fh
,
off
,
SEEK_SET
);
if
(
lc
<
0
)
{
fuse_reply_err
(
req
,
1
);
return
;
}
p
+=
entsize
;
rem
-=
entsize
;
d
->
entry
=
NULL
;
d
->
offset
=
nextoff
;
int
rc
=
gkfs
::
syscall
::
gkfs_write
(
fi
->
fh
,
buf
,
size
);
if
(
rc
<
0
)
{
fuse_reply_err
(
req
,
1
);
return
;
}
err
=
0
;
error
:
// 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
);
if
(
rc
<
0
)
{
fuse_reply_err
(
req
,
1
);
return
;
}
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
);
fuse_reply_write
(
req
,
rc
);
}
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
)
{
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
;
}
static
void
lo_releasedir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
struct
lo_dirp
*
d
=
lo_dirp
(
fi
);
(
void
)
ino
;
closedir
(
d
->
dp
);
free
(
d
);
fuse_reply_err
(
req
,
0
);
std
::
string
path
=
parent_inode
->
path
+
name
;
int
rc
=
gkfs
::
syscall
::
gkfs_create
(
path
,
mode
);
if
(
rc
==
-
1
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"here here mode %i flags %i
\n
"
,
mode
,
fi
->
flags
);
fuse_reply_err
(
req
,
1
);
return
;
}
static
void
lo_tmpfile
(
fuse_req_t
req
,
fuse_ino_t
parent
,
mode_t
mode
,
struct
fuse_file_info
*
fi
)
{
int
fd
;
struct
lo_data
*
lo
=
lo_data
(
req
);
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
);
struct
stat
st
;
int
sc
=
gkfs
::
syscall
::
gkfs_stat
(
path
,
&
st
);
if
(
sc
==
-
1
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"thats why its not allowed
\n
"
);
fuse_reply_err
(
req
,
1
);
return
;
}
static
void
lo_create
(
fuse_req_t
req
,
fuse_ino_t
parent
,
const
char
*
name
,
mode_t
mode
,
struct
fuse_file_info
*
fi
)
{
int
fd
;
struct
lo_data
*
lo
=
lo_data
(
req
);
struct
fuse_entry_param
e
;
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_ino_t
ino
=
alloc_inode
(
path
);
ino_map
[
ino
].
st
=
st
;
fuse_entry_param
e
=
{};
e
.
ino
=
ino
;
e
.
attr
=
st
;
e
.
attr_timeout
=
1.0
;
e
.
entry_timeout
=
1.0
;
fuse_reply_create
(
req
,
&
e
,
fi
);
}
static
void
lo_fsyncdir
(
fuse_req_t
req
,
fuse_ino_t
ino
,
int
datasync
,
struct
fuse_file_info
*
fi
)
{
int
res
;
int
fd
=
dirfd
(
lo_dirp
(
fi
)
->
dp
);
(
void
)
ino
;
if
(
datasync
)
res
=
fdatasync
(
fd
);
else
res
=
fsync
(
fd
);
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
opendir_handler
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
fuse_log
(
FUSE_LOG_DEBUG
,
"opendir handler
\n
"
);
auto
*
inode
=
get_inode
(
ino
);
if
(
!
inode
)
{
fuse_reply_err
(
req
,
ENOTDIR
);
return
;
}
static
void
lo_open
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
int
fd
;
char
buf
[
64
];
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
;
struct
stat
st
;
fuse_log
(
FUSE_LOG_DEBUG
,
"open dir %s
\n
"
,
inode
->
path
.
c_str
());
if
(
gkfs
::
syscall
::
gkfs_stat
(
inode
->
path
,
&
st
)
!=
0
||
S_ISREG
(
st
.
st_mode
))
{
fuse_reply_err
(
req
,
ENOTDIR
);
return
;
}
/* With writeback cache, O_APPEND is handled by the kernel.
This breaks atomicity (since the file may change in the
underlying filesystem, so that the kernel's idea of the
end of the file isn't accurate anymore). In this example,
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
);
const
int
fd
=
gkfs
::
syscall
::
gkfs_opendir
(
inode
->
path
);
if
(
fd
<
0
)
{
fuse_reply_err
(
req
,
ENOTDIR
);
return
;
}
static
void
lo_release
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
(
void
)
ino
;
close
(
fi
->
fh
);
fuse_reply_err
(
req
,
0
);
// Simulate DIR structure for GekkoFS
DIR
*
dirp
=
static_cast
<
DIR
*>
(
malloc
(
sizeof
(
DIR
)
+
inode
->
path
.
length
()
+
1
));
// Approximate size for DIR and path
if
(
dirp
==
nullptr
)
{
gkfs
::
syscall
::
gkfs_close
(
fd
);
// Clean up opened GekkoFS fd
fuse_reply_err
(
req
,
ENOMEM
);
return
;
}
static
void
lo_flush
(
fuse_req_t
req
,
fuse_ino_t
ino
,
struct
fuse_file_info
*
fi
)
{
int
res
;
(
void
)
ino
;
res
=
close
(
dup
(
fi
->
fh
));
fuse_reply_err
(
req
,
res
==
-
1
?
errno
:
0
);
GkfsDir
*
gkfs_dir
=
reinterpret_cast
<
GkfsDir
*>
(
dirp
);
gkfs_dir
->
fd
=
fd
;
gkfs_dir
->
path
=
strdup
(
inode
->
path
.
c_str
());
// strdup allocates memory
if
(
!
gkfs_dir
->
path
)
{
free
(
dirp
);
gkfs
::
syscall
::
gkfs_close
(
fd
);
fuse_reply_err
(
req
,
ENOMEM
);
return
;
}
static
void
lo_fsync
(
fuse_req_t
req
,
fuse_ino_t
ino
,
int
datasync
,
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
);
fi
->
fh
=
(
uint64_t
)
dirp
;
// pointer trick
fuse_reply_open
(
req
,
fi
);
}
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_bufvec
buf
=
FUSE_BUFVEC_INIT
(
size
);
if
(
lo_debug
(
req
))
fuse_log
(
FUSE_LOG_DEBUG
,
"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
);
fuse_log
(
FUSE_LOG_DEBUG
,
"readdir handler
\n
"
);
auto
*
dir_ptr
=
reinterpret_cast
<
GkfsDir
*>
(
fi
->
fh
);
if
(
!
dir_ptr
)
{
fuse_reply_err
(
req
,
EBADF
);
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
)
{
value
=
(
char
*
)
malloc
(
size
);
if
(
!
value
)
goto
out_err
;
fuse_log
(
FUSE_LOG_DEBUG
,
"read dir %s
\n
"
,
open_dir
->
path
().
c_str
());
ret
=
listxattr
(
procname
,
value
,
size
);
if
(
ret
==
-
1
)
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
);
if
(
open_dir
==
nullptr
)
{
fuse_reply_err
(
req
,
EBADF
);
return
;
out_err
:
saverr
=
errno
;
out
:
fuse_reply_err
(
req
,
saverr
);
goto
out_free
;
}
static
void
lo_setxattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
const
char
*
name
,
const
char
*
value
,
size_t
size
,
int
flags
)
{
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_setxattr(ino=%"
PRIu64
", name=%s value=%s size=%zd)
\n
"
,
ino
,
name
,
value
,
size
);
// Allocate a buffer to accumulate entries
char
*
buf
=
static_cast
<
char
*>
(
malloc
(
size
));
if
(
!
buf
)
{
fuse_reply_err
(
req
,
ENOMEM
);
return
;
}
sprintf
(
procname
,
"/proc/self/fd/%i"
,
inode
->
fd
);
ret
=
setxattr
(
procname
,
name
,
value
,
size
,
flags
);
saverr
=
ret
==
-
1
?
errno
:
0
;
size_t
bytes_filled
=
0
;
off_t
pos
=
off
;
out
:
fuse_reply_err
(
req
,
saverr
);
}
while
(
pos
<
open_dir
->
size
())
{
auto
de
=
open_dir
->
getdent
(
pos
);
static
void
lo_removexattr
(
fuse_req_t
req
,
fuse_ino_t
ino
,
const
char
*
name
)
{
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_removexattr(ino=%"
PRIu64
", name=%s)
\n
"
,
ino
,
name
);
}
struct
stat
st
{};
// TODO cannot be right, right?
st
.
st_ino
=
std
::
hash
<
std
::
string
>
()(
open_dir
->
path
()
+
"/"
+
de
.
name
());
st
.
st_mode
=
(
de
.
type
()
==
gkfs
::
filemap
::
FileType
::
regular
)
?
S_IFREG
:
S_IFDIR
;
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
);
saverr
=
ret
==
-
1
?
errno
:
0
;
if
(
entry_size
>
size
-
bytes_filled
)
break
;
// not enough space left
out
:
fuse_reply_err
(
req
,
saverr
)
;
bytes_filled
+=
entry_size
;
pos
+=
1
;
}
#ifdef HAVE_COPY_FILE_RANGE
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
open_dir
->
pos
(
pos
);
// update internal position if needed
static
void
lo_lseek
(
fuse_req_t
req
,
fuse_ino_t
ino
,
off_t
off
,
int
whence
,
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
);
fuse_reply_buf
(
req
,
buf
,
bytes_filled
);
free
(
buf
);
}
#ifdef HAVE_STATX
static
void
lo_statx
(
fuse_req_t
req
,
fuse_ino_t
ino
,
int
flags
,
int
mask
,
struct
fuse_file_info
*
fi
)
{
struct
lo_data
*
lo
=
lo_data
(
req
);
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
);
init_handler
(
void
*
userdata
,
struct
fuse_conn_info
*
conn
)
{
// userdata is GekkoFuse* if passed
// optional: adjust conn->max_write, enable writeback etc.
}
#endif
static
const
struct
fuse_lowlevel_ops
lo_oper
=
{
.
init
=
lo_init
,
.
destroy
=
lo_destroy
,
.
lookup
=
lo_
lookup
,
.
forget
=
lo_forget
,
.
getattr
=
lo_
getattr
,
.
setattr
=
lo_
setattr
,
.
readlink
=
lo_readlink
,
.
mknod
=
lo_mknod
,
.
mkdir
=
lo_mkdir
,
.
unlink
=
lo_unlink
,
.
rmdir
=
lo_rmdir
,
.
symlink
=
lo_symlink
,
.
rename
=
lo_rename
,
.
link
=
lo_link
,
.
open
=
lo_
open
,
.
read
=
lo_
read
,
// write
.
flush
=
lo_flush
,
.
release
=
lo_release
,
.
fsync
=
lo_fsync
,
.
opendir
=
lo_
opendir
,
.
readdir
=
lo_
readdir
,
.
releasedir
=
lo_releasedir
,
.
fsyncdir
=
lo_fsyncdir
,
.
statfs
=
lo_statfs
,
.
setxattr
=
lo_setxattr
,
.
getxattr
=
lo_getxattr
,
.
listxattr
=
lo_listxattr
,
.
removexattr
=
lo_removexattr
,
.
init
=
init_handler
,
//
lo_init,
//
.destroy = lo_destroy,
.
lookup
=
lookup
_handler
,
//
.forget = lo_forget,
.
getattr
=
getattr
_handler
,
.
setattr
=
setattr
_handler
,
//
.readlink = lo_readlink,
//
.mknod = lo_mknod,
//
.mkdir = lo_mkdir,
//
.unlink = lo_unlink,
//
.rmdir = lo_rmdir,
//
.symlink = lo_symlink,
//
.rename = lo_rename,
//
.link = lo_link,
.
open
=
open
_handler
,
.
read
=
read
_handler
,
.
write
=
write_handler
,
//
.flush = lo_flush,
//
.release = lo_release,
//
.fsync = lo_fsync,
.
opendir
=
opendir
_handler
,
.
readdir
=
readdir
_handler
,
//
.releasedir = lo_releasedir,
//
.fsyncdir = lo_fsyncdir,
//
.statfs = lo_statfs,
//
.setxattr = lo_setxattr,
//
.getxattr = lo_getxattr,
//
.listxattr = lo_listxattr,
//
.removexattr = lo_removexattr,
// access
.
create
=
lo_
create
,
.
create
=
create
_handler
,
// getlk
// setlk
// bmap
// ioctl
.
write_buf
=
lo_write_buf
,
//
.write_buf = lo_write_buf,
// poll
// retrive_reply
.
forget_multi
=
lo_forget_multi
,
.
flock
=
lo_flock
,
.
fallocate
=
lo_fallocate
,
.
readdirplus
=
lo_readdirplus
,
//
.forget_multi = lo_forget_multi,
//
.flock = lo_flock,
//
.fallocate = lo_fallocate,
//
.readdirplus = lo_readdirplus,
#ifdef HAVE_COPY_FILE_RANGE
.
copy_file_range
=
lo_copy_file_range
,
//
.copy_file_range = lo_copy_file_range,
#endif
.
lseek
=
lo_lseek
,
.
tmpfile
=
lo_tmpfile
,
//
.lseek = lo_lseek,
//
.tmpfile = lo_tmpfile,
#ifdef HAVE_STATX
.
statx
=
lo_statx
,
//
.statx = lo_statx,
#endif
};
...
...
@@ -1212,6 +532,32 @@ main(int argc, char* argv[]) {
lo
.
root
.
fd
=
-
1
;
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
)
return
1
;
if
(
opts
.
show_help
)
{
...
...
@@ -1281,12 +627,14 @@ main(int argc, char* argv[]) {
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
)
{
fuse_log
(
FUSE_LOG_ERR
,
"open(
\"
%s
\"
, O_PATH): %m
\n
"
,
lo
.
source
);
exit
(
1
);
}
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 2
\n
"
);
se
=
fuse_session_new
(
&
args
,
&
lo_oper
,
sizeof
(
lo_oper
),
&
lo
);
if
(
se
==
NULL
)
goto
err_out1
;
...
...
@@ -1313,10 +661,13 @@ main(int argc, char* argv[]) {
fuse_session_unmount
(
se
);
err_out3
:
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 3
\n
"
);
fuse_remove_signal_handlers
(
se
);
err_out2
:
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 4
\n
"
);
fuse_session_destroy
(
se
);
err_out1
:
fuse_log
(
FUSE_LOG_DEBUG
,
"hier 5
\n
"
);
free
(
opts
.
mountpoint
);
fuse_opt_free_args
(
&
args
);
...
...
src/client/gkfs_functions.cpp
View file @
9936cd50
...
...
@@ -185,7 +185,7 @@ test_lock_file(const std::string& path) {
* @param path
* @param mode
* @param flags
* @return
0
on success, -1 on failure
* @return
fd
on success, -1 on failure
*/
int
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) {
* wrapper function for opening directories
* errno may be set
* @param path
* @return
0
on success or -1 on error
* @return
fd
on success or -1 on error
*/
int
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) {
/**
* Send an RPC request to receive all entries of a directory.
* @param open_dir
* @return error code
* @return error code
, OpenDir
*/
pair
<
int
,
shared_ptr
<
gkfs
::
filemap
::
OpenDir
>>
forward_get_dirents
(
const
string
&
path
)
{
...
...