Browse Source

Bug 1619: Failure when .NET assembly starts reading an XML log file in a short moment when it's empty yet

https://winscp.net/tracker/1619

Source commit: e039a0c5d8da14913ad3042d9abefb95418efcda
Martin Prikryl 7 years ago
parent
commit
956ca5bfe8
1 changed files with 108 additions and 12 deletions
  1. 108 12
      dotnet/internal/PatientFileStream.cs

+ 108 - 12
dotnet/internal/PatientFileStream.cs

@@ -2,31 +2,27 @@
 
 namespace WinSCP
 {
-    internal class PatientFileStream : FileStream
+    internal class PatientFileStream : Stream
     {
-        public PatientFileStream(Session session, string path, FileMode mode, FileAccess access, FileShare share) :
-            base(path, mode, access, share)
+        public PatientFileStream(Session session, string path, FileMode mode, FileAccess access, FileShare share)
         {
+            _stream = new FileStream(path, mode, access, share);
             _session = session;
         }
 
+        private const int InitialInterval = 50;
+
         public override int Read(byte[] array, int offset, int count)
         {
             int result;
 
-            int interval = 50;
+            int interval = InitialInterval;
             do
             {
-                result = base.Read(array, offset, count);
+                result = _stream.Read(array, offset, count);
                 if (result == 0)
                 {
-                    _session.Logger.WriteLine("Waiting for log update and dispatching events for {0}", interval);
-                    _session.DispatchEvents(interval);
-                    _session.CheckForTimeout();
-                    if (interval < 500)
-                    {
-                        interval *= 2;
-                    }
+                    Wait(ref interval);
                 }
                 else
                 {
@@ -41,6 +37,106 @@ namespace WinSCP
             return result;
         }
 
+        private void Wait(ref int interval)
+        {
+            _session.Logger.WriteLine("Waiting for log update and dispatching events for {0}", interval);
+            _session.DispatchEvents(interval);
+            _session.CheckForTimeout();
+            if (interval < 500)
+            {
+                interval *= 2;
+            }
+        }
+
+        public override void Flush()
+        {
+            throw _session.Logger.WriteException(new System.NotImplementedException());
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw _session.Logger.WriteException(new System.NotImplementedException());
+        }
+
+        public override void SetLength(long value)
+        {
+            throw _session.Logger.WriteException(new System.NotImplementedException());
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw _session.Logger.WriteException(new System.NotImplementedException());
+        }
+
+        public override bool CanRead
+        {
+            get
+            {
+                bool result = _stream.CanRead;
+                _session.Logger.WriteLineLevel(2, "Can read = {0}", result);
+                return result;
+            }
+        }
+
+        public override bool CanSeek
+        {
+            get
+            {
+                bool result = _stream.CanSeek;
+                _session.Logger.WriteLineLevel(2, "Can seek = {0}", result);
+                return result;
+            }
+        }
+
+        public override bool CanWrite => false;
+
+        public override long Length
+        {
+            get
+            {
+                long result = _stream.Length;
+
+                if (result == 0)
+                {
+                    _session.Logger.WriteLineLevel(2, "File is empty yet, waiting", result);
+
+                    int interval = InitialInterval;
+                    do
+                    {
+                        result = _stream.Length;
+                        if (result == 0)
+                        {
+                            Wait(ref interval);
+                        }
+                        else
+                        {
+                            _session.Logger.WriteLineLevel(2, "File length = {0}", result);
+                        }
+                    }
+                    while (result == 0);
+                }
+
+                return result;
+            }
+        }
+
+        public override long Position
+        {
+            get
+            {
+                long result = _stream.Length;
+                _session.Logger.WriteLineLevel(2, "File position = {0}", result);
+                return result;
+            }
+
+            set
+            {
+                _session.Logger.WriteLineLevel(2, "Setting file position to {0}", value);
+                _stream.Position = value;
+            }
+        }
+
+        private FileStream _stream;
         private Session _session;
     }
 }