4848#endif
4949
5050constexpr auto propagations_flag = (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE);
51+ constexpr auto max_symlink_depth{ 32 };
5152
5253namespace linyaps_box {
5354
@@ -399,29 +400,48 @@ void do_remount(const remount_t &mount)
399400 }
400401}
401402
402- [[nodiscard]] linyaps_box::utils::file_descriptor create_destination_file (
403+ [[nodiscard]] linyaps_box::utils::file_descriptor create_destination_directory (
403404 const linyaps_box::utils::file_descriptor &root, const std::filesystem::path &destination)
404405{
405- LINYAPS_BOX_DEBUG () << " Creating file " << destination.string () << " under "
406+ LINYAPS_BOX_DEBUG () << " Creating directory " << destination.string () << " under "
406407 << linyaps_box::utils::inspect_path (root.get ());
407- const auto &parent = linyaps_box::utils::mkdir (root, destination.parent_path ());
408- return linyaps_box::utils::touch (parent, destination.filename ());
408+ return linyaps_box::utils::mkdir (root, destination);
409409}
410410
411- [[nodiscard]] linyaps_box::utils::file_descriptor create_destination_directory (
412- const linyaps_box::utils::file_descriptor &root, const std::filesystem::path &destination)
411+ [[nodiscard]] linyaps_box::utils::file_descriptor
412+ create_destination_file (const linyaps_box::utils::file_descriptor &root,
413+ const std::filesystem::path &destination,
414+ int max_depth)
413415{
414- LINYAPS_BOX_DEBUG () << " Creating directory " << destination.string () << " under "
416+ if (max_depth < 0 ) {
417+ throw std::system_error (ELOOP, std::system_category (), " failed to create file" );
418+ }
419+
420+ LINYAPS_BOX_DEBUG () << " Creating file " << destination.string () << " under "
415421 << linyaps_box::utils::inspect_path (root.get ());
416- return linyaps_box::utils::mkdir (root, destination);
422+ const auto &parent = create_destination_directory (root, destination.parent_path ());
423+
424+ try {
425+ auto ret = linyaps_box::utils::touch (parent,
426+ destination.filename (),
427+ O_CLOEXEC | O_CREAT | O_WRONLY | O_NOFOLLOW);
428+ return ret;
429+ } catch (std::system_error &e) {
430+ if (e.code () != std::errc::too_many_symbolic_link_levels) {
431+ throw ;
432+ }
433+
434+ auto target = linyaps_box::utils::readlinkat (parent, destination.filename ());
435+ return create_destination_file (root, target, max_depth - 1 );
436+ }
417437}
418438
419439[[nodiscard]] linyaps_box::utils::file_descriptor
420440create_destination_symlink (const linyaps_box::utils::file_descriptor &root,
421441 const std::filesystem::path &source,
422442 std::filesystem::path destination)
423443{
424- auto ret = std::filesystem::read_symlink (source);
444+ auto ret = linyaps_box::utils::readlink (source);
425445 auto parent = linyaps_box::utils::mkdir (root, destination.parent_path ());
426446
427447 LINYAPS_BOX_DEBUG () << " Creating symlink " << destination.string () << " under "
@@ -447,13 +467,8 @@ create_destination_symlink(const linyaps_box::utils::file_descriptor &root,
447467 + " already exists and is not a symlink" );
448468 }
449469
450- std::array<char , PATH_MAX + 1 > buf{};
451- auto to = ::readlinkat (root.get (), destination.c_str (), buf.data (), buf.size ());
452- if (to == -1 ) {
453- throw std::system_error (errno, std::system_category (), " readlinkat" );
454- }
455-
456- if (std::string_view{ buf.data (), static_cast <size_t >(to) } == ret) {
470+ auto target = linyaps_box::utils::readlinkat (root, destination);
471+ if (target == ret) {
457472 return linyaps_box::utils::open_at (root, destination, O_PATH | O_NOFOLLOW | O_CLOEXEC);
458473 }
459474
@@ -469,11 +484,9 @@ ensure_mount_destination(bool isDir,
469484 const linyaps_box::config::mount_t &mount)
470485try {
471486 assert (mount.destination .has_value ());
472- auto open_flag = O_PATH;
473- if ((mount.flags & LINGYAPS_MS_NOSYMFOLLOW) != 0 ) {
474- open_flag |= O_NOFOLLOW;
475- }
476-
487+ auto open_flag = O_PATH | O_CLOEXEC;
488+ LINYAPS_BOX_DEBUG () << " Opening " << (isDir ? " directory " : " file " )
489+ << mount.destination .value () << " under " << root.current_path ();
477490 return linyaps_box::utils::open_at (root, mount.destination .value (), open_flag);
478491} catch (const std::system_error &e) {
479492 if (e.code ().value () != ENOENT) {
@@ -492,7 +505,7 @@ try {
492505 return create_destination_directory (root, path);
493506 }
494507
495- return create_destination_file (root, path);
508+ return create_destination_file (root, path, max_symlink_depth );
496509}
497510
498511void do_propagation_mount (const linyaps_box::utils::file_descriptor &destination,
0 commit comments