From a62733ed089aad80f51cb19844ecef4c36982290 Mon Sep 17 00:00:00 2001
From: david-sarah <david-sarah@jacaranda.org>
Date: Tue, 18 May 2010 22:39:33 -0700
Subject: [PATCH] SFTP: add tests for more combinations of open flags.

---
 src/allmydata/frontends/sftpd.py | 11 ++++----
 src/allmydata/test/test_sftp.py  | 45 +++++++++++++++++++++++++++++---
 2 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/src/allmydata/frontends/sftpd.py b/src/allmydata/frontends/sftpd.py
index 68fb5192..70cd8595 100644
--- a/src/allmydata/frontends/sftpd.py
+++ b/src/allmydata/frontends/sftpd.py
@@ -876,10 +876,9 @@ class SFTPUserHandler(ConchUser, PrefixingLogMixin):
             raise SFTPError(FX_BAD_MESSAGE,
                             "invalid file open flags: at least one of FXF_READ and FXF_WRITE must be set")
 
-        if not (flags & FXF_CREAT):
-            if flags & FXF_EXCL:
-                raise SFTPError(FX_BAD_MESSAGE,
-                                "invalid file open flags: FXF_EXCL cannot be set without FXF_CREAT")
+        if (flags & FXF_EXCL) and not (flags & FXF_CREAT):
+            raise SFTPError(FX_BAD_MESSAGE,
+                            "invalid file open flags: FXF_EXCL cannot be set without FXF_CREAT")
 
         path = self._path_from_string(pathstring)
         if not path:
@@ -993,7 +992,7 @@ class SFTPUserHandler(ConchUser, PrefixingLogMixin):
 
                         metadata['readonly'] = _is_readonly(parent_readonly, filenode)
                         return _make_sftp_file(self.check_abort, flags, self._convergence, parent=parent,
-                                              childname=childname, filenode=filenode, metadata=metadata)
+                                               childname=childname, filenode=filenode, metadata=metadata)
                     def _no_child(f):
                         if noisy: self.log("_no_child(%r)" % (f,), level=NOISY)
                         f.trap(NoSuchChildError)
@@ -1006,7 +1005,7 @@ class SFTPUserHandler(ConchUser, PrefixingLogMixin):
                                             "cannot create a file when the parent directory is read-only")
 
                         return _make_sftp_file(self.check_abort, flags, self._convergence, parent=parent,
-                                              childname=childname)
+                                               childname=childname)
                     d3.addCallbacks(_got_child, _no_child)
                     return d3
 
diff --git a/src/allmydata/test/test_sftp.py b/src/allmydata/test/test_sftp.py
index eb9eb9ee..609e8fcd 100644
--- a/src/allmydata/test/test_sftp.py
+++ b/src/allmydata/test/test_sftp.py
@@ -747,18 +747,57 @@ class Handler(GridTestMixin, ShouldFailMixin, unittest.TestCase):
         d.addCallback(lambda node: download_to_data(node))
         d.addCallback(lambda data: self.failUnlessReallyEqual(data, "012345678901234"))
 
-        # test WRITE | CREAT without TRUNC
+        # test WRITE | CREAT | APPEND when the file does not already exist
+        d.addCallback(lambda ign:
+                      self.handler.openFile("creatappend", sftp.FXF_WRITE | sftp.FXF_CREAT |
+                                                           sftp.FXF_APPEND, {}))
+        def _write_creat_append_new(wf):
+            d2 = wf.writeChunk(10, "0123456789")
+            d2.addCallback(lambda ign: wf.writeChunk(5, "01234"))
+            d2.addCallback(lambda ign: wf.close())
+            return d2
+        d.addCallback(_write_creat_append_new)
+        d.addCallback(lambda ign: self.root.get(u"creatappend"))
+        d.addCallback(lambda node: download_to_data(node))
+        d.addCallback(lambda data: self.failUnlessReallyEqual(data, "012345678901234"))
+
+        # ... and when it does exist
+        d.addCallback(lambda ign:
+                      self.handler.openFile("creatappend", sftp.FXF_WRITE | sftp.FXF_CREAT |
+                                                           sftp.FXF_APPEND, {}))
+        def _write_creat_append_existing(wf):
+            d2 = wf.writeChunk(5, "01234")
+            d2.addCallback(lambda ign: wf.close())
+            return d2
+        d.addCallback(_write_creat_append_existing)
+        d.addCallback(lambda ign: self.root.get(u"creatappend"))
+        d.addCallback(lambda node: download_to_data(node))
+        d.addCallback(lambda data: self.failUnlessReallyEqual(data, "01234567890123401234"))
+
+        # test WRITE | CREAT without TRUNC, when the file does not already exist
         d.addCallback(lambda ign:
                       self.handler.openFile("newfile2", sftp.FXF_WRITE | sftp.FXF_CREAT, {}))
-        def _write_notrunc(wf):
+        def _write_creat_new(wf):
             d2 =  wf.writeChunk(0, "0123456789")
             d2.addCallback(lambda ign: wf.close())
             return d2
-        d.addCallback(_write_notrunc)
+        d.addCallback(_write_creat_new)
         d.addCallback(lambda ign: self.root.get(u"newfile2"))
         d.addCallback(lambda node: download_to_data(node))
         d.addCallback(lambda data: self.failUnlessReallyEqual(data, "0123456789"))
 
+        # ... and when it does exist
+        d.addCallback(lambda ign:
+                      self.handler.openFile("newfile2", sftp.FXF_WRITE | sftp.FXF_CREAT, {}))
+        def _write_creat_existing(wf):
+            d2 =  wf.writeChunk(0, "abcde")
+            d2.addCallback(lambda ign: wf.close())
+            return d2
+        d.addCallback(_write_creat_existing)
+        d.addCallback(lambda ign: self.root.get(u"newfile2"))
+        d.addCallback(lambda node: download_to_data(node))
+        d.addCallback(lambda data: self.failUnlessReallyEqual(data, "abcde56789"))
+
         # test writing to a mutable file
         d.addCallback(lambda ign:
                       self.handler.openFile("mutable", sftp.FXF_WRITE, {}))
-- 
2.45.2