allow double-move
authorGerd von Egidy <gerd.von.egidy@intra2net.com>
Thu, 11 Mar 2010 10:51:08 +0000 (11:51 +0100)
committerGerd von Egidy <gerd.von.egidy@intra2net.com>
Thu, 11 Mar 2010 10:51:08 +0000 (11:51 +0100)
src/tmpfstream_impl.hpp
test/test_tmpfstream.cpp

index 3534178..2de4a91 100644 (file)
@@ -101,25 +101,33 @@ bool tmpfstreamTempl<Device,Tr,Alloc>::move(const std::string& targetpath,
     if (get_tmp_filename().empty() || is_unlinked())
         return false;
 
+    bool success=false;
+
     if (overwrite)
     {
         // this overwrites an already existing target without further warning
         // other errors possible, see errno
-        int res = ::rename( get_tmp_filename().c_str(), targetpath.c_str() );
-        return (res == 0);
+        if (::rename( get_tmp_filename().c_str(), targetpath.c_str() ) == 0)
+            success=true;
     }
     else
     {
         // fails if the target already exists
         // other errors possible, see errno
-        int res = ::link( get_tmp_filename().c_str(), targetpath.c_str() );
-        if (res != 0)
-            return false;
-        ::unlink(get_tmp_filename().c_str());
-        return true;
+        if (::link( get_tmp_filename().c_str(), targetpath.c_str() ) == 0)
+        {
+            success=true;
+            ::unlink(get_tmp_filename().c_str());
+        }
+    }
+
+    if (success)
+    {
+        // store tmpfilename to allow double-move
+        tmpfilename=targetpath;
     }
 
-    // TODO: set tmpfilename to new name to correctly handle double moves
+    return success;
 }
 
 template< typename Device, typename Tr, typename Alloc >
index 6b3782a..24bd8ac 100644 (file)
@@ -219,6 +219,44 @@ BOOST_AUTO_TEST_CASE(TmpofstreamMoveAfterUnlink)
     unlink(".foobar");
 } 
 
+BOOST_AUTO_TEST_CASE(TmpofstreamDoubleMove)
+{
+    // just to be sure
+    unlink(".foobar");
+    unlink(".foobar2");
+
+    tmpofstream tmpf("./tmp.XXXXXX");
+
+    BOOST_CHECK_EQUAL( true, tmpf.is_open() );
+
+    Stat stat(tmpf.get_tmp_filename());
+    BOOST_CHECK_EQUAL( true, (bool)stat );
+
+    tmpf << "hello world" << endl;
+    tmpf.flush();
+
+    BOOST_CHECK_EQUAL( true, tmpf.move(".foobar") );
+
+    stat.recheck();
+    BOOST_CHECK_EQUAL( false, (bool)stat );
+
+    Stat stat2(".foobar");
+    BOOST_CHECK_EQUAL( true, (bool)stat2 );
+
+    BOOST_CHECK_EQUAL( true, tmpf.move(".foobar2") );
+
+    stat.recheck();
+    BOOST_CHECK_EQUAL( false, (bool)stat );
+
+    stat2.recheck();
+    BOOST_CHECK_EQUAL( false, (bool)stat2 );
+
+    Stat stat3(".foobar2");
+    BOOST_CHECK_EQUAL( true, (bool)stat3 );
+
+    tmpf.unlink();
+} 
+
 BOOST_AUTO_TEST_CASE(TmpfstreamReadWrite)
 {
     tmpfstream tmpf("./tmp.XXXXXX",std::ios_base::out | std::ios_base::in );