Fix egregious logic bug in FileSource::removable() and introduce FileSource::is_stub...
[ardour.git] / libs / ardour / file_source.cc
index e35ee81364ce17afd9353b5137d16fa1ec633ca8..c6f3a9cd5d9f120739dc5de41127f4ae1ae3cbd3 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"
 
@@ -56,8 +55,8 @@ PBD::Signal3<int,std::string,std::string,std::vector<std::string> > FileSource::
 
 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)
@@ -102,7 +101,7 @@ FileSource::removable () const
 {
         bool r = ((_flags & Removable)
                   && ((_flags & RemoveAtDestroy) ||
-                      ((_flags & RemovableIfEmpty) && empty() == 0)));
+                      ((_flags & RemovableIfEmpty) && empty())));
 
         return r;
 }
@@ -112,26 +111,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;
@@ -270,6 +267,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 +279,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;
                                }
@@ -528,7 +521,7 @@ out:
 int
 FileSource::set_source_name (const string& newname, bool destructive)
 {
-       Glib::Mutex::Lock lm (_lock);
+       Glib::Threads::Mutex::Lock lm (_lock);
        string oldpath = _path;
        string newpath = _session.change_source_path_by_name (oldpath, _name, newname, destructive);
 
@@ -563,6 +556,15 @@ FileSource::mark_immutable ()
        }
 }
 
+void
+FileSource::mark_immutable_except_write ()
+{
+       /* destructive sources stay writable, and their other flags don't change.  */
+       if (!(_flags & Destructive)) {
+               _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
+       }
+}
+
 void
 FileSource::mark_nonremovable ()
 {
@@ -587,3 +589,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;
+}
+