diff --git a/ChangeLog b/ChangeLog index 1d2de9e42..27bdee47f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -96,6 +96,9 @@ Bugs narrow characters (thanks to Roy Zuo). + Fixed bug #1191, which kept file locks active for longer than necessary, and caused the 'execute' command to be considered a 'write' command. + + Fixed bug #1192, which failed to expand braces internally, as POSIX /bin/sh + does not do {} expansion, thereby causing push/pull errors (thanks to Russell + Steicke). + Fixed bug #1194, so that $HOME has precedence over the passwd db when looking for the user's home directory (thanks to Jakub Wilk). + Fixed bug #1199, where 'stat' was used instead of 'lstat' (thanks to Jakub diff --git a/src/Transport.cpp b/src/Transport.cpp index d01ba5b9c..4e6f79000 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -126,4 +126,42 @@ bool Transport::is_filelist(const std::string& path) } //////////////////////////////////////////////////////////////////////////////// +void Transport::expand_braces(const std::string& path, + const std::string& sourceortarget, + std::vector& paths) +{ + // Is is_filelist appropriate here? We only care about {} + if (is_filelist(path)) + { + std::string::size_type pos; + pos = path.find("{"); + if (pos == std::string::npos) + throw std::string (STRING_TRANSPORT_CURL_WILDCD); + + if (!is_directory(sourceortarget)) + throw format (STRING_TRANSPORT_URI_NODIR, sourceortarget); + + std::string toSplit; + std::string suffix; + std::string prefix = path.substr (0, pos); + std::vector splitted; + toSplit = path.substr (pos+1); + pos = toSplit.find ("}"); + suffix = toSplit.substr (pos+1); + split (splitted, toSplit.substr(0, pos), ','); + + std::vector ::iterator file; + for (file = splitted.begin (); file != splitted.end (); ++file) { + std::cout << " -- " << (prefix + *file + suffix) << "\n"; + paths.push_back (prefix + *file + suffix); + } + } + else + { + // Not brace expandable - use the path as is. + paths.push_back (path); + } +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Transport.h b/src/Transport.h index 10b395eb8..bac263ba9 100644 --- a/src/Transport.h +++ b/src/Transport.h @@ -43,6 +43,9 @@ public: virtual void send (const std::string&) = 0; virtual void recv (std::string) = 0; + void expand_braces(const std::string& path, const std::string& sourceortarget, + std::vector& paths); + static bool is_directory(const std::string&); static bool is_filelist(const std::string&); diff --git a/src/TransportCurl.cpp b/src/TransportCurl.cpp index 0a28179d6..bab4dc0d0 100644 --- a/src/TransportCurl.cpp +++ b/src/TransportCurl.cpp @@ -41,6 +41,9 @@ TransportCurl::TransportCurl(const Uri& uri) : Transport(uri) //////////////////////////////////////////////////////////////////////////////// void TransportCurl::send(const std::string& source) { + std::vector sourcelist; + std::vector::const_iterator source_iter; + if (_uri._host == "") throw std::string (STRING_TRANSPORT_CURL_URI); @@ -50,24 +53,22 @@ void TransportCurl::send(const std::string& source) _arguments.push_back(_uri._user); } - if (is_filelist(source)) - { - std::string::size_type pos; - pos = source.find("{"); + if (is_filelist (source)) { + expand_braces (source, _uri._data, sourcelist); + // Is there more than one source? + // Then path has to end with a '/' + if (sourcelist.size () > 1 && !_uri.is_directory ()) + throw format (STRING_TRANSPORT_URI_NODIR, _uri); - if (pos == std::string::npos) - throw std::string (STRING_TRANSPORT_CURL_WILDCD); - - if (!_uri.is_directory()) - throw format (STRING_TRANSPORT_URI_NODIR, _uri._path); - - _arguments.push_back ("-T"); - _arguments.push_back ("\"" + escape (source, ' ') + "\""); + for (source_iter = sourcelist.begin (); source_iter != sourcelist.end (); ++source_iter) { + _arguments.push_back ("-T"); + _arguments.push_back ("\"" + escape (*source_iter, ' ') + "\""); + } } else { _arguments.push_back ("-T"); - _arguments.push_back (escape (source, ' ')); + _arguments.push_back ("\"" + escape (source, ' ') + "\""); } // cmd line is: curl -T source protocol://host:port/path @@ -100,28 +101,14 @@ void TransportCurl::recv(std::string target) if (is_filelist(_uri._path)) { - std::string::size_type pos; - pos = _uri._path.find("{"); - if (pos == std::string::npos) - throw std::string (STRING_TRANSPORT_CURL_WILDCD); - - if (!is_directory(target)) - throw format (STRING_TRANSPORT_URI_NODIR, target); - - std::string toSplit; - std::string suffix; - std::string prefix = target; - std::vector splitted; - toSplit = _uri._path.substr (pos+1); - pos = toSplit.find ("}"); - suffix = toSplit.substr (pos+1); - split (splitted, toSplit.substr(0, pos), ','); + std::vector paths; + expand_braces (_uri._path, target, paths); std::vector ::iterator file; - for (file = splitted.begin (); file != splitted.end (); ++file) { + for (file = paths.begin (); file != paths.end (); ++file) { targetargs.push_back ("-o"); - targetargs.push_back (prefix + *file + suffix); + targetargs.push_back (*file); } } else diff --git a/src/TransportRSYNC.cpp b/src/TransportRSYNC.cpp index e32f9bc8a..3a083c0e1 100644 --- a/src/TransportRSYNC.cpp +++ b/src/TransportRSYNC.cpp @@ -40,21 +40,34 @@ TransportRSYNC::TransportRSYNC(const Uri& uri) : Transport(uri) //////////////////////////////////////////////////////////////////////////////// void TransportRSYNC::send(const std::string& source) { + std::vector sourcelist; + std::vector::const_iterator source_iter; + if (_uri._host == "") throw std::string (STRING_TRANSPORT_RSYNC_URI); - // Is there more than one file to transfer? - // Then path has to end with a '/' - if (is_filelist(source) && !_uri.is_directory()) - throw format (STRING_TRANSPORT_URI_NODIR, _uri._path); - // cmd line is: rsync [--port=PORT] source [user@]host::path if (_uri._port != "") { _arguments.push_back ("--port=" + _uri._port); } - _arguments.push_back (source); + if (is_filelist (source)) + { + expand_braces (source, _uri._data, sourcelist); + // Is there more than one file to transfer? + // Then path has to end with a '/' + if (sourcelist.size () > 1 && !_uri.is_directory ()) + throw format (STRING_TRANSPORT_URI_NODIR, _uri); + + for (source_iter = sourcelist.begin (); source_iter != sourcelist.end (); ++source_iter) { + _arguments.push_back (*source_iter); + } + } + else + { + _arguments.push_back (source); + } if (_uri._user != "") { @@ -72,21 +85,36 @@ void TransportRSYNC::send(const std::string& source) //////////////////////////////////////////////////////////////////////////////// void TransportRSYNC::recv(std::string target) { + std::vector paths; + std::vector::const_iterator paths_iter; + if (_uri._host == "") throw std::string (STRING_TRANSPORT_RSYNC_URI); - // Is there more than one file to transfer? - // Then target has to end with a '/' - if (is_filelist(_uri._path) && !is_directory(target)) - throw format (STRING_TRANSPORT_URI_NODIR, target); - // cmd line is: rsync [--port=PORT] [user@]host::path target if (_uri._port != "") _arguments.push_back ("--port=" + _uri._port); - if (_uri._user != "") - { - _arguments.push_back (_uri._user + "@" + _uri._host + "::" + _uri._path); + if (is_filelist(_uri._path)) { + + // Rsync servers do not to {} expansion, so we have to do it on the client. + expand_braces (_uri._path, target, paths); + + // Is there more than one file to transfer? + // Then target has to end with a '/' + if (paths.size () > 1 && ! is_directory (target)) + throw format (STRING_TRANSPORT_URI_NODIR, target); + + for (paths_iter = paths.begin (); paths_iter != paths.end (); ++paths_iter) { + if (_uri._user != "") + { + _arguments.push_back (_uri._user + "@" + _uri._host + "::" + *paths_iter); + } + else + { + _arguments.push_back (_uri._host + "::" + *paths_iter); + } + } } else { diff --git a/src/TransportSSH.cpp b/src/TransportSSH.cpp index 39cf9ba21..9785582b3 100644 --- a/src/TransportSSH.cpp +++ b/src/TransportSSH.cpp @@ -41,14 +41,12 @@ TransportSSH::TransportSSH(const Uri& uri) : Transport(uri) //////////////////////////////////////////////////////////////////////////////// void TransportSSH::send(const std::string& source) { + std::vector sourcelist; + std::vector::const_iterator source_iter; + if (_uri._host == "") throw std::string (STRING_TRANSPORT_SSH_URI); - // Is there more than one file to transfer? - // Then path has to end with a '/' - if (is_filelist(source) && !_uri.is_directory()) - throw format (STRING_TRANSPORT_URI_NODIR, _uri._path); - // cmd line is: scp [-p port] [user@]host:path if (_uri._port != "") { @@ -56,7 +54,22 @@ void TransportSSH::send(const std::string& source) _arguments.push_back (_uri._port); } - _arguments.push_back (source); + if (is_filelist (source)) + { + expand_braces (source, _uri._data, sourcelist); + // Is there more than one source? + // Then path has to end with a '/' + if (sourcelist.size () > 1 && !_uri.is_directory ()) + throw format (STRING_TRANSPORT_URI_NODIR, _uri); + + for (source_iter = sourcelist.begin (); source_iter != sourcelist.end (); ++source_iter) { + _arguments.push_back (*source_iter); + } + } + else + { + _arguments.push_back (source); + } if (_uri._user != "") { @@ -89,6 +102,8 @@ void TransportSSH::recv(std::string target) _arguments.push_back (_uri._port); } + // We do not do {} expansion of the URI, as ssh servers do that for us. + if (_uri._user != "") { _arguments.push_back (_uri._user + "@" + _uri._host + ":" + escape (_uri._path, ' ')); diff --git a/src/TransportShell.cpp b/src/TransportShell.cpp index 1d5a18b8f..fb8dc5e10 100644 --- a/src/TransportShell.cpp +++ b/src/TransportShell.cpp @@ -41,16 +41,26 @@ TransportShell::TransportShell(const Uri& uri) : Transport(uri) //////////////////////////////////////////////////////////////////////////////// void TransportShell::send(const std::string& source) { + std::vector sourcelist; + std::vector::const_iterator source_iter; + if (_uri._path == "") throw std::string (STRING_TRANSPORT_SHELL_NOPATH); - // Is there more than one file to transfer? - // Then path has to end with a '/' - if (is_filelist(source) && !_uri.is_directory()) - throw format (STRING_TRANSPORT_URI_NODIR, _uri._path); - - _arguments.push_back (source); - + if (is_filelist(source)) + { + expand_braces (source, _uri._path, sourcelist); + // Is there more than one file to transfer? + // Then path has to end with a '/' + if (sourcelist.size() > 1 && !_uri.is_directory()) + throw format (STRING_TRANSPORT_URI_NODIR, _uri._path); + for (source_iter = sourcelist.begin (); source_iter != sourcelist.end (); ++source_iter) + _arguments.push_back (*source_iter); + } + else + { + _arguments.push_back (source); + } _arguments.push_back (_uri._path); if (execute ()) @@ -60,15 +70,28 @@ void TransportShell::send(const std::string& source) //////////////////////////////////////////////////////////////////////////////// void TransportShell::recv(std::string target) { + std::vector paths; + std::vector::const_iterator paths_iter; + if (_uri._path == "") throw std::string (STRING_TRANSPORT_SHELL_NOPATH); - // Is there more than one file to transfer? - // Then target has to end with a '/' - if (is_filelist(_uri._path) && !is_directory(target)) - throw format (STRING_TRANSPORT_URI_NODIR, target); + if (is_filelist(_uri._path)) + { + expand_braces (_uri._path, target, paths); - _arguments.push_back (_uri._path); + // Is there more than one file to transfer? + // Then target has to end with a '/' + if (paths.size() > 1 && !is_directory(target)) + throw format (STRING_TRANSPORT_URI_NODIR, target); + + for (paths_iter = paths.begin (); paths_iter != paths.end (); ++paths_iter) + _arguments.push_back (*paths_iter); + } + else + { + _arguments.push_back (_uri._path); + } _arguments.push_back (target); diff --git a/src/commands/CmdPush.cpp b/src/commands/CmdPush.cpp index f9c92e1ec..9f4493851 100644 --- a/src/commands/CmdPush.cpp +++ b/src/commands/CmdPush.cpp @@ -68,6 +68,7 @@ int CmdPush::execute (std::string& output) Transport* transport; if ((transport = Transport::getTransport (uri)) != NULL ) { + std::vector sourcelist; transport->send (location._data + "/{pending,undo,completed}.data"); delete transport; }