Use PLATFORM_WINDOWS (in preference to WIN32) for consistency with the other libraries
[ardour.git] / libs / ardour / file_source.cc
index e35ee81364ce17afd9353b5137d16fa1ec633ca8..109539ce2d7539fe242861a0d189b6e55e5f701b 100644 (file)
 
 #include "pbd/convert.h"
 #include "pbd/basename.h"
-#include "pbd/mountpoint.h"
 #include "pbd/stl_delete.h"
 #include "pbd/strsplit.h"
 #include "pbd/shortpath.h"
 #include "pbd/enumwriter.h"
+#include "pbd/file_utils.h"
 
 #include <glibmm/miscutils.h>
 #include <glibmm/fileutils.h>
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
 
+#include "ardour/data_type.h"
 #include "ardour/file_source.h"
-#include "ardour/directory_names.h"
 #include "ardour/session.h"
-#include "ardour/session_directory.h"
-#include "ardour/source_factory.h"
-#include "ardour/filename_extensions.h"
+#include "ardour/source.h"
+#include "ardour/utils.h"
 
 #include "i18n.h"
 
@@ -52,19 +51,17 @@ using namespace ARDOUR;
 using namespace PBD;
 using namespace Glib;
 
-PBD::Signal3<int,std::string,std::string,std::vector<std::string> > FileSource::AmbiguousFileName;
+PBD::Signal2<int,std::string,std::vector<std::string> > FileSource::AmbiguousFileName;
 
 FileSource::FileSource (Session& session, DataType type, const string& path, const string& origin, Source::Flag flag)
        : Source(session, type, path, flag)
-       , _path(path)
-       , _file_is_new(true)
+       , _path (path)
+       , _file_is_new (!origin.empty()) // origin empty => new file VS. origin !empty => new file
        , _channel (0)
         , _origin (origin)
         , _open (false)
 {
        set_within_session_from_path (path);
-
-        prevent_deletion ();
 }
 
 FileSource::FileSource (Session& session, const XMLNode& node, bool /*must_exist*/)
@@ -78,23 +75,28 @@ FileSource::FileSource (Session& session, const XMLNode& node, bool /*must_exist
 
        _path = _name;
        _within_session = true;
+}
 
-        prevent_deletion ();
+FileSource::~FileSource()
+{
 }
 
 void
-FileSource::prevent_deletion ()
+FileSource::existence_check ()
 {
-        /* if this file already exists, it cannot be removed, ever
-         */
-
         if (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)) {
-                if (!(_flags & Destructive)) {
-                        mark_immutable ();
-                } else {
-                        _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));
-                }
-        }
+               prevent_deletion ();
+       }
+}
+
+void
+FileSource::prevent_deletion ()
+{
+       if (!(_flags & Destructive)) {
+               mark_immutable ();
+       } else {
+               _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));
+       }
 }
 
 bool
@@ -102,7 +104,7 @@ FileSource::removable () const
 {
         bool r = ((_flags & Removable)
                   && ((_flags & RemoveAtDestroy) ||
-                      ((_flags & RemovableIfEmpty) && empty() == 0)));
+                      ((_flags & RemovableIfEmpty) && empty())));
 
         return r;
 }
@@ -112,26 +114,24 @@ FileSource::init (const string& pathstr, bool must_exist)
 {
        _timeline_position = 0;
 
-        if (Stateful::loading_state_version < 3000) {
-                if (!find_2X (_session, _type, pathstr, must_exist, _file_is_new, _channel, _path)) {
-                        throw MissingSource (pathstr, _type);
-                }
-        } else {
-                if (!find (_session, _type, pathstr, must_exist, _file_is_new, _channel, _path)) {
-                        throw MissingSource (pathstr, _type);
-                }
-        }
+       if (Stateful::loading_state_version < 3000) {
+               if (!find_2X (_session, _type, pathstr, must_exist, _file_is_new, _channel, _path)) {
+                       throw MissingSource (pathstr, _type);
+               }
+       } else {
+               if (!find (_session, _type, pathstr, must_exist, _file_is_new, _channel, _path)) {
+                       throw MissingSource (pathstr, _type);
+               }
+       }
 
        set_within_session_from_path (_path);
 
-        if (!within_session()) {
-                _session.ensure_search_path_includes (Glib::path_get_dirname (_path), _type);
-        }
-
         _name = Glib::path_get_basename (_path);
 
-       if (_file_is_new && must_exist) {
-               return -1;
+       if (must_exist) {
+               if (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS)) {
+                       throw MissingSource (pathstr, _type);
+               }
        }
 
        return 0;
@@ -243,19 +243,15 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
        isnew = false;
 
         if (!Glib::path_is_absolute (path)) {
-                vector<string> dirs;
                 vector<string> hits;
                 string fullpath;
+               std::vector<std::string> dirs = s.source_search_path (type);
 
-                string search_path = s.source_search_path (type);
-
-                if (search_path.length() == 0) {
+                if (dirs.size() == 0) {
                         error << _("FileSource: search path not set") << endmsg;
                         goto out;
                 }
 
-                split (search_path, dirs, ':');
-
                 hits.clear ();
 
                 for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
@@ -270,6 +266,8 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
 
                /* Remove duplicate inodes from the list of ambiguous files, since if there are symlinks
                   in the session path it is possible to arrive at the same file via more than one path.
+
+                  I suppose this is not necessary on Windows.
                */
 
                vector<string> de_duped_hits;
@@ -280,13 +278,7 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
                        ++j;
                        
                        while (j != hits.end()) {
-
-                               struct stat bufA;
-                               int const rA = stat (i->c_str(), &bufA);
-                               struct stat bufB;
-                               int const rB = stat (j->c_str(), &bufB);
-
-                               if (rA == 0 && rB == 0 && bufA.st_ino == bufB.st_ino) {
+                               if (PBD::equivalent_paths (*i, *j)) {
                                        /* *i and *j are the same file; break out of the loop early */
                                        break;
                                }
@@ -303,7 +295,7 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
 
                        /* more than one match: ask the user */
 
-                        int which = FileSource::AmbiguousFileName (path, search_path, de_duped_hits).get_value_or (-1);
+                        int which = FileSource::AmbiguousFileName (path, de_duped_hits).get_value_or (-1);
 
                         if (which < 0) {
                                 goto out;
@@ -317,8 +309,7 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
 
                         if (must_exist) {
                                 error << string_compose(
-                                        _("Filesource: cannot find required file (%1): while searching %2"),
-                                        path, search_path) << endmsg;
+                                        _("Filesource: cannot find required file (%1)"), path) << endmsg;
                                 goto out;
                         } else {
                                 isnew = true;
@@ -364,8 +355,6 @@ bool
 FileSource::find_2X (Session& s, DataType type, const string& path, bool must_exist,
                      bool& isnew, uint16_t& chan, string& found_path)
 {
-       string search_path = s.source_search_path (type);
-
        string pathstr = path;
        string::size_type pos;
        bool ret = false;
@@ -376,18 +365,17 @@ FileSource::find_2X (Session& s, DataType type, const string& path, bool must_ex
 
                /* non-absolute pathname: find pathstr in search path */
 
-               vector<string> dirs;
+               vector<string> dirs = s.source_search_path (type);
+
                int cnt;
                string fullpath;
                string keeppath;
 
-               if (search_path.length() == 0) {
+               if (dirs.size() == 0) {
                        error << _("FileSource: search path not set") << endmsg;
                        goto out;
                }
 
-               split (search_path, dirs, ':');
-
                cnt = 0;
 
                for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
@@ -444,16 +432,14 @@ FileSource::find_2X (Session& s, DataType type, const string& path, bool must_ex
                if (cnt > 1) {
 
                        error << string_compose (
-                                       _("FileSource: \"%1\" is ambigous when searching %2\n\t"),
-                                       pathstr, search_path) << endmsg;
+                                       _("FileSource: \"%1\" is ambigous when searching\n\t"), pathstr) << endmsg;
                        goto out;
 
                } else if (cnt == 0) {
 
                        if (must_exist) {
                                error << string_compose(
-                                               _("Filesource: cannot find required file (%1): while searching %2"),
-                                               pathstr, search_path) << endmsg;
+                                               _("Filesource: cannot find required file (%1)"), pathstr) << endmsg;
                                goto out;
                        } else {
                                isnew = true;
@@ -503,13 +489,14 @@ FileSource::find_2X (Session& s, DataType type, const string& path, bool must_ex
                                goto out;
                        }
 
+#ifndef PLATFORM_WINDOWS
                        if (errno != ENOENT) {
                                error << string_compose(
                                                _("Filesource: cannot check for existing file (%1): %2"),
                                                path, strerror (errno)) << endmsg;
                                goto out;
                        }
-
+#endif
                        /* a new file */
                        isnew = true;
                        ret = true;
@@ -525,41 +512,21 @@ out:
        return ret;
 }
 
-int
-FileSource::set_source_name (const string& newname, bool destructive)
+void
+FileSource::mark_immutable ()
 {
-       Glib::Mutex::Lock lm (_lock);
-       string oldpath = _path;
-       string newpath = _session.change_source_path_by_name (oldpath, _name, newname, destructive);
-
-       if (newpath.empty()) {
-               error << string_compose (_("programming error: %1"), "cannot generate a changed file path") << endmsg;
-               return -1;
-       }
-
-       // Test whether newpath exists, if yes notify the user but continue.
-       if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
-               error << string_compose (_("Programming error! %1 tried to rename a file over another file! It's safe to continue working, but please report this to the developers."), PROGRAM_NAME) << endmsg;
-               return -1;
+       /* destructive sources stay writable, and their other flags don't change.  */
+       if (!(_flags & Destructive)) {
+               _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
        }
-
-        if (::rename (oldpath.c_str(), newpath.c_str()) != 0) {
-                error << string_compose (_("cannot rename file %1 to %2 (%3)"), oldpath, newpath, strerror(errno)) << endmsg;
-                return -1;
-        }
-
-       _name = Glib::path_get_basename (newpath);
-       _path = newpath;
-
-       return 0;
 }
 
 void
-FileSource::mark_immutable ()
+FileSource::mark_immutable_except_write ()
 {
        /* destructive sources stay writable, and their other flags don't change.  */
        if (!(_flags & Destructive)) {
-               _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
+               _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
        }
 }
 
@@ -587,3 +554,21 @@ FileSource::inc_use_count ()
         Source::inc_use_count ();
 }
 
+bool
+FileSource::is_stub () const
+{
+       if (!empty()) {
+               return false;
+       }
+       
+       if (!removable()) {
+               return false;
+       }
+
+       if (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)) {
+               return false;
+       }
+
+       return true;
+}
+