Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVojtech Bubnik <bubnikv@gmail.com>2021-03-15 18:19:22 +0300
committerVojtech Bubnik <bubnikv@gmail.com>2021-03-15 18:19:22 +0300
commit01406fd52182d72cf1789174dd64ee4284e9f2cc (patch)
tree4ce3cdc519ed1cb16b44096fd7c92aeab9b811ef /src
parent84a333e4eda49fe8d3c15aeda1c44ccd75933b49 (diff)
Worked around some quirky Linux file system issues. Namely
the Chromebooks share their file system to Linux using the 9p file system, which does not support setting file ownership. Newly PrusaSlicer will detect platform and it will not panick if copy_file() cannot set file ownership after copying. It just logs the incident, and on chromebooks the loglevel for that incident is "Info", not "Error". Adjusted the full screen mode to contain menu bar. Moved Platform.cpp/hpp to libslic3r
Diffstat (limited to 'src')
-rw-r--r--src/PrusaSlicer.cpp3
-rw-r--r--src/libslic3r/CMakeLists.txt2
-rw-r--r--src/libslic3r/Platform.cpp (renamed from src/slic3r/Utils/Platform.cpp)8
-rw-r--r--src/libslic3r/Platform.hpp (renamed from src/slic3r/Utils/Platform.hpp)9
-rw-r--r--src/libslic3r/utils.cpp148
-rw-r--r--src/slic3r/CMakeLists.txt2
-rw-r--r--src/slic3r/GUI/GUI_Init.cpp3
-rw-r--r--src/slic3r/GUI/MainFrame.cpp6
-rw-r--r--src/slic3r/GUI/OpenGLManager.cpp5
-rw-r--r--src/slic3r/GUI/Plater.cpp5
-rw-r--r--src/slic3r/GUI/PresetHints.cpp1
-rw-r--r--src/slic3r/GUI/RemovableDriveManager.cpp6
12 files changed, 168 insertions, 30 deletions
diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index ed2d70272..10da1cb07 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -38,6 +38,7 @@
#include "libslic3r/GCode/PostProcessor.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/ModelArrange.hpp"
+#include "libslic3r/Platform.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/TriangleMesh.hpp"
@@ -68,6 +69,8 @@ int CLI::run(int argc, char **argv)
{
// Mark the main thread for the debugger and for runtime checks.
set_current_thread_name("slic3r_main");
+ // Detect the operating system flavor.
+ detect_platform();
#ifdef __WXGTK__
// On Linux, wxGTK has no support for Wayland, and the app crashes on
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 6159b2c5c..4a762f7e1 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -141,6 +141,8 @@ add_library(libslic3r STATIC
PerimeterGenerator.hpp
PlaceholderParser.cpp
PlaceholderParser.hpp
+ Platform.cpp
+ Platform.hpp
Point.cpp
Point.hpp
Polygon.cpp
diff --git a/src/slic3r/Utils/Platform.cpp b/src/libslic3r/Platform.cpp
index 3d101d662..4c8805149 100644
--- a/src/slic3r/Utils/Platform.cpp
+++ b/src/libslic3r/Platform.cpp
@@ -1,15 +1,8 @@
#include "Platform.hpp"
-
-// For starting another PrusaSlicer instance on OSX.
-// Fails to compile on Windows on the build server.
-
-#include <wx/stdpaths.h>
-
#include <boost/log/trivial.hpp>
namespace Slic3r {
-namespace GUI {
static auto s_platform = Platform::Uninitialized;
static auto s_platform_flavor = PlatformFlavor::Uninitialized;
@@ -74,5 +67,4 @@ PlatformFlavor platform_flavor()
return s_platform_flavor;
}
-} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/Utils/Platform.hpp b/src/libslic3r/Platform.hpp
index c0ee3541d..735728e89 100644
--- a/src/slic3r/Utils/Platform.hpp
+++ b/src/libslic3r/Platform.hpp
@@ -1,8 +1,7 @@
-#ifndef SLIC3R_GUI_Utils_Platform_HPP
-#define SLIC3R_GUI_Utils_Platform_HPP
+#ifndef SLIC3R_Platform_HPP
+#define SLIC3R_Platform_HPP
namespace Slic3r {
-namespace GUI {
enum class Platform
{
@@ -37,8 +36,6 @@ void detect_platform();
Platform platform();
PlatformFlavor platform_flavor();
-
-} // namespace GUI
} // namespace Slic3r
-#endif // SLIC3R_GUI_Utils_Platform_HPP
+#endif // SLIC3R_Platform_HPP
diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp
index 0c26d42c8..1ac45f1b5 100644
--- a/src/libslic3r/utils.cpp
+++ b/src/libslic3r/utils.cpp
@@ -6,6 +6,7 @@
#include <cstdarg>
#include <stdio.h>
+#include "Platform.hpp"
#include "Time.hpp"
#ifdef WIN32
@@ -19,9 +20,14 @@
#ifdef BSD
#include <sys/sysctl.h>
#endif
- #ifdef __APPLE__
+ #ifdef __APPLE__
#include <mach/mach.h>
#endif
+ #ifdef __linux__
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <sys/sendfile.h>
+ #endif
#endif
#include <boost/log/core.hpp>
@@ -417,6 +423,140 @@ std::error_code rename_file(const std::string &from, const std::string &to)
#endif
}
+#ifdef __linux__
+// Copied from boost::filesystem, to support copying a file to a weird filesystem, which does not support changing file attributes,
+// for example ChromeOS Linux integration or FlashAIR WebDAV.
+// Copied and simplified from boost::filesystem::detail::copy_file() with option = overwrite_if_exists and with just the Linux path kept,
+// and only features supported by Linux 3.10 (on our build server with CentOS 7) are kept, namely sendfile with ranges and statx() are not supported.
+bool copy_file_linux(const boost::filesystem::path &from, const boost::filesystem::path &to, boost::system::error_code &ec)
+{
+ using namespace boost::filesystem;
+
+ struct fd_wrapper
+ {
+ int fd { -1 };
+ fd_wrapper() = default;
+ explicit fd_wrapper(int fd) throw() : fd(fd) {}
+ ~fd_wrapper() throw() { if (fd >= 0) ::close(fd); }
+ };
+
+ ec.clear();
+ int err = 0;
+
+ // Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors
+ fd_wrapper infile, outfile;
+
+ while (true) {
+ infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC);
+ if (infile.fd < 0) {
+ err = errno;
+ if (err == EINTR)
+ continue;
+ fail:
+ ec.assign(err, boost::system::system_category());
+ return false;
+ }
+ break;
+ }
+
+ struct ::stat from_stat;
+ if (::fstat(infile.fd, &from_stat) != 0) {
+ fail_errno:
+ err = errno;
+ goto fail;
+ }
+
+ const mode_t from_mode = from_stat.st_mode;
+ if (!S_ISREG(from_mode)) {
+ err = ENOSYS;
+ goto fail;
+ }
+
+ // Enable writing for the newly created files. Having write permission set is important e.g. for NFS,
+ // which checks the file permission on the server, even if the client's file descriptor supports writing.
+ mode_t to_mode = from_mode | S_IWUSR;
+ int oflag = O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC;
+
+ while (true) {
+ outfile.fd = ::open(to.c_str(), oflag, to_mode);
+ if (outfile.fd < 0) {
+ err = errno;
+ if (err == EINTR)
+ continue;
+ goto fail;
+ }
+ break;
+ }
+
+ struct ::stat to_stat;
+ if (::fstat(outfile.fd, &to_stat) != 0)
+ goto fail_errno;
+
+ to_mode = to_stat.st_mode;
+ if (!S_ISREG(to_mode)) {
+ err = ENOSYS;
+ goto fail;
+ }
+
+ if (from_stat.st_dev == to_stat.st_dev && from_stat.st_ino == to_stat.st_ino) {
+ err = EEXIST;
+ goto fail;
+ }
+
+ //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors.
+ //FIXME Vojtech: This is a copy loop valid for Linux 2.6.33 and newer.
+ // copy_file_data_copy_file_range() supports cross-filesystem copying since 5.3, but Vojtech did not want to polute this
+ // function with that, we don't think the performance gain is worth it for the types of files we are copying,
+ // and our build server based on CentOS 7 with Linux 3.10 does not support that anyways.
+ {
+ // sendfile will not send more than this amount of data in one call
+ constexpr std::size_t max_send_size = 0x7ffff000u;
+ uintmax_t offset = 0u;
+ while (off_t(offset) < from_stat.st_size) {
+ uintmax_t size_left = from_stat.st_size - offset;
+ std::size_t size_to_copy = max_send_size;
+ if (size_left < static_cast<uintmax_t>(max_send_size))
+ size_to_copy = static_cast<std::size_t>(size_left);
+ ssize_t sz = ::sendfile(outfile.fd, infile.fd, nullptr, size_to_copy);
+ if (sz < 0) {
+ err = errno;
+ if (err == EINTR)
+ continue;
+ if (err == 0)
+ break;
+ goto fail; // err already contains the error code
+ }
+ offset += sz;
+ }
+ }
+
+ // If we created a new file with an explicitly added S_IWUSR permission,
+ // we may need to update its mode bits to match the source file.
+ if (to_mode != from_mode && ::fchmod(outfile.fd, from_mode) != 0) {
+ if (platform_flavor() == PlatformFlavor::LinuxOnChromium) {
+ // Ignore that. 9p filesystem does not allow fmod().
+ BOOST_LOG_TRIVIAL(info) << "copy_file_linux() failed to fchmod() the output file \"" << to.string() << "\" to " << from_mode << ": " << ec.message() <<
+ " This may be expected when writing to a 9p filesystem.";
+ } else {
+ // Generic linux. Write out an error to console. At least we may get some feedback.
+ BOOST_LOG_TRIVIAL(error) << "copy_file_linux() failed to fchmod() the output file \"" << to.string() << "\" to " << from_mode << ": " << ec.message();
+ }
+ }
+
+ // Note: Use fsync/fdatasync followed by close to avoid dealing with the possibility of close failing with EINTR.
+ // Even if close fails, including with EINTR, most operating systems (presumably, except HP-UX) will close the
+ // file descriptor upon its return. This means that if an error happens later, when the OS flushes data to the
+ // underlying media, this error will go unnoticed and we have no way to receive it from close. Calling fsync/fdatasync
+ // ensures that all data have been written, and even if close fails for some unfathomable reason, we don't really
+ // care at that point.
+ err = ::fdatasync(outfile.fd);
+ if (err != 0)
+ goto fail_errno;
+
+ return true;
+}
+#endif // __linux__
+
CopyFileResult copy_file_inner(const std::string& from, const std::string& to, std::string& error_message)
{
const boost::filesystem::path source(from);
@@ -434,7 +574,13 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
if (ec)
BOOST_LOG_TRIVIAL(debug) << "boost::filesystem::permisions before copy error message (this could be irrelevant message based on file system): " << ec.message();
ec.clear();
+#ifdef __linux__
+ // We want to allow copying files on Linux to succeed even if changing the file attributes fails.
+ // That may happen when copying on some exotic file system, for example Linux on Chrome.
+ copy_file_linux(source, target, ec);
+#else // __linux__
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
+#endif // __linux__
if (ec) {
error_message = ec.message();
return FAIL_COPY_FILE;
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 6436de2ca..4b3a1c6ca 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -209,8 +209,6 @@ set(SLIC3R_GUI_SOURCES
Utils/Bonjour.hpp
Utils/PresetUpdater.cpp
Utils/PresetUpdater.hpp
- Utils/Platform.cpp
- Utils/Platform.hpp
Utils/Process.cpp
Utils/Process.hpp
Utils/Profile.hpp
diff --git a/src/slic3r/GUI/GUI_Init.cpp b/src/slic3r/GUI/GUI_Init.cpp
index 3c77f3335..839782741 100644
--- a/src/slic3r/GUI/GUI_Init.cpp
+++ b/src/slic3r/GUI/GUI_Init.cpp
@@ -9,7 +9,6 @@
#include "slic3r/GUI/format.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/GUI/Plater.hpp"
-#include "slic3r/Utils/Platform.hpp"
// To show a message box if GUI initialization ends up with an exception thrown.
#include <wx/msgdlg.h>
@@ -37,8 +36,6 @@ int GUI_Run(GUI_InitParams &params)
signal(SIGCHLD, SIG_DFL);
#endif // __APPLE__
- detect_platform();
-
try {
GUI::GUI_App* gui = new GUI::GUI_App(params.start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index f50c7e356..ad4468683 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -1218,8 +1218,10 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this,
[]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this);
append_menu_check_item(viewMenu, wxID_ANY, _L("&Full screen") + "\t" + "F11", _L("Full screen"),
- [this](wxCommandEvent&) { this->ShowFullScreen(!this->IsFullScreen()); }, this,
- []() { return true; }, [this]() { return this->IsFullScreen(); }, this);
+ [this](wxCommandEvent&) { this->ShowFullScreen(!this->IsFullScreen(),
+ // wxFULLSCREEN_ALL: wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOTOOLBAR | wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION
+ wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION); },
+ this, []() { return true; }, [this]() { return this->IsFullScreen(); }, this);
}
// Help menu
diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp
index 8e8774036..c843da460 100644
--- a/src/slic3r/GUI/OpenGLManager.cpp
+++ b/src/slic3r/GUI/OpenGLManager.cpp
@@ -4,7 +4,8 @@
#include "GUI.hpp"
#include "I18N.hpp"
#include "3DScene.hpp"
-#include "slic3r/Utils/Platform.hpp"
+
+#include "libslic3r/Platform.hpp"
#include <GL/glew.h>
@@ -324,7 +325,7 @@ void OpenGLManager::detect_multisample(int* attribList)
enable_multisample &&
// Disable multi-sampling on ChromeOS, as the OpenGL virtualization swaps Red/Blue channels with multi-sampling enabled,
// at least on some platforms.
- (platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium) &&
+ platform_flavor() != PlatformFlavor::LinuxOnChromium &&
wxGLCanvas::IsDisplaySupported(attribList)
? EMultisampleState::Enabled : EMultisampleState::Disabled;
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 15e89168a..273f39b1e 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -76,7 +76,6 @@
#include "../Utils/FixModelByWin10.hpp"
#include "../Utils/UndoRedo.hpp"
#include "../Utils/PresetUpdater.hpp"
-#include "../Utils/Platform.hpp"
#include "../Utils/Process.hpp"
#include "RemovableDriveManager.hpp"
#include "InstanceCheck.hpp"
@@ -89,7 +88,9 @@
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
#include "WipeTowerDialog.hpp"
+
#include "libslic3r/CustomGCode.hpp"
+#include "libslic3r/Platform.hpp"
using boost::optional;
namespace fs = boost::filesystem;
@@ -3660,7 +3661,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
show_action_buttons(false);
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path,
// Don't offer the "Eject" button on ChromeOS, the Linux side has no control over it.
- platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium);
+ platform_flavor() != PlatformFlavor::LinuxOnChromium);
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
diff --git a/src/slic3r/GUI/PresetHints.cpp b/src/slic3r/GUI/PresetHints.cpp
index 0e5e10d45..181dcfda4 100644
--- a/src/slic3r/GUI/PresetHints.cpp
+++ b/src/slic3r/GUI/PresetHints.cpp
@@ -139,7 +139,6 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
const ConfigOptionFloatOrPercent *first_layer_extrusion_width_ptr = (first_layer && first_layer_extrusion_width.value > 0) ?
&first_layer_extrusion_width : nullptr;
const float lh = float(first_layer ? first_layer_height : layer_height);
- const float bfr = bridging ? bridge_flow_ratio : 0.f;
double max_flow = 0.;
std::string max_flow_extrusion_type;
auto limit_by_first_layer_speed = [&first_layer_speed, first_layer](double speed_normal, double speed_max) {
diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp
index c200956e1..33e61ab90 100644
--- a/src/slic3r/GUI/RemovableDriveManager.cpp
+++ b/src/slic3r/GUI/RemovableDriveManager.cpp
@@ -1,5 +1,5 @@
#include "RemovableDriveManager.hpp"
-#include "slic3r/Utils/Platform.hpp"
+#include "libslic3r/Platform.hpp"
#include <libslic3r/libslic3r.h>
#include <boost/nowide/convert.hpp>
@@ -232,7 +232,7 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
#else
- if (platform() == Platform::Linux && platform_flavor() == PlatformFlavor::LinuxOnChromium) {
+ if (platform_flavor() == PlatformFlavor::LinuxOnChromium) {
// ChromeOS specific: search /mnt/chromeos/removable/* folder
search_for_drives_internal::search_path("/mnt/chromeos/removable/*", "/mnt/chromeos/removable", current_drives);
} else {
@@ -452,7 +452,7 @@ RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status()
tbb::mutex::scoped_lock lock(m_drives_mutex);
out.has_eject =
// Cannot control eject on Chromium.
- (platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium) &&
+ platform_flavor() != PlatformFlavor::LinuxOnChromium &&
this->find_last_save_path_drive_data() != m_current_drives.end();
out.has_removable_drives = ! m_current_drives.empty();
}