Skip to content

Commit 3ab0423

Browse files
committed
Massively improved write speed
1 parent 2367aff commit 3ab0423

5 files changed

Lines changed: 41 additions & 37 deletions

File tree

SecureFolderFS.Core/Chunks/Implementation/BaseCleartextChunk.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public virtual void CopyFrom(ReadOnlySpan<byte> sourceBuffer, int offset, ref in
3636

3737
var readCount = Math.Min(buffer.Length - offset, sourceBuffer.Length - positionInBuffer);
3838
var destination = buffer.AsSpan(offset, readCount);
39-
sourceBuffer.Slice(0, readCount).CopyTo(destination);
39+
sourceBuffer.Slice(positionInBuffer, readCount).CopyTo(destination);
4040
positionInBuffer += readCount;
4141

4242
ActualLength = Math.Max(ActualLength, readCount + offset);

SecureFolderFS.Core/FileSystem/FileSystemAdapter/Dokan/Callback/Implementation/ReadFileCallback.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,18 @@ public NtStatus ReadFile(string fileName, IntPtr buffer, uint bufferLength, out
4444
}
4545

4646
// Read file
47-
bytesRead = StreamHelpers.ReadToIntPtrBuffer(fileHandle.CleartextFileStream, buffer, bufferLength, offset);
47+
if (opened)
48+
{
49+
bytesRead = StreamHelpers.ReadToIntPtrBuffer(fileHandle.CleartextFileStream, buffer, bufferLength, offset);
50+
}
51+
else
52+
{
53+
lock (fileHandle.CleartextFileStream)
54+
{
55+
bytesRead = StreamHelpers.ReadToIntPtrBuffer(fileHandle.CleartextFileStream, buffer, bufferLength, offset);
56+
}
57+
}
58+
4859
return DokanResult.Success;
4960
}
5061
catch (PathTooLongException)

SecureFolderFS.Core/FileSystem/FileSystemAdapter/Dokan/Callback/Implementation/WriteFileCallback.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,28 @@ public NtStatus WriteFile(string fileName, IntPtr buffer, uint bufferLength, out
4848
if (handles.GetHandle(contextHandle) is not FileHandle fileHandle)
4949
{
5050
// Invalid handle...
51-
contextHandle = handles.OpenHandleToFile(ciphertextPath, FileMode.Open, System.IO.FileAccess.ReadWrite,
51+
contextHandle = handles.OpenHandleToFile(ciphertextPath, appendToFile ? FileMode.Append : FileMode.Open, System.IO.FileAccess.ReadWrite,
5252
FileShare.Read, FileOptions.None);
5353
fileHandle = (FileHandle)handles.GetHandle(contextHandle);
5454

5555
opened = true;
5656
}
5757

58+
var correctOffset = !appendToFile ? offset : fileHandle.CleartextFileStream.Length;
59+
5860
// Write file
59-
bytesWritten = StreamHelpers.WriteFromIntPtrBuffer(fileHandle.CleartextFileStream, buffer, bufferLength, appendToFile ? fileHandle.CleartextFileStream.Length : offset);
61+
if (opened)
62+
{
63+
bytesWritten = StreamHelpers.WriteFromIntPtrBuffer(fileHandle.CleartextFileStream, buffer, bufferLength, correctOffset);
64+
}
65+
else
66+
{
67+
lock (fileHandle.CleartextFileStream)
68+
{
69+
bytesWritten = StreamHelpers.WriteFromIntPtrBuffer(fileHandle.CleartextFileStream, buffer, bufferLength, correctOffset);
70+
}
71+
}
72+
6073
return DokanResult.Success;
6174
}
6275
catch (PathTooLongException)
@@ -69,6 +82,11 @@ public NtStatus WriteFile(string fileName, IntPtr buffer, uint bufferLength, out
6982
bytesWritten = 0;
7083
return NtStatus.CrcError;
7184
}
85+
catch (UnavailableStreamException)
86+
{
87+
bytesWritten = 0;
88+
return DokanResult.InvalidHandle;
89+
}
7290
catch (Exception ex)
7391
{
7492
_ = ex;

SecureFolderFS.Core/Helpers/StreamHelpers.cs

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.IO;
33
using System.Text;
4-
using System.Runtime.InteropServices;
54
using System.Security.Cryptography;
65
using SecureFolderFS.Sdk.Streams;
76
using System.Runtime.CompilerServices;
@@ -11,56 +10,32 @@ namespace SecureFolderFS.Core.Helpers
1110
internal static class StreamHelpers
1211
{
1312
[MethodImpl(MethodImplOptions.Synchronized)]
14-
public static int ReadToIntPtrBuffer(IBaseFileStream baseFileStream, IntPtr nativeBuffer, uint bufferLength, long offset)
13+
public unsafe static int ReadToIntPtrBuffer(IBaseFileStream baseFileStream, IntPtr nativeBuffer, uint bufferLength, long offset)
1514
{
1615
if (offset >= baseFileStream.Length)
1716
{
1817
return Constants.IO.FILE_EOF;
1918
}
2019
else
2120
{
22-
var readBuffer = new byte[Constants.IO.READ_BUFFER_SIZE];
23-
var position = 0;
2421
baseFileStream.Position = offset;
2522

26-
do
27-
{
28-
var remaining = (int)bufferLength - position;
29-
var read = baseFileStream.Read(readBuffer, 0, Math.Min(readBuffer.Length, remaining));
23+
var nativeBufferSpan = new Span<byte>(nativeBuffer.ToPointer(), (int)bufferLength);
24+
baseFileStream.Read(nativeBufferSpan);
3025

31-
if (read == Constants.IO.FILE_EOF)
32-
{
33-
return position; // Reached End-of-File EOF
34-
}
35-
else
36-
{
37-
Marshal.Copy(readBuffer, 0, nativeBuffer + position, read);
38-
position += read;
39-
}
40-
} while (position < bufferLength);
41-
42-
return position;
26+
return (int)bufferLength;
4327
}
4428
}
4529

4630
[MethodImpl(MethodImplOptions.Synchronized)]
4731
public unsafe static int WriteFromIntPtrBuffer(IBaseFileStream baseFileStream, IntPtr nativeBuffer, uint bufferLength, long offset)
4832
{
49-
var position = 0;
50-
5133
baseFileStream.Position = offset;
52-
do
53-
{
54-
var remaining = bufferLength - position;
55-
var writeLength = (int)Math.Min(remaining, Constants.IO.WRITE_BUFFER_SIZE);
56-
var writeBuffer = new Span<byte>((nativeBuffer + position).ToPointer(), writeLength);
57-
58-
baseFileStream.Write(writeBuffer.Slice(0, writeLength));
5934

60-
position += writeLength;
61-
} while (position < bufferLength);
35+
var nativeBufferSpan = new ReadOnlySpan<byte>(nativeBuffer.ToPointer(), (int)bufferLength);
36+
baseFileStream.Write(nativeBufferSpan);
6237

63-
return position;
38+
return (int)bufferLength;
6439
}
6540

6641
public static void WriteToStream(Stream sourceStream, Stream destinationStream)

SecureFolderFS.Core/Security/ContentCrypt/FileContent/AesGcmContentCryptor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ protected override ICiphertextChunk EncryptChunk(CleartextAesGcmChunk cleartextC
3232
secureRandom.GetBytes(fullCiphertextChunkSpan.Slice(0, CiphertextAesGcmChunk.CHUNK_NONCE_SIZE));
3333

3434
// Big Endian chunk number and file header nonce
35-
var beChunkNumberWithFileHeaderNonce = new byte[sizeof(long) + fileHeader.Nonce.Length]; // TODO: Rent array? (and in xchacha20 too)
35+
var beChunkNumberWithFileHeaderNonce = new byte[sizeof(long) + fileHeader.Nonce.Length];
3636
var beChunkNumber = BitConverter.GetBytes(chunkNumber).AsBigEndian();
3737

3838
Buffer.BlockCopy(beChunkNumber, 0, beChunkNumberWithFileHeaderNonce, 0, beChunkNumber.Length);

0 commit comments

Comments
 (0)