Skip to content

Commit f92cbf9

Browse files
committed
Retry file operations if they are locked
1 parent f2aa58d commit f92cbf9

6 files changed

+134
-39
lines changed
2.49 KB
Binary file not shown.

AsyncToSyncCodeRoundtripSynchroniserMonitorNet.csproj

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<DefineConstants>DEBUG;TRACE</DefineConstants>
2424
<ErrorReport>prompt</ErrorReport>
2525
<WarningLevel>4</WarningLevel>
26-
<NoWarn>SEC0122;S125;S1125;S1135;S2589;S3881;S3358;CA1063;CCN0011;CCN0021;CCN0031;1701;1702;AsyncFixed01;MS002;MS003;IDE0018;AD0001;SEC0112</NoWarn>
26+
<NoWarn>SEC0122;S125;S1125;S1135;S1199;S2589;S3881;S3358;S4136;CA1034;CA1063;CCN0011;CCN0021;CCN0031;1701;1702;AsyncFixed01;MS002;MS003;IDE0018;AD0001;SEC0112</NoWarn>
2727
<WarningsAsErrors>NU1605</WarningsAsErrors>
2828
</PropertyGroup>
2929
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
@@ -34,7 +34,7 @@
3434
<DefineConstants>TRACE</DefineConstants>
3535
<ErrorReport>prompt</ErrorReport>
3636
<WarningLevel>4</WarningLevel>
37-
<NoWarn>SEC0122;S125;S1125;S1135;S2589;S3881;S3358;CA1063;CCN0011;CCN0021;CCN0031;1701;1702;AsyncFixed01;MS002;MS003;IDE0018;AD0001;SEC0112</NoWarn>
37+
<NoWarn>SEC0122;S125;S1125;S1135;S1199;S2589;S3881;S3358;S4136;CA1034;CA1063;CCN0011;CCN0021;CCN0031;1701;1702;AsyncFixed01;MS002;MS003;IDE0018;AD0001;SEC0112</NoWarn>
3838
<WarningsAsErrors>NU1605</WarningsAsErrors>
3939
<DebugSymbols>true</DebugSymbols>
4040
</PropertyGroup>
@@ -183,4 +183,11 @@
183183
<Folder Include="icon\" />
184184
</ItemGroup>
185185
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
186+
<PropertyGroup>
187+
<PostBuildEvent>copy /Y "$(ProjectDir)\AsyncToSyncCodeRoundtripSynchroniserMonitor.bat - Shortcut.lnk" "$(TargetDir)"</PostBuildEvent>
188+
</PropertyGroup>
189+
<PropertyGroup>
190+
<PreBuildEvent>
191+
</PreBuildEvent>
192+
</PropertyGroup>
186193
</Project>

BinaryFileExtensions.cs

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
// See the LICENSE file for more information.
77
//
88

9+
#define ASYNC
10+
using System;
911
using System.Data.Linq;
1012
using System.IO;
1113
using System.Threading;
@@ -23,34 +25,78 @@ public static bool BinaryEqual(Binary a, Binary b)
2325

2426
public static async Task<byte[]> ReadAllBytesAsync(string path, CancellationToken cancellationToken = default(CancellationToken))
2527
{
26-
using (FileStream stream = new FileStream(
27-
path,
28-
FileMode.Open,
29-
FileAccess.Read,
30-
FileShare.ReadWrite,
31-
bufferSize: 1024 * 1024,
32-
useAsync: true
33-
))
28+
while (true)
3429
{
35-
var len = (int)stream.Length; //NB! the lenght might change during the code execution, so need to save it into separate variable
36-
byte[] result = new byte[len];
37-
await stream.ReadAsync(result, 0, len, cancellationToken);
38-
return result;
30+
if (cancellationToken.IsCancellationRequested)
31+
return await Task.FromCanceled<byte[]>(cancellationToken);
32+
33+
try
34+
{
35+
using (FileStream stream = new FileStream(
36+
path,
37+
FileMode.Open,
38+
FileAccess.Read,
39+
FileShare.ReadWrite,
40+
bufferSize: 1024 * 1024,
41+
useAsync: true
42+
))
43+
{
44+
var len = (int)stream.Length; //NB! the lenght might change during the code execution, so need to save it into separate variable
45+
byte[] result = new byte[len];
46+
await stream.ReadAsync(result, 0, len, cancellationToken);
47+
return result;
48+
}
49+
}
50+
catch (IOException)
51+
{
52+
//retry after delay
53+
try
54+
{
55+
#if !NOASYNC
56+
await Task.Delay(1000, cancellationToken); //TODO: config file?
57+
#else
58+
cancellationToken.WaitHandle.WaitOne(1000);
59+
#endif
60+
}
61+
catch (TaskCanceledException)
62+
{
63+
//do nothing here
64+
return await Task.FromCanceled<byte[]>(cancellationToken);
65+
}
66+
}
3967
}
4068
}
4169

4270
public static async Task WriteAllBytesAsync(string path, byte[] contents, CancellationToken cancellationToken = default(CancellationToken))
4371
{
44-
using (FileStream stream = new FileStream(
45-
path,
46-
FileMode.OpenOrCreate,
47-
FileAccess.Write,
48-
FileShare.Read,
49-
bufferSize: 1024 * 1024,
50-
useAsync: true
51-
))
72+
while (true)
5273
{
53-
await stream.WriteAsync(contents, 0, contents.Length, cancellationToken);
74+
cancellationToken.ThrowIfCancellationRequested();
75+
76+
try
77+
{
78+
using (FileStream stream = new FileStream(
79+
path,
80+
FileMode.OpenOrCreate,
81+
FileAccess.Write,
82+
FileShare.Read,
83+
bufferSize: 1024 * 1024,
84+
useAsync: true
85+
))
86+
{
87+
await stream.WriteAsync(contents, 0, contents.Length, cancellationToken);
88+
return;
89+
}
90+
}
91+
catch (IOException)
92+
{
93+
//retry after delay
94+
#if !NOASYNC
95+
await Task.Delay(1000, cancellationToken); //TODO: config file?
96+
#else
97+
cancellationToken.WaitHandle.WaitOne(1000);
98+
#endif
99+
}
54100
}
55101
}
56102

FileExtensions.cs

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ private static StreamReader AsyncStreamReader(string path, Encoding encoding)
4343
public static Task<string> ReadAllTextAsync(string path, CancellationToken cancellationToken = default(CancellationToken))
4444
=> ReadAllTextAsync(path, UTF8NoBOM, cancellationToken);
4545

46-
public static Task<string> ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
46+
public static async Task<string> ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
4747
{
4848
if (path == null)
4949
throw new ArgumentNullException(nameof(path));
@@ -52,9 +52,32 @@ private static StreamReader AsyncStreamReader(string path, Encoding encoding)
5252
if (path.Length == 0)
5353
throw new ArgumentException("SR.Argument_EmptyPath: {0}", nameof(path));
5454

55-
return cancellationToken.IsCancellationRequested
56-
? Task.FromCanceled<string>(cancellationToken)
57-
: InternalReadAllTextAsync(path, encoding, cancellationToken);
55+
while (true) //roland
56+
{
57+
try //roland
58+
{
59+
return cancellationToken.IsCancellationRequested
60+
? await Task.FromCanceled<string>(cancellationToken)
61+
: await InternalReadAllTextAsync(path, encoding, cancellationToken);
62+
}
63+
catch (IOException) //roland
64+
{
65+
//retry after delay
66+
try
67+
{
68+
#if !NOASYNC
69+
await Task.Delay(1000, cancellationToken); //TODO: config file?
70+
#else
71+
cancellationToken.WaitHandle.WaitOne(1000);
72+
#endif
73+
}
74+
catch (TaskCanceledException)
75+
{
76+
//do nothing here
77+
return await Task.FromCanceled<string>(cancellationToken);
78+
}
79+
}
80+
}
5881
}
5982

6083
private static async Task<string> InternalReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken)
@@ -112,7 +135,7 @@ private static StreamWriter AsyncStreamWriter(string path, Encoding encoding, bo
112135
public static Task WriteAllTextAsync(string path, string contents, CancellationToken cancellationToken = default(CancellationToken))
113136
=> WriteAllTextAsync(path, contents, UTF8NoBOM, cancellationToken);
114137

115-
public static Task WriteAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
138+
public static async Task WriteAllTextAsync(string path, string contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
116139
{
117140
if (path == null)
118141
throw new ArgumentNullException(nameof(path));
@@ -121,18 +144,35 @@ private static StreamWriter AsyncStreamWriter(string path, Encoding encoding, bo
121144
if (path.Length == 0)
122145
throw new ArgumentException("SR.Argument_EmptyPath: {0}", nameof(path));
123146

124-
if (cancellationToken.IsCancellationRequested)
147+
while (true) //roland
125148
{
126-
return Task.FromCanceled(cancellationToken);
127-
}
149+
try //roland
150+
{
151+
cancellationToken.ThrowIfCancellationRequested();
152+
//if (cancellationToken.IsCancellationRequested)
153+
//{
154+
// return Task.FromCanceled(cancellationToken);
155+
//}
128156

129-
if (string.IsNullOrEmpty(contents))
130-
{
131-
new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read).Dispose();
132-
return Task.CompletedTask;
133-
}
157+
if (string.IsNullOrEmpty(contents))
158+
{
159+
new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read).Dispose();
160+
return; // await Task.CompletedTask;
161+
}
134162

135-
return InternalWriteAllTextAsync(AsyncStreamWriter(path, encoding, append: false), contents, cancellationToken);
163+
await InternalWriteAllTextAsync(AsyncStreamWriter(path, encoding, append: false), contents, cancellationToken);
164+
return;
165+
}
166+
catch (IOException) //roland
167+
{
168+
//retry after delay
169+
#if !NOASYNC
170+
await Task.Delay(1000, cancellationToken); //TODO: config file?
171+
#else
172+
cancellationToken.WaitHandle.WaitOne(1000);
173+
#endif
174+
}
175+
}
136176
}
137177

138178
private static async Task InternalWriteAllTextAsync(StreamWriter sw, string contents, CancellationToken cancellationToken)

Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
using Microsoft.Extensions.Configuration;
2020
using myoddweb.directorywatcher;
2121
using myoddweb.directorywatcher.interfaces;
22-
using Nito.AsyncEx;
2322

2423
namespace AsyncToSyncCodeRoundtripSynchroniserMonitor
2524
{
@@ -394,7 +393,9 @@ public static async Task DeleteFile(string fullName, Context context)
394393
try
395394
{
396395
if (File.Exists(fullName + "~"))
396+
#pragma warning disable SEC0116 //Warning SEC0116 Unvalidated file paths are passed to a file delete API, which can allow unauthorized file system operations (e.g. read, write, delete) to be performed on unintended server files.
397397
File.Delete(fullName + "~");
398+
#pragma warning restore SEC0116
398399

399400
if (File.Exists(fullName))
400401
File.Move(fullName, fullName + "~");

Synchronisation.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
#define ASYNC
2+
using System;
23
using System.Collections.Generic;
34
using System.Threading;
45
using System.Threading.Tasks;

0 commit comments

Comments
 (0)