Files CCore/inc/sys/SysFile.h CCore/src/sys/SysFile.cpp
This part contains OS backed file access tools. These tools comply with the general file operation set.
#ifndef CCore_inc_sys_SysFile_h #define CCore_inc_sys_SysFile_h #include <CCore/inc/sys/SysWait.h> #include <CCore/inc/TimeScope.h> #include <CCore/inc/GenFile.h> namespace CCore { namespace Sys { /* classes */ struct File; struct AltFile; struct AltAsyncFile; struct AsyncFileWait; /* struct File */ struct File { // private .... // public struct IOResult { ulen len; FileError error; }; struct PosResult { FilePosType pos; FileError error; }; // public FileError open(StrLen file_name,FileOpenFlags oflags) noexcept; void close(FileMultiError &errout,bool preserve_file=false) noexcept; void close() noexcept; IOResult write(const uint8 *buf,ulen len) noexcept; IOResult read(uint8 *buf,ulen len) noexcept; PosResult getLen() noexcept; PosResult getPos() noexcept; FileError setPos(FilePosType pos) noexcept; }; /* struct AltFile */ struct AltFile { // private .... // public struct Result { FilePosType file_len; FileError error; }; // public Result open(StrLen file_name,FileOpenFlags oflags) noexcept; void close(FileMultiError &errout,bool preserve_file=false) noexcept; void close() noexcept; Result write(FilePosType off,const uint8 *buf,ulen len) noexcept; FileError read(FilePosType off,uint8 *buf,ulen len) noexcept; }; /* struct AltAsyncFile */ struct AltAsyncFile { // private .... // public struct AsyncState; using Async = AsyncState * ; struct Result { FilePosType file_len; FileError error; }; struct RWResult { bool pending; FileError error; }; // public static const ulen MaxRWLen = .... ; Result open(StrLen file_name,FileOpenFlags oflags) noexcept; void close(FileMultiError &errout,bool preserve_file=false) noexcept; void close() noexcept; FileError testRead(FilePosType off,ulen len) noexcept; Result setWrite(FilePosType off,ulen len) noexcept; RWResult startRead(Async async,FilePosType off,uint8 *buf,ulen len) noexcept; FileError completeRead(Async async,ulen len) noexcept; RWResult startWrite(Async async,FilePosType off,const uint8 *buf,ulen len) noexcept; FileError completeWrite(Async async,ulen len) noexcept; }; /* struct AsyncFileWait */ struct AsyncFileWait { // private .... // public static const ulen MaxAsyncs = .... ; FileError init(ulen async_count) noexcept; void exit() noexcept; AltAsyncFile::Async getAsync(ulen index) noexcept; bool addWait(ulen index) noexcept; bool delWait(ulen index) noexcept; WaitResult wait(MSec timeout) noexcept; WaitResult wait(TimeScope time_scope) noexcept; void interrupt() noexcept; // async , semaphore }; } // namespace Sys } // namespace CCore #endif
These structures uses types and constants from the GenFile.h, this includes error codes.
The structure File implements the classical file access.
struct File
{
// private
....
// public
struct IOResult
{
ulen len;
FileError error;
};
struct PosResult
{
FilePosType pos;
FileError error;
};
// public
FileError open(StrLen file_name,FileOpenFlags oflags) noexcept;
void close(FileMultiError &errout,bool preserve_file=false) noexcept;
void close() noexcept;
IOResult write(const uint8 *buf,ulen len) noexcept;
IOResult read(uint8 *buf,ulen len) noexcept;
PosResult getLen() noexcept;
PosResult getPos() noexcept;
FileError setPos(FilePosType pos) noexcept;
};
To work with a file you create an instance of this structure. Then you open the required file using the method open(). Then you use its methods to do file operations. Finally, you uninitialize the instance. Copying of the instances is prohibited. The private content of the structure is target-dependent.
open() initializes the instance and prepares it to perform file operations with the given file. The error code is returned. The first argument is the file name. The second is the open flags. The meaning of the flags is described in the general file operation set. If the object is successfully initialized, it must be uninitialized by the method close().
close() closes the file. The first variant uses the provided FileMultiError object to return operation error(s). If the flag preserve_file is true, the file is preserved, even if it was opened with the Open_AutoDelete flag. The second variant does not report any errors and does not preserve the file, opened with the Open_AutoDelete flag.
write() writes the given byte range to the file at the current file position. The file position is updated. The return value has the inner type IOResult. This structure has two fields: len and error. The len is the number of bytes have been written and the error is the error code. The len is less or equal than the argument len. The file may be extended by this operation. If the operation is successful, the resulting length should be equal the input length. Other behavior is not recommended. This operation is available only if the file has been opened with the flag Open_Write.
read() reads the byte range from the file to the provided buffer from the current file position. The file position is updated. The return value has the inner type IOResult. This structure has two fields: len and error. The len is the number of bytes have been red and the error is the error code. The len is less or equal than the argument len. If the operation is successful, the resulting length should be equal minimum of the input length and the number of bytes after the current file position to the end of file. Other behavior is not recommended. This operation is available only if the file has been opened with the flag Open_Read.
getLen() returns the current length of the file. The return value is represented by the inner structure PosResult. This structure has two fields: pos and error. pos is the length of the file, error is the error code. This operation is available only if the file has been opened with the flag Open_Pos.
getPos() returns the current position of the file. The return value is represented by the inner structure PosResult. This structure has two fields: pos and error. The pos is the file position, the error is the error code. This operation is available only if the file has been opened with the flag Open_Pos.
setPos() sets the current position of the file. The error code is returned. If the position is after the end-of-file, the behavior is undefined. If you want to extend the file, it can be done by the method write(). This operation is available only if the file has been opened with the flag Open_Pos.
The structure AltFile implements an alternative file access.
struct AltFile
{
// private
....
// public
struct Result
{
FilePosType file_len;
FileError error;
};
// public
Result open(StrLen file_name,FileOpenFlags oflags) noexcept;
void close(FileMultiError &errout,bool preserve_file=false) noexcept;
void close() noexcept;
Result write(FilePosType off,const uint8 *buf,ulen len) noexcept;
FileError read(FilePosType off,uint8 *buf,ulen len) noexcept;
};
To work with a file you create an instance of this structure. Then you open the required file using the method open(). Then you use its methods to do file operations. Finally, you uninitialize the instance. Copying of the instances is prohibited. The private content of the structure is target-dependent.
open() initializes the instance and prepares it to perform file operations with the given file. The return value has the inner type Result. This structure has two fields: file_len and error. The file_len is the length of the file, the error is the error code. The first argument is the file name. The second is the open flags. This kind of file has no an internal file position. The meaning of the flags is described in the general file operation set. If the object is successfully initialized, it must be uninitialized by the method close().
close() closes the file. The first variant uses the provided FileMultiError object to return operation error(s). If the flag preserve_file is true, the file is preserved, even if it was opened with the Open_AutoDelete flag. The second variant does not report any errors and does not preserve the file, opened with the Open_AutoDelete flag.
write() writes the given byte range to the file. The file position to write is given by the first argument. This operation may extend the file. The return value has the inner type Result. This structure has two fields: file_len and error. The file_len is the new length of the file, the error is the error code. This operation is available only if the file has been opened with the flag Open_Write.
read() reads the byte range from the file to the provided buffer. The file position to read is given by the first argument. The error code is returned. The read range must not cross end-of-file. This operation is available only if the file has been opened with the flag Open_Read.
The structure AltFile implements an alternative file access in an asynchronous manner.
struct AltAsyncFile
{
// private
....
// public
struct AsyncState;
using Async = AsyncState * ;
struct Result
{
FilePosType file_len;
FileError error;
};
struct RWResult
{
bool pending;
FileError error;
};
// public
static const ulen MaxRWLen = .... ; // like 1_MByte
Result open(StrLen file_name,FileOpenFlags oflags) noexcept;
void close(FileMultiError &errout,bool preserve_file=false) noexcept;
void close() noexcept;
FileError testRead(FilePosType off,ulen len) noexcept;
Result setWrite(FilePosType off,ulen len) noexcept;
RWResult startRead(Async async,FilePosType off,uint8 *buf,ulen len) noexcept;
FileError completeRead(Async async,ulen len) noexcept;
RWResult startWrite(Async async,FilePosType off,const uint8 *buf,ulen len) noexcept;
FileError completeWrite(Async async,ulen len) noexcept;
};
To work with a file you create an instance of this structure. Then you open the required file using the method open(). Then you use its methods to do file operations. Finally, you uninitialize the instance. Copying of the instances is prohibited. The private content of the structure is target-dependent.
open() initializes the instance and prepares it to perform file operations with the given file. The return value has the inner type Result. This structure has two fields: file_len and error. The file_len is the length of the file, the error is the error code. The first argument is the file name. The second is the open flags. This kind of file has no an internal file position. The meaning of the flags is described in the general file operation set. If the object is successfully initialized, it must be uninitialized by the method close().
close() closes the file. The first variant uses the provided FileMultiError object to return operation error(s). If the flag preserve_file is true, the file is preserved, even if it was opened with the Open_AutoDelete flag. The second variant does not report any errors and does not preserve the file, opened with the Open_AutoDelete flag. All pending file read/write operations must be finished before the call of this method.
testRead() checks the read position. If the read range does not fit into the file range it returns the error. The error code is returned. This operation is available only if the file has been opened with the flag Open_Read.
setWrite() prepares the file write operation. It checks the write range for overflow and increases the internal file length field, if the file is to be extended. This method must be called before the startWrite(). This operation is available only if the file has been opened with the flag Open_Write.
startRead() starts the read operation. The first argument is an async token. The type of this token is the inner type Async and usually it is the pointer to some structure (AsyncState). The return value has the inner type RWResult. It has two fields: pending and error. The first field is true, if the operation is pending, otherwise it is finished. The second is the error code. If the operation is finished, no other steps are required. If the operation is pending, you must wait until the token is finished and then call the method completeRead(). This operation is available only if the file has been opened with the flag Open_Read.
completeRead() completes the read operation. The first argument is the operation token, the second is the original argument len from the startRead() call. This method must be used only after the correspondent async token is reported finished. The error code is returned. This operation is available only if the file has been opened with the flag Open_Read.
startWrite() starts the write operation. The first argument is an async token. The type of this token is the inner type Async and usually it is the pointer to some structure (AsyncState). The return value has the inner type RWResult. It has two fields: pending and error. The first field is true, if the operation is pending, otherwise it is finished. The second is the error code. If the operation is finished, no other steps are required. If the operation is pending, you must wait until the token is finished and then call the method completeWrite(). This operation is available only if the file has been opened with the flag Open_Write.
completeWrite() completes the write operation. The first argument is the operation token, the second is the original argument len from the startWrite() call. This method must be used only after the correspondent async token is reported finished. The error code is returned. This operation is available only if the file has been opened with the flag Open_Write.
The length of any read or write operation must not exceed MaxRWLen, which should has the value like 1 MByte. The data buffer is in use during the whole read or write operation, so it must be held intact until the operation is complete.
Here is a pattern to do a read operation:
AltAsyncFile::Async async=<acquire an unused async token>; if( auto error=file.testRead(off,len) ) { <release async>; return error; } auto result=file.startRead(async,off,buf,len); if( result.error ) { <release async>; return result.error; } if( result.pending ) { <wait until async is finished>; auto error=file.completeRead(async,len); <release async>; return error; } else { <release async>; return FileError_Ok; }
Here is a pattern to do a write operation:
AltAsyncFile::Async async=<acquire an unused async token>; auto op_result=file.startWrite(off,len); if( op_result.error ) { <release async>; return {op_result.error,0}; } auto result=file.startWrite(async,off,buf,len); if( result.error ) { <release async>; return {result.error,0}; } if( result.pending ) { <wait until async is finished>; auto error=file.completeWrite(async,len); <release async>; return {error,op_result.file_len}; } else { <release async>; return {FileError_Ok,op_result.file_len}; }
To work with async tokens there is the structure AsyncFileWait.
struct AsyncFileWait
{
// private
....
// public
static const ulen MaxAsyncs = .... ; // like 50-100
FileError init(ulen async_count) noexcept;
void exit() noexcept;
AltAsyncFile::Async getAsync(ulen index) noexcept;
bool addWait(ulen index) noexcept;
bool delWait(ulen index) noexcept;
WaitResult wait(MSec timeout) noexcept;
WaitResult wait(TimeScope time_scope) noexcept;
void interrupt() noexcept; // async , semaphore
};
This structure is a pool of tokens. To work with tokens you create an instance of this structure and initialize it. Then you use its methods to do async file operations. Finally, you uninitialize the instance. Copying of the instances is prohibited. The private content of the structure is target-dependent.
init() initializes the instance. The argument is the async pool size. This value must not exceed the inner constant MaxAsyncs. Otherwise the method returns a error. If the object is successfully initialized, it must be uninitialized by the method exit(). The pool contains async_count async tokens. They are indexed by the numbers from the range [0,async_count). Some of them comprise the "wait set". Initially the set is empty.
exit() uninitializes the instance.
getAsync() returns the token with the given index.
addWait() adds the token with the given index to the wait set. The return value is true, if the token was included in the set, and false, if the token is already in the set.
delWait() removes the token with the given index from the wait set. The return value is true, if the token was excluded from the set, and false, if the token is already not in the set.
wait() waits while one of the tokens from the wait set is finished, i.e. some async file operation is started with this token and it is finished. The return value has the type WaitResult. The value is the index of the token been finished, or one of the negative special values. Two variants of wait() accepts timeouts of different kinds: as a MSec or as a TimeScope. The special return values have the following meanings:
interrupt() is a special method. This method can be used to interrupt the wait(). Unlike other methods, this one can be called in parallel to other method calls. This method has a "semaphore behavior", i.e. several calls provide several interrupts.