diff --git a/BeefLibs/Beefy2D/src/Utils.bf b/BeefLibs/Beefy2D/src/Utils.bf index 06fd2d66..299a1ac0 100644 --- a/BeefLibs/Beefy2D/src/Utils.bf +++ b/BeefLibs/Beefy2D/src/Utils.bf @@ -295,11 +295,13 @@ namespace Beefy public static Result WriteTextFile(StringView path, StringView text) { - var stream = scope FileStream(); - if (stream.Create(path) case .Err) - { + var stream = scope UnbufferedFileStream(); + if (stream.Open(path, .OpenOrCreate, .Write) case .Err) return .Err; - } + + if (stream.SetLength(text.Length) case .Err) + return .Err; + if (stream.WriteStrUnsized(text) case .Err) return .Err; diff --git a/BeefLibs/corlib/src/IO/BufferedStream.bf b/BeefLibs/corlib/src/IO/BufferedStream.bf index a3d6048c..08bde0ac 100644 --- a/BeefLibs/corlib/src/IO/BufferedStream.bf +++ b/BeefLibs/corlib/src/IO/BufferedStream.bf @@ -88,14 +88,12 @@ namespace System.IO data.RemoveFromStart((.)spaceLeft); } - if (mWriteDirtyPos >= 0) - Try!(Flush()); + Try!(Flush()); if ((mBuffer == null) || (data.Length > mBuffer.Count)) { - var result = TryReadUnderlying(mPos, data); - if (result case .Ok(let len)) - mPos += len; + let len = Try!(TryReadUnderlying(mPos, data)); + mPos += len; return (.)(mPos - readStart); } @@ -148,10 +146,9 @@ namespace System.IO if ((mBuffer == null) || (data.Length > mBuffer.Count)) { - var result = TryWriteUnderlying(mPos, data); - if (result case .Ok(let len)) - mPos += len; - writeCount += result; + let len = Try!(TryWriteUnderlying(mPos, data)); + mPos += len; + writeCount += len; return writeCount; } diff --git a/BeefLibs/corlib/src/IO/File.bf b/BeefLibs/corlib/src/IO/File.bf index 06d6abd7..87315500 100644 --- a/BeefLibs/corlib/src/IO/File.bf +++ b/BeefLibs/corlib/src/IO/File.bf @@ -49,7 +49,7 @@ namespace System.IO public static Result WriteAll(StringView path, Span data, bool doAppend = false) { - FileStream fs = scope FileStream(); + UnbufferedFileStream fs = scope UnbufferedFileStream(); var result = fs.Open(path, doAppend ? .Append : .Create, .Write); if (result case .Err) return .Err; @@ -76,7 +76,7 @@ namespace System.IO public static Result WriteAllText(StringView path, StringView text, bool doAppend = false) { - FileStream fs = scope FileStream(); + UnbufferedFileStream fs = scope UnbufferedFileStream(); var result = fs.Open(path, doAppend ? .Append : .Create, .Write); if (result case .Err) return .Err; @@ -87,7 +87,7 @@ namespace System.IO public static Result WriteAllText(StringView path, StringView text, Encoding encoding) { - FileStream fs = scope FileStream(); + UnbufferedFileStream fs = scope UnbufferedFileStream(); int len = encoding.GetEncodedSize(text); uint8* data = new uint8[len]*; diff --git a/BeefLibs/corlib/src/IO/FileStream.bf b/BeefLibs/corlib/src/IO/FileStream.bf index 36b5daa0..9df7f8a3 100644 --- a/BeefLibs/corlib/src/IO/FileStream.bf +++ b/BeefLibs/corlib/src/IO/FileStream.bf @@ -178,7 +178,7 @@ namespace System.IO case .Open: createKind = .OpenExisting; case .OpenOrCreate: - createKind = .CreateAlways; + createKind = .OpenAlways; case .Truncate: createKind = .CreateAlways; createFlags |= .Truncate; @@ -235,6 +235,32 @@ namespace System.IO return .Err; return .Ok; } + + public override Result SetLength(int64 length) + { + int64 pos = Position; + + if (pos != length) + Seek(length); + + Platform.BfpFileResult result = .Ok; + Platform.BfpFile_Truncate(mBfpFile, &result); + if (result != .Ok) + { + Seek(pos); + return .Err; + } + + if (pos != length) + { + if (pos < length) + Seek(pos); + else + Seek(0, .FromEnd); + } + + return .Ok; + } } class BufferedFileStream : BufferedStream @@ -253,6 +279,22 @@ namespace System.IO } } + public override bool CanRead + { + get + { + return mFileAccess.HasFlag(FileAccess.Read); + } + } + + public override bool CanWrite + { + get + { + return mFileAccess.HasFlag(FileAccess.Write); + } + } + public this() { @@ -274,22 +316,6 @@ namespace System.IO mFileAccess = access; } - public override bool CanRead - { - get - { - return mFileAccess.HasFlag(FileAccess.Read); - } - } - - public override bool CanWrite - { - get - { - return mFileAccess.HasFlag(FileAccess.Write); - } - } - public Result Create(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null) { return Open(path, FileMode.Create, access, share, bufferSize, options, secAttrs); @@ -337,7 +363,7 @@ namespace System.IO case .Open: createKind = .OpenExisting; case .OpenOrCreate: - createKind = .CreateAlways; + createKind = .OpenAlways; case .Truncate: createKind = .CreateAlways; createFlags |= .Truncate; @@ -406,15 +432,20 @@ namespace System.IO mUnderlyingLength = Platform.BfpFile_GetFileSize(mBfpFile); } + protected Result SeekUnderlying(int64 offset, Platform.BfpFileSeekKind seekKind = .Absolute) + { + int64 newPos = Platform.BfpFile_Seek(mBfpFile, offset, seekKind); + Result result = ((seekKind == .Absolute) && (newPos != offset)) ? .Err : .Ok; + if (result case .Ok) + mBfpFilePos = newPos; + return result; + } + protected override Result TryReadUnderlying(int64 pos, Span data) { if (mBfpFilePos != pos) - { - int64 newPos = Platform.BfpFile_Seek(mBfpFile, pos, .Absolute); - if (newPos != pos) - return .Err; - mBfpFilePos = pos; - } + Try!(SeekUnderlying(pos)); + Platform.BfpFileResult result = .Ok; int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result); if ((result != .Ok) && (result != .PartialData)) @@ -426,12 +457,8 @@ namespace System.IO protected override Result TryWriteUnderlying(int64 pos, Span data) { if (mBfpFilePos != pos) - { - int64 newPos = Platform.BfpFile_Seek(mBfpFile, pos, .Absolute); - if (newPos != pos) - return .Err; - mBfpFilePos = pos; - } + Try!(SeekUnderlying(pos)); + Platform.BfpFileResult result = .Ok; int numBytesRead = Platform.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result); if ((result != .Ok) && (result != .PartialData)) @@ -443,12 +470,7 @@ namespace System.IO public Result TryRead(Span data, int timeoutMS) { if (mBfpFilePos != mPos) - { - int64 newPos = Platform.BfpFile_Seek(mBfpFile, mPos, .Absolute); - if (newPos != mPos) - return .Err; - mBfpFilePos = mPos; - } + Try!(SeekUnderlying(mPos)); Platform.BfpFileResult result = .Ok; int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result); @@ -456,6 +478,40 @@ namespace System.IO return .Err; return numBytesRead; } + + public override Result SetLength(int64 length) + { + Try!(Flush()); + + int64 pos = Position; + + if (pos != length || pos != mBfpFilePos) + { + Try!(SeekUnderlying(length)); + mPos = length; + } + + Platform.BfpFileResult result = .Ok; + Platform.BfpFile_Truncate(mBfpFile, &result); + if (result != .Ok) + { + Try!(SeekUnderlying(pos)); + return .Err; + } + + mUnderlyingLength = length; + mPos = Math.Min(pos, Length); + + if (pos != length) + { + if (pos < length) + Try!(SeekUnderlying(pos)); + else + Try!(SeekUnderlying(0, .FromEnd)); + } + + return .Ok; + } } class FileStream : BufferedFileStream diff --git a/BeefLibs/corlib/src/IO/Stream.bf b/BeefLibs/corlib/src/IO/Stream.bf index 00e8bab5..404a5d8b 100644 --- a/BeefLibs/corlib/src/IO/Stream.bf +++ b/BeefLibs/corlib/src/IO/Stream.bf @@ -203,6 +203,11 @@ namespace System.IO return .Ok; } + public virtual Result SetLength(int64 length) + { + return .Err; + } + public void Align(int alignSize) { int64 pos = Length; diff --git a/BeefLibs/corlib/src/Platform.bf b/BeefLibs/corlib/src/Platform.bf index 8e518186..f110c709 100644 --- a/BeefLibs/corlib/src/Platform.bf +++ b/BeefLibs/corlib/src/Platform.bf @@ -271,6 +271,7 @@ namespace System CreateAlways, CreateIfNotExists, OpenExisting, + OpenAlways, }; public enum BfpFileCreateFlags : int32 @@ -351,7 +352,7 @@ namespace System [CallingConvention(.Stdcall), CLink] public static extern int64 BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind); [CallingConvention(.Stdcall), CLink] - public static extern void BfpFile_Truncate(BfpFile* file); + public static extern void BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult); [CallingConvention(.Stdcall), CLink] public static extern BfpTimeStamp BfpFile_GetTime_LastWrite(char8* path); [CallingConvention(.Stdcall), CLink] diff --git a/BeefySysLib/FileStream.cpp b/BeefySysLib/FileStream.cpp index 1e850d76..08ee6f3d 100644 --- a/BeefySysLib/FileStream.cpp +++ b/BeefySysLib/FileStream.cpp @@ -219,7 +219,8 @@ void SysFileStream::SetSizeFast(int size) int curPos = GetPos(); SetPos(size); - BfpFile_Truncate(mFile); + BfpFileResult result = BfpFileResult_Ok; + BfpFile_Truncate(mFile, &result); SetPos(curPos); return; } diff --git a/BeefySysLib/platform/PlatformInterface.h b/BeefySysLib/platform/PlatformInterface.h index aa6fc380..79b08843 100644 --- a/BeefySysLib/platform/PlatformInterface.h +++ b/BeefySysLib/platform/PlatformInterface.h @@ -344,6 +344,7 @@ enum BfpFileCreateKind BfpFileCreateKind_CreateAlways, BfpFileCreateKind_CreateIfNotExists, BfpFileCreateKind_OpenExisting, + BfpFileCreateKind_OpenAlways }; enum BfpFileCreateFlags @@ -421,7 +422,7 @@ BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr BFP_EXPORT void BFP_CALLTYPE BfpFile_Flush(BfpFile* file); BFP_EXPORT int64 BFP_CALLTYPE BfpFile_GetFileSize(BfpFile* file); BFP_EXPORT int64 BFP_CALLTYPE BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind); -BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file); +BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult); BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFile_GetTime_LastWrite(const char* path); BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFile_GetAttributes(const char* path, BfpFileResult* outResult); BFP_EXPORT void BFP_CALLTYPE BfpFile_SetAttributes(const char* path, BfpFileAttributes attribs, BfpFileResult* outResult); diff --git a/BeefySysLib/platform/posix/PosixCommon.cpp b/BeefySysLib/platform/posix/PosixCommon.cpp index 4fa4c52b..9e55deda 100644 --- a/BeefySysLib/platform/posix/PosixCommon.cpp +++ b/BeefySysLib/platform/posix/PosixCommon.cpp @@ -1858,6 +1858,10 @@ BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* inName, BfpFileCreat } return result; }; + + // POSIX doesn't need the OpenAlways kind. + if (createKind == BfpFileCreateKind_OpenAlways) + createKind = BfpFileCreateKind_CreateAlways; BfpFile* bfpFile = NULL; @@ -2079,13 +2083,15 @@ BFP_EXPORT int64 BFP_CALLTYPE BfpFile_Seek(BfpFile* file, int64 offset, BfpFileS return lseek64(file->mHandle, offset, whence); } -BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file) +BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult) { int64 curPos = (int64)lseek64(file->mHandle, 0, SEEK_CUR); if (ftruncate64(file->mHandle, curPos) != 0) - { - //TODO: Report error? - } + { + OUTRESULT(BfpFileResult_UnknownError); + return; + } + OUTRESULT(BfpFileResult_Ok); } BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFile_GetTime_LastWrite(const char* path) diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index 81aebe2c..e8a91d1e 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -2741,9 +2741,13 @@ BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* path, BfpFileCreateK creationDisposition = CREATE_ALWAYS; } else if (createKind == BfpFileCreateKind_CreateIfNotExists) - { + { creationDisposition = CREATE_NEW; } + else if (createKind == BfpFileCreateKind_OpenAlways) + { + creationDisposition = OPEN_ALWAYS; + } else { creationDisposition = OPEN_EXISTING; @@ -3019,9 +3023,14 @@ BFP_EXPORT int64 BFP_CALLTYPE BfpFile_Seek(BfpFile* file, int64 offset, BfpFileS return newPos.QuadPart; } -BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file) +BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult) { - SetEndOfFile(file->mHandle); + if (!SetEndOfFile(file->mHandle)) + { + OUTRESULT(BfpFileResult_UnknownError); + return; + } + OUTRESULT(BfpFileResult_Ok); } BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFile_GetTime_LastWrite(const char* path) diff --git a/IDE/mintest/minlib/src/System/Platform.bf b/IDE/mintest/minlib/src/System/Platform.bf index c4259103..35a72d33 100644 --- a/IDE/mintest/minlib/src/System/Platform.bf +++ b/IDE/mintest/minlib/src/System/Platform.bf @@ -234,6 +234,7 @@ namespace System CreateAlways, CreateIfNotExists, OpenExisting, + OpenAlways, }; public enum BfpFileCreateFlags : int32 @@ -303,7 +304,7 @@ namespace System [CallingConvention(.Stdcall), CLink] public static extern int64 BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind); [CallingConvention(.Stdcall), CLink] - public static extern void BfpFile_Truncate(BfpFile* file); + public static extern void BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult); [CallingConvention(.Stdcall), CLink] public static extern BfpTimeStamp BfpFile_GetTime_LastWrite(char8* path); [CallingConvention(.Stdcall), CLink]