Inrease the export "chunk size" to speed it up over 10% at least in some situations
[ardour.git] / libs / ardour / file_source.cc
index e6990aa487bfa09f2f1e896bde3add2632f6ee57..2f7ad2caa870b9f2739ae0c451619849d87a5135 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 "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"
 
@@ -68,7 +67,7 @@ FileSource::FileSource (Session& session, DataType type, const string& path, con
 }
 
 FileSource::FileSource (Session& session, const XMLNode& node, bool /*must_exist*/)
-       : Source(session, node)
+       : Source (session, node)
        , _file_is_new (false)
 {
        /* this setting of _path is temporary - we expect derived classes
@@ -87,7 +86,7 @@ FileSource::prevent_deletion ()
 {
         /* if this file already exists, it cannot be removed, ever
          */
-        
+
         if (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)) {
                 if (!(_flags & Destructive)) {
                         mark_immutable ();
@@ -101,9 +100,9 @@ bool
 FileSource::removable () const
 {
         bool r = ((_flags & Removable)
-                  && ((_flags & RemoveAtDestroy) || 
+                  && ((_flags & RemoveAtDestroy) ||
                       ((_flags & RemovableIfEmpty) && empty() == 0)));
-        
+
         return r;
 }
 
@@ -123,11 +122,7 @@ FileSource::init (const string& pathstr, bool must_exist)
         }
 
        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) {
@@ -235,17 +230,16 @@ FileSource::move_to_trash (const string& trash_dir_name)
  */
 bool
 FileSource::find (Session& s, DataType type, const string& path, bool must_exist,
-                 bool& isnew, uint16_t& chan, string& found_path)
+                 bool& isnew, uint16_t& /* chan */, string& found_path)
 {
        bool ret = false;
         string keeppath;
 
        isnew = false;
-        
+
         if (!Glib::path_is_absolute (path)) {
                 vector<string> dirs;
                 vector<string> hits;
-                int cnt;
                 string fullpath;
 
                 string search_path = s.source_search_path (type);
@@ -256,33 +250,62 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
                 }
 
                 split (search_path, dirs, ':');
-                
-                cnt = 0;
+
                 hits.clear ();
-                
+
                 for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
-                        
+
                         fullpath = Glib::build_filename (*i, path);
-                        
+
                         if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
                                 keeppath = fullpath;
                                 hits.push_back (fullpath);
-                                ++cnt;
                         }
                 }
-                
-                if (cnt > 1) {
-                        
-                        int which = FileSource::AmbiguousFileName (path, search_path, hits).get_value_or (-1);
-                        
+
+               /* 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;
+
+               for (vector<string>::iterator i = hits.begin(); i != hits.end(); ++i) {
+
+                       vector<string>::iterator j = i;
+                       ++j;
+                       
+                       while (j != hits.end()) {
+                               if (PBD::equivalent_paths (*i, *j)) {
+                                       /* *i and *j are the same file; break out of the loop early */
+                                       break;
+                               }
+
+                               ++j;
+                       }
+
+                       if (j == hits.end ()) {
+                               de_duped_hits.push_back (*i);
+                       }
+               }
+
+                if (de_duped_hits.size() > 1) {
+
+                       /* more than one match: ask the user */
+
+                        int which = FileSource::AmbiguousFileName (path, search_path, de_duped_hits).get_value_or (-1);
+
                         if (which < 0) {
                                 goto out;
                         } else {
-                                keeppath = hits[which];
+                                keeppath = de_duped_hits[which];
                         }
-                        
-                } else if (cnt == 0) {
-                        
+
+                } else if (de_duped_hits.size() == 0) {
+
+                       /* no match: error */
+
                         if (must_exist) {
                                 error << string_compose(
                                         _("Filesource: cannot find required file (%1): while searching %2"),
@@ -291,13 +314,19 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
                         } else {
                                 isnew = true;
                         }
-                }
+                } else {
+
+                       /* only one match: happy days */
+                       
+                       keeppath = de_duped_hits[0];
+               }
+                                                 
         } else {
                 keeppath = path;
         }
-        
+
         /* Current find() is unable to parse relative path names to yet non-existant
-           sources. QuickFix(tm) 
+           sources. QuickFix(tm)
         */
         if (keeppath == "") {
                 if (must_exist) {
@@ -306,11 +335,11 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
                         keeppath = path;
                 }
         }
-        
+
         found_path = keeppath;
-        
+
         ret = true;
-        
+
   out:
        return ret;
 }
@@ -353,7 +382,7 @@ FileSource::find_2X (Session& s, DataType type, const string& path, bool must_ex
                cnt = 0;
 
                for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
-                        
+
                         fullpath = Glib::build_filename (*i, pathstr);
 
                        /* i (paul) made a nasty design error by using ':' as a special character in
@@ -504,7 +533,7 @@ FileSource::set_source_name (const string& newname, bool destructive)
                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;
        }
-        
+
         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;
@@ -543,9 +572,9 @@ FileSource::set_path (const std::string& newpath)
         _path = newpath;
 }
 
-void 
+void
 FileSource::inc_use_count ()
 {
         Source::inc_use_count ();
 }
+