]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- transfer filelist by pipe instead of DBus message 698/head
authorArvin Schnell <aschnell@suse.de>
Tue, 22 Mar 2022 08:02:54 +0000 (09:02 +0100)
committerArvin Schnell <aschnell@suse.de>
Tue, 22 Mar 2022 08:02:54 +0000 (09:02 +0100)
16 files changed:
VERSION
client/commands.cc
client/commands.h
client/proxy-dbus.cc
dbus/DBusPipe.cc [new file with mode: 0644]
dbus/DBusPipe.h [new file with mode: 0644]
dbus/Makefile.am
doc/dbus-protocol.txt
package/snapper.changes
server/Client.cc
server/Client.h
server/FilesTransferTask.cc [new file with mode: 0644]
server/FilesTransferTask.h [new file with mode: 0644]
server/Makefile.am
server/snapperd.cc
testsuite/dbus-escape.cc

diff --git a/VERSION b/VERSION
index f374f6662e9a1983e9b8a534a3295df618772ffe..78bc1abd14f2c1f6330989d876c4ee7d5daf7ff6 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.9.1
+0.10.0
index ecb7ef0a408a040d1b7ef18b4bf69110e7b4e7af..dda9d3c687747f631ae8c72d408be880c944efd4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) [2012-2015] Novell, Inc.
- * Copyright (c) [2016,2018] SUSE LLC
+ * Copyright (c) [2016-2022] SUSE LLC
  *
  * All Rights Reserved.
  *
  */
 
 
+#include <stdio.h>
 #include <iostream>
 
 #include "commands.h"
 #include "errors.h"
 #include "utils/text.h"
+#include "dbus/DBusPipe.h"
 #include "snapper/AppUtil.h"
 
 using namespace std;
@@ -487,8 +489,71 @@ command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned i
     DBus::Hihi hihi(reply);
     hihi >> files;
 
-    sort(files.begin(), files.end());  // snapperd can have different locale than client
-                                       // so sorting is required here
+    sort(files.begin(), files.end());
+
+    return files;
+}
+
+
+vector<XFile>
+command_get_xfiles_by_pipe(DBus::Connection& conn, const string& config_name, unsigned int number1,
+                          unsigned int number2)
+{
+    DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "GetFilesByPipe");
+
+    DBus::Hoho hoho(call);
+    hoho << config_name << number1 << number2;
+
+    DBus::Message reply = conn.send_with_reply_and_block(call);
+
+    DBus::FileDescriptor fd;
+
+    DBus::Hihi hihi(reply);
+    hihi >> fd;
+
+    vector<XFile> files;
+
+    FILE* fin = fdopen(fd.get_fd(), "r");
+    if (!fin)
+       SN_THROW(IOErrorException("reading pipe failed, fdopen failed: " + stringerror(errno)));
+
+    char* buffer = nullptr;
+    size_t len = 0;
+
+    while (true)
+    {
+       ssize_t n = getline(&buffer, &len, fin);
+       if (n == -1)
+       {
+           if (feof(fin) != 0)
+               break;
+
+           SN_THROW(IOErrorException("reading pipe failed, getline failed: " + stringerror(errno)));
+       }
+
+       if (n > 0 && buffer[n - 1] == '\n')
+           --n;
+
+       const string line = string(buffer, 0, n);
+
+       string::size_type pos1 = line.find(" ");
+       if (pos1 == string::npos)
+           SN_THROW(IOErrorException("reading pipe failed, parse error"));
+
+       string::size_type pos2 = line.find(" ", pos1 + 1);
+
+       XFile file;
+       file.name = DBus::Pipe::unescape(line.substr(0, pos1));
+       file.status = stoi(line.substr(pos1 + 1, pos2 - pos1 - 1));
+       files.push_back(file);
+    }
+
+    free(buffer);
+
+    if (fclose(fin) != 0)
+       SN_THROW(IOErrorException("reading pipe failed, fclose failed: " + stringerror(errno)));
+
+    sort(files.begin(), files.end());
 
     return files;
 }
index 11cbc0e6b42b7d4c946e1f047cb3517686c89640..c7e00bdc42556a1d219d260451431be88ad7f3bc 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) [2012-2015] Novell, Inc.
- * Copyright (c) [2016,2018] SUSE LLC
+ * Copyright (c) [2016-2022] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -126,6 +126,10 @@ vector<XFile>
 command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1,
                   unsigned int number2);
 
+vector<XFile>
+command_get_xfiles_by_pipe(DBus::Connection& conn, const string& config_name, unsigned int number1,
+                          unsigned int number2);
+
 void
 command_setup_quota(DBus::Connection& conn, const string& config_name);
 
index 9feab6fb16ffc02ba2723aeb5828b3a5eb4a3f21..3e4cfef1c341c8bbcc5ddb477a52cbb18632529a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2016-2020] SUSE LLC
+ * Copyright (c) [2016-2022] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -378,8 +378,26 @@ ProxyComparisonDbus::ProxyComparisonDbus(ProxySnapperDbus* backref, const ProxyS
            file_paths.post_path = file_paths.system_path;
     }
 
-    vector<XFile> tmp1 = command_get_xfiles(backref->conn(), backref->config_name, lhs.getNum(),
-                                           rhs.getNum());
+    vector<XFile> tmp1;
+
+    try
+    {
+       tmp1 = command_get_xfiles_by_pipe(backref->conn(), backref->config_name, lhs.getNum(),
+                                         rhs.getNum());
+    }
+    catch (const DBus::ErrorException& e)
+    {
+       SN_CAUGHT(e);
+
+       // If snapper was just updated and the old snapperd is still running it might not
+       // know the GetFilesByPipe method.
+
+       if (strcmp(e.name(), "error.unknown_method") != 0)
+           SN_RETHROW(e);
+
+       tmp1 = command_get_xfiles(backref->conn(), backref->config_name, lhs.getNum(),
+                                 rhs.getNum());
+    }
 
     vector<File> tmp2;
 
diff --git a/dbus/DBusPipe.cc b/dbus/DBusPipe.cc
new file mode 100644 (file)
index 0000000..df26324
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * Copyright (c) 2022 SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "DBusPipe.h"
+#include "DBusMessage.h"
+
+
+namespace DBus
+{
+
+    void
+    FileDescriptor::close()
+    {
+       if (_fd != -1)
+       {
+           ::close(_fd);
+           _fd = -1;
+       }
+    }
+
+
+    Hihi&
+    operator>>(Hihi& hihi, FileDescriptor& data)
+    {
+       if (hihi.get_type() != DBUS_TYPE_UNIX_FD)
+           throw MarshallingException();
+
+       int fd;
+       dbus_message_iter_get_basic(hihi.top(), &fd);
+       dbus_message_iter_next(hihi.top());
+       data.set_fd(fd);
+
+       return hihi;
+    }
+
+
+    Hoho&
+    operator<<(Hoho& hoho, const FileDescriptor& data)
+    {
+       const int fd = data.get_fd();
+       if (!dbus_message_iter_append_basic(hoho.top(), DBUS_TYPE_UNIX_FD, &fd))
+           throw FatalException();
+
+       return hoho;
+    }
+
+
+    Pipe::Pipe()
+    {
+       int pipefd[2];
+
+       if (pipe2(pipefd, O_CLOEXEC) != 0)
+           throw PipeException();
+
+       _read_end.set_fd(pipefd[0]);
+       _write_end.set_fd(pipefd[1]);
+    }
+
+
+    string
+    Pipe::escape(const string& in)
+    {
+       string out;
+
+       for (const char c : in)
+       {
+           if (c == '\\')
+           {
+               out += "\\\\";
+           }
+           else if (c <= ' ')
+           {
+               char s[5];
+               snprintf(s, 5, "\\x%02x", c);
+               out += string(s);
+           }
+           else
+           {
+               out += c;
+           }
+       }
+
+       return out;
+    }
+
+
+    string
+    Pipe::unescape(const string& in)
+    {
+       return Hihi::unescape(in);
+    }
+
+}
diff --git a/dbus/DBusPipe.h b/dbus/DBusPipe.h
new file mode 100644 (file)
index 0000000..8d91fac
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * Copyright (c) 2022 SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef SNAPPER_DBUSPIPE_H
+#define SNAPPER_DBUSPIPE_H
+
+
+#include <boost/noncopyable.hpp>
+
+#include "DBusMessage.h"
+
+
+namespace DBus
+{
+
+    class FileDescriptor : boost::noncopyable
+    {
+    public:
+
+       FileDescriptor() = default;
+       FileDescriptor(int fd) : _fd(fd) {}
+       ~FileDescriptor() { close(); }
+
+       void close();
+
+       int get_fd() const { return _fd; }
+       void set_fd(int fd) { _fd = fd; }
+
+    private:
+
+       int _fd = -1;
+
+    };
+
+
+    Hihi& operator>>(Hihi& hoho, FileDescriptor& data);
+    Hoho& operator<<(Hoho& hoho, const FileDescriptor& data);
+
+
+    struct PipeException : public Exception
+    {
+       explicit PipeException() : Exception("pipe exception") {}
+    };
+
+
+    class Pipe : boost::noncopyable
+    {
+    public:
+
+       Pipe();
+
+       FileDescriptor& get_read_end() { return _read_end; }
+       FileDescriptor& get_write_end() { return _write_end; }
+
+       static string escape(const string&);
+       static string unescape(const string&);
+
+    private:
+
+       FileDescriptor _read_end;
+       FileDescriptor _write_end;
+
+    };
+
+}
+
+#endif
index f9521a8b15c9f779728408eb7ceaacd477493f56..560b02f367e806bc0924dda289bf88517be6a034 100644 (file)
@@ -8,6 +8,7 @@ noinst_LTLIBRARIES = libdbus.la
 
 libdbus_la_SOURCES =                                   \
        DBusMessage.cc          DBusMessage.h           \
+       DBusPipe.cc             DBusPipe.h              \
        DBusConnection.cc       DBusConnection.h        \
        DBusMainLoop.cc         DBusMainLoop.h
 
index 2bb3d7a97695631b7f1d5a3dd2f326fb133262f3..dbd925d1146734b5da8dbf2b8898da08c80972a0 100644 (file)
@@ -1,4 +1,7 @@
 
+Methods and Signals
+-------------------
+
 method ListConfigs
 method GetConfig config-name
 method SetConfig config-name configdata
@@ -54,23 +57,49 @@ method Sync config-name
 method CreateComparison config-name number1 number2 -> num-files
 method DeleteComparison config-name number1 number2
 
-The following command require a successful CreateComparison in advance.
+The following two commands require a successful CreateComparison in advance.
 
 method GetFiles config-name number1 number2 -> list(filename status)
+method GetFilesByPipe config-name number1 number2 -> fd
 
-Sorting for files is undefined, esp. since server and client can use
-different locales.
+Filenames do not include the subvolume.
+
+GetFilesByPipe returns a file descriptor from which the client can
+read the file list. This avoids the problem of GetFiles with exceeding
+the allowed DBus message size. GetFiles is deprecated.
+
+The file descriptor returned by GetFilesByPipe has one entry per file
+with two fields (separated by spaces), first the filename and second
+the status as an integer. Additional fields must be ignored by
+clients.
 
 
 Intentionally not documented are SetupQuota, PrepareQuota, QueryQuota
 and QueryFreeSpace.
 
 
-Filenames do not include the subvolume.
+Encoding and Escaping
+---------------------
+
+Strings passed via DBus are UTF-8. Other characters (e.g. in
+filenames) must be encoded hexadecimal as "\x??". As a consequence,
+"\" is encoded as "\\".
+
+In strings passed via pipe the newline and space are escaped as
+"\x??". As a consequence, "\" is encoded as "\\".
+
+In general any character can be escaped as "\x??".
+
+
+Sorting
+-------
+
+Sorting for files is undefined, esp. since server and client can use
+different locales.
 
-Strings are UTF-8. Other characters (e.g. in filenames) must be encoded
-hexadecimal as "\x??". As a consequence "\" must be encoded as "\\".
 
+Misc Notes
+----------
 
 Due to security concerns there are no methods to get, compare or revert
 files. This can be done in the client.
index 54ce64a34e333db770b625c35211b7d99a115730..67a0e7cf17cbc833c6d8e42a6e1d5136df2a1812 100644 (file)
@@ -1,3 +1,10 @@
+-------------------------------------------------------------------
+Mon Mar 21 17:29:07 CET 2022 - aschnell@suse.com
+
+- transfer filelist by pipe instead of DBus message to avoid
+  exceeding allowed DBus message size
+- version 0.10.0
+
 -------------------------------------------------------------------
 Wed Nov 24 14:20:38 CET 2021 - aschnell@suse.com
 
index cd2f4e9609c8038d9a7def9c967fe04f1ce555ba..1e2ff183a342180a9998481253855b6cbf448d0c 100644 (file)
@@ -47,10 +47,14 @@ Client::Client(const string& name, uid_t uid, const Clients& clients)
 Client::~Client()
 {
     method_call_thread.interrupt();
+    file_transfer_thread.interrupt();
 
     if (method_call_thread.joinable())
        method_call_thread.join();
 
+    if (file_transfer_thread.joinable())
+       file_transfer_thread.join();
+
     for (list<Comparison*>::iterator it = comparisons.begin(); it != comparisons.end(); ++it)
     {
        delete_comparison(it);
@@ -370,6 +374,13 @@ Client::introspect(DBus::Connection& conn, DBus::Message& msg)
        "      <arg name='files' type='a(su)' direction='out'/>\n"
        "    </method>\n"
 
+       "    <method name='GetFilesByPipe'>\n"
+       "      <arg name='config-name' type='s' direction='in'/>\n"
+       "      <arg name='number1' type='u' direction='in'/>\n"
+       "      <arg name='number2' type='u' direction='in'/>\n"
+       "      <arg name='fd' type='h' direction='out'/>\n"
+       "    </method>\n"
+
        "    <method name='Sync'>\n"
        "      <arg name='config-name' type='s' direction='in'/>\n"
        "    </method>\n"
@@ -1442,6 +1453,42 @@ Client::get_files(DBus::Connection& conn, DBus::Message& msg)
 }
 
 
+void
+Client::get_files_by_pipe(DBus::Connection& conn, DBus::Message& msg)
+{
+    string config_name;
+    dbus_uint32_t num1, num2;
+
+    DBus::Hihi hihi(msg);
+    hihi >> config_name >> num1 >> num2;
+
+    y2deb("GetFilesByPipe config_name:" << config_name << " num1:" << num1 << " num2:" << num2);
+
+    boost::unique_lock<boost::shared_mutex> lock(big_mutex);
+
+    MetaSnappers::iterator it = meta_snappers.find(config_name);
+
+    check_permission(conn, msg, *it);
+
+    list<Comparison*>::iterator it2 = find_comparison(it->getSnapper(), num1, num2);
+
+    const Files& files = (*it2)->getFiles();
+
+    DBus::MessageMethodReturn reply(msg);
+
+    DBus::Hoho hoho(reply);
+
+    shared_ptr<FilesTransferTask> file_transfer_task = make_shared<FilesTransferTask>(files);
+
+    hoho << file_transfer_task->get_read_end();
+    conn.send(reply);
+
+    file_transfer_task->get_read_end().close();
+
+    add_file_transfer_task(file_transfer_task);
+}
+
+
 void
 Client::setup_quota(DBus::Connection& conn, DBus::Message& msg)
 {
@@ -1700,6 +1747,8 @@ Client::dispatch(DBus::Connection& conn, DBus::Message& msg)
            delete_comparison(conn, msg);
        else if (msg.is_method_call(INTERFACE, "GetFiles"))
            get_files(conn, msg);
+       else if (msg.is_method_call(INTERFACE, "GetFilesByPipe"))
+           get_files_by_pipe(conn, msg);
        else if (msg.is_method_call(INTERFACE, "SetupQuota"))
            setup_quota(conn, msg);
        else if (msg.is_method_call(INTERFACE, "PrepareQuota"))
@@ -1878,6 +1927,12 @@ Client::dispatch(DBus::Connection& conn, DBus::Message& msg)
        DBus::MessageError reply(msg, "error.unsupported", e.what());
        conn.send(reply);
     }
+    catch (const StreamException& e)
+    {
+       SN_CAUGHT(e);
+       DBus::MessageError reply(msg, "error.stream", DBUS_ERROR_FAILED);
+       conn.send(reply);
+    }
     catch (const Exception& e)
     {
        SN_CAUGHT(e);
@@ -1907,6 +1962,20 @@ Client::add_method_call_task(DBus::Connection& conn, DBus::Message& msg)
 }
 
 
+void
+Client::add_file_transfer_task(shared_ptr<FilesTransferTask> file_transfer_task)
+{
+    if (file_transfer_thread.get_id() == boost::thread::id())
+       file_transfer_thread = boost::thread(boost::bind(&Client::files_transfer_worker, this));
+
+    boost::unique_lock<boost::mutex> lock(file_transfer_mutex);
+    file_transfer_tasks.push(file_transfer_task);
+    lock.unlock();
+
+    file_transfer_condition.notify_one();
+}
+
+
 void
 Client::method_call_worker()
 {
@@ -1988,3 +2057,36 @@ Clients::has_zombies() const
 
     return false;
 }
+
+
+void
+Client::files_transfer_worker()
+{
+    try
+    {
+       while (true)
+       {
+           boost::unique_lock<boost::mutex> lock(file_transfer_mutex);
+           while (file_transfer_tasks.empty())
+               file_transfer_condition.wait(lock);
+
+           shared_ptr<FilesTransferTask> ptr(file_transfer_tasks.front());
+           file_transfer_tasks.pop();
+           lock.unlock();
+
+           try
+           {
+               ptr->run();
+           }
+           catch (const StreamException& e)
+           {
+               SN_CAUGHT(e);
+               y2err("error occured during files transfer");
+           }
+       }
+    }
+    catch (const boost::thread_interrupted&)
+    {
+       y2deb("files transfer worker interrupted");
+    }
+}
index 9f48c0487e88e6ddc66928fbeeffda072d30bd76..996360aa193a16bccd1c0004e593b776712b765f 100644 (file)
@@ -38,6 +38,7 @@
 #include <dbus/DBusMessage.h>
 
 #include "MetaSnapper.h"
+#include "FilesTransferTask.h"
 
 
 using namespace std;
@@ -111,6 +112,7 @@ public:
     void create_comparison(DBus::Connection& conn, DBus::Message& msg);
     void delete_comparison(DBus::Connection& conn, DBus::Message& msg);
     void get_files(DBus::Connection& conn, DBus::Message& msg);
+    void get_files_by_pipe(DBus::Connection& conn, DBus::Message& msg);
     void setup_quota(DBus::Connection& conn, DBus::Message& msg);
     void prepare_quota(DBus::Connection& conn, DBus::Message& msg);
     void query_quota(DBus::Connection& conn, DBus::Message& msg);
@@ -162,12 +164,18 @@ public:
     queue<MethodCallTask> method_call_tasks;
     void add_method_call_task(DBus::Connection& conn, DBus::Message& msg);
 
-    bool zombie = false;
+    boost::condition_variable file_transfer_condition;
+    boost::mutex file_transfer_mutex;
+    boost::thread file_transfer_thread;
+    queue<shared_ptr<FilesTransferTask>> file_transfer_tasks;
+    void add_file_transfer_task(shared_ptr<FilesTransferTask> file_transfer_task);
 
+    bool zombie = false;
 
 private:
 
     void method_call_worker();
+    void files_transfer_worker();
 
     const Clients& clients;
 
diff --git a/server/FilesTransferTask.cc b/server/FilesTransferTask.cc
new file mode 100644 (file)
index 0000000..27d55d9
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * Copyright (c) 2022 SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include <stdio.h>
+
+#include "FilesTransferTask.h"
+
+
+FilesTransferTask::FilesTransferTask(const Files& files)
+    : files(files)
+{
+}
+
+
+void
+FilesTransferTask::run()
+{
+    FILE* fout = fdopen(get_write_end().get_fd(), "w");
+    if (!fout)
+       SN_THROW(StreamException());
+
+    for (const File& file : files)
+    {
+       if (fprintf(fout, "%s %d\n", DBus::Pipe::escape(file.getName()).c_str(), file.getPreToPostStatus()) < 4)
+           SN_THROW(StreamException());
+    }
+
+    if (fflush(fout) != 0)
+       SN_THROW(StreamException());
+
+    if (fclose(fout) != 0)
+       SN_THROW(StreamException());
+}
diff --git a/server/FilesTransferTask.h b/server/FilesTransferTask.h
new file mode 100644 (file)
index 0000000..a6c6034
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * Copyright (c) 2022 SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef SNAPPER_FILES_TRANSFER_TASK_H
+#define SNAPPER_FILES_TRANSFER_TASK_H
+
+
+#include <dbus/DBusPipe.h>
+
+#include <snapper/File.h>
+
+
+using namespace snapper;
+
+
+struct StreamException : Exception
+{
+    explicit StreamException() : Exception("stream exception") {}
+};
+
+
+class FilesTransferTask
+{
+public:
+
+    FilesTransferTask(const Files& files);
+
+    DBus::FileDescriptor& get_read_end() { return pipe.get_read_end(); }
+    DBus::FileDescriptor& get_write_end() { return pipe.get_write_end(); }
+
+    void run();
+
+private:
+
+    // Keep a copy of the files. This way the Comparison can be deleted before the
+    // transfer is complete. If that copy is ever a problem it could be turned into some
+    // shared object.
+    const Files files;
+
+    DBus::Pipe pipe;
+
+};
+
+
+#endif
index 3b07eaa63d2dbeefcda2d4ae4ab6b44b25aa0ace..c03f37319247b423f0db04f1b6416e9fff8267d7 100644 (file)
@@ -12,7 +12,8 @@ snapperd_SOURCES =                                    \
        MetaSnapper.cc          MetaSnapper.h           \
        Background.cc           Background.h            \
        Types.cc                Types.h                 \
-       RefCounter.cc           RefCounter.h
+       RefCounter.cc           RefCounter.h            \
+       FilesTransferTask.cc    FilesTransferTask.h
 
 snapperd_LDADD = ../snapper/libsnapper.la ../dbus/libdbus.la -lrt
 snapperd_LDFLAGS = -lboost_system -lboost_thread -lpthread
index 879c9af225dc3b57cbcae72fa5387d4b503a10a9..daa99e021e9cf681c533920cc224d26aee04269b 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 #include <getopt.h>
+#include <signal.h>
 #include <iostream>
 #include <string>
 
@@ -131,6 +132,7 @@ MyMainLoop::client_disconnected(const string& name)
     {
        client->zombie = true;
        client->method_call_thread.interrupt();
+       client->file_transfer_thread.interrupt();
     }
 
     reset_idle_count();
@@ -270,6 +272,8 @@ main(int argc, char** argv)
        setLogQuery(&log_query);
     }
 
+    signal(SIGPIPE, SIG_IGN);
+
     dbus_threads_init_default();
 
     MyMainLoop mainloop(DBUS_BUS_SYSTEM);
index c79dca02498c016663e7f95b3c2f45ddf2f845a2..038a7b2cb9c89bcb5d4351e4d89fe7d4165261c3 100644 (file)
@@ -5,12 +5,13 @@
 #include <boost/test/unit_test.hpp>
 
 #include <dbus/DBusMessage.h>
+#include <dbus/DBusPipe.h>
 
 
 using namespace DBus;
 
 
-BOOST_AUTO_TEST_CASE(escape)
+BOOST_AUTO_TEST_CASE(hoho_escape)
 {
     BOOST_CHECK_EQUAL(Hoho::escape("\\"), "\\\\");
 
@@ -21,7 +22,7 @@ BOOST_AUTO_TEST_CASE(escape)
 }
 
 
-BOOST_AUTO_TEST_CASE(unescape)
+BOOST_AUTO_TEST_CASE(hihi_unescape)
 {
     BOOST_CHECK_EQUAL(Hihi::unescape("\\\\"), "\\");
 
@@ -35,3 +36,15 @@ BOOST_AUTO_TEST_CASE(unescape)
     BOOST_CHECK_THROW(Hihi::unescape("\\x0"), MarshallingException);
     BOOST_CHECK_THROW(Hihi::unescape("\\x0?"), MarshallingException);
 }
+
+
+BOOST_AUTO_TEST_CASE(pipe_escape)
+{
+    BOOST_CHECK_EQUAL(Pipe::escape("hello world\n"), "hello\\x20world\\x0a");
+}
+
+
+BOOST_AUTO_TEST_CASE(pipe_unescape)
+{
+    BOOST_CHECK_EQUAL(Pipe::unescape("hello\\x20world\\x0a"), "hello world\n");
+}