diff -r 2c38c3c3b49a -r f3ab6c20c1e1 Lib/test/test_os_jy.py --- a/Lib/test/test_os_jy.py Thu Feb 19 16:41:54 2015 -0700 +++ b/Lib/test/test_os_jy.py Fri Feb 20 15:04:39 2015 -0800 @@ -58,6 +58,21 @@ else: self.assertTrue(False) + def test_issue2068(self): + os.remove(test_support.TESTFN) + for i in range(2): + fd = os.open(test_support.TESTFN, os.O_RDWR | os.O_CREAT | os.O_APPEND) + try: + os.write(fd, bytes('one')) + os.write(fd, bytes('two')) + os.write(fd, bytes('three')) + finally: + fd.close() + + with open(test_support.TESTFN, 'rb') as f: + content = f.read() + self.assertEqual(content, 2 * b'onetwothree') + class OSDirTestCase(unittest.TestCase): diff -r 2c38c3c3b49a -r f3ab6c20c1e1 src/org/python/core/io/FileIO.java --- a/src/org/python/core/io/FileIO.java Thu Feb 19 16:41:54 2015 -0700 +++ b/src/org/python/core/io/FileIO.java Fri Feb 20 15:04:39 2015 -0800 @@ -306,13 +306,22 @@ checkClosed(); checkWritable(); try { - return !emulateAppend ? fileChannel.write(buf) : - fileChannel.write(buf, fileChannel.position()); + return emulateAppend ? appendFromByteBuffer(buf) // use this helper function to advance the file channel's position post-write + : fileChannel.write(buf); // this does change the file channel's position } catch (IOException ioe) { throw Py.IOError(ioe); } } + private int appendFromByteBuffer(ByteBuffer buf) throws IOException { + int written = fileChannel.write(buf, fileChannel.position()); // this does not change the file channel's position! + if (written > 0) { + // we need to manually update the file channel's position post-write + fileChannel.position(fileChannel.position() + written); + } + return written; + } + /** * Write bytes from each of the specified ByteBuffers via gather * i/o. @@ -344,7 +353,8 @@ if (!buf.hasRemaining()) { continue; } - if ((bufCount = fileChannel.write(buf, fileChannel.position())) == 0) { + bufCount = appendFromByteBuffer(buf); + if (bufCount == 0) { break; } count += bufCount;