// Copyright (c) 2005-2008 Hartmut Kaiser // Copyright (c) 2005-2007 Andre Merzky (andre@merzky.net) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include "default_dir.hpp" #include "default_file.hpp" #include #include "default_namespace_dir.hpp" #include "default_namespace_dir_impl.hpp" #include "common_helpers.hpp" #ifndef MAX_PATH # define MAX_PATH _POSIX_PATH_MAX #endif /* * constructor */ dir_cpi_impl::dir_cpi_impl (saga::impl::proxy* p, saga::impl::v1_0::cpi_info const & info, saga::ini::ini const & glob_ini, saga::ini::ini const & adap_ini, TR1::shared_ptr adaptor) : base_type (p, info, glob_ini, adap_ini, adaptor, cpi::Noflags) { namespace fs = boost::filesystem; instance_data data (this); saga::url dir_url(data->location_); fs::path path (dir_url.get_path(), fs::native); std::string host(dir_url.get_host()); if (!host.empty() && host != "localhost" && !boost::iequals(host, ::detail::get_hostname())) { SAGA_OSSTREAM strm; strm << "dir_cpi_impl::init: cannot handle file: " << dir_url.get_url(); SAGA_ADAPTOR_THROW(SAGA_OSSTREAM_GETSTRING(strm), saga::BadParameter); } std::string scheme(dir_url.get_scheme()); if (!scheme.empty() && scheme != "file" && scheme != "any") { SAGA_OSSTREAM strm; strm << "dir_cpi_impl::init: cannot handle file: " << dir_url.get_url(); SAGA_ADAPTOR_THROW(SAGA_OSSTREAM_GETSTRING(strm), saga::BadParameter); } // check if file exists AND is a dir (not a file) bool exists = fs::exists(path); bool is_dir = false; if(exists) is_dir = fs::is_directory(path); // check for openmode // saga::filesystem::flags OpenMode = (saga::filesystem::flags)data->mode_; if(exists) { if(!is_dir) { SAGA_ADAPTOR_THROW ("URL does not point to a directory: " + data->location_.get_url(), saga::BadParameter); } else { if((OpenMode & saga::filesystem::Create) && (OpenMode & saga::filesystem::Exclusive)) { SAGA_ADAPTOR_THROW ("Directory " + data->location_.get_url() + " already exists.", saga::AlreadyExists); } } } else // !exists { if(!(OpenMode & saga::filesystem::Create)) { SAGA_ADAPTOR_THROW ("Directory does not exist and saga::filesystem::Create flag not given: " + data->location_.get_url(), saga::DoesNotExist); } else { if (!fs::create_directory (path)) { SAGA_ADAPTOR_THROW(path.string() + ": couldn't create the directory", saga::DoesNotExist); } } } // #if !defined(SAGA_WINDOWS) // // std::string path_comp = dir_url.get_path(); // // // A relative SAGA path MUST start with ./ or ../ (./tmp/) // // A relative boost::fs path can start without a / (tmp/) // // int idx = path_comp.find("./"); // if( idx == 0 ) // { // // the path is relative: ./ // char buf[MAX_PATH+1]; // getcwd (buf, MAX_PATH); // path_comp = std::string(buf) + "/" + path_comp; // } // else if( idx == 1 ) // { // // the path is relative: ../ // } // else // { // // the path is absolute - we have to make sure that boost::fs // // understands it. // int idx = path_comp.find("/"); // if( idx != 0 ) // path_comp.insert(0, "/"); // } // // fs::path modified_path (path_comp, fs::native); // modified_path.normalize(); // // //THIS IS REALLY NASTY! It replaces the whole URL with just the path component. // //Other adaptors that depend on a hostname component dont't like it ;-) // // // //data->location_ = modified_path.string(); // // // //...better this way: // // // dir_url.set_path(modified_path.string()); // data->location_ = dir_url.get_url(); // // #endif // #if !defined(SAGA_WINDOWS) // make sure directory exists if ((data->mode_ & saga::filesystem::Create || data->mode_ & saga::filesystem::CreateParents) && data->mode_ & saga::filesystem::Exclusive) { // is_directory if (fs::exists(path)) { SAGA_ADAPTOR_THROW(path.string () + ": already exists", saga::AlreadyExists); } } if (!fs::exists(path)) { // create directory, if needed if (data->mode_ & saga::filesystem::Create) { if (!fs::create_directory (path)) { SAGA_ADAPTOR_THROW(path.string () + ": couldn't create the directory", saga::DoesNotExist); } } else if ( (data->mode_ & saga::filesystem::CreateParents) && ! fs::create_directories (path)) { SAGA_ADAPTOR_THROW(path.string () + ": couldn't create the directory hierarchy", saga::DoesNotExist); } } // we don't need to create the directory twice data->mode_ &= ~(saga::filesystem::Create | saga::filesystem::CreateParents); if (data->mode_ & saga::filesystem::Read || data->mode_ & saga::filesystem::Write || data->mode_ & saga::filesystem::ReadWrite) { if (!fs::exists(path) || !fs::is_directory (path)) { SAGA_ADAPTOR_THROW( path.string () + ": doesn't refer to a directory object", saga::BadParameter); } } if (data->mode_ & ~( saga::filesystem::Create | saga::filesystem::CreateParents | saga::filesystem::Exclusive | saga::filesystem::Overwrite | saga::filesystem::Read | saga::filesystem::Write | saga::filesystem::ReadWrite )) { SAGA_ADAPTOR_THROW("Unknown openmode value: " + boost::lexical_cast(data->mode_), saga::BadParameter); } } /* * destructor */ dir_cpi_impl::~dir_cpi_impl (void) { } /* * SAGA API functions */ /////////////////////////////////////////////////////////////////////////////// void dir_cpi_impl::sync_open (saga::filesystem::file & entry, saga::url name_to_open, int openmode) { namespace fs = boost::filesystem; instance_data data (this); // verify the file can be handled if (!::detail::file_islocal(name_to_open)) { SAGA_OSSTREAM strm; strm << "dir_cpi_impl::sync_open: " "cannot handle remote target directory: " << name_to_open.get_url(); SAGA_ADAPTOR_THROW(SAGA_OSSTREAM_GETSTRING(strm), saga::NotImplemented); } saga::url file_url(data->location_); if (!::detail::file_islocal(file_url)) { SAGA_OSSTREAM strm; strm << "dir_cpi_impl::sync_open: " "cannot handle remote current directory: " << file_url.get_url(); SAGA_ADAPTOR_THROW(SAGA_OSSTREAM_GETSTRING(strm), saga::NotImplemented); } fs::path name (::detail::get_filepath(name_to_open), fs::native); fs::path path (file_url.get_path(), fs::native); if ( ! name.has_root_path () ) { path /= name; file_url.set_path(path.string()); } else { path = name; file_url = saga::url(name.string()); } if ( fs::exists(path) && fs::is_directory (path) ) { SAGA_ADAPTOR_THROW(path.string () + ": doesn't refer to a file object", saga::DoesNotExist); } // is_entry # FIXME: what? (also below...) -- AM entry = saga::filesystem::file (this->get_proxy()->get_session(), file_url.get_url(), openmode); } /////////////////////////////////////////////////////////////////////////////// void dir_cpi_impl::sync_open_dir(saga::filesystem::directory & entry, saga::url name_to_open, int openmode) { namespace fs = boost::filesystem; instance_data data (this); // verify the file can be handled if (!::detail::file_islocal(name_to_open)) { SAGA_OSSTREAM strm; strm << "dir_cpi_impl::sync_open_dir: " "cannot handle remote target directory: " << name_to_open.get_url(); SAGA_ADAPTOR_THROW(SAGA_OSSTREAM_GETSTRING(strm), saga::NotImplemented); } saga::url file_url(data->location_); if (!::detail::file_islocal(file_url)) { SAGA_OSSTREAM strm; strm << "dir_cpi_impl::sync_open_dir: " "cannot handle remote current directory: " << file_url.get_url(); SAGA_ADAPTOR_THROW(SAGA_OSSTREAM_GETSTRING(strm), saga::NotImplemented); } fs::path name (::detail::get_filepath(name_to_open), fs::native); fs::path path (file_url.get_path(), fs::native); if ( ! name.has_root_path () ) { path /= name; file_url.set_path(path.string()); } else { path = name; file_url = saga::url(name.string()); } if ( fs::exists(path) && !fs::is_directory(path)) { SAGA_ADAPTOR_THROW(path.string () + ": doesn't refer to a file object", saga::DoesNotExist); } entry = saga::filesystem::directory (this->get_proxy()->get_session(), file_url.get_url(), openmode); } #if ! defined (SAGA_DEFAULT_FILE_ADAPTOR_NO_ASYNCS) /////////////////////////////////////////////////////////////////////////////// // This adaptor implements the async functions based on its own synchronous // functions for testing purposes only. SInce there is no principal need // to do so, we allow these to be 'switched off'. saga::task dir_cpi_impl::async_open (saga::url name, int openmode) { return saga::adaptors::task("dir_cpi_impl::sync_open", shared_from_this(), &dir_cpi_impl::sync_open, name, openmode ); } saga::task dir_cpi_impl::async_open_dir(saga::url name, int openmode) { return saga::adaptors::task("dir_cpi_impl::sync_open_dir", shared_from_this(), &dir_cpi_impl::sync_open_dir, name, openmode); } #endif // SAGA_DEFAULT_FILE_ADAPTOR_NO_ASYNCS