Hello community,

here is the log from the commit of package snapper for openSUSE:Factory checked 
in at 2015-05-06 11:18:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/snapper (Old)
 and      /work/SRC/openSUSE:Factory/.snapper.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "snapper"

Changes:
--------
--- /work/SRC/openSUSE:Factory/snapper/snapper.changes  2015-03-09 
09:59:41.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.snapper.new/snapper.changes     2015-05-06 
11:18:17.000000000 +0200
@@ -1,0 +2,11 @@
+Tue May 05 14:08:03 CEST 2015 - aschn...@suse.de
+
+- added option --sync to delete command (fate#317066)
+
+-------------------------------------------------------------------
+Tue Apr 14 17:58:17 CEST 2015 - aschn...@suse.de
+
+- added option --input to diff command
+- sort files according to locale
+
+-------------------------------------------------------------------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ snapper-0.2.6.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/LIBVERSION new/snapper-0.2.6/LIBVERSION
--- old/snapper-0.2.6/LIBVERSION        2015-02-18 18:54:03.000000000 +0100
+++ new/snapper-0.2.6/LIBVERSION        2015-04-15 14:16:56.000000000 +0200
@@ -1 +1 @@
-3.0.0
+3.1.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/client/commands.cc 
new/snapper-0.2.6/client/commands.cc
--- old/snapper-0.2.6/client/commands.cc        2014-04-10 12:28:10.000000000 
+0200
+++ new/snapper-0.2.6/client/commands.cc        2015-05-05 15:36:17.000000000 
+0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2012-2014] Novell, Inc.
+ * Copyright (c) [2012-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -351,6 +351,13 @@
 }
 
 
+int
+operator<(const XFile& lhs, const XFile& rhs)
+{
+    return File::cmp_lt(lhs.name, rhs.name);
+}
+
+
 list<XFile>
 command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned 
int number1,
                   unsigned int number2)
@@ -367,10 +374,25 @@
     DBus::Hihi hihi(reply);
     hihi >> files;
 
+    files.sort();              // snapperd can have different locale than 
client
+                               // so sorting is required here
+
     return files;
 }
 
 
+void
+command_xsync(DBus::Connection& conn, const string& config_name)
+{
+    DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "Sync");
+
+    DBus::Hoho hoho(call);
+    hoho << config_name;
+
+    conn.send_with_reply_and_block(call);
+}
+
+
 vector<string>
 command_xdebug(DBus::Connection& conn)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/client/commands.h 
new/snapper-0.2.6/client/commands.h
--- old/snapper-0.2.6/client/commands.h 2014-04-10 12:28:10.000000000 +0200
+++ new/snapper-0.2.6/client/commands.h 2015-05-05 15:36:17.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2012-2014] Novell, Inc.
+ * Copyright (c) [2012-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -115,5 +115,8 @@
 command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned 
int number1,
                   unsigned int number2);
 
+void
+command_xsync(DBus::Connection& conn, const string& config_name);
+
 vector<string>
 command_xdebug(DBus::Connection& conn);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/client/snapper.cc 
new/snapper-0.2.6/client/snapper.cc
--- old/snapper-0.2.6/client/snapper.cc 2015-02-18 18:54:03.000000000 +0100
+++ new/snapper-0.2.6/client/snapper.cc 2015-05-05 15:36:17.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -95,9 +95,74 @@
 
     MyFiles(const FilePaths* file_paths)
        : Files(file_paths) {}
+
+    void bulk_process(FILE* file, std::function<void(File& file)> callback);
+
 };
 
 
+void
+MyFiles::bulk_process(FILE* file, std::function<void(File& file)> callback)
+{
+    if (file)
+    {
+       AsciiFileReader asciifile(file);
+
+       string line;
+       while (asciifile.getline(line))
+       {
+           if (line.empty())
+               continue;
+
+           string name = line;
+
+           // strip optional status
+           if (name[0] != '/')
+           {
+               string::size_type pos = name.find(" ");
+               if (pos == string::npos)
+                   continue;
+
+               name.erase(0, pos + 1);
+           }
+
+           Files::iterator it = findAbsolutePath(name);
+           if (it == end())
+           {
+               cerr << sformat(_("File '%s' not found."), name.c_str()) << 
endl;
+               exit(EXIT_FAILURE);
+           }
+
+           callback(*it);
+       }
+    }
+    else
+    {
+       if (getopts.numArgs() == 0)
+       {
+           for (Files::iterator it = begin(); it != end(); ++it)
+               callback(*it);
+       }
+       else
+       {
+           while (getopts.numArgs() > 0)
+           {
+               string name = getopts.popArg();
+
+               Files::iterator it = findAbsolutePath(name);
+               if (it == end())
+               {
+                   cerr << sformat(_("File '%s' not found."), name.c_str()) << 
endl;
+                   exit(EXIT_FAILURE);
+               }
+
+               callback(*it);
+           }
+       }
+    }
+}
+
+
 struct MyComparison
 {
     MyComparison(DBus::Connection& conn, pair<unsigned int, unsigned int> 
nums, bool mount)
@@ -779,7 +844,6 @@
     };
 
     GetOpts::parsed_opts opts = getopts.parse("modify", options);
-
     if (!getopts.hasArgs())
     {
        cerr << _("Command 'modify' needs at least one argument.") << endl;
@@ -813,6 +877,9 @@
 {
     cout << _("  Delete snapshot:") << endl
         << _("\tsnapper delete <number>") << endl
+        << endl
+        << _("    Options for 'delete' command:") << endl
+        << _("\t--sync, -s\t\t\tSync after deletion.") << endl
         << endl;
 }
 
@@ -820,13 +887,25 @@
 void
 command_delete(DBus::Connection* conn, Snapper* snapper)
 {
-    getopts.parse("delete", GetOpts::no_options);
+    const struct option options[] = {
+       { "sync",               no_argument,            0,      's' },
+       { 0, 0, 0, 0 }
+    };
+
+    GetOpts::parsed_opts opts = getopts.parse("delete", options);
     if (!getopts.hasArgs())
     {
        cerr << _("Command 'delete' needs at least one argument.") << endl;
        exit(EXIT_FAILURE);
     }
 
+    bool sync = false;
+
+    GetOpts::parsed_opts::const_iterator opt;
+
+    if ((opt = opts.find("sync")) != opts.end())
+       sync = true;
+
     XSnapshots snapshots = command_list_xsnapshots(*conn, config_name);
 
     list<unsigned int> nums;
@@ -859,6 +938,9 @@
     }
 
     command_delete_xsnapshots(*conn, config_name, nums);
+
+    if (sync)
+       command_xsync(*conn, config_name);
 }
 
 
@@ -1005,6 +1087,7 @@
         << _("\tsnapper diff <number1>..<number2> [files]") << endl
         << endl
         << _("    Options for 'diff' command:") << endl
+        << _("\t--input, -i <file>\t\tRead files to diff from file.") << endl
         << _("\t--diff-cmd <command>\t\tCommand used for comparing files.") << 
endl
         << _("\t--extensions, -x <options>\tExtra options passed to the diff 
command.") << endl
         << endl;
@@ -1015,23 +1098,34 @@
 command_diff(DBus::Connection* conn, Snapper* snapper)
 {
     const struct option options[] = {
+       { "input",              required_argument,      0,      'i' },
        { "diff-cmd",           required_argument,      0,      0 },
        { "extensions",         required_argument,      0,      'x' },
        { 0, 0, 0, 0 }
     };
 
     GetOpts::parsed_opts opts = getopts.parse("diff", options);
-
     if (getopts.numArgs() < 1)
     {
        cerr << _("Command 'diff' needs at least one argument.") << endl;
        exit(EXIT_FAILURE);
     }
 
+    FILE* file = NULL;
     Differ differ;
 
     GetOpts::parsed_opts::const_iterator opt;
 
+    if ((opt = opts.find("input")) != opts.end())
+    {
+       file = fopen(opt->second.c_str(), "r");
+       if (!file)
+       {
+           cerr << sformat(_("Opening file '%s' failed."), 
opt->second.c_str()) << endl;
+           exit(EXIT_FAILURE);
+       }
+    }
+
     if ((opt = opts.find("diff-cmd")) != opts.end())
        differ.command = opt->second;
 
@@ -1043,22 +1137,9 @@
     MyComparison comparison(*conn, nums, true);
     MyFiles& files = comparison.files;
 
-    if (getopts.numArgs() == 0)
-    {
-       for (Files::const_iterator it1 = files.begin(); it1 != files.end(); 
++it1)
-           differ.run(it1->getAbsolutePath(LOC_PRE), 
it1->getAbsolutePath(LOC_POST));
-    }
-    else
-    {
-       while (getopts.numArgs() > 0)
-       {
-           string name = getopts.popArg();
-
-           Files::const_iterator it1 = files.findAbsolutePath(name);
-           if (it1 != files.end())
-               differ.run(it1->getAbsolutePath(LOC_PRE), 
it1->getAbsolutePath(LOC_POST));
-       }
-    }
+    files.bulk_process(file, [differ](const File& file) {
+       differ.run(file.getAbsolutePath(LOC_PRE), 
file.getAbsolutePath(LOC_POST));
+    });
 }
 
 
@@ -1114,57 +1195,9 @@
     MyComparison comparison(*conn, nums, true);
     MyFiles& files = comparison.files;
 
-    if (file)
-    {
-       AsciiFileReader asciifile(file);
-
-       string line;
-       while (asciifile.getline(line))
-       {
-           if (line.empty())
-               continue;
-
-           string name = line;
-
-           // strip optional status
-           if (name[0] != '/')
-           {
-               string::size_type pos = name.find(" ");
-               if (pos == string::npos)
-                   continue;
-
-               name.erase(0, pos + 1);
-           }
-
-           Files::iterator it = files.findAbsolutePath(name);
-           if (it == files.end())
-            {
-                cerr << sformat(_("File '%s' not found."), name.c_str()) << 
endl;
-                exit(EXIT_FAILURE);
-            }
-
-           it->setUndo(true);
-       }
-    }
-    else
-    {
-       if (getopts.numArgs() == 0)
-       {
-           for (Files::iterator it = files.begin(); it != files.end(); ++it)
-               it->setUndo(true);
-       }
-       else
-       {
-           while (getopts.numArgs() > 0)
-           {
-               Files::iterator it = files.findAbsolutePath(getopts.popArg());
-               if (it == files.end())
-                    continue;
-
-               it->setUndo(true);
-           }
-       }
-    }
+    files.bulk_process(file, [](File& file) {
+       file.setUndo(true);
+    });
 
     UndoStatistic undo_statistic = files.getUndoStatistic();
 
@@ -1455,7 +1488,6 @@
 command_xa_diff(DBus::Connection* conn, Snapper* snapper)
 {
     GetOpts::parsed_opts opts = getopts.parse("xadiff", GetOpts::no_options);
-
     if (getopts.numArgs() < 1)
     {
         cerr << _("Command 'xadiff' needs at least one argument.") << endl;
@@ -1553,7 +1585,7 @@
 int
 main(int argc, char** argv)
 {
-    setlocale(LC_ALL, "");
+    locale::global(locale(""));
 
     setLogDo(&log_do);
     setLogQuery(&log_query);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/doc/dbus-protocol.txt 
new/snapper-0.2.6/doc/dbus-protocol.txt
--- old/snapper-0.2.6/doc/dbus-protocol.txt     2015-01-19 16:56:41.000000000 
+0100
+++ new/snapper-0.2.6/doc/dbus-protocol.txt     2015-05-05 15:36:17.000000000 
+0200
@@ -42,6 +42,8 @@
 Snapshots mounted with user-request set to false will be unmounted (delayed)
 after the client disconnects.
 
+method Sync config-name
+
 
 method CreateComparison config-name number1 number2
 method DeleteComparison config-name number1 number2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/doc/snapper.xml.in 
new/snapper-0.2.6/doc/snapper.xml.in
--- old/snapper-0.2.6/doc/snapper.xml.in        2014-12-11 18:21:17.000000000 
+0100
+++ new/snapper-0.2.6/doc/snapper.xml.in        2015-05-05 15:36:17.000000000 
+0200
@@ -409,6 +409,18 @@
        <replaceable>number1-number2</replaceable></option></term>
        <listitem>
          <para>Delete a snapshot or a range of snapshots.</para>
+         <variablelist>
+           <varlistentry>
+             <term><option>-s, --sync</option></term>
+             <listitem>
+               <para>Sync the filesystem after deleting the snapshots. The
+               details depend on the filesystem type.</para>
+               <para>Btrfs normally asynchronously frees space after deleting
+               snapshots. With this option snapper will wait until the space 
once used by the
+               deleted snapshots is actually available again.</para>
+             </listitem>
+           </varlistentry>
+         </variablelist>
        </listitem>
       </varlistentry>
 
@@ -485,6 +497,12 @@
          deleted in the time between the two snapshots have been made.</para>
          <variablelist>
            <varlistentry>
+             <term><option>-i, --input</option> 
<replaceable>file</replaceable></term>
+             <listitem>
+               <para>Read files to diff from file 
<replaceable>file</replaceable>.</para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
              <term><option>--diff-cmd</option> 
<replaceable>command</replaceable></term>
              <listitem>
                <para>Command used for comparing files. The default is
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/server/Client.cc 
new/snapper-0.2.6/server/Client.cc
--- old/snapper-0.2.6/server/Client.cc  2015-02-18 18:54:03.000000000 +0100
+++ new/snapper-0.2.6/server/Client.cc  2015-05-05 15:36:17.000000000 +0200
@@ -347,6 +347,10 @@
        "      <arg name='files' type='v' direction='out'/>\n"
        "    </method>\n"
 
+       "    <method name='Sync'>\n"
+       "      <arg name='config-name' type='s' direction='in'/>\n"
+       "    </method>\n"
+
        "  </interface>\n"
        "</node>\n";
 
@@ -1288,6 +1292,30 @@
 
 
 void
+Client::sync(DBus::Connection& conn, DBus::Message& msg)
+{
+    string config_name;
+
+    DBus::Hihi hihi(msg);
+    hihi >> config_name;
+
+    y2deb("Sync config_name:" << config_name);
+
+    MetaSnappers::iterator it = meta_snappers.find(config_name);
+
+    check_permission(conn, msg, *it);
+
+    Snapper* snapper = it->getSnapper();
+
+    snapper->syncFilesystem();
+
+    DBus::MessageMethodReturn reply(msg);
+
+    conn.send(reply);
+}
+
+
+void
 Client::debug(DBus::Connection& conn, DBus::Message& msg) const
 {
     y2deb("Debug");
@@ -1403,6 +1431,8 @@
            delete_comparison(conn, msg);
        else if (msg.is_method_call(INTERFACE, "GetFiles"))
            get_files(conn, msg);
+       else if (msg.is_method_call(INTERFACE, "Sync"))
+           sync(conn, msg);
        else if (msg.is_method_call(INTERFACE, "Debug"))
            debug(conn, msg);
        else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/server/Client.h 
new/snapper-0.2.6/server/Client.h
--- old/snapper-0.2.6/server/Client.h   2014-04-10 12:28:10.000000000 +0200
+++ new/snapper-0.2.6/server/Client.h   2015-05-05 15:36:17.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2012-2014] Novell, Inc.
+ * Copyright (c) [2012-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -104,6 +104,7 @@
     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 sync(DBus::Connection& conn, DBus::Message& msg);
     void debug(DBus::Connection& conn, DBus::Message& msg) const;
 
     void dispatch(DBus::Connection& conn, DBus::Message& msg);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/Btrfs.cc 
new/snapper-0.2.6/snapper/Btrfs.cc
--- old/snapper-0.2.6/snapper/Btrfs.cc  2015-02-18 18:54:03.000000000 +0100
+++ new/snapper-0.2.6/snapper/Btrfs.cc  2015-05-05 15:36:17.000000000 +0200
@@ -305,7 +305,7 @@
     Btrfs::createSnapshotOfDefault(unsigned int num, bool read_only) const
     {
        SDir subvolume_dir = openSubvolumeDir();
-       unsigned long long id = get_default_id(subvolume_dir.fd());
+       subvolid_t id = get_default_id(subvolume_dir.fd());
        string name = get_subvolume(subvolume_dir.fd(), id);
 
        bool found = false;
@@ -352,7 +352,11 @@
 
        try
        {
+           subvolid_t subvolid = get_id(openSnapshotDir(num).fd());
+
            delete_subvolume(info_dir.fd(), "snapshot");
+
+           deleted_subvolids.push_back(subvolid);
        }
        catch (const runtime_error& e)
        {
@@ -402,6 +406,8 @@
        }
        catch (const IOErrorException& e)
        {
+           // TODO the openInfoDir above logs an error although when this
+           // function is used from nextNumber the failure is ok
            return false;
        }
     }
@@ -1357,13 +1363,13 @@
            if (num == 0)
            {
                SDir subvolume_dir = openSubvolumeDir();
-               unsigned long long id = get_id(subvolume_dir.fd());
+               subvolid_t id = get_id(subvolume_dir.fd());
                set_default_id(subvolume_dir.fd(), id);
            }
            else
            {
                SDir snapshot_dir = openSnapshotDir(num);
-               unsigned long long id = get_id(snapshot_dir.fd());
+               subvolid_t id = get_id(snapshot_dir.fd());
 
                SDir subvolume_dir = openSubvolumeDir();
                set_default_id(subvolume_dir.fd(), id);
@@ -1387,6 +1393,28 @@
 #endif
 
 
+    void
+    Btrfs::sync() const
+    {
+       SDir subvolume_dir = openSubvolumeDir();
+
+       BtrfsUtils::sync(subvolume_dir.fd());
+
+       if (!deleted_subvolids.empty())
+       {
+           for (subvolid_t subvolid : deleted_subvolids)
+           {
+               while (!does_subvolume_exist(subvolume_dir.fd(), subvolid))
+                   sleep(1);
+           }
+
+           deleted_subvolids.clear();
+
+           BtrfsUtils::sync(subvolume_dir.fd());
+       }
+    }
+
+
 #ifdef ENABLE_ROLLBACK
 
     class MntTable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/Btrfs.h 
new/snapper-0.2.6/snapper/Btrfs.h
--- old/snapper-0.2.6/snapper/Btrfs.h   2015-02-18 18:54:03.000000000 +0100
+++ new/snapper-0.2.6/snapper/Btrfs.h   2015-05-05 15:36:17.000000000 +0200
@@ -31,6 +31,9 @@
 namespace snapper
 {
 
+    using namespace BtrfsUtils;
+
+
     class Btrfs : public Filesystem
     {
     public:
@@ -73,10 +76,14 @@
 
        virtual void setDefault(unsigned int num) const;
 
+       virtual void sync() const;
+
     private:
 
        qgroup_t qgroup;
 
+       mutable vector<subvolid_t> deleted_subvolids;
+
        void addToFstabHelper(const string& default_subvolume_name) const;
        void removeFromFstabHelper() const;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/BtrfsUtils.cc 
new/snapper-0.2.6/snapper/BtrfsUtils.cc
--- old/snapper-0.2.6/snapper/BtrfsUtils.cc     2014-06-30 15:03:26.000000000 
+0200
+++ new/snapper-0.2.6/snapper/BtrfsUtils.cc     2015-05-05 15:36:17.000000000 
+0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -77,200 +77,237 @@
 namespace snapper
 {
 
-    // See btrfsprogs source code for references.
+    namespace BtrfsUtils
+    {
 
+       // See btrfsprogs source code for references.
 
-    bool
-    is_subvolume(const struct stat& stat)
-    {
-       return stat.st_ino == 256 && S_ISDIR(stat.st_mode);
-    }
 
+       bool
+       is_subvolume(const struct stat& stat)
+       {
+           return stat.st_ino == 256 && S_ISDIR(stat.st_mode);
+       }
 
-    bool
-    is_subvolume_read_only(int fd)
-    {
-       __u64 flags;
-       if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_GETFLAGS) 
failed", errno);
 
-       return flags & BTRFS_SUBVOL_RDONLY;
-    }
+       bool
+       is_subvolume_read_only(int fd)
+       {
+           __u64 flags;
+           if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) != 0)
+               throw 
runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_GETFLAGS) failed", errno);
 
+           return flags & BTRFS_SUBVOL_RDONLY;
+       }
 
-    void
-    create_subvolume(int fddst, const string& name)
-    {
-       struct btrfs_ioctl_vol_args args;
-       memset(&args, 0, sizeof(args));
 
-       strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
+       void
+       create_subvolume(int fddst, const string& name)
+       {
+           struct btrfs_ioctl_vol_args args;
+           memset(&args, 0, sizeof(args));
 
-       if (ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_CREATE) 
failed", errno);
-    }
+           strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
 
+           if (ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_CREATE) 
failed", errno);
+       }
 
-    void
-    create_snapshot(int fd, int fddst, const string& name, bool read_only, 
qgroup_t qgroup)
-    {
-       struct btrfs_ioctl_vol_args_v2 args_v2;
-       memset(&args_v2, 0, sizeof(args_v2));
 
-       args_v2.fd = fd;
-       args_v2.flags = read_only ? BTRFS_SUBVOL_RDONLY : 0;
-       strncpy(args_v2.name, name.c_str(), sizeof(args_v2.name) - 1);
+       void
+       create_snapshot(int fd, int fddst, const string& name, bool read_only, 
qgroup_t qgroup)
+       {
+           struct btrfs_ioctl_vol_args_v2 args_v2;
+           memset(&args_v2, 0, sizeof(args_v2));
+
+           args_v2.fd = fd;
+           args_v2.flags = read_only ? BTRFS_SUBVOL_RDONLY : 0;
+           strncpy(args_v2.name, name.c_str(), sizeof(args_v2.name) - 1);
 
 #ifdef ENABLE_BTRFS_QUOTA
-       if (qgroup != no_qgroup)
-       {
-           size_t size = sizeof(btrfs_qgroup_inherit) + 
sizeof(((btrfs_qgroup_inherit*) 0)->qgroups[0]);
-           vector<char> buffer(size, 0);
-           struct btrfs_qgroup_inherit* inherit = (btrfs_qgroup_inherit*) 
&buffer[0];
-
-           inherit->num_qgroups = 1;
-           inherit->num_ref_copies = 0;
-           inherit->num_excl_copies = 0;
-           inherit->qgroups[0] = qgroup;
-
-           args_v2.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
-           args_v2.size = size;
-           args_v2.qgroup_inherit = inherit;
-       }
+           if (qgroup != no_qgroup)
+           {
+               size_t size = sizeof(btrfs_qgroup_inherit) + 
sizeof(((btrfs_qgroup_inherit*) 0)->qgroups[0]);
+               vector<char> buffer(size, 0);
+               struct btrfs_qgroup_inherit* inherit = (btrfs_qgroup_inherit*) 
&buffer[0];
+
+               inherit->num_qgroups = 1;
+               inherit->num_ref_copies = 0;
+               inherit->num_excl_copies = 0;
+               inherit->qgroups[0] = qgroup;
+
+               args_v2.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
+               args_v2.size = size;
+               args_v2.qgroup_inherit = inherit;
+           }
 #endif
 
-       if (ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args_v2) == 0)
-           return;
-       else if (errno != ENOTTY && errno != EINVAL)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_CREATE_V2) 
failed", errno);
+           if (ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args_v2) == 0)
+               return;
+           else if (errno != ENOTTY && errno != EINVAL)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_CREATE_V2) 
failed", errno);
 
-       struct btrfs_ioctl_vol_args args;
-       memset(&args, 0, sizeof(args));
+           struct btrfs_ioctl_vol_args args;
+           memset(&args, 0, sizeof(args));
 
-       args.fd = fd;
-       strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
+           args.fd = fd;
+           strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
 
-       if (ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_CREATE) 
failed", errno);
-    }
+           if (ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_CREATE) 
failed", errno);
+       }
 
 
-    void
-    delete_subvolume(int fd, const string& name)
-    {
-       struct btrfs_ioctl_vol_args args;
-       memset(&args, 0, sizeof(args));
+       void
+       delete_subvolume(int fd, const string& name)
+       {
+           struct btrfs_ioctl_vol_args args;
+           memset(&args, 0, sizeof(args));
 
-       strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
+           strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
 
-       if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_DESTROY) 
failed", errno);
-    }
+           if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_DESTROY) 
failed", errno);
+       }
 
 
 #ifdef ENABLE_ROLLBACK
 
-    void
-    set_default_id(int fd, unsigned long long id)
-    {
-       if (ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &id) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_DEFAULT_SUBVOL) 
failed", errno);
-    }
+       void
+       set_default_id(int fd, subvolid_t id)
+       {
+           if (ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &id) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_DEFAULT_SUBVOL) 
failed", errno);
+       }
 
 
-    unsigned long long
-    get_default_id(int fd)
-    {
-       struct btrfs_ioctl_search_args args;
-       memset(&args, 0, sizeof(args));
+       subvolid_t
+       get_default_id(int fd)
+       {
+           struct btrfs_ioctl_search_args args;
+           memset(&args, 0, sizeof(args));
 
-       struct btrfs_ioctl_search_key* sk = &args.key;
-       sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
-       sk->nr_items = 1;
-       sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
-       sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
-       sk->max_type = BTRFS_DIR_ITEM_KEY;
-       sk->min_type = BTRFS_DIR_ITEM_KEY;
-       sk->max_offset = (__u64) -1;
-       sk->max_transid = (__u64) -1;
-
-       if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_TREE_SEARCH) 
failed", errno);
-
-       if (sk->nr_items == 0)
-           throw std::runtime_error("sk->nr_items == 0");
-
-       struct btrfs_ioctl_search_header* sh = (struct 
btrfs_ioctl_search_header*) args.buf;
-       if (sh->type != BTRFS_DIR_ITEM_KEY)
-           throw std::runtime_error("sh->type != BTRFS_DIR_ITEM_KEY");
-
-       struct btrfs_dir_item* di = (struct btrfs_dir_item*)(sh + 1);
-       int name_len = btrfs_stack_dir_name_len(di);
-       const char* name = (const char*)(di + 1);
-       if (strncmp("default", name, name_len) != 0)
-           throw std::runtime_error("name != default");
+           struct btrfs_ioctl_search_key* sk = &args.key;
+           sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+           sk->nr_items = 1;
+           sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+           sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+           sk->max_type = BTRFS_DIR_ITEM_KEY;
+           sk->min_type = BTRFS_DIR_ITEM_KEY;
+           sk->max_offset = (__u64) -1;
+           sk->max_transid = (__u64) -1;
+
+           if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_TREE_SEARCH) 
failed", errno);
+
+           if (sk->nr_items == 0)
+               throw std::runtime_error("sk->nr_items == 0");
+
+           struct btrfs_ioctl_search_header* sh = (struct 
btrfs_ioctl_search_header*) args.buf;
+           if (sh->type != BTRFS_DIR_ITEM_KEY)
+               throw std::runtime_error("sh->type != BTRFS_DIR_ITEM_KEY");
+
+           struct btrfs_dir_item* di = (struct btrfs_dir_item*)(sh + 1);
+           int name_len = btrfs_stack_dir_name_len(di);
+           const char* name = (const char*)(di + 1);
+           if (strncmp("default", name, name_len) != 0)
+               throw std::runtime_error("name != default");
 
-       return btrfs_disk_key_objectid(&di->location);
-    }
+           return btrfs_disk_key_objectid(&di->location);
+       }
 
 
-    string
-    get_subvolume(int fd, unsigned long long id)
-    {
-       char path[BTRFS_PATH_NAME_MAX + 1];
+       string
+       get_subvolume(int fd, subvolid_t id)
+       {
+           char path[BTRFS_PATH_NAME_MAX + 1];
 
-       if (btrfs_subvolid_resolve(fd, path, sizeof(path), id) != 0)
-           throw std::runtime_error("btrfs_subvolid_resolve failed");
+           if (btrfs_subvolid_resolve(fd, path, sizeof(path), id) != 0)
+               throw std::runtime_error("btrfs_subvolid_resolve failed");
 
-       path[BTRFS_PATH_NAME_MAX] = '\0';
-       return path;
-    }
+           path[BTRFS_PATH_NAME_MAX] = '\0';
+           return path;
+       }
 
+#endif
 
-    unsigned long long
-    get_id(int fd)
-    {
-       struct btrfs_ioctl_ino_lookup_args args;
-       memset(&args, 0, sizeof(args));
-       args.treeid = 0;
-       args.objectid = BTRFS_FIRST_FREE_OBJECTID;
 
-       if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_INO_LOOKUP) 
failed", errno);
+       subvolid_t
+       get_id(int fd)
+       {
+           struct btrfs_ioctl_ino_lookup_args args;
+           memset(&args, 0, sizeof(args));
+           args.treeid = 0;
+           args.objectid = BTRFS_FIRST_FREE_OBJECTID;
 
-       return args.treeid;
-    }
+           if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_INO_LOOKUP) 
failed", errno);
 
-#endif
+           return args.treeid;
+       }
 
 
-    qgroup_t
-    make_qgroup(uint64_t level, uint64_t id)
-    {
-       return (level << 48) | id;
-    }
+       qgroup_t
+       make_qgroup(uint64_t level, subvolid_t id)
+       {
+           return (level << 48) | id;
+       }
 
 
-    qgroup_t
-    make_qgroup(const string& str)
-    {
-       string::size_type pos = str.find('/');
-       if (pos == string::npos)
-           throw std::runtime_error("parsing qgroup failed");
-
-       std::istringstream a(str.substr(0, pos));
-       uint64_t level = 0;
-       a >> level;
-       if (a.fail() || !a.eof())
-           throw std::runtime_error("parsing qgroup failed");
-
-       std::istringstream b(str.substr(pos + 1));
-       uint64_t id = 0;
-       b >> id;
-       if (b.fail() || !b.eof())
-           throw std::runtime_error("parsing qgroup failed");
+       qgroup_t
+       make_qgroup(const string& str)
+       {
+           string::size_type pos = str.find('/');
+           if (pos == string::npos)
+               throw std::runtime_error("parsing qgroup failed");
+
+           std::istringstream a(str.substr(0, pos));
+           uint64_t level = 0;
+           a >> level;
+           if (a.fail() || !a.eof())
+               throw std::runtime_error("parsing qgroup failed");
+
+           std::istringstream b(str.substr(pos + 1));
+           subvolid_t id = 0;
+           b >> id;
+           if (b.fail() || !b.eof())
+               throw std::runtime_error("parsing qgroup failed");
+
+           return make_qgroup(level, id);
+       }
+
+
+       bool
+       does_subvolume_exist(int fd, subvolid_t subvolid)
+       {
+           struct btrfs_ioctl_search_args args;
+           struct btrfs_ioctl_search_key* sk = &args.key;
+
+           sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+           sk->min_objectid = subvolid;
+           sk->max_objectid = subvolid;
+           sk->min_type = BTRFS_ROOT_ITEM_KEY;
+           sk->max_type = BTRFS_ROOT_ITEM_KEY;
+           sk->min_offset = 0;
+           sk->max_offset = (u64) -1;
+           sk->min_transid = 0;
+           sk->max_transid = (u64) -1;
+           sk->nr_items = 1;
+
+           if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_TREE_SEARCH) 
failed", errno);
+
+           return sk->nr_items == 0;
+       }
+
+
+       void
+       sync(int fd)
+       {
+           if (ioctl(fd, BTRFS_IOC_SYNC) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SYNC) failed", 
errno);
+       }
 
-       return make_qgroup(level, id);
     }
 
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/BtrfsUtils.h 
new/snapper-0.2.6/snapper/BtrfsUtils.h
--- old/snapper-0.2.6/snapper/BtrfsUtils.h      2014-06-30 15:03:26.000000000 
+0200
+++ new/snapper-0.2.6/snapper/BtrfsUtils.h      2015-05-05 15:36:17.000000000 
+0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -32,26 +32,37 @@
     using std::string;
 
 
-    typedef uint64_t qgroup_t;
-    const qgroup_t no_qgroup = 0;
+    namespace BtrfsUtils
+    {
 
-    bool is_subvolume(const struct stat& stat);
+       typedef uint64_t subvolid_t;
 
-    bool is_subvolume_read_only(int fd);
+       typedef uint64_t qgroup_t;
+       const qgroup_t no_qgroup = 0;
 
-    void create_subvolume(int fddst, const string& name);
-    void create_snapshot(int fd, int fddst, const string& name, bool read_only,
-                        qgroup_t qgroup);
-    void delete_subvolume(int fd, const string& name);
+       bool is_subvolume(const struct stat& stat);
 
-    void set_default_id(int fd, unsigned long long id);
-    unsigned long long get_default_id(int fd);
+       bool is_subvolume_read_only(int fd);
 
-    string get_subvolume(int fd, unsigned long long id);
-    unsigned long long get_id(int fd);
+       bool does_subvolume_exist(int fd, subvolid_t id);
 
-    qgroup_t make_qgroup(uint64_t level, uint64_t id);
-    qgroup_t make_qgroup(const string& str);
+       void create_subvolume(int fddst, const string& name);
+       void create_snapshot(int fd, int fddst, const string& name, bool 
read_only,
+                            qgroup_t qgroup);
+       void delete_subvolume(int fd, const string& name);
+
+       void set_default_id(int fd, subvolid_t id);
+       subvolid_t get_default_id(int fd);
+
+       string get_subvolume(int fd, subvolid_t id);
+       subvolid_t get_id(int fd);
+
+       qgroup_t make_qgroup(uint64_t level, subvolid_t id);
+       qgroup_t make_qgroup(const string& str);
+
+       void sync(int fd);
+
+    }
 
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/File.cc 
new/snapper-0.2.6/snapper/File.cc
--- old/snapper-0.2.6/snapper/File.cc   2014-02-28 13:36:50.000000000 +0100
+++ new/snapper-0.2.6/snapper/File.cc   2015-04-15 14:16:56.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -29,6 +29,7 @@
 #include <fnmatch.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <locale>
 #include <boost/algorithm/string.hpp>
 
 #include "snapper/File.h"
@@ -72,33 +73,34 @@
     }
 
 
-    struct FilterHelper
+    void
+    Files::filter(const vector<string>& ignore_patterns)
     {
-       FilterHelper(const vector<string>& patterns)
-           : patterns(patterns) {}
-       bool operator()(const File& file)
-           {
-               for (vector<string>::const_iterator it = patterns.begin(); it 
!= patterns.end(); ++it)
-                   if (fnmatch(it->c_str(), file.getName().c_str(), 
FNM_LEADING_DIR) == 0)
-                       return true;
-               return false;
-           }
-       const vector<string>& patterns;
-    };
+       std::function<bool(const File&)> pred = [&ignore_patterns](const File& 
file) {
+           for (const string& ignore_pattern : ignore_patterns)
+               if (fnmatch(ignore_pattern.c_str(), file.getName().c_str(), 
FNM_LEADING_DIR) == 0)
+                   return true;
+           return false;
+       };
 
+       entries.erase(remove_if(entries.begin(), entries.end(), pred), 
entries.end());
+    }
 
-    void
-    Files::filter(const vector<string>& ignore_patterns)
+
+    bool
+    File::cmp_lt(const string& lhs, const string& rhs)
     {
-       entries.erase(remove_if(entries.begin(), entries.end(), 
FilterHelper(ignore_patterns)),
-                     entries.end());
+       const std::collate<char>& c = 
std::use_facet<std::collate<char>>(std::locale());
+
+       return c.compare(lhs.c_str(), lhs.c_str() + lhs.length(),
+                        rhs.c_str(), rhs.c_str() + rhs.length()) < 0;
     }
 
 
-    int
-    operator<(const File& a, const File& b)
+    bool
+    operator<(const File& lhs, const File& rhs)
     {
-       return a.getName() < b.getName();
+       return File::cmp_lt(lhs.getName(), rhs.getName());
     }
 
 
@@ -110,16 +112,16 @@
 
 
     bool
-    file_name_less(const File& file, const string& name)
+    operator<(const File& file, const string& name)
     {
-       return file.getName() < name;
+       return File::cmp_lt(file.getName(), name);
     }
 
 
     Files::iterator
     Files::find(const string& name)
     {
-       iterator ret = lower_bound(entries.begin(), entries.end(), name, 
file_name_less);
+       iterator ret = lower_bound(entries.begin(), entries.end(), name);
        return (ret != end() && ret->getName() == name) ? ret : end();
     }
 
@@ -127,7 +129,7 @@
     Files::const_iterator
     Files::find(const string& name) const
     {
-       const_iterator ret = lower_bound(entries.begin(), entries.end(), name, 
file_name_less);
+       const_iterator ret = lower_bound(entries.begin(), entries.end(), name);
        return (ret != end() && ret->getName() == name) ? ret : end();
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/File.h 
new/snapper-0.2.6/snapper/File.h
--- old/snapper-0.2.6/snapper/File.h    2014-02-26 18:11:56.000000000 +0100
+++ new/snapper-0.2.6/snapper/File.h    2015-04-15 14:16:56.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -140,6 +140,9 @@
 
        XAUndoStatistic getXAUndoStatistic() const;
 
+       // C++ locale aware less-than comparison
+       static bool cmp_lt(const string& lhs, const string& rhs);
+
     private:
 
        bool createParentDirectories(const string& path) const;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/Filesystem.cc 
new/snapper-0.2.6/snapper/Filesystem.cc
--- old/snapper-0.2.6/snapper/Filesystem.cc     2015-02-18 18:54:03.000000000 
+0100
+++ new/snapper-0.2.6/snapper/Filesystem.cc     2015-05-05 15:36:17.000000000 
+0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2013] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -174,4 +174,10 @@
        throw std::logic_error("not implemented");
     }
 
+
+    void
+    Filesystem::sync() const
+    {
+    }
+
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/Filesystem.h 
new/snapper-0.2.6/snapper/Filesystem.h
--- old/snapper-0.2.6/snapper/Filesystem.h      2015-02-18 18:54:03.000000000 
+0100
+++ new/snapper-0.2.6/snapper/Filesystem.h      2015-05-05 15:36:17.000000000 
+0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -83,6 +83,8 @@
 
        virtual void setDefault(unsigned int num) const;
 
+       virtual void sync() const;
+
     protected:
 
        const string subvolume;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/Snapper.cc 
new/snapper-0.2.6/snapper/Snapper.cc
--- old/snapper-0.2.6/snapper/Snapper.cc        2015-02-18 18:54:03.000000000 
+0100
+++ new/snapper-0.2.6/snapper/Snapper.cc        2015-05-05 15:36:17.000000000 
+0200
@@ -492,6 +492,13 @@
     }
 
 
+    void
+    Snapper::syncFilesystem() const
+    {
+       filesystem->sync();
+    }
+
+
     static void
     set_acl_permissions(acl_entry_t entry)
     {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/Snapper.h 
new/snapper-0.2.6/snapper/Snapper.h
--- old/snapper-0.2.6/snapper/Snapper.h 2015-02-18 18:54:03.000000000 +0100
+++ new/snapper-0.2.6/snapper/Snapper.h 2015-05-05 15:36:17.000000000 +0200
@@ -153,6 +153,8 @@
 
        void syncAcl() const;
 
+       void syncFilesystem() const;
+
        static const char* compileVersion();
        static const char* compileFlags();
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/snapper/Version.h 
new/snapper-0.2.6/snapper/Version.h
--- old/snapper-0.2.6/snapper/Version.h 2015-03-03 11:07:56.000000000 +0100
+++ new/snapper-0.2.6/snapper/Version.h 2015-05-05 15:38:23.000000000 +0200
@@ -25,7 +25,7 @@
 
 
 #define LIBSNAPPER_MAJOR="3"
-#define LIBSNAPPER_MINOR="0"
+#define LIBSNAPPER_MINOR="1"
 #define LIBSNAPPER_PATCHLEVEL="0"
 
 #define LIBSNAPPER_VERSION ( LIBSNAPPER_MAJOR * 10000 + \\
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/testsuite/Makefile.am 
new/snapper-0.2.6/testsuite/Makefile.am
--- old/snapper-0.2.6/testsuite/Makefile.am     2015-01-19 16:56:41.000000000 
+0100
+++ new/snapper-0.2.6/testsuite/Makefile.am     2015-04-15 14:16:56.000000000 
+0200
@@ -7,7 +7,7 @@
 LDADD = ../snapper/libsnapper.la ../dbus/libdbus.la -lboost_unit_test_framework
 
 check_PROGRAMS = sysconfig-get1.test dirname1.test basename1.test              
\
-       equal-date.test dbus-escape.test
+       equal-date.test dbus-escape.test cmp-lt.test
 
 TESTS = $(check_PROGRAMS)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/testsuite/Makefile.in 
new/snapper-0.2.6/testsuite/Makefile.in
--- old/snapper-0.2.6/testsuite/Makefile.in     2015-03-03 11:07:54.000000000 
+0100
+++ new/snapper-0.2.6/testsuite/Makefile.in     2015-05-05 15:38:19.000000000 
+0200
@@ -83,7 +83,7 @@
 host_triplet = @host@
 check_PROGRAMS = sysconfig-get1.test$(EXEEXT) dirname1.test$(EXEEXT) \
        basename1.test$(EXEEXT) equal-date.test$(EXEEXT) \
-       dbus-escape.test$(EXEEXT)
+       dbus-escape.test$(EXEEXT) cmp-lt.test$(EXEEXT)
 subdir = testsuite
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
        $(top_srcdir)/depcomp $(top_srcdir)/test-driver
@@ -104,6 +104,10 @@
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
+cmp_lt_test_SOURCES = cmp-lt.cc
+cmp_lt_test_OBJECTS = cmp-lt.$(OBJEXT)
+cmp_lt_test_LDADD = $(LDADD)
+cmp_lt_test_DEPENDENCIES = ../snapper/libsnapper.la ../dbus/libdbus.la
 dbus_escape_test_SOURCES = dbus-escape.cc
 dbus_escape_test_OBJECTS = dbus-escape.$(OBJEXT)
 dbus_escape_test_LDADD = $(LDADD)
@@ -156,10 +160,10 @@
 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
 am__v_CXXLD_1 = 
-SOURCES = basename1.cc dbus-escape.cc dirname1.cc equal-date.cc \
-       sysconfig-get1.cc
-DIST_SOURCES = basename1.cc dbus-escape.cc dirname1.cc equal-date.cc \
-       sysconfig-get1.cc
+SOURCES = basename1.cc cmp-lt.cc dbus-escape.cc dirname1.cc \
+       equal-date.cc sysconfig-get1.cc
+DIST_SOURCES = basename1.cc cmp-lt.cc dbus-escape.cc dirname1.cc \
+       equal-date.cc sysconfig-get1.cc
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -583,6 +587,10 @@
        @rm -f basename1.test$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(basename1_test_OBJECTS) 
$(basename1_test_LDADD) $(LIBS)
 
+cmp-lt.test$(EXEEXT): $(cmp_lt_test_OBJECTS) $(cmp_lt_test_DEPENDENCIES) 
$(EXTRA_cmp_lt_test_DEPENDENCIES) 
+       @rm -f cmp-lt.test$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(cmp_lt_test_OBJECTS) $(cmp_lt_test_LDADD) 
$(LIBS)
+
 dbus-escape.test$(EXEEXT): $(dbus_escape_test_OBJECTS) 
$(dbus_escape_test_DEPENDENCIES) $(EXTRA_dbus_escape_test_DEPENDENCIES) 
        @rm -f dbus-escape.test$(EXEEXT)
        $(AM_V_CXXLD)$(CXXLINK) $(dbus_escape_test_OBJECTS) 
$(dbus_escape_test_LDADD) $(LIBS)
@@ -606,6 +614,7 @@
        -rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basename1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmp-lt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-escape.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirname1.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/equal-date.Po@am__quote@
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/snapper-0.2.6/testsuite/cmp-lt.cc 
new/snapper-0.2.6/testsuite/cmp-lt.cc
--- old/snapper-0.2.6/testsuite/cmp-lt.cc       1970-01-01 01:00:00.000000000 
+0100
+++ new/snapper-0.2.6/testsuite/cmp-lt.cc       2015-04-15 14:16:56.000000000 
+0200
@@ -0,0 +1,71 @@
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE snapper
+
+#include <locale>
+#include <boost/test/unit_test.hpp>
+
+#include <snapper/File.h>
+
+using namespace snapper;
+
+
+namespace std
+{
+    std::ostream&
+    operator<<(std::ostream& s, const vector<string>& v)
+    {
+       for(std::vector<string>::const_iterator it = v.begin(); it != v.end(); 
++it)
+       {
+           if (it != v.begin())
+               s << " ";
+           s << *it;
+       }
+
+       return s;
+    }
+}
+
+
+BOOST_AUTO_TEST_CASE(test1)
+{
+    std::locale::global(std::locale("C"));
+
+    vector<string> v = { "A", "B", "b", "a" };
+    sort(v.begin(), v.end(), File::cmp_lt);
+
+    BOOST_CHECK_EQUAL(v, vector<string>({ "A", "B", "a", "b" }));
+}
+
+
+BOOST_AUTO_TEST_CASE(test2)
+{
+    std::locale::global(std::locale("en_US.UTF-8"));
+
+    vector<string> v = { "A", "B", "b", "a" };
+    sort(v.begin(), v.end(), File::cmp_lt);
+
+    BOOST_CHECK_EQUAL(v, vector<string>({ "a", "A", "b", "B" }));
+}
+
+
+BOOST_AUTO_TEST_CASE(test3)
+{
+    std::locale::global(std::locale("de_DE.UTF-8"));
+
+    vector<string> v = { "a", "b", "ä" };
+    sort(v.begin(), v.end(), File::cmp_lt);
+
+    BOOST_CHECK_EQUAL(v, vector<string>({ "a", "ä", "b" }));
+}
+
+
+BOOST_AUTO_TEST_CASE(test4)
+{
+    std::locale::global(std::locale("en_US.UTF-8"));
+
+    vector<string> v = { "a", "\344" }; // invalid UTF-8
+    sort(v.begin(), v.end(), File::cmp_lt);
+
+    BOOST_CHECK_EQUAL(v, vector<string>({ "\344", "a" }));
+}


Reply via email to