diff --git a/libs/client/ArchiveJob.cpp b/libs/client/ArchiveJob.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99f432fb27aada0bc14e36477cc3da0de8d7f43a --- /dev/null +++ b/libs/client/ArchiveJob.cpp @@ -0,0 +1,50 @@ +#include "ArchiveJob.hpp" + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::ArchiveJob::ArchiveJob(): + m_creationTime(time(NULL)) { +} + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::ArchiveJob::ArchiveJob( + const std::string &id, + const UserIdentity &creator, + const std::string &comment): + m_id(id), + m_creationTime(time(NULL)), + m_creator(creator), + m_comment(comment) { +} + +//------------------------------------------------------------------------------ +// getId +//------------------------------------------------------------------------------ +const std::string &cta::ArchiveJob::getId() const throw() { + return m_id; +} + +//------------------------------------------------------------------------------ +// getCreationTime +//------------------------------------------------------------------------------ +time_t cta::ArchiveJob::getCreationTime() const throw() { + return m_creationTime; +} + +//------------------------------------------------------------------------------ +// getCreator +//------------------------------------------------------------------------------ +const cta::UserIdentity &cta::ArchiveJob::getCreator() + const throw() { + return m_creator; +} + +//------------------------------------------------------------------------------ +// getComment +//------------------------------------------------------------------------------ +const std::string &cta::ArchiveJob::getComment() const throw() { + return m_comment; +} diff --git a/libs/client/ArchiveJob.hpp b/libs/client/ArchiveJob.hpp new file mode 100644 index 0000000000000000000000000000000000000000..40cc06576539fff28a54fee3e039586752fafc74 --- /dev/null +++ b/libs/client/ArchiveJob.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "UserIdentity.hpp" + +#include <string> + +namespace cta { + +/** + * Class representing a archive job. + */ +class ArchiveJob { +public: + + /** + * Constructor. + */ + ArchiveJob(); + + /** + * Constructor. + * + * @param id The identification string of the archive job. + * @param creator The identity of the user that created the archive job. + * @param comment The comment describing the archive job. + */ + ArchiveJob( + const std::string &id, + const UserIdentity &creator, + const std::string &comment); + + /** + * Returns the identification string of the archive job. + * + * @return The identification string of the archive job. + */ + const std::string &getId() const throw(); + + /** + * Returns the time when the archive job was created. + * + * @return The time when the archive job was created. + */ + time_t getCreationTime() const throw(); + + /** + * Returns the identity of the user that created the archive job. + * + * @return The identity of the user that created the archive job. + */ + const UserIdentity &getCreator() const throw(); + + /** + * Returns the comment describing the archive job. + * + * @return The comment describing the archive job. + */ + const std::string &getComment() const throw(); + +private: + + /** + * The identification string of the archive job. + */ + std::string m_id; + + /** + * The time when the archive job was created. + */ + time_t m_creationTime; + + /** + * The identity of the user that created the archive job. + */ + UserIdentity m_creator; + + /** + * Comment describing the archive job. + */ + std::string m_comment; + +}; // class ArchiveJob + +} // namespace cta diff --git a/libs/client/CMakeLists.txt b/libs/client/CMakeLists.txt index 549629a74ad35d8bdedb293469d502c399272898..92fbac3f94862aa583a3a819436b13fbfddefbc7 100644 --- a/libs/client/CMakeLists.txt +++ b/libs/client/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required (VERSION 2.6) set (CLIENT_LIB_SRC_FILES + ArchiveJob.cpp ClientAPI.cpp DirectoryEntry.cpp DirectoryIterator.cpp diff --git a/libs/client/ClientAPI.hpp b/libs/client/ClientAPI.hpp index ee7b2cdc68dbd2700f6e1ca568a3001c5d1e1f22..ce6747b17302df948f299de5b6a988d9b3b741b9 100644 --- a/libs/client/ClientAPI.hpp +++ b/libs/client/ClientAPI.hpp @@ -264,7 +264,7 @@ public: */ virtual std::string getDirectoryStorageClass( const SecurityIdentity &requester, - const std::string &dirPath) = 0; + const std::string &dirPath) const = 0; /** * Archives the specified list of source files to the specified destination @@ -282,12 +282,12 @@ public: * @param requester The identity of the user requesting the archival. * @param srcUrls List of one or more source files. * @param dst Destination file or directory within the archive namespace. - * @return The identifier of the archive job. + * @return The string identifier of the archive job. */ - virtual std::string archiveToTape( + virtual std::string archive( const SecurityIdentity &requester, const std::list<std::string> &srcUrls, - std::string dst) = 0; + const std::string &dst) = 0; }; // class ClientAPI diff --git a/libs/client/DirectoryEntry.cpp b/libs/client/DirectoryEntry.cpp index b3f646e8955d9ff88e864f19fcc22c1b9c859e84..bc9ac0d6127181fec2e23046b1532435f0778ea3 100644 --- a/libs/client/DirectoryEntry.cpp +++ b/libs/client/DirectoryEntry.cpp @@ -35,9 +35,9 @@ cta::DirectoryEntry::DirectoryEntry(const EntryType entryType, } //------------------------------------------------------------------------------ -// getEntryType +// getType //------------------------------------------------------------------------------ -cta::DirectoryEntry::EntryType cta::DirectoryEntry::getEntryType() +cta::DirectoryEntry::EntryType cta::DirectoryEntry::getType() const throw() { return m_entryType; } diff --git a/libs/client/DirectoryEntry.hpp b/libs/client/DirectoryEntry.hpp index b45463e42a8f92268c2c3174f52fbf257057f027..4854cdcf3196bfb04b2941516f7a4a1b5ff0d16d 100644 --- a/libs/client/DirectoryEntry.hpp +++ b/libs/client/DirectoryEntry.hpp @@ -51,7 +51,7 @@ public: * * @return The type of the directory entry. */ - EntryType getEntryType() const throw(); + EntryType getType() const throw(); /** * Returns the name of the directory entry. diff --git a/libs/client/MockClientAPI.cpp b/libs/client/MockClientAPI.cpp index b99f4895d04191b596433da6ca294acdb3bcc311..14795cc73344bd9361ec145d862a1ca1f85e4053 100644 --- a/libs/client/MockClientAPI.cpp +++ b/libs/client/MockClientAPI.cpp @@ -278,7 +278,7 @@ void cta::MockClientAPI::createDirectory(const SecurityIdentity &requester, FileSystemNode &enclosingNode = getFileSystemNode(enclosingPath); if(DirectoryEntry::ENTRYTYPE_DIRECTORY != - enclosingNode.getFileSystemEntry().getEntry().getEntryType()) { + enclosingNode.getFileSystemEntry().getEntry().getType()) { std::ostringstream message; message << enclosingPath << " is not a directory"; throw Exception(message.str()); @@ -468,7 +468,7 @@ void cta::MockClientAPI::deleteDirectory(const SecurityIdentity &requester, FileSystemNode &dirNode = getFileSystemNode(dirPath); if(DirectoryEntry::ENTRYTYPE_DIRECTORY != - dirNode.getFileSystemEntry().getEntry().getEntryType()) { + dirNode.getFileSystemEntry().getEntry().getType()) { std::ostringstream message; message << "The absolute path " << dirPath << " is not a directory"; throw(message.str()); @@ -496,7 +496,7 @@ cta::DirectoryIterator cta::MockClientAPI::getDirectoryContents( const FileSystemNode &dirNode = getFileSystemNode(dirPath); if(DirectoryEntry::ENTRYTYPE_DIRECTORY != - dirNode.getFileSystemEntry().getEntry().getEntryType()) { + dirNode.getFileSystemEntry().getEntry().getType()) { std::ostringstream message; message << "The absolute path " << dirPath << " is not a directory"; throw(message.str()); @@ -568,7 +568,7 @@ void cta::MockClientAPI::setDirectoryStorageClass( FileSystemNode &dirNode = getFileSystemNode(dirPath); if(DirectoryEntry::ENTRYTYPE_DIRECTORY != - dirNode.getFileSystemEntry().getEntry().getEntryType()) { + dirNode.getFileSystemEntry().getEntry().getType()) { std::ostringstream message; message << dirPath << " is not a directory"; throw Exception(message.str()); @@ -585,7 +585,7 @@ void cta::MockClientAPI::clearDirectoryStorageClass( const std::string &dirPath) { FileSystemNode &dirNode = getFileSystemNode(dirPath); if(DirectoryEntry::ENTRYTYPE_DIRECTORY != - dirNode.getFileSystemEntry().getEntry().getEntryType()) { + dirNode.getFileSystemEntry().getEntry().getType()) { std::ostringstream message; message << dirPath << " is not a directory"; throw Exception(message.str()); @@ -599,10 +599,10 @@ void cta::MockClientAPI::clearDirectoryStorageClass( //------------------------------------------------------------------------------ std::string cta::MockClientAPI::getDirectoryStorageClass( const SecurityIdentity &requester, - const std::string &dirPath) { - FileSystemNode &dirNode = getFileSystemNode(dirPath); + const std::string &dirPath) const { + const FileSystemNode &dirNode = getFileSystemNode(dirPath); if(DirectoryEntry::ENTRYTYPE_DIRECTORY != - dirNode.getFileSystemEntry().getEntry().getEntryType()) { + dirNode.getFileSystemEntry().getEntry().getType()) { std::ostringstream message; message << dirPath << " is not a directory"; throw Exception(message.str()); @@ -612,9 +612,72 @@ std::string cta::MockClientAPI::getDirectoryStorageClass( } //------------------------------------------------------------------------------ -// archiveToTape +// archive +//------------------------------------------------------------------------------ +std::string cta::MockClientAPI::archive(const SecurityIdentity &requester, + const std::list<std::string> &srcUrls, const std::string &dst) { + checkAbsolutePathSyntax(dst); + if(isAnExistingDirectory(dst)) { + return archiveToDirectory(requester, srcUrls, dst); + } else { + return archiveToFile(requester, srcUrls, dst); + } +} + +//------------------------------------------------------------------------------ +// isAnExistingDirectory +//------------------------------------------------------------------------------ +bool cta::MockClientAPI::isAnExistingDirectory(const std::string &path) + const throw() { + try { + const FileSystemNode &node = getFileSystemNode(path); + const DirectoryEntry &entry = node.getFileSystemEntry().getEntry(); + if(DirectoryEntry::ENTRYTYPE_DIRECTORY == entry.getType()) { + return true; + } + } catch(...) { + } + return false; +} + +//------------------------------------------------------------------------------ +// archiveToDirectory +//------------------------------------------------------------------------------ +std::string cta::MockClientAPI::archiveToDirectory( + const SecurityIdentity &requester, + const std::list<std::string> &srcUrls, + const std::string &dstDir) { + if(0 == srcUrls.size()) { + throw Exception("At least one source file should be provided"); + } + + FileSystemNode &dstDirNode = getFileSystemNode(dstDir); + checkUserIsAuthorisedToArchive(requester, dstDirNode); + return "Funny_archive_to_dir_ID"; +} + +//------------------------------------------------------------------------------ +// archiveToFile +//------------------------------------------------------------------------------ +std::string cta::MockClientAPI::archiveToFile( + const SecurityIdentity &requester, + const std::list<std::string> &srcUrls, + const std::string &dstFile) { + if(1 != srcUrls.size()) { + throw Exception("One and only one source file must be provided when " + "archiving to a single destination file"); + } + + FileSystemNode &enclosingDirNode = getFileSystemNode(dstFile); + checkUserIsAuthorisedToArchive(requester, enclosingDirNode); + return "Funny_archive_to_file_ID"; +} + +//------------------------------------------------------------------------------ +// checkUserIsAuthorisedToArchive //------------------------------------------------------------------------------ -std::string cta::MockClientAPI::archiveToTape(const SecurityIdentity &requester, - const std::list<std::string> &srcUrls, std::string dst) { - return "Funny_Job_ID"; +void cta::MockClientAPI::checkUserIsAuthorisedToArchive( + const SecurityIdentity &user, + const FileSystemNode &dstDir) { + // TO BE DONE } diff --git a/libs/client/MockClientAPI.hpp b/libs/client/MockClientAPI.hpp index 7bc792deeda9025af283fed95fd3477e5d887e0e..2a7689ce9f71b626e36ace92e586d10c0e1856c0 100644 --- a/libs/client/MockClientAPI.hpp +++ b/libs/client/MockClientAPI.hpp @@ -266,7 +266,7 @@ public: */ std::string getDirectoryStorageClass( const SecurityIdentity &requester, - const std::string &dirPath); + const std::string &dirPath) const; /** * Archives the specified list of source files to the specified destination @@ -284,12 +284,12 @@ public: * @param requester The identity of the user requesting the archival. * @param srcUrls List of one or more source files. * @param dst Destination file or directory within the archive namespace. - * @return The identifier of the archive job. + * @return The string identifier of the archive job. */ - std::string archiveToTape( + std::string archive( const SecurityIdentity &requester, const std::list<std::string> &srcUrls, - std::string dst); + const std::string &dst); protected: @@ -465,6 +465,65 @@ protected: */ void checkStorageClassIsNotInAMigrationRoute(const std::string &name) const; + /** + * Returns true if the specified absolute path is that of an existing + * directory within the archive namepsace. + * + * @param path The specified absolute path. + * @return True if the specified absolute path is that of an existing + * directory within the archive namepsace. + */ + bool isAnExistingDirectory(const std::string &path) const throw(); + + /** + * Archives the specified list of source files to the specified destination + * directory within the archive namespace. + * + * The list of source files should contain at least one file. + * + * The storage class of the archived file will be inherited from its + * destination directory. + * + * @param requester The identity of the user requesting the archival. + * @param srcUrls List of one or more source files. + * @param dstDir Destination directory within the archive namespace. + * @return The string identifier of the archive job. + */ + std::string archiveToDirectory( + const SecurityIdentity &requester, + const std::list<std::string> &srcUrls, + const std::string &dstDir); + + /** + * Archives the specified list of source files to the specified destination + * file within the archive namespace. + * + * The list of source files should contain one and only one file. + * + * The storage class of the archived file will be inherited from its + * destination directory. + * + * @param requester The identity of the user requesting the archival. + * @param srcUrls List of one or more source files. + * @param dstFile Destination file within the archive namespace. + * @return The string identifier of the archive job. + */ + std::string archiveToFile( + const SecurityIdentity &requester, + const std::list<std::string> &srcUrls, + const std::string &dstFile); + + /** + * Throws an exception if the specified requester is not authorised to archive + * a file to the specified destination directory within the archive namespace. + * + * @param requester The identity of the user requesting the archival. + * @param dstDir Destination directory within the archive namespace. + */ + void checkUserIsAuthorisedToArchive( + const SecurityIdentity &user, + const FileSystemNode &dstDir); + }; // class MockClientAPI } // namespace cta diff --git a/xroot_plugins/XrdProFilesystem.cpp b/xroot_plugins/XrdProFilesystem.cpp index 17c53ed8be986e7860b6e11979a2edf53ac8a07e..e744392eded35cae3e661dc178f70c3a1e75976f 100644 --- a/xroot_plugins/XrdProFilesystem.cpp +++ b/xroot_plugins/XrdProFilesystem.cpp @@ -108,7 +108,7 @@ int XrdProFilesystem::executeArchiveCommand(const ParsedRequest &req, XrdOucErrI for(size_t i=0; i<req.args.size()-1; i++) { sourceFiles.push_back(req.args.at(i)); } - std::string jobID = m_clientAPI->archiveToTape(requester, sourceFiles, destinationPath); + std::string jobID = m_clientAPI->archive(requester, sourceFiles, destinationPath); std::ostringstream responseSS; responseSS << "[OK] Requested archival of the following files:\n"; for(std::list<std::string>::iterator it = sourceFiles.begin(); it != sourceFiles.end(); it++) { @@ -421,7 +421,7 @@ int XrdProFilesystem::executeLsCommand(const ParsedRequest &req, XrdOucErrInfo & const cta::DirectoryEntry &entry = itor.next(); responseSS << "\n"; - responseSS << ((entry.getEntryType() == cta::DirectoryEntry::ENTRYTYPE_DIRECTORY) ? "d" : "-"); + responseSS << ((entry.getType() == cta::DirectoryEntry::ENTRYTYPE_DIRECTORY) ? "d" : "-"); responseSS << ((entry.getMode() & S_IRUSR) ? "r" : "-"); responseSS << ((entry.getMode() & S_IWUSR) ? "w" : "-"); responseSS << ((entry.getMode() & S_IXUSR) ? "x" : "-");