From f0945526ce829a617ac42b34632859225d6518f6 Mon Sep 17 00:00:00 2001
From: david-sarah <david-sarah@jacaranda.org>
Date: Tue, 18 May 2010 21:32:40 -0700
Subject: [PATCH] SFTP: allow FXF_WRITE | FXF_TRUNC (#1050).

---
 src/allmydata/frontends/sftpd.py |  4 ----
 src/allmydata/test/test_sftp.py  | 20 +++++++++++++++++---
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/src/allmydata/frontends/sftpd.py b/src/allmydata/frontends/sftpd.py
index d68eeca2..68fb5192 100644
--- a/src/allmydata/frontends/sftpd.py
+++ b/src/allmydata/frontends/sftpd.py
@@ -657,7 +657,6 @@ class GeneralSFTPFile(PrefixingLogMixin):
 
         if (flags & FXF_TRUNC) or not filenode:
             # We're either truncating or creating the file, so we don't need the old contents.
-            assert flags & FXF_CREAT, flags
             self.consumer = OverwriteableFileConsumer(self.check_abort, 0, tempfile_maker)
             self.consumer.finish()
         else:
@@ -878,9 +877,6 @@ class SFTPUserHandler(ConchUser, PrefixingLogMixin):
                             "invalid file open flags: at least one of FXF_READ and FXF_WRITE must be set")
 
         if not (flags & FXF_CREAT):
-            if flags & FXF_TRUNC:
-                raise SFTPError(FX_BAD_MESSAGE,
-                                "invalid file open flags: FXF_TRUNC cannot be set without FXF_CREAT")
             if flags & FXF_EXCL:
                 raise SFTPError(FX_BAD_MESSAGE,
                                 "invalid file open flags: FXF_EXCL cannot be set without FXF_CREAT")
diff --git a/src/allmydata/test/test_sftp.py b/src/allmydata/test/test_sftp.py
index 04c67ef7..eb9eb9ee 100644
--- a/src/allmydata/test/test_sftp.py
+++ b/src/allmydata/test/test_sftp.py
@@ -534,9 +534,9 @@ class Handler(GridTestMixin, ShouldFailMixin, unittest.TestCase):
             self.shouldFailWithSFTPError(sftp.FX_NO_SUCH_FILE, "openFile '' WRITE|CREAT|TRUNC",
                                          self.handler.openFile, "", sftp.FXF_WRITE | sftp.FXF_CREAT | sftp.FXF_TRUNC, {}))
 
-        # TRUNC is not valid without CREAT
+        # TRUNC is not valid without CREAT if the file does not already exist
         d.addCallback(lambda ign:
-            self.shouldFailWithSFTPError(sftp.FX_BAD_MESSAGE, "openFile newfile WRITE|TRUNC",
+            self.shouldFailWithSFTPError(sftp.FX_NO_SUCH_FILE, "openFile newfile WRITE|TRUNC",
                                          self.handler.openFile, "newfile", sftp.FXF_WRITE | sftp.FXF_TRUNC, {}))
 
         # EXCL is not valid without CREAT
@@ -672,6 +672,20 @@ class Handler(GridTestMixin, ShouldFailMixin, unittest.TestCase):
         d.addCallback(lambda node: download_to_data(node))
         d.addCallback(lambda data: self.failUnlessReallyEqual(data, "01234567890123"))
 
+        # test WRITE | TRUNC without CREAT, when the file already exists
+        # This is invalid according to section 6.3 of the SFTP spec, but required for interoperability,
+        # since POSIX does allow O_WRONLY | O_TRUNC.
+        d.addCallback(lambda ign:
+                      self.handler.openFile("newfile", sftp.FXF_WRITE | sftp.FXF_TRUNC, {}))
+        def _write_trunc(wf):
+            d2 = wf.writeChunk(0, "01234")
+            d2.addCallback(lambda ign: wf.close())
+            return d2
+        d.addCallback(_write_trunc)
+        d.addCallback(lambda ign: self.root.get(u"newfile"))
+        d.addCallback(lambda node: download_to_data(node))
+        d.addCallback(lambda data: self.failUnlessReallyEqual(data, "01234"))
+
         # test EXCL flag
         d.addCallback(lambda ign:
                       self.handler.openFile("excl", sftp.FXF_WRITE | sftp.FXF_CREAT |
@@ -1033,4 +1047,4 @@ class Handler(GridTestMixin, ShouldFailMixin, unittest.TestCase):
             self.shouldFailWithSFTPError(sftp.FX_OP_UNSUPPORTED, "extendedRequest foo bar",
                                          self.handler.extendedRequest, "foo", "bar"))
 
-        return d
\ No newline at end of file
+        return d
-- 
2.45.2