summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/asyncfile.nim10
-rw-r--r--tests/async/tasyncfilewrite.nim17
-rw-r--r--tools/nimgrab.nim6
3 files changed, 28 insertions, 5 deletions
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
index 9bd060e30..8fb30075c 100644
--- a/lib/pure/asyncfile.nim
+++ b/lib/pure/asyncfile.nim
@@ -339,13 +339,17 @@ proc writeBuffer*(f: AsyncFile, buf: pointer, size: int): Future[void] =
         if not retFuture.finished:
           if errcode == OSErrorCode(-1):
             assert bytesCount == size.int32
-            f.offset.inc(size)
             retFuture.complete()
           else:
             retFuture.fail(newException(OSError, osErrorMsg(errcode)))
     )
+    # passing -1 here should work according to MSDN, but doesn't. For more
+    # information see
+    # http://stackoverflow.com/questions/33650899/does-asynchronous-file-
+    #   appending-in-windows-preserve-order
     ol.offset = DWord(f.offset and 0xffffffff)
     ol.offsetHigh = DWord(f.offset shr 32)
+    f.offset.inc(size)
 
     # According to MSDN we're supposed to pass nil to lpNumberOfBytesWritten.
     let ret = writeFile(f.fd.Handle, buf, size.int32, nil,
@@ -364,7 +368,6 @@ proc writeBuffer*(f: AsyncFile, buf: pointer, size: int): Future[void] =
         retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
       else:
         assert bytesWritten == size.int32
-        f.offset.inc(size)
         retFuture.complete()
   else:
     var written = 0
@@ -410,7 +413,6 @@ proc write*(f: AsyncFile, data: string): Future[void] =
         if not retFuture.finished:
           if errcode == OSErrorCode(-1):
             assert bytesCount == data.len.int32
-            f.offset.inc(data.len)
             retFuture.complete()
           else:
             retFuture.fail(newException(OSError, osErrorMsg(errcode)))
@@ -420,6 +422,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
     )
     ol.offset = DWord(f.offset and 0xffffffff)
     ol.offsetHigh = DWord(f.offset shr 32)
+    f.offset.inc(data.len)
 
     # According to MSDN we're supposed to pass nil to lpNumberOfBytesWritten.
     let ret = writeFile(f.fd.Handle, buffer, data.len.int32, nil,
@@ -441,7 +444,6 @@ proc write*(f: AsyncFile, data: string): Future[void] =
         retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
       else:
         assert bytesWritten == data.len.int32
-        f.offset.inc(data.len)
         retFuture.complete()
   else:
     var written = 0
diff --git a/tests/async/tasyncfilewrite.nim b/tests/async/tasyncfilewrite.nim
new file mode 100644
index 000000000..cda612bae
--- /dev/null
+++ b/tests/async/tasyncfilewrite.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''string 1
+string 2
+string 3'''
+"""
+# bug #5532
+import os, asyncfile, asyncdispatch
+
+removeFile("test.txt")
+let f = openAsync("test.txt", fmWrite)
+var futs = newSeq[Future[void]]()
+for i in 1..3:
+  futs.add(f.write("string " & $i & "\n"))
+waitFor(all(futs))
+f.close()
+echo readFile("test.txt")
+
diff --git a/tools/nimgrab.nim b/tools/nimgrab.nim
index 69824369e..937a5dcd4 100644
--- a/tools/nimgrab.nim
+++ b/tools/nimgrab.nim
@@ -7,7 +7,11 @@ when defined(windows):
     proc progress(status: DownloadStatus, progress: uint, total: uint,
                   message: string) {.procvar, gcsafe.} =
       echo "Downloading " & url
-      echo clamp(int(progress.BiggestInt*100 div total.BiggestInt), 0, 100), "%"
+      let t = total.BiggestInt
+      if t != 0:
+        echo clamp(int(progress.BiggestInt*100 div t), 0, 100), "%"
+      else:
+        echo "0%"
 
     downloadToFile(url, file, {optUseCache}, progress)
     echo "100%"