diff --git a/CMakeLists.txt b/CMakeLists.txt
index 628615be88a9d5030cd8b1a25931c1c1cfb6505d..e8380d37cb3664135721258e380fc49dce1c484b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,6 +35,7 @@ add_subdirectory(cmdline)
 add_subdirectory(common)
 add_subdirectory(objectstore)
 add_subdirectory(nameserver)
+add_subdirectory(remotestorage)
 add_subdirectory(scheduler)
 add_subdirectory(tests)
 add_subdirectory(xroot_plugins)
diff --git a/remotestorage/CMakeLists.txt b/remotestorage/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..457ca91a1141c1ee911a40a7b61fb34925ec1b08
--- /dev/null
+++ b/remotestorage/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required (VERSION 2.6)
+
+set (CTA_REMOTE_STORAGE_SRC_FILES
+  EosRemoteStorage.cpp
+  MockRemoteStorage.cpp
+  RemoteStorage.cpp)
+
+add_library (ctaremotestorage SHARED
+  ${CTA_REMOTE_STORAGE_SRC_FILES})
diff --git a/scheduler/EosRemoteStorage.cpp b/remotestorage/EosRemoteStorage.cpp
similarity index 69%
rename from scheduler/EosRemoteStorage.cpp
rename to remotestorage/EosRemoteStorage.cpp
index c3d031e06f2e9409c32d09a4524d0af07f30da69..6de1a15a558d21aa53c0c139d87f4a38c82db31e 100644
--- a/scheduler/EosRemoteStorage.cpp
+++ b/remotestorage/EosRemoteStorage.cpp
@@ -16,9 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "scheduler/EosRemoteStorage.hpp"
 #include "common/exception/Exception.hpp"
-using cta::exception::Exception;
+#include "remotestorage/EosRemoteStorage.hpp"
 
 //------------------------------------------------------------------------------
 // destructor
@@ -27,10 +26,18 @@ cta::EosRemoteStorage::~EosRemoteStorage() throw() {
 }
 
 //------------------------------------------------------------------------------
-// fileExists
+// regularFileExists
 //------------------------------------------------------------------------------
-bool cta::EosRemoteStorage::fileExists(const std::string &remoteFile) {
-  throw  Exception("EosRemoteStorage::fileExists() not implemented");
+bool cta::EosRemoteStorage::regularFileExists(const std::string &remoteFile)
+  const {
+  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
+}
+
+//------------------------------------------------------------------------------
+// dirExists
+//------------------------------------------------------------------------------
+bool cta::EosRemoteStorage::dirExists(const std::string &remoteFile) const {
+  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
 }
 
 //------------------------------------------------------------------------------
@@ -38,5 +45,5 @@ bool cta::EosRemoteStorage::fileExists(const std::string &remoteFile) {
 //------------------------------------------------------------------------------
 void cta::EosRemoteStorage::rename(const std::string &remoteFile,
   const std::string &newRemoteFile) {
-  throw Exception("EosRemoteStorage::rename() not implemented");
+  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
 }
diff --git a/scheduler/EosRemoteStorage.hpp b/remotestorage/EosRemoteStorage.hpp
similarity index 72%
rename from scheduler/EosRemoteStorage.hpp
rename to remotestorage/EosRemoteStorage.hpp
index 444ebaced2c9292f32b7ecb36ff9b530dcced760..b10ee5fc24519bb79688f4f9fd4ae036a8dcc3cc 100644
--- a/scheduler/EosRemoteStorage.hpp
+++ b/remotestorage/EosRemoteStorage.hpp
@@ -18,7 +18,7 @@
 
 #pragma once
 
-#include "scheduler/RemoteStorage.hpp"
+#include "remotestorage/RemoteStorage.hpp"
 
 namespace cta {
 
@@ -34,12 +34,20 @@ public:
   ~EosRemoteStorage() throw();
 
   /**
-   * Returns true if the specified remote file exists or false if not.
+   * Returns true if the specified regular file exists.
    *
-   * @param remoteFile The URL of the remote file.
-   * @return true if the specified remote file exists or false if not.
+   * @param path The absolute path of the file.
+   * @return True if the specified directory exists.
    */
-  bool fileExists(const std::string &remoteFile);
+  bool regularFileExists(const std::string &path) const;
+
+  /**
+   * Returns true if the specified directory exists.
+   *
+   * @param path The absolute path of the file.
+   * @return True if the specified directory exists.
+   */
+  bool dirExists(const std::string &path) const;
 
   /**
    * Renames the specified remote file to the specified new name.
diff --git a/remotestorage/MockRemoteStorage.cpp b/remotestorage/MockRemoteStorage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3c01b52e0483760ad9412fea94b06ccd6965ebf2
--- /dev/null
+++ b/remotestorage/MockRemoteStorage.cpp
@@ -0,0 +1,49 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/exception/Exception.hpp"
+#include "remotestorage/MockRemoteStorage.hpp"
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::MockRemoteStorage::~MockRemoteStorage() throw() {
+}
+
+//------------------------------------------------------------------------------
+// regularFileExists
+//------------------------------------------------------------------------------
+bool cta::MockRemoteStorage::regularFileExists(const std::string &remoteFile)
+  const {
+  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
+}
+
+//------------------------------------------------------------------------------
+// dirExists
+//------------------------------------------------------------------------------
+bool cta::MockRemoteStorage::dirExists(const std::string &remoteFile) const {
+  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
+}
+
+//------------------------------------------------------------------------------
+// rename
+//------------------------------------------------------------------------------
+void cta::MockRemoteStorage::rename(const std::string &remoteFile,
+  const std::string &newRemoteFile) {
+  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
+}
diff --git a/remotestorage/MockRemoteStorage.hpp b/remotestorage/MockRemoteStorage.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5894ce2209e06f4e46a198ff30cc0d6d8d02e3a9
--- /dev/null
+++ b/remotestorage/MockRemoteStorage.hpp
@@ -0,0 +1,63 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "remotestorage/RemoteStorage.hpp"
+
+namespace cta {
+
+/**
+ * A mock proxy class for a remote storage system.
+ */
+class MockRemoteStorage: public RemoteStorage {
+public:
+
+  /**
+   * Destructor.
+   */
+  ~MockRemoteStorage() throw();
+
+  /**
+   * Returns true if the specified regular file exists.
+   *
+   * @param path The absolute path of the file.
+   * @return True if the specified directory exists.
+   */
+  bool regularFileExists(const std::string &path) const;
+
+  /**
+   * Returns true if the specified directory exists.
+   *
+   * @param path The absolute path of the file.
+   * @return True if the specified directory exists.
+   */
+  bool dirExists(const std::string &path) const;
+
+  /**
+   * Renames the specified remote file to the specified new name.
+   *
+   * @param remoteFile The current URL of the remote file.
+   * @param newRemoteFile The new URL of the remote file.
+   */
+  void rename(const std::string &remoteFile,
+    const std::string &newRemoteFile);
+
+}; // class MockRemoteStorage
+
+} // namespace cta
diff --git a/scheduler/RemoteStorage.cpp b/remotestorage/RemoteStorage.cpp
similarity index 95%
rename from scheduler/RemoteStorage.cpp
rename to remotestorage/RemoteStorage.cpp
index 5cc7176dc8a43caac47bb6d1c3f33d2622eebf30..8d1219ad0a38d38f469086f92d2d2baec672828a 100644
--- a/scheduler/RemoteStorage.cpp
+++ b/remotestorage/RemoteStorage.cpp
@@ -16,7 +16,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "scheduler/RemoteStorage.hpp"
+#include "remotestorage/RemoteStorage.hpp"
 
 //------------------------------------------------------------------------------
 // destructor
diff --git a/scheduler/RemoteStorage.hpp b/remotestorage/RemoteStorage.hpp
similarity index 74%
rename from scheduler/RemoteStorage.hpp
rename to remotestorage/RemoteStorage.hpp
index 8f66f5066c2dcf7730ed74a94b6c1616d281a168..26dba5d300f8fafc6331de34e8a9a6e8d161827f 100644
--- a/scheduler/RemoteStorage.hpp
+++ b/remotestorage/RemoteStorage.hpp
@@ -34,12 +34,20 @@ public:
   virtual ~RemoteStorage() throw() = 0;
 
   /**
-   * Returns true if the specified remote file exists or false if not.
+   * Returns true if the specified regular file exists.
    *
-   * @param remoteFile The URL of the remote file.
-   * @return true if the specified remote file exists or false if not.
+   * @param path The absolute path of the file.
+   * @return True if the specified directory exists.
    */
-  virtual bool fileExists(const std::string &remoteFile) = 0;
+  virtual bool regularFileExists(const std::string &path) const = 0;
+
+  /**
+   * Returns true if the specified directory exists.
+   *
+   * @param path The absolute path of the file.
+   * @return True if the specified directory exists.
+   */
+  virtual bool dirExists(const std::string &path) const = 0;
 
   /**
    * Renames the specified remote file to the specified new name.
diff --git a/scheduler/CMakeLists.txt b/scheduler/CMakeLists.txt
index 37b9925aa26f794a26fb766b200aa491f7e50f66..102a04a4f35c70f3291207d181c2803942bbc988 100644
--- a/scheduler/CMakeLists.txt
+++ b/scheduler/CMakeLists.txt
@@ -20,7 +20,6 @@ set (CTA_SCHEDULER_SRC_FILES
   DirIterator.cpp
   DiskException.cpp
   DriveQuota.cpp
-  EosRemoteStorage.cpp
   FileAttribute.cpp
   FileSystemDirEntry.cpp
   FileSystemNode.cpp
@@ -32,7 +31,6 @@ set (CTA_SCHEDULER_SRC_FILES
   MockSchedulerDatabaseFactory.cpp
   Mount.cpp
   MountCriteria.cpp
-  RemoteStorage.cpp
   RetrievalFileTransfer.cpp
   RetrievalMount.cpp
   RetrieveRequest.cpp