Browse Source

Rework movefile and cow break to use copyfile (#1488)

pull/1489/head
trapexit 3 months ago
committed by GitHub
parent
commit
e216a81a27
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 7
      src/fs_attr.hpp
  2. 39
      src/fs_attr_linux.icpp
  3. 86
      src/fs_clonefile.cpp
  4. 25
      src/fs_clonefile.hpp
  5. 13
      src/fs_copydata.cpp
  6. 36
      src/fs_copydata_copy_file_range.cpp
  7. 7
      src/fs_copydata_copy_file_range.hpp
  8. 52
      src/fs_copydata_readwrite.cpp
  9. 6
      src/fs_copydata_readwrite.hpp
  10. 120
      src/fs_copyfile.cpp
  11. 19
      src/fs_copyfile.hpp
  12. 79
      src/fs_cow.cpp
  13. 58
      src/fs_fcntl.hpp
  14. 36
      src/fs_file_unchanged.hpp
  15. 180
      src/fs_movefile.cpp
  16. 147
      src/fs_movefile_and_open.cpp
  17. 12
      src/fs_movefile_and_open.hpp
  18. 2
      src/fsck_mergerfs.cpp
  19. 8
      src/fuse_write.cpp

7
src/fs_attr.hpp

@ -18,13 +18,18 @@
#include <string>
#include "int_types.h"
#define FS_ATTR_NONE (0)
#define FS_ATTR_CLEAR_IMMUTABLE (1 << 0)
namespace fs
{
namespace attr
{
int copy(const int fdin,
const int fdout);
const int fdout,
const u32 flags);
int copy(const std::string &from,
const std::string &to);
}

39
src/fs_attr_linux.icpp

@ -14,6 +14,8 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "fs_attr.hpp"
#include "errno.hpp"
#include "fs_close.hpp"
#include "fs_open.hpp"
@ -26,14 +28,9 @@
using std::string;
namespace fs
{
namespace attr
{
static
int
get_fs_ioc_flags(const int fd,
_get_fs_ioc_flags(const int fd,
int &flags)
{
int rv;
@ -47,7 +44,7 @@ namespace fs
static
int
get_fs_ioc_flags(const string &file,
_get_fs_ioc_flags(const string &file,
int &flags)
{
int fd;
@ -58,7 +55,7 @@ namespace fs
if(fd == -1)
return -1;
rv = get_fs_ioc_flags(fd,flags);
rv = ::_get_fs_ioc_flags(fd,flags);
if(rv == -1)
{
int error = errno;
@ -72,7 +69,7 @@ namespace fs
static
int
set_fs_ioc_flags(const int fd,
_set_fs_ioc_flags(const int fd,
const int flags)
{
int rv;
@ -86,7 +83,7 @@ namespace fs
static
int
set_fs_ioc_flags(const string &file,
_set_fs_ioc_flags(const string &file,
const int flags)
{
int fd;
@ -97,7 +94,7 @@ namespace fs
if(fd == -1)
return -1;
rv = set_fs_ioc_flags(fd,flags);
rv = ::_set_fs_ioc_flags(fd,flags);
if(rv == -1)
{
int error = errno;
@ -110,31 +107,33 @@ namespace fs
}
int
copy(const int fdin,
const int fdout)
fs::attr::copy(const int fdin,
const int fdout,
const u32 flags_)
{
int rv;
int flags;
rv = get_fs_ioc_flags(fdin,flags);
rv = ::_get_fs_ioc_flags(fdin,flags);
if(rv == -1)
return -1;
return set_fs_ioc_flags(fdout,flags);
if(flags_ & FS_ATTR_CLEAR_IMMUTABLE)
flags = (flags & ~FS_IMMUTABLE_FL);
return ::_set_fs_ioc_flags(fdout,flags);
}
int
copy(const string &from,
fs::attr::copy(const string &from,
const string &to)
{
int rv;
int flags;
rv = get_fs_ioc_flags(from,flags);
rv = ::_get_fs_ioc_flags(from,flags);
if(rv == -1)
return -1;
return set_fs_ioc_flags(to,flags);
}
}
return ::_set_fs_ioc_flags(to,flags);
}

86
src/fs_clonefile.cpp

@ -1,86 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "fs_fstat.hpp"
#include "fs_copydata.hpp"
#include "fs_attr.hpp"
#include "fs_xattr.hpp"
#include "fs_fchown.hpp"
#include "fs_fchmod.hpp"
#include "fs_futimens.hpp"
namespace l
{
static
bool
ignorable_error(const int err_)
{
switch(err_)
{
case ENOTTY:
case ENOTSUP:
#if ENOTSUP != EOPNOTSUPP
case EOPNOTSUPP:
#endif
return true;
}
return false;
}
}
namespace fs
{
int
clonefile(const int src_fd_,
const int dst_fd_)
{
int rv;
struct stat src_st;
rv = fs::fstat(src_fd_,&src_st);
if(rv < 0)
return -1;
rv = fs::copydata(src_fd_,dst_fd_,src_st.st_size);
if(rv == -1)
return -1;
// TODO: should not copy "immutable" flag till last
rv = fs::attr::copy(src_fd_,dst_fd_);
if((rv == -1) && !l::ignorable_error(errno))
return -1;
rv = fs::xattr::copy(src_fd_,dst_fd_);
if((rv == -1) && !l::ignorable_error(errno))
return -1;
rv = fs::fchown_check_on_error(dst_fd_,src_st);
if(rv == -1)
return -1;
rv = fs::fchmod_check_on_error(dst_fd_,src_st);
if(rv == -1)
return -1;
rv = fs::futimens(dst_fd_,src_st);
if(rv == -1)
return -1;
return 0;
}
}

25
src/fs_clonefile.hpp

@ -1,25 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
namespace fs
{
int
clonefile(const int src_fd,
const int dst_fd);
}

13
src/fs_copydata.cpp

@ -16,11 +16,12 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "errno.hpp"
#include "fs_copydata_copy_file_range.hpp"
#include "fs_copydata_readwrite.hpp"
#include "fs_fadvise.hpp"
#include "fs_fallocate.hpp"
#include "fs_ficlone.hpp"
#include "fs_ftruncate.hpp"
#include <stddef.h>
@ -34,9 +35,9 @@ namespace fs
{
int rv;
rv = fs::ftruncate(dst_fd_,count_);
if(rv == -1)
return -1;
rv = fs::fallocate(dst_fd_,0,0,count_);
if((rv == -1) && (errno == ENOSPC))
return rv;
rv = fs::ficlone(src_fd_,dst_fd_);
if(rv != -1)
@ -45,10 +46,10 @@ namespace fs
fs::fadvise_willneed(src_fd_,0,count_);
fs::fadvise_sequential(src_fd_,0,count_);
rv = fs::copydata_copy_file_range(src_fd_,dst_fd_);
rv = fs::copydata_copy_file_range(src_fd_,dst_fd_,count_);
if(rv != -1)
return rv;
return fs::copydata_readwrite(src_fd_,dst_fd_);
return fs::copydata_readwrite(src_fd_,dst_fd_,count_);
}
}

36
src/fs_copydata_copy_file_range.cpp

@ -18,20 +18,19 @@
#include "fs_copy_file_range.hpp"
#include "fs_fstat.hpp"
#include <cstdint>
#include "int_types.h"
namespace l
{
int64_t
copydata_copy_file_range(const int src_fd_,
static
s64
_copydata_copy_file_range(const int src_fd_,
const int dst_fd_,
uint64_t size_)
const u64 size_)
{
int64_t rv;
uint64_t nleft;
int64_t src_off;
int64_t dst_off;
s64 rv;
u64 nleft;
s64 src_off;
s64 dst_off;
src_off = 0;
dst_off = 0;
@ -52,23 +51,16 @@ namespace l
return size_;
}
}
namespace fs
{
int64_t
s64
copydata_copy_file_range(const int src_fd_,
const int dst_fd_)
const int dst_fd_,
const u64 count_)
{
int rv;
struct stat st;
rv = fs::fstat(src_fd_,&st);
if(rv < 0)
return -1;
return l::copydata_copy_file_range(src_fd_,
return ::_copydata_copy_file_range(src_fd_,
dst_fd_,
st.st_size);
count_);
}
}

7
src/fs_copydata_copy_file_range.hpp

@ -16,12 +16,13 @@
#pragma once
#include <cstdint>
#include "int_types.h"
namespace fs
{
int64_t
s64
copydata_copy_file_range(const int src_fd,
const int dst_fd);
const int dst_fd,
const u64 count);
}

52
src/fs_copydata_readwrite.cpp

@ -14,6 +14,8 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "fs_copydata_readwrite.hpp"
#include "errno.hpp"
#include "fs_fstat.hpp"
#include "fs_lseek.hpp"
@ -22,19 +24,15 @@
#include <vector>
using std::vector;
namespace l
{
static
int
writen(const int fd_,
s64
_writen(const int fd_,
const char *buf_,
const size_t size_)
const u64 size_)
{
ssize_t rv;
size_t nleft;
s64 rv;
u64 nleft;
nleft = size_;
do
@ -56,16 +54,16 @@ namespace l
}
static
int
copydata_readwrite(const int src_fd_,
s64
_copydata_readwrite(const int src_fd_,
const int dst_fd_,
const size_t count_)
const u64 count_)
{
ssize_t nr;
ssize_t nw;
ssize_t bufsize;
size_t totalwritten;
vector<char> buf;
s64 nr;
s64 nw;
s64 bufsize;
u64 totalwritten;
std::vector<char> buf;
bufsize = (1024 * 1024);
buf.resize(bufsize);
@ -83,7 +81,7 @@ namespace l
if(nr == -1)
return -1;
nw = l::writen(dst_fd_,&buf[0],nr);
nw = ::_writen(dst_fd_,&buf[0],nr);
if(nw == -1)
return -1;
@ -92,23 +90,17 @@ namespace l
return totalwritten;
}
}
namespace fs
{
int
s64
copydata_readwrite(const int src_fd_,
const int dst_fd_)
const int dst_fd_,
const u64 count_)
{
int rv;
struct stat st;
rv = fs::fstat(src_fd_,&st);
if(rv < 0)
return -1;
return l::copydata_readwrite(src_fd_,
return ::_copydata_readwrite(src_fd_,
dst_fd_,
st.st_size);
count_);
}
}

6
src/fs_copydata_readwrite.hpp

@ -16,10 +16,12 @@
#pragma once
#include "int_types.h"
namespace fs
{
int
s64
copydata_readwrite(const int src_fd,
const int dst_fd);
const int dst_fd,
const u64 count);
}

120
src/fs_copyfile.cpp

@ -1,39 +1,153 @@
#include "fs_copyfile.hpp"
#include "fs_clonefile.hpp"
#include "fs_attr.hpp"
#include "fs_close.hpp"
#include "fs_copydata.hpp"
#include "fs_fchmod.hpp"
#include "fs_fchown.hpp"
#include "fs_fcntl.hpp"
#include "fs_file_unchanged.hpp"
#include "fs_fstat.hpp"
#include "fs_futimens.hpp"
#include "fs_mktemp.hpp"
#include "fs_open.hpp"
#include "fs_rename.hpp"
#include "fs_unlink.hpp"
#include "fs_xattr.hpp"
#include "scope_guard.hpp"
#include <fcntl.h>
#include <signal.h>
static
bool
_ignorable_error(const int err_)
{
switch(err_)
{
case ENOTTY:
case ENOTSUP:
#if ENOTSUP != EOPNOTSUPP
case EOPNOTSUPP:
#endif
return true;
}
return false;
}
int
fs::copyfile(const int src_fd_,
const struct stat &src_st_,
const int dst_fd_)
{
int rv;
rv = fs::copydata(src_fd_,dst_fd_,src_st_.st_size);
if(rv == -1)
return -1;
rv = fs::xattr::copy(src_fd_,dst_fd_);
if((rv == -1) && !::_ignorable_error(errno))
return -1;
rv = fs::attr::copy(src_fd_,dst_fd_,FS_ATTR_CLEAR_IMMUTABLE);
if((rv == -1) && !::_ignorable_error(errno))
return -1;
rv = fs::fchown_check_on_error(dst_fd_,src_st_);
if(rv == -1)
return -1;
rv = fs::fchmod_check_on_error(dst_fd_,src_st_);
if(rv == -1)
return -1;
rv = fs::futimens(dst_fd_,src_st_);
if(rv == -1)
return -1;
return 0;
}
// Limitations:
// * Doesn't handle immutable files well. Will ignore the flag on attr
// copy.
// * Does not handle non-regular files.
int
fs::copyfile(const std::filesystem::path &src_,
const std::filesystem::path &dst_)
const std::filesystem::path &dst_,
const u32 flags_)
{
int rv;
int src_fd;
int dst_fd;
struct stat src_st = {0};
std::string dst_tmppath;
struct sigaction old_act;
struct sigaction new_act;
// Done in case fcntl(F_SETLEASE) works.
new_act.sa_handler = SIG_IGN;
new_act.sa_flags = 0;
sigemptyset(&new_act.sa_mask);
sigaction(SIGIO,&new_act,&old_act);
DEFER { sigaction(SIGIO,&old_act,NULL); };
src_fd = fs::open(src_,O_RDONLY|O_NOFOLLOW);
if(src_fd < 0)
return src_fd;
DEFER { fs::close(src_fd); };
while(true)
{
std::tie(dst_fd,dst_tmppath) = fs::mktemp(dst_,O_RDWR);
if(dst_fd < 0)
return dst_fd;
DEFER { fs::close(dst_fd); };
rv = fs::clonefile(src_fd,dst_fd);
// If it fails or is unsupported... so be it. This will help
// limit the possibility of the file being modified while the
// copy happens. Opening read-only is fine but open for write or
// truncate will block for others till this finishes or the
// kernel wide timeout (/proc/sys/fs/lease-break-time).
fs::fcntl_setlease_rdlck(src_fd);
DEFER { fs::fcntl_setlease_unlck(src_fd); };
// For comparison after the copy to see if the file was
// modified. This could be made more thorough by adding some
// hashing but probably overkill. Also used to provide size and
// other details for data copying.
rv = fs::fstat(src_fd,&src_st);
if(rv < 0)
return rv;
rv = fs::copyfile(src_fd,src_st,dst_fd);
if(rv < 0)
{
if(flags_ & FS_COPYFILE_CLEANUP_FAILURE)
fs::unlink(dst_tmppath);
return rv;
}
rv = fs::file_changed(src_fd,src_st);
if(rv == FS_FILE_CHANGED)
{
fs::unlink(dst_tmppath);
continue;
}
rv = fs::rename(dst_tmppath,dst_);
if((rv < 0) && (flags_ & FS_COPYFILE_CLEANUP_FAILURE))
fs::unlink(dst_tmppath);
break;
}
return rv;
}

19
src/fs_copyfile.hpp

@ -1,9 +1,24 @@
#pragma once
#include "int_types.h"
#include <filesystem>
#include <sys/stat.h>
#define FS_COPYFILE_NONE (0)
#define FS_COPYFILE_CLEANUP_FAILURE (1 << 0)
namespace fs
{
int copyfile(const std::filesystem::path &src,
const std::filesystem::path &dst);
int
copyfile(const int src_fd,
const struct stat &src_st,
const int dst_fd);
int
copyfile(const std::filesystem::path &src,
const std::filesystem::path &dst,
const u32 flags);
}

79
src/fs_cow.cpp

@ -16,17 +16,11 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "fs_cow.hpp"
#include "errno.hpp"
#include "fs_clonefile.hpp"
#include "fs_close.hpp"
#include "fs_lstat.hpp"
#include "fs_mktemp.hpp"
#include "fs_open.hpp"
#include "fs_path.hpp"
#include "fs_rename.hpp"
#include "fs_unlink.hpp"
#include <string>
#include "fs_copyfile.hpp"
#include <fcntl.h>
#include <sys/stat.h>
@ -34,35 +28,8 @@
#include <unistd.h>
namespace l
{
static
int
cleanup_on_error(const int src_fd_,
const int dst_fd_ = -1,
const std::string &dst_fullpath_ = {})
{
int error = errno;
if(src_fd_ >= 0)
fs::close(src_fd_);
if(dst_fd_ >= 0)
fs::close(dst_fd_);
if(!dst_fullpath_.empty())
fs::unlink(dst_fullpath_);
errno = error;
return -1;
}
}
namespace fs
{
namespace cow
{
bool
is_eligible(const int flags_)
fs::cow::is_eligible(const int flags_)
{
int accmode;
@ -73,20 +40,20 @@ namespace fs
}
bool
is_eligible(const struct stat &st_)
fs::cow::is_eligible(const struct stat &st_)
{
return ((S_ISREG(st_.st_mode)) && (st_.st_nlink > 1));
}
bool
is_eligible(const int flags_,
fs::cow::is_eligible(const int flags_,
const struct stat &st_)
{
return (is_eligible(flags_) && is_eligible(st_));
}
bool
is_eligible(const char *fullpath_,
fs::cow::is_eligible(const char *fullpath_,
const int flags_)
{
int rv;
@ -103,33 +70,9 @@ namespace fs
}
int
break_link(const char *src_fullpath_)
fs::cow::break_link(const char *src_filepath_)
{
int rv;
int src_fd;
int dst_fd;
std::string dst_fullpath;
src_fd = fs::open(src_fullpath_,O_RDONLY|O_NOFOLLOW);
if(src_fd == -1)
return -1;
std::tie(dst_fd,dst_fullpath) = fs::mktemp(src_fullpath_,O_WRONLY);
if(dst_fd < 0)
return l::cleanup_on_error(src_fd);
rv = fs::clonefile(src_fd,dst_fd);
if(rv == -1)
return l::cleanup_on_error(src_fd,dst_fd,dst_fullpath);
rv = fs::rename(dst_fullpath,src_fullpath_);
if(rv == -1)
return l::cleanup_on_error(src_fd,dst_fd,dst_fullpath);
fs::close(src_fd);
fs::close(dst_fd);
return 0;
}
}
return fs::copyfile(src_filepath_,
src_filepath_,
FS_COPYFILE_CLEANUP_FAILURE);
}

58
src/fs_fcntl.hpp

@ -0,0 +1,58 @@
#pragma once
#include <fcntl.h>
namespace fs
{
static
inline
int
fcntl(const int fd_,
const int op_)
{
int rv;
rv = ::fcntl(fd_,op_);
return ((rv == -1) ? -errno : rv);
}
static
inline
int
fcntl(const int fd_,
const int op_,
const int arg_)
{
int rv;
rv = ::fcntl(fd_,op_,arg_);
return ((rv == -1) ? -errno : rv);
}
static
inline
int
fcntl_setlease_rdlck(const int fd_)
{
#if defined(F_SETLEASE) && defined(F_RDLCK)
return fs::fcntl(fd_,F_SETLEASE,F_RDLCK);
#else
return -ENOTSUP;
#endif
}
static
inline
int
fcntl_setlease_unlck(const int fd_)
{
#if defined(F_SETLEASE) && defined(F_UNLCK)
return fs::fcntl(fd_,F_SETLEASE,F_UNLCK);
#else
return -ENOTSUP;
#endif
}
}

36
src/fs_file_unchanged.hpp

@ -0,0 +1,36 @@
#pragma once
#include "fs_fstat.hpp"
#define FS_FILE_CHANGED 0
#define FS_FILE_UNCHANGED 1
namespace fs
{
static
inline
int
file_changed(const int fd_,
const struct stat &orig_st_)
{
int rv;
struct stat new_st;
rv = fs::fstat(fd_,&new_st);
if(rv < 0)
return rv;
if(orig_st_.st_ino != new_st.st_ino)
return FS_FILE_CHANGED;
if(orig_st_.st_dev != new_st.st_dev)
return FS_FILE_CHANGED;
if(orig_st_.st_size != new_st.st_size)
return FS_FILE_CHANGED;
if(orig_st_.st_mtim.tv_sec != new_st.st_mtim.tv_sec)
return FS_FILE_CHANGED;
if(orig_st_.st_mtim.tv_nsec != new_st.st_mtim.tv_nsec)
return FS_FILE_CHANGED;
return FS_FILE_UNCHANGED;
}
}

180
src/fs_movefile.cpp

@ -1,180 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "errno.hpp"
#include "fs_clonefile.hpp"
#include "fs_clonepath.hpp"
#include "fs_close.hpp"
#include "fs_file_size.hpp"
#include "fs_findonfs.hpp"
#include "fs_getfl.hpp"
#include "fs_has_space.hpp"
#include "fs_mktemp.hpp"
#include "fs_open.hpp"
#include "fs_path.hpp"
#include "fs_rename.hpp"
#include "fs_stat.hpp"
#include "fs_unlink.hpp"
#include "policy.hpp"
#include "ugid.hpp"
#include <string>
#include <vector>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static
int
cleanup_flags(const int flags_)
{
int rv;
rv = flags_;
rv = (rv & ~O_TRUNC);
rv = (rv & ~O_CREAT);
rv = (rv & ~O_EXCL);
return rv;
}
namespace l
{
static
int
movefile(const Policy::Create &createFunc_,
const Branches::Ptr &branches_,
const std::string &fusepath_,
int origfd_)
{
int rv;
int srcfd;
int dstfd;
int dstfd_flags;
int origfd_flags;
int64_t srcfd_size;
std::string fusedir;
std::string srcfd_branch;
std::string srcfd_filepath;
std::string dstfd_filepath;
std::string dstfd_tmp_filepath;
std::vector<Branch*> dstfd_branch;
srcfd = -1;
dstfd = -1;
rv = fs::findonfs(branches_,fusepath_,origfd_,&srcfd_branch);
if(rv == -1)
return -errno;
rv = createFunc_(branches_,fusepath_.c_str(),dstfd_branch);
if(rv == -1)
return -errno;
origfd_flags = fs::getfl(origfd_);
if(origfd_flags == -1)
return -errno;
srcfd_size = fs::file_size(origfd_);
if(srcfd_size == -1)
return -errno;
if(fs::has_space(dstfd_branch[0]->path,srcfd_size) == false)
return -ENOSPC;
fusedir = fs::path::dirname(fusepath_);
rv = fs::clonepath(srcfd_branch,dstfd_branch[0]->path,fusedir);
if(rv == -1)
return -ENOSPC;
srcfd_filepath = srcfd_branch;
fs::path::append(srcfd_filepath,fusepath_);
srcfd = fs::open(srcfd_filepath,O_RDONLY);
if(srcfd == -1)
return -ENOSPC;
dstfd_filepath = dstfd_branch[0]->path;
fs::path::append(dstfd_filepath,fusepath_);
std::tie(dstfd,dstfd_tmp_filepath) = fs::mktemp(dstfd_filepath,O_WRONLY);
if(dstfd < 0)
{
fs::close(srcfd);
return -ENOSPC;
}
rv = fs::clonefile(srcfd,dstfd);
if(rv == -1)
{
fs::close(srcfd);
fs::close(dstfd);
fs::unlink(dstfd_tmp_filepath);
return -ENOSPC;
}
rv = fs::rename(dstfd_tmp_filepath,dstfd_filepath);
if(rv == -1)
{
fs::close(srcfd);
fs::close(dstfd);
fs::unlink(dstfd_tmp_filepath);
return -ENOSPC;
}
fs::close(srcfd);
fs::close(dstfd);
dstfd_flags = ::cleanup_flags(origfd_flags);
rv = fs::open(dstfd_filepath,dstfd_flags);
if(rv == -1)
{
fs::unlink(dstfd_tmp_filepath);
return -ENOSPC;
}
fs::unlink(srcfd_filepath);
return rv;
}
}
namespace fs
{
int
movefile(const Policy::Create &policy_,
const Branches::Ptr &basepaths_,
const std::string &fusepath_,
int origfd_)
{
return l::movefile(policy_,basepaths_,fusepath_,origfd_);
}
int
movefile_as_root(const Policy::Create &policy_,
const Branches::Ptr &basepaths_,
const std::string &fusepath_,
int origfd_)
{
const ugid::Set ugid(0,0);
return fs::movefile(policy_,basepaths_,fusepath_,origfd_);
}
}

147
src/fs_movefile_and_open.cpp

@ -0,0 +1,147 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "fs_movefile_and_open.hpp"
#include "errno.hpp"
#include "fs_clonepath.hpp"
#include "fs_close.hpp"
#include "fs_copyfile.hpp"
#include "fs_file_size.hpp"
#include "fs_findonfs.hpp"
#include "fs_getfl.hpp"
#include "fs_has_space.hpp"
#include "fs_mktemp.hpp"
#include "fs_open.hpp"
#include "fs_path.hpp"
#include "fs_rename.hpp"
#include "fs_stat.hpp"
#include "fs_unlink.hpp"
#include "int_types.h"
#include "policy.hpp"
#include "ugid.hpp"
#include <string>
#include <vector>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static
int
_cleanup_flags(const int flags_)
{
int rv;
rv = flags_;
rv = (rv & ~O_TRUNC);
rv = (rv & ~O_CREAT);
rv = (rv & ~O_EXCL);
return rv;
}
static
int
_movefile_and_open(const Policy::Create &createFunc_,
const Branches::Ptr &branches_,
const std::string &branchpath_,
const std::string &fusepath_,
int origfd_)
{
int rv;
int dstfd_flags;
int origfd_flags;
s64 src_size;
std::string fusedir;
std::string src_branch;
std::string src_filepath;
std::string dst_filepath;
std::vector<Branch*> dst_branch;
src_branch = branchpath_;
rv = createFunc_(branches_,fusepath_.c_str(),dst_branch);
if(rv == -1)
return -errno;
origfd_flags = fs::getfl(origfd_);
if(origfd_flags == -1)
return -errno;
src_size = fs::file_size(origfd_);
if(src_size == -1)
return -errno;
if(fs::has_space(dst_branch[0]->path,src_size) == false)
return -ENOSPC;
fusedir = fs::path::dirname(fusepath_);
rv = fs::clonepath(src_branch,dst_branch[0]->path,fusedir);
if(rv == -1)
return -ENOSPC;
src_filepath = fs::path::make(src_branch,fusepath_);
dst_filepath = fs::path::make(dst_branch[0]->path,fusepath_);
rv = fs::copyfile(src_filepath,dst_filepath,FS_COPYFILE_CLEANUP_FAILURE);
if(rv < 0)
return -ENOSPC;
dstfd_flags = ::_cleanup_flags(origfd_flags);
rv = fs::open(dst_filepath,dstfd_flags);
if(rv == -1)
return -ENOSPC;
fs::unlink(src_filepath);
return rv;
}
int
fs::movefile_and_open(const Policy::Create &policy_,
const Branches::Ptr &branches_,
const std::string &branchpath_,
const std::string &fusepath_,
const int origfd_)
{
return ::_movefile_and_open(policy_,
branches_,
branchpath_,
fusepath_,
origfd_);
}
int
fs::movefile_and_open_as_root(const Policy::Create &policy_,
const Branches::Ptr &branches_,
const std::string &branchpath_,
const std::string &fusepath_,
const int origfd_)
{
const ugid::Set ugid(0,0);
return fs::movefile_and_open(policy_,
branches_,
branchpath_,
fusepath_,
origfd_);
}

12
src/fs_movefile.hpp → src/fs_movefile_and_open.hpp

@ -25,14 +25,16 @@
namespace fs
{
int
movefile(const Policy::Create &policy,
const Branches::Ptr &branches,
movefile_and_open(const Policy::Create &policy,
const Branches::Ptr &branches_,
const std::string &branchpath,
const std::string &fusepath,
int origfd);
const int origfd);
int
movefile_as_root(const Policy::Create &policy,
const Branches::Ptr &branches,
movefile_and_open_as_root(const Policy::Create &policy,
const Branches::Ptr &branches_,
const std::string &branchpath,
const std::string &fusepath,
int origfd);
}

2
src/fsck_mergerfs.cpp

@ -239,7 +239,7 @@ _copy_files(const std::string &src_,
if(src_ == dst.path)
continue;
rv = fs::copyfile(src_,dst.path);
rv = fs::copyfile(src_,dst.path,FS_COPYFILE_NONE);
if(rv < 0)
fmt::print(stderr,
"ERROR: failed copying to {} - {}",

8
src/fuse_write.cpp

@ -19,7 +19,7 @@
#include "fileinfo.hpp"
#include "fs_close.hpp"
#include "fs_dup2.hpp"
#include "fs_movefile.hpp"
#include "fs_movefile_and_open.hpp"
#include "fs_pwrite.hpp"
#include "fs_pwriten.hpp"
@ -51,8 +51,9 @@ namespace l
if(cfg->moveonenospc.enabled == false)
return err_;
rv = fs::movefile_as_root(cfg->moveonenospc.policy,
rv = fs::movefile_and_open_as_root(cfg->moveonenospc.policy,
cfg->branches,
fi_->branch.path,
fi_->fusepath,
fi_->fd);
if(rv < 0)
@ -82,8 +83,9 @@ namespace l
if(cfg->moveonenospc.enabled == false)
return err_;
rv = fs::movefile_as_root(cfg->moveonenospc.policy,
rv = fs::movefile_and_open_as_root(cfg->moveonenospc.policy,
cfg->branches,
fi_->branch.path,
fi_->fusepath,
fi_->fd);
if(rv < 0)

Loading…
Cancel
Save