Replace use of PBD::sys::path in ardour/session_state_utils.h
[ardour.git] / libs / ardour / session_state.cc
index efde3e2f4e30f5f4cf9bc7c529e4ee0a2a68ca6a..3656e0f07eac41370c5789b407f4267f916c29cc 100644 (file)
 #include <sys/mount.h>
 #endif
 
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
 #include <glib.h>
 
 #include <glibmm.h>
@@ -57,6 +61,8 @@
 #include "midi++/port.h"
 #include "midi++/manager.h"
 
+#include "evoral/SMF.hpp"
+
 #include "pbd/boost_debug.h"
 #include "pbd/basename.h"
 #include "pbd/controllable_descriptor.h"
 
 #include "ardour/amp.h"
 #include "ardour/audio_diskstream.h"
-#include "ardour/audio_playlist_source.h"
 #include "ardour/audio_track.h"
 #include "ardour/audioengine.h"
 #include "ardour/audiofilesource.h"
-#include "ardour/audioplaylist.h"
 #include "ardour/audioregion.h"
-#include "ardour/auditioner.h"
 #include "ardour/automation_control.h"
-#include "ardour/buffer.h"
 #include "ardour/butler.h"
-#include "ardour/configuration.h"
 #include "ardour/control_protocol_manager.h"
-#include "ardour/cycle_timer.h"
 #include "ardour/directory_names.h"
 #include "ardour/filename_extensions.h"
-#include "ardour/io_processor.h"
 #include "ardour/location.h"
-#include "ardour/midi_diskstream.h"
 #include "ardour/midi_model.h"
 #include "ardour/midi_patch_manager.h"
-#include "ardour/midi_playlist.h"
 #include "ardour/midi_region.h"
 #include "ardour/midi_source.h"
 #include "ardour/midi_track.h"
 #include "ardour/named_selection.h"
 #include "ardour/pannable.h"
-#include "ardour/processor.h"
+#include "ardour/playlist_factory.h"
 #include "ardour/port.h"
+#include "ardour/processor.h"
 #include "ardour/proxy_controllable.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/region_factory.h"
 #include "ardour/session.h"
 #include "ardour/session_directory.h"
 #include "ardour/session_metadata.h"
-#include "ardour/session_state_utils.h"
 #include "ardour/session_playlists.h"
+#include "ardour/session_state_utils.h"
 #include "ardour/session_utils.h"
 #include "ardour/silentfilesource.h"
-#include "ardour/slave.h"
-#include "ardour/smf_source.h"
-#include "ardour/sndfile_helpers.h"
 #include "ardour/sndfilesource.h"
 #include "ardour/source_factory.h"
 #include "ardour/speakers.h"
 #include "ardour/tempo.h"
 #include "ardour/ticker.h"
 #include "ardour/user_bundle.h"
-#include "ardour/utils.h"
-#include "ardour/utils.h"
-#include "ardour/version.h"
-#include "ardour/playlist_factory.h"
 
 #include "control_protocol/control_protocol.h"
 
@@ -178,6 +169,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        _solo_isolated_cnt = 0;
        g_atomic_int_set (&processing_prohibited, 0);
        _transport_speed = 0;
+       _default_transport_speed = 1.0;
        _last_transport_speed = 0;
        _target_transport_speed = 0;
        auto_play_legal = false;
@@ -296,7 +288,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
 int
 Session::second_stage_init ()
 {
-       AudioFileSource::set_peak_dir (_session_dir->peak_path().to_string());
+       AudioFileSource::set_peak_dir (_session_dir->peak_path());
 
        if (!_is_new) {
                if (load_state (_current_snapshot_name)) {
@@ -400,7 +392,7 @@ Session::raid_path () const
        SearchPath raid_search_path;
 
        for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
-               raid_search_path += sys::path((*i).path);
+               raid_search_path += (*i).path;
        }
 
        return raid_search_path.to_string ();
@@ -423,7 +415,7 @@ Session::setup_raid_path (string path)
        SearchPath midi_search_path;
 
        for (SearchPath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
-               sp.path = (*i).to_string ();
+               sp.path = *i;
                sp.blocks = 0; // not needed
                session_dirs.push_back (sp);
 
@@ -441,7 +433,7 @@ bool
 Session::path_is_within_session (const std::string& path)
 {
        for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
-               if (path.find ((*i).path) == 0) {
+               if (PBD::sys::path_is_within (i->path, path)) {
                        return true;
                }
        }
@@ -453,35 +445,35 @@ Session::ensure_subdirs ()
 {
        string dir;
 
-       dir = session_directory().peak_path().to_string();
+       dir = session_directory().peak_path();
 
        if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
                error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
                return -1;
        }
 
-       dir = session_directory().sound_path().to_string();
+       dir = session_directory().sound_path();
 
        if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
                error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
                return -1;
        }
 
-       dir = session_directory().midi_path().to_string();
+       dir = session_directory().midi_path();
 
        if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
                error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
                return -1;
        }
 
-       dir = session_directory().dead_path().to_string();
+       dir = session_directory().dead_path();
 
        if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
                error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
                return -1;
        }
 
-       dir = session_directory().export_path().to_string();
+       dir = session_directory().export_path();
 
        if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
                error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
@@ -664,8 +656,8 @@ Session::rename_state (string old_name, string new_name)
        const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
        const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
 
-       const sys::path old_xml_path = _session_dir->root_path() / old_xml_filename;
-       const sys::path new_xml_path = _session_dir->root_path() / new_xml_filename;
+       const sys::path old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
+       const sys::path new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
 
        try
        {
@@ -684,14 +676,14 @@ Session::rename_state (string old_name, string new_name)
 void
 Session::remove_state (string snapshot_name)
 {
-       if (snapshot_name == _current_snapshot_name || snapshot_name == _name) {
+       if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
                // refuse to remove the current snapshot or the "main" one
                return;
        }
 
-       sys::path xml_path(_session_dir->root_path());
+       std::string xml_path(_session_dir->root_path());
 
-       xml_path /= legalize_for_path (snapshot_name) + statefile_suffix;
+       xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
 
        if (!create_backup_file (xml_path)) {
                // don't remove it if a backup can't be made
@@ -761,7 +753,7 @@ int
 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
 {
        XMLTree tree;
-       sys::path xml_path(_session_dir->root_path());
+       std::string xml_path(_session_dir->root_path());
 
        if (!_writable || (_state_of_the_state & CannotSave)) {
                return 1;
@@ -782,7 +774,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
                } catch (Evoral::SMF::FileError& e) {
                        error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
                }
-        }
+       }
 
        tree.set_root (&get_state());
 
@@ -796,7 +788,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
 
                /* proper save: use statefile_suffix (.ardour in English) */
 
-               xml_path /= legalize_for_path (snapshot_name) + statefile_suffix;
+               xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
 
                /* make a backup copy of the old file */
 
@@ -808,7 +800,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
        } else {
 
                /* pending save: use pending_suffix (.pending in English) */
-               xml_path /= legalize_for_path (snapshot_name) + pending_suffix;
+               xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
        }
 
        sys::path tmp_path(_session_dir->root_path());
@@ -824,9 +816,9 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
 
        } else {
 
-               if (::rename (tmp_path.to_string().c_str(), xml_path.to_string().c_str()) != 0) {
+               if (::rename (tmp_path.to_string().c_str(), xml_path.c_str()) != 0) {
                        error << string_compose (_("could not rename temporary session file %1 to %2"),
-                                       tmp_path.to_string(), xml_path.to_string()) << endmsg;
+                                       tmp_path.to_string(), xml_path) << endmsg;
                        sys::remove (tmp_path);
                        return -1;
                }
@@ -925,39 +917,42 @@ Session::load_state (string snapshot_name)
                /* no version implies very old version of Ardour */
                Stateful::loading_state_version = 1000;
        } else {
-               int major;
-               int minor;
-               int micro;
-
-               sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, &micro);
-               Stateful::loading_state_version = (major * 1000) + minor;
+               if (prop->value().find ('.') != string::npos) {
+                       /* old school version format */
+                       if (prop->value()[0] == '2') {
+                               Stateful::loading_state_version = 2000;
+                       } else {
+                               Stateful::loading_state_version = 3000;
+                       }
+               } else {
+                       Stateful::loading_state_version = atoi (prop->value());
+               }
        }
 
-       if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION) {
+       if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
 
                sys::path backup_path(_session_dir->root_path());
 
-               backup_path /= legalize_for_path (snapshot_name) + "-1" + statefile_suffix;
+               backup_path /= string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
 
-               // only create a backup once
-               if (sys::exists (backup_path)) {
-                       return 0;
-               }
-
-               info << string_compose (_("Copying old session file %1 to %2\nUse %2 with %3 versions before 2.0 from now on"),
-                                       xmlpath.to_string(), backup_path.to_string(), PROGRAM_NAME)
-                    << endmsg;
+               // only create a backup for a given statefile version once
 
-               try
-               {
-                       sys::copy_file (xmlpath, backup_path);
-               }
-               catch(sys::filesystem_error& ex)
-               {
-                       error << string_compose (_("Unable to make backup of state file %1 (%2)"),
-                                       xmlpath.to_string(), ex.what())
-                               << endmsg;
-                       return -1;
+               if (!sys::exists (backup_path)) {
+                       
+                       info << string_compose (_("Copying old session file %1 to %2\nUse %2 with %3 versions before 2.0 from now on"),
+                                               xmlpath.to_string(), backup_path.to_string(), PROGRAM_NAME)
+                            << endmsg;
+                       
+                       try {
+                               sys::copy_file (xmlpath, backup_path);
+                               
+                       } catch (sys::filesystem_error& ex) {
+                               
+                               error << string_compose (_("Unable to make backup of state file %1 (%2)"),
+                                                        xmlpath.to_string(), ex.what())
+                                     << endmsg;
+                               return -1;
+                       }
                }
        }
 
@@ -992,15 +987,14 @@ Session::get_template()
 }
 
 XMLNode&
-Session::state(bool full_state)
+Session::state (bool full_state)
 {
        XMLNode* node = new XMLNode("Session");
        XMLNode* child;
 
-       // store libardour version, just in case
        char buf[16];
-       snprintf(buf, sizeof(buf), "%d.%d.%d", libardour3_major_version, libardour3_minor_version, libardour3_micro_version);
-       node->add_property("version", string(buf));
+       snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
+       node->add_property("version", buf);
 
        /* store configuration settings */
 
@@ -1216,10 +1210,6 @@ Session::set_state (const XMLNode& node, int version)
                return -1;
        }
 
-       if ((prop = node.property ("version")) != 0) {
-               version = atoi (prop->value ()) * 1000;
-       }
-
        if ((prop = node.property ("name")) != 0) {
                _name = prop->value ();
        }
@@ -1236,7 +1226,7 @@ Session::set_state (const XMLNode& node, int version)
                }
        }
 
-       setup_raid_path(_session_dir->root_path().to_string());
+       setup_raid_path(_session_dir->root_path());
 
        if ((prop = node.property (X_("id-counter"))) != 0) {
                uint64_t x;
@@ -2094,23 +2084,48 @@ Session::save_template (string template_name)
 void
 Session::refresh_disk_space ()
 {
-#if HAVE_SYS_VFS_H
-       struct statfs statfsbuf;
-       vector<space_and_path>::iterator i;
+#if HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H
+       
        Glib::Mutex::Lock lm (space_lock);
-       double scale;
 
        /* get freespace on every FS that is part of the session path */
 
        _total_free_4k_blocks = 0;
+       _total_free_4k_blocks_uncertain = false;
 
-       for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
-               statfs ((*i).path.c_str(), &statfsbuf);
+       for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+
+               struct statfs statfsbuf;
+               statfs (i->path.c_str(), &statfsbuf);
+
+               double const scale = statfsbuf.f_bsize / 4096.0;
 
-               scale = statfsbuf.f_bsize/4096.0;
+               /* See if this filesystem is read-only */
+               struct statvfs statvfsbuf;
+               statvfs (i->path.c_str(), &statvfsbuf);
 
-               (*i).blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
-               _total_free_4k_blocks += (*i).blocks;
+               /* f_bavail can be 0 if it is undefined for whatever
+                  filesystem we are looking at; Samba shares mounted
+                  via GVFS are an example of this.
+               */
+               if (statfsbuf.f_bavail == 0) {
+                       /* block count unknown */
+                       i->blocks = 0;
+                       i->blocks_unknown = true;
+               } else if (statvfsbuf.f_flag & ST_RDONLY) {
+                       /* read-only filesystem */
+                       i->blocks = 0;
+                       i->blocks_unknown = false;
+               } else {
+                       /* read/write filesystem with known space */
+                       i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
+                       i->blocks_unknown = false;
+               }
+
+               _total_free_4k_blocks += i->blocks;
+               if (i->blocks_unknown) {
+                       _total_free_4k_blocks_uncertain = true;
+               }
        }
 #endif
 }
@@ -2119,7 +2134,7 @@ string
 Session::get_best_session_directory_for_new_source ()
 {
        vector<space_and_path>::iterator i;
-       string result = _session_dir->root_path().to_string();
+       string result = _session_dir->root_path();
 
        /* handle common case without system calls */
 
@@ -2735,7 +2750,7 @@ Session::cleanup_sources (CleanupReport& rep)
                ++nexti;
 
                SessionDirectory sdir ((*i).path);
-               audio_path += sdir.sound_path().to_string();
+               audio_path += sdir.sound_path();
 
                if (nexti != session_dirs.end()) {
                        audio_path += ':';
@@ -2753,7 +2768,7 @@ Session::cleanup_sources (CleanupReport& rep)
                ++nexti;
 
                SessionDirectory sdir ((*i).path);
-               midi_path += sdir.midi_path().to_string();
+               midi_path += sdir.midi_path();
 
                if (nexti != session_dirs.end()) {
                        midi_path += ':';
@@ -3237,8 +3252,8 @@ Session::save_history (string snapshot_name)
 
        const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
        const string backup_filename = history_filename + backup_suffix;
-       const sys::path xml_path = _session_dir->root_path() / history_filename;
-       const sys::path backup_path = _session_dir->root_path() / backup_filename;
+       const sys::path xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
+       const sys::path backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
 
        if (sys::exists (xml_path)) {
                try
@@ -3289,7 +3304,7 @@ Session::restore_history (string snapshot_name)
        }
 
        const string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
-       const sys::path xml_path = _session_dir->root_path() / xml_filename;
+       const sys::path xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
 
        info << "Loading history from " << xml_path.to_string() << endmsg;
 
@@ -3666,7 +3681,7 @@ Session::rename (const std::string& new_name)
        string newstr;
        bool first = true;
 
-       string const old_sources_root = _session_dir->sources_root().to_string ();
+       string const old_sources_root = _session_dir->sources_root();
 
 #define RENAME ::rename
 
@@ -3795,7 +3810,7 @@ Session::rename (const std::string& new_name)
                boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
                if (fs) {
                        string p = fs->path ();
-                       boost::replace_all (p, old_sources_root, _session_dir->sources_root().to_string ());
+                       boost::replace_all (p, old_sources_root, _session_dir->sources_root());
                        fs->set_path (p);
                }
        }