aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-07-24 03:49:22 +0200
committerSven Gothel <[email protected]>2022-07-24 03:49:22 +0200
commit9cad4eb8e62ce958295c7ba8c78e512439747797 (patch)
treea8fa02d66b32ecd3d7871b3f1726c92c8bca52a7
parent1e2807584f97473f427640d9c6a8fb948ba20824 (diff)
FreeBSD Support: file_util.cpp: Use macros for statx/stat and sendfile variants, fix missing POSIX _LARGEFILE64_SOURCE on FreeBSD (8/n)
Missing POSIX_LARGEFILE64_SOURCE on FreeBSD should be no issue as long its operated under 64bit. Missing POSIX_LARGEFILE64_SOURCE API elements are replaced as follows - struct ::stat64 -> struct ::stat - ::off64_t -> ::off_t - __posix_fstatat64: fstatat64 -> fstatat - __posix_openat64: openat64 -> openat Further: - O_NOATIME usage is dropped on file-copy - all ::open64() are replaced with __posix_openat64(AT_FDCWD, ...) - FreeBSD API uses ::unmount(), Linux ::umount(), else warning -> error - umount(): Return error if no loopback is supported (FreeBSD) TODO: - FreeBSD: Support loopback device for mount()/umount()
-rw-r--r--src/file_util.cpp136
1 files changed, 82 insertions, 54 deletions
diff --git a/src/file_util.cpp b/src/file_util.cpp
index 8f775e9..6d33ef4 100644
--- a/src/file_util.cpp
+++ b/src/file_util.cpp
@@ -59,12 +59,20 @@ inline constexpr const int _open_dir_flags = O_RDONLY|O_BINARY|O_NOCTTY|O_DIRECT
using namespace jau;
using namespace jau::fs;
-#ifdef __linux__
- static constexpr const bool _use_statx = true;
- static constexpr const bool _use_sendfile = true;
+#if defined(__linux__)
+ #define _USE_STATX_ 1
+ #define _USE_SENDFILE_ 1
+#endif
+
+#if defined(__FreeBSD__)
+ typedef struct ::stat struct_stat64;
+ typedef off_t off64_t;
+ #define __posix_fstatat64 ::fstatat
+ #define __posix_openat64 ::openat
#else
- static constexpr const bool _use_statx = false;
- static constexpr const bool _use_sendfile = false;
+ typedef struct ::stat64 struct_stat64;
+ #define __posix_fstatat64 ::fstatat64
+ #define __posix_openat64 ::openat64
#endif
std::string jau::fs::get_cwd() noexcept {
@@ -398,7 +406,9 @@ file_stats::file_stats() noexcept
errno_res_(0)
{}
-static constexpr bool jau_has_stat(const uint32_t mask, const uint32_t bit) { return bit == ( mask & bit ); }
+#if _USE_STATX_
+ static constexpr bool jau_has_stat(const uint32_t mask, const uint32_t bit) { return bit == ( mask & bit ); }
+#endif
file_stats::file_stats(const ctor_cookie& cc, const int dirfd, const dir_item& item, const bool dirfd_is_item_dirname) noexcept
: has_fields_(field_t::none), item_(item), link_target_path_(), link_target_(), mode_(fmode_t::none), fd_(-1),
@@ -418,7 +428,7 @@ file_stats::file_stats(const ctor_cookie& cc, const int dirfd, const dir_item& i
}
}
-if constexpr ( _use_statx ) {
+#if _USE_STATX_
struct ::statx s;
::bzero(&s, sizeof(s));
int stat_res = ::statx(dirfd, dirfd_path.c_str(),
@@ -573,10 +583,10 @@ if constexpr ( _use_statx ) {
jau::fprintf_td(stderr, "file_stats(%d): '%s', %d, errno %d (%s)\n", (int)cc.rec_level, to_string().c_str(), stat_res, errno, ::strerror(errno));
}
}
-} else { /* constexpr !_use_statx */
- struct ::stat64 s;
+#else /* _USE_STATX_ */
+ struct_stat64 s;
::bzero(&s, sizeof(s));
- int stat_res = ::fstatat64(dirfd, dirfd_path.c_str(), &s, AT_SYMLINK_NOFOLLOW); // lstat64 compatible
+ int stat_res = __posix_fstatat64(dirfd, dirfd_path.c_str(), &s, AT_SYMLINK_NOFOLLOW); // lstat64 compatible
if( 0 != stat_res ) {
if constexpr ( _debug ) {
jau::fprintf_td(stderr, "file_stats(%d): Test ERROR: '%s', %d, errno %d (%s)\n", (int)cc.rec_level, full_path.c_str(), stat_res, errno, ::strerror(errno));
@@ -646,7 +656,7 @@ if constexpr ( _use_statx ) {
if( 0 == cc.rec_level ) {
// Initial symbolic followed: Test recursive loop-error
::bzero(&s, sizeof(s));
- stat_res = ::fstatat64(dirfd, dirfd_path.c_str(), &s, 0); // stat64 compatible
+ stat_res = __posix_fstatat64(dirfd, dirfd_path.c_str(), &s, 0); // stat64 compatible
if( 0 != stat_res ) {
if constexpr ( _debug ) {
jau::fprintf_td(stderr, "file_stats(%d): Test link ERROR: '%s', %d, errno %d (%s)\n", (int)cc.rec_level, full_path.c_str(), stat_res, errno, ::strerror(errno));
@@ -694,7 +704,7 @@ if constexpr ( _use_statx ) {
jau::fprintf_td(stderr, "file_stats(%d): '%s', %d, errno %d (%s)\n", (int)cc.rec_level, to_string().c_str(), stat_res, errno, ::strerror(errno));
}
}
-} /* constexpr !_use_statx */
+#endif /* _USE_STATX_ */
errorout: ;
}
@@ -943,7 +953,7 @@ static bool _visit(const file_stats& item_stats, const traverse_options topts, c
return false;
}
const int parent_dirfd = dirfds.back();
- const int this_dirfd = ::openat64(parent_dirfd, item_stats.item().basename().c_str(), _open_dir_flags);
+ const int this_dirfd = __posix_openat64(parent_dirfd, item_stats.item().basename().c_str(), _open_dir_flags);
if ( 0 > this_dirfd ) {
ERR_PRINT("entered path dir couldn't be opened, source %s", item_stats.to_string().c_str());
return false;
@@ -1009,7 +1019,7 @@ bool jau::fs::visit(const file_stats& item_stats, const traverse_options topts,
return false;
}
// initial parent directory dirfd of initial item_stats (a directory)
- const int dirfd = ::openat64(AT_FDCWD, item_stats.item().dirname().c_str(), _open_dir_flags);
+ const int dirfd = __posix_openat64(AT_FDCWD, item_stats.item().dirname().c_str(), _open_dir_flags);
if ( 0 > dirfd ) {
ERR_PRINT("path dirname couldn't be opened, source %s", item_stats.to_string().c_str());
return false;
@@ -1134,12 +1144,12 @@ bool jau::fs::compare(const file_stats& source1, const file_stats& source2, cons
uint64_t offset = 0;
bool res = false;
- src1 = ::open64(source1.path().c_str(), src_flags);
+ src1 = __posix_openat64(AT_FDCWD, source1.path().c_str(), src_flags);
if ( 0 > src1 ) {
ERR_PRINT("Failed to open source1 %s, errno %d, %s", source1.to_string().c_str());
goto errout;
}
- src2 = ::open64(source2.path().c_str(), src_flags);
+ src2 = __posix_openat64(AT_FDCWD, source2.path().c_str(), src_flags);
if ( 0 > src2 ) {
ERR_PRINT("Failed to open source2 %s, errno %d, %s", source2.to_string().c_str());
goto errout;
@@ -1300,10 +1310,12 @@ static bool copy_file(const int src_dirfd, const file_stats& src_stats,
uint64_t offset = 0;
bool res = false;
+#if defined(__linux__)
if( caller_uid == target_stats->uid() ) {
src_flags |= O_NOATIME;
} // else we are not allowed to not use O_NOATIME
- src = ::openat64(src_dirfd, src_stats.item().basename().c_str(), src_flags);
+#endif /* defined(__linux__) */
+ src = __posix_openat64(src_dirfd, src_stats.item().basename().c_str(), src_flags);
if ( 0 > src ) {
if( src_stats.is_link() ) {
res = is_set(copts, copy_options::ignore_symlink_errors);
@@ -1315,40 +1327,41 @@ static bool copy_file(const int src_dirfd, const file_stats& src_stats,
}
goto errout;
}
- dst = ::openat64 (dst_dirfd, dst_basename.c_str(), O_CREAT|O_WRONLY|O_BINARY|O_EXCL|O_NOCTTY, jau::fs::posix_protection_bits( dest_mode & ~omitted_permissions ) );
+ dst = __posix_openat64 (dst_dirfd, dst_basename.c_str(), O_CREAT|O_WRONLY|O_BINARY|O_EXCL|O_NOCTTY, jau::fs::posix_protection_bits( dest_mode & ~omitted_permissions ) );
if ( 0 > dst ) {
ERR_PRINT("Failed to open target_path '%s'", dst_basename.c_str());
goto errout;
}
while ( offset < src_stats.size()) {
ssize_t rc1, rc2=0;
- if constexpr ( _use_sendfile ) {
- off64_t offset_i = (off64_t)offset; // we drop 1 bit of value-range as off64_t is int64_t
- const uint64_t count = std::max<uint64_t>(std::numeric_limits<ssize_t>::max(), src_stats.size() - offset);
- if( ( rc1 = ::sendfile64(dst, src, &offset_i, (size_t)count) ) >= 0 ) {
- offset = (uint64_t)offset_i;
- }
- } else {
- char buffer[BUFSIZ];
- if( ( rc1 = ::read(src, buffer, sizeof(buffer)) ) > 0 ) {
- ssize_t bytes_to_write = rc1;
- size_t buffer_offset = 0;
- while( 0 < bytes_to_write ) { // write the read chunk, allowing potential multiple write-ops
- if( ( rc2 = ::write(dst, buffer+buffer_offset, bytes_to_write) ) < 0 ) {
- break;
- }
- buffer_offset += rc2;
- bytes_to_write -= rc2;
- offset += rc2;
+#ifdef _USE_SENDFILE_
+ off64_t offset_i = (off64_t)offset; // we drop 1 bit of value-range as off64_t is int64_t
+ const uint64_t count = std::max<uint64_t>(std::numeric_limits<ssize_t>::max(), src_stats.size() - offset);
+ if( ( rc1 = ::sendfile64(dst, src, &offset_i, (size_t)count) ) >= 0 ) {
+ offset = (uint64_t)offset_i;
+ }
+#else /* _USE_SENDFILE_ */
+ char buffer[BUFSIZ];
+ if( ( rc1 = ::read(src, buffer, sizeof(buffer)) ) > 0 ) {
+ ssize_t bytes_to_write = rc1;
+ size_t buffer_offset = 0;
+ while( 0 < bytes_to_write ) { // write the read chunk, allowing potential multiple write-ops
+ if( ( rc2 = ::write(dst, buffer+buffer_offset, bytes_to_write) ) < 0 ) {
+ break;
}
+ buffer_offset += rc2;
+ bytes_to_write -= rc2;
+ offset += rc2;
}
}
+#endif/* _USE_SENDFILE_ */
if ( 0 > rc1 || 0 > rc2 ) {
- if constexpr ( _use_sendfile ) {
- ERR_PRINT("Failed to copy bytes @ %s / %s, %s -> '%s'",
- jau::to_decstring(offset).c_str(), jau::to_decstring(src_stats.size()).c_str(),
- src_stats.to_string().c_str(), dst_basename.c_str());
- } else if ( 0 > rc1 ) {
+#ifdef _USE_SENDFILE_
+ ERR_PRINT("Failed to copy bytes @ %s / %s, %s -> '%s'",
+ jau::to_decstring(offset).c_str(), jau::to_decstring(src_stats.size()).c_str(),
+ src_stats.to_string().c_str(), dst_basename.c_str());
+#else /* _USE_SENDFILE_ */
+ if ( 0 > rc1 ) {
ERR_PRINT("Failed to read bytes @ %s / %s, %s",
jau::to_decstring(offset).c_str(), jau::to_decstring(src_stats.size()).c_str(),
src_stats.to_string().c_str());
@@ -1357,6 +1370,7 @@ static bool copy_file(const int src_dirfd, const file_stats& src_stats,
jau::to_decstring(offset).c_str(), jau::to_decstring(src_stats.size()).c_str(),
dst_basename.c_str());
}
+#endif/* _USE_SENDFILE_ */
goto errout;
}
if ( 0 == rc1 ) {
@@ -1459,7 +1473,7 @@ static bool copy_push_mkdir(const file_stats& dst_stats, copy_context_t& ctx) no
return false;
}
// open dirfd
- const int new_dirfd = ::openat64(dest_dirfd, basename_.c_str(), _open_dir_flags);
+ const int new_dirfd = __posix_openat64(dest_dirfd, basename_.c_str(), _open_dir_flags);
if ( 0 > new_dirfd ) {
if( new_dir ) {
ERR_PRINT("Couldn't open new dir %s, temp '%s'", dst_stats.to_string().c_str(), basename_.c_str());
@@ -1483,8 +1497,13 @@ static bool copy_push_mkdir(const file_stats& dst_stats, copy_context_t& ctx) no
return false;
}
if( new_dir ) {
+#if defined(__linux__)
const int rename_flags = 0; // Not supported on all fs: RENAME_NOREPLACE
- if( 0 != ::renameat2(dest_dirfd, basename_.c_str(), dest_dirfd, dst_stats.item().basename().c_str(), rename_flags) ) {
+ const int rename_res = ::renameat2(dest_dirfd, basename_.c_str(), dest_dirfd, dst_stats.item().basename().c_str(), rename_flags);
+#else /* defined(__linux__) */
+ const int rename_res = ::renameat(dest_dirfd, basename_.c_str(), dest_dirfd, dst_stats.item().basename().c_str());
+#endif /* defined(__linux__) */
+ if( 0 != rename_res ) {
ERR_PRINT("rename temp to dest, temp '%s', dest %s", basename_.c_str(), dst_stats.to_string().c_str());
::unlinkat(dest_dirfd, basename_.c_str(), AT_REMOVEDIR);
::close(new_dirfd);
@@ -1566,7 +1585,7 @@ bool jau::fs::copy(const std::string& source_path, const std::string& target_pat
}
} // else file2file to directory
} // else file2file to explicit new file
- const int src_dirfd = ::openat64(AT_FDCWD, source_stats.item().dirname().c_str(), _open_dir_flags);
+ const int src_dirfd = __posix_openat64(AT_FDCWD, source_stats.item().dirname().c_str(), _open_dir_flags);
if ( 0 > src_dirfd ) {
ERR_PRINT("source_path dir couldn't be opened, source %s", source_stats.to_string().c_str());
return false;
@@ -1576,7 +1595,7 @@ bool jau::fs::copy(const std::string& source_path, const std::string& target_pat
int dst_dirfd = -1;
if( target_stats.is_dir() ) {
// file2file to directory
- dst_dirfd = ::openat64(AT_FDCWD, target_stats.path().c_str(), _open_dir_flags);
+ dst_dirfd = __posix_openat64(AT_FDCWD, target_stats.path().c_str(), _open_dir_flags);
if ( 0 > dst_dirfd ) {
ERR_PRINT("target dir couldn't be opened, target %s", target_stats.to_string().c_str());
::close(src_dirfd);
@@ -1594,7 +1613,7 @@ bool jau::fs::copy(const std::string& source_path, const std::string& target_pat
::close(src_dirfd);
return false;
}
- dst_dirfd = ::openat64(AT_FDCWD, target_parent_stats.path().c_str(), _open_dir_flags);
+ dst_dirfd = __posix_openat64(AT_FDCWD, target_parent_stats.path().c_str(), _open_dir_flags);
if ( 0 > dst_dirfd ) {
ERR_PRINT("target_parent dir couldn't be opened, target %s, target_parent %s",
target_stats.to_string().c_str(), target_parent_stats.to_string().c_str());
@@ -1639,7 +1658,7 @@ bool jau::fs::copy(const std::string& source_path, const std::string& target_pat
// src_dirfd of 'source_stats.item().dirname().c_str()' will be pushed by visit() itself
if( target_stats.is_dir() ) {
// Case: If dest_path exists as a directory, source_path dir will be copied below the dest_path directory.
- const int dst_dirfd = ::openat64(AT_FDCWD, target_stats.path().c_str(), _open_dir_flags);
+ const int dst_dirfd = __posix_openat64(AT_FDCWD, target_stats.path().c_str(), _open_dir_flags);
if ( 0 > dst_dirfd ) {
ERR_PRINT("target dir couldn't be opened, target %s", target_stats.to_string().c_str());
return false;
@@ -1655,7 +1674,7 @@ bool jau::fs::copy(const std::string& source_path, const std::string& target_pat
}
return false;
}
- const int dst_dirfd = ::openat64(AT_FDCWD, target_parent_stats.path().c_str(), _open_dir_flags);
+ const int dst_dirfd = __posix_openat64(AT_FDCWD, target_parent_stats.path().c_str(), _open_dir_flags);
if ( 0 > dst_dirfd ) {
ERR_PRINT("target dirname couldn't be opened, target %s, target_parent %s",
target_stats.to_string().c_str(), target_parent_stats.to_string().c_str());
@@ -1755,7 +1774,7 @@ jau::fs::mount_ctx jau::fs::mount_image(const std::string& image_path, const std
if( !target_stats.is_dir()) {
return mount_ctx();
}
- int backingfile = ::open64(image_stats.path().c_str(), O_RDWR);
+ int backingfile = __posix_openat64(AT_FDCWD, image_stats.path().c_str(), O_RDWR);
if( 0 > backingfile ) {
ERR_PRINT("Couldn't open image-file '%s': res %d", image_stats.to_string().c_str(), backingfile);
return mount_ctx();
@@ -1776,7 +1795,7 @@ jau::fs::mount_ctx jau::fs::mount_image(const std::string& image_path, const std
goto errout_child;
}
}
- loop_ctl_fd = ::open64("/dev/loop-control", O_RDWR);
+ loop_ctl_fd = __posix_openat64(AT_FDCWD, "/dev/loop-control", O_RDWR);
if( 0 > loop_ctl_fd ) {
ERR_PRINT("Couldn't open loop-control: res %d", loop_ctl_fd);
goto errout_child;
@@ -1797,7 +1816,7 @@ jau::fs::mount_ctx jau::fs::mount_image(const std::string& image_path, const std
snprintf(loopname, sizeof(loopname), "/dev/loop%d", loop_device_id);
jau::INFO_PRINT("mount: Info: Using loop-device '%s'", loopname);
- loop_device_fd = ::open64(loopname, O_RDWR);
+ loop_device_fd = __posix_openat64(AT_FDCWD, loopname, O_RDWR);
if( 0 > loop_device_fd ) {
ERR_PRINT("Couldn't open loop-device '%s': res %d", loopname, loop_device_fd);
goto errout_child;
@@ -1886,7 +1905,14 @@ bool jau::fs::umount(const mount_ctx& context)
::_exit(EXIT_FAILURE);
}
}
+#if defined(__linux__)
const int umount_res = ::umount(target_stats.path().c_str());
+#elif defined(__FreeBSD__)
+ const int umount_res = ::unmount(target_stats.path().c_str(), 0);
+#else
+ #warning Add OS support
+ const int umount_res = -1;
+#endif
if( 0 != umount_res ) {
ERR_PRINT("Couldn't umount '%s': res %d\n", target_stats.to_string().c_str(), umount_res);
}
@@ -1894,14 +1920,14 @@ bool jau::fs::umount(const mount_ctx& context)
// mounted w/o loop-device, done
::_exit(0 == umount_res ? EXIT_SUCCESS : EXIT_FAILURE);
}
-#ifdef __linux__
+#if defined(__linux__)
int loop_device_fd = -1;
char loopname[4096];
snprintf(loopname, sizeof(loopname), "/dev/loop%d", context.loop_device_id);
jau::INFO_PRINT("umount: Info: Using loop-device '%s'", loopname);
- loop_device_fd = ::open64(loopname, O_RDWR);
+ loop_device_fd = __posix_openat64(AT_FDCWD, loopname, O_RDWR);
if( 0 > loop_device_fd ) {
ERR_PRINT("Couldn't open loop-device '%s': res %d", loopname, loop_device_fd);
goto errout_child;
@@ -1912,9 +1938,11 @@ bool jau::fs::umount(const mount_ctx& context)
}
::close(loop_device_fd);
loop_device_fd = -1;
+ ::_exit(0 == umount_res ? EXIT_SUCCESS : EXIT_FAILURE);
#endif
- ::_exit(0 == umount_res ? EXIT_SUCCESS : EXIT_FAILURE);
+ // No loop-device handling for OS
+ ::_exit(EXIT_FAILURE);
#ifdef __linux__
errout_child: