Files CCore/inc/sys/SysAsyncFile.h CCore/src/sys/SysAsyncFile.cpp
Files CCore/inc/sys/SysAsyncFileSystem.h CCore/src/sys/SysAsyncFileSystem.cpp
Async file and file system devices are packet processing devices, that performs file and file system operations in asynchronous manner. To be used, the device must be registered in the default Object Host. The name of the object must be used as a device name in file names on that device. For example, if some object is registered under the name "host", the file name "host:/file.txt" refers to the file "/file.txt" on that device or "host:c:/file.txt" refers to "c:/file.txt".
Sys::AsyncFileDevice is an abstract interface of an async file device. An async file device class must implement this interface.
struct Sys::AsyncFileDevice
{
static const Unid TypeUnid;
virtual Sys::AsyncFileState * createState(const ObjHook &hook) noexcept =0;
};
To work with a file, a file state object must be created. The class of this object must implement the Sys::AsyncFileState interface. A state is created by the createState() method. A pointer to the Sys::AsyncFileState is returned. If the operation is failed, null pointer is returned. The argument hook should be a hook, which was used to pick the device object (or a hook to an "upper" object). It is used for the life-time control of the device object itself to prevent its destruction while one of states is alive.
class Sys::AsyncFileState : public MemBase_nocopy
{
ObjHook hook;
protected:
PacketFormat write_format; // filled by derived class
ulen max_read_len; // filled by derived class
public:
explicit AsyncFileState(const ObjHook &hook_) : hook(hook_) {}
virtual ~AsyncFileState() {}
PacketFormat getWriteFormat() const { return write_format; }
ulen getMaxReadLen() const { return max_read_len; }
virtual void open(Packet<uint8,Sys::AsyncFile::OpenExt> packet,StrLen file_name,FileOpenFlags oflags)=0;
virtual void close(Packet<uint8,Sys::AsyncFile::CloseExt> packet,bool preserve_file)=0;
virtual void write(Packet<uint8,Sys::AsyncFile::WriteExt> packet,FilePosType off)=0;
virtual void read(Packet<uint8,Sys::AsyncFile::ReadExt> packet)=0;
virtual void read(Packet<uint8,Sys::AsyncFile::ReadBufExt> packet)=0;
};
Sys::AsyncFileState contains inside a copy of the hook, provided to the method createState().
Destructor is virtual, so it is safe to destroy an object using a base class pointer.
Two data fields: write_format and max_read_len must be filled by a derived class. These fields can be red by the methods getWriteFormat() and getMaxReadLen(). File operations are performed with the following abstract methods. Each operation requires a packet to be prepared and provided. A method starts an operation, using this packet. Once the operation is complete, the packet is completed and the result of the operation can be retrieved. The packet can be cancelled to cancel the operation. A packet must not be short, its data buffer may be used to perform the operation (and may not).
open() opens a file. Once this is done, read and write operations can be performed with this file. Packet data are not required (but packet buffer may be used). File name and open flags are provided as the method arguments. An implementation may use the packet buffer to store and transfer this information further, for example, over a network. The packet extension Sys::AsyncFile::OpenExt is used to return the operation result:
struct Sys::AsyncFile::OpenExt
{
PacketFormat write_format; // output
ulen max_read_len; // output
FilePosType file_len; // output
FileError error; // output
// methods
void setFileLen(FilePosType file_len_)
{
file_len=file_len_;
error=FileError_Ok;
}
void setError(FileError error_)
{
write_format=Nothing;
max_read_len=0;
file_len=0;
error=error_;
}
};
The open operation should use provided methods to fill the result of the operation. First two fields are not used to return a value, but should be cleared in case of error. These fields are filled by the method Sys::AsyncFile::open() before the Sys::AsyncFileState::open() is called.
close() closes the opened file. preserve_file cancels the Open_AutoDelete flag. This operation must be performed after all read/write operations on this state are completed. Once close is done, the state can be deleted. State deletion, while file is not closed, is not recommended (but not completely avoidable). Packet data are not required (but packet buffer may be used). The packet extension Sys::AsyncFile::CloseExt is used to return the operation result:
struct Sys::AsyncFile::CloseExt
{
FileError error; // output
// methods
void noError()
{
error=FileError_Ok;
}
void setError(FileError error_)
{
error=error_;
}
};
write() writes data to the file at the given file position. Packet data are processed according the write_format. The packet extension Sys::AsyncFile::WriteExt is used to return the operation result: file_len is the file length after this operation. Multiple write operation may overlap, but the file_len result must be reported as if these operations execution is serialized.
struct Sys::AsyncFile::WriteExt
{
FilePosType file_len; // output
FileError error; // output
// methods
void setFileLen(FilePosType file_len_)
{
file_len=file_len_;
error=FileError_Ok;
}
void setError(FileError error_)
{
file_len=0;
error=error_;
}
};
There are two read() methods.
The first read() passes the read buffer pointer as the argument. The file position and the read buffer are input parameters and preserved on output, so you can use them in a complete function. Buffer must be red all, otherwise error must be reported. Packet data are not required (but packet buffer may be used). The read length must not exceed the max_read_len.
struct Sys::AsyncFile::ReadExt
{
FilePosType off; // input, preserved
PtrLen<uint8> buf; // input, preserved, read all
FileError error; // output
// methods
ReadExt(FilePosType off_,PtrLen<uint8> buf_) : off(off_),buf(buf_) {}
void copyData(const uint8 *data)
{
buf.copy(data);
error=FileError_Ok;
}
void setError(FileError error_)
{
error=error_;
}
};
The second read() passes only the read length. The file position and the read length are input parameters and preserved on output, so you can use them in a complete function. Data must be red all, otherwise error must be reported. Packet buffer is used to deliver data, the pointer data points somewhere inside the packet buffer. Packet buffer may be reattached to store the required volume of data. The read length must not exceed the max_read_len.
struct Sys::AsyncFile::ReadBufExt
{
FilePosType off; // input, preserved
ulen len; // input, preserved, read all
const uint8 *data; // output
FileError error; // output
// methods
ReadBufExt(FilePosType off_,ulen len_) : off(off_),len(len_) {}
PtrLen<const uint8> getData() const { return Range(data,len); }
void setData(const uint8 *data_)
{
data=data_;
error=FileError_Ok;
}
void setError(FileError error_)
{
data=0;
error=error_;
}
};
The class Sys::AsyncFile is to deal with a single file on some async file device.
struct Sys::AsyncFile
{
// public
struct OpenExt;
struct CloseExt;
struct WriteExt;
struct ReadExt;
struct ReadBufExt;
// private data
Sys::AsyncFileState *file_state;
FileOpenFlags oflags;
// public
void open(Sys::AsyncFileState *file_state_,FileOpenFlags oflags_)
{
file_state=file_state_;
oflags=oflags_;
}
void open(Packet<uint8,OpenExt> packet,StrLen file_name,FileOpenFlags oflags);
void open(Packet<uint8,OpenExt> packet,StrLen dev_name,StrLen dev_file_name,FileOpenFlags oflags);
//
// open is successfully finished, no pending operations, last operation
//
void close(Packet<uint8,CloseExt> packet,bool preserve_file=false);
//
// after close or open with error
//
void closeState();
//
// open is successfully finished
//
void write(Packet<uint8,WriteExt> packet,FilePosType off);
void read(Packet<uint8,ReadExt> packet);
void read(Packet<uint8,ReadBufExt> packet);
};
Sys::AsyncFile operates on some Sys::AsyncFileState. Most of operations are a call propagation to the Sys::AsyncFileState methods.
closeState() deletes the state. It must be called after close() or failed open() to cleanup the object.
There are three open() operation. First is a simple initialization with the given state and open flags.
The second open() splits the file name, searches for the async file device and opens the file on this device. It also fills OpenExt fields, write_format and max_read_len to return these values with the packet. If the file name is "host:c:/file.txt", the the device with the name "host" is used and the file with the name "c:/file.txt" will be opened on this device.
The third open() works the same as the second, except it takes the device name and the device path as two arguments.
Sys::AsyncFileSystemDevice is an abstract interface of an async file system device. See Files for the generic file system operation list.
struct Sys::AsyncFileSystemDevice
{
static const Unid TypeUnid;
virtual void getFileType(Packet<uint8,Sys::AsyncFileSystem::FileTypeExt> packet,StrLen path)=0;
virtual void getFileUpdateTime(Packet<uint8,Sys::AsyncFileSystem::CmpFileTimeExt> packet,StrLen path)=0;
virtual void getFileList(ObjHook &hook,Packet<uint8,Sys::AsyncFileSystem::FileExt> packet,StrLen dir_name)=0;
virtual void createFile(Packet<uint8,Sys::AsyncFileSystem::ErrorExt> packet,StrLen file_name)=0;
virtual void deleteFile(Packet<uint8,Sys::AsyncFileSystem::ErrorExt> packet,StrLen file_name)=0;
virtual void createDir(Packet<uint8,Sys::AsyncFileSystem::ErrorExt> packet,StrLen dir_name)=0;
virtual void deleteDir(Packet<uint8,Sys::AsyncFileSystem::ErrorExt> packet,StrLen dir_name,bool recursive)=0;
virtual void rename(Packet<uint8,Sys::AsyncFileSystem::ErrorExt> packet,StrLen old_path,StrLen new_path,bool allow_overwrite)=0;
virtual void remove(Packet<uint8,Sys::AsyncFileSystem::ErrorExt> packet,StrLen path)=0;
virtual void exec(Packet<uint8,Sys::AsyncFileSystem::ErrorExt> packet,StrLen dir,StrLen program,StrLen arg)=0;
virtual void exec2(ObjHook &hook,Packet<uint8,Sys::AsyncFileSystem::FileExt> packet,StrLen dir,StrLen program)=0;
};
The number of file system operations can be performed asynchronously using packets on this device. The packet buffer is not used for operation parameters, but may be used by an implementation, so packets must not be short.
getFileType() returns the file type of the file, specified by the path. The packet extension Sys::AsyncFileSystem::FileTypeExt is used to return the operation result:
struct Sys::AsyncFileSystem::FileTypeExt
{
FileType file_type; // output
FileError error; // output
// methods
void setFileType(FileType file_type_)
{
file_type=file_type_;
error=FileError_Ok;
}
void setError(FileError error_)
{
file_type=FileType_none;
error=error_;
}
};
getFileUpdateTime() returns the last modification time of the file or directory, specified by the path. The packet extension Sys::AsyncFileSystem::CmpFileTimeExt is used to return the operation result:
struct Sys::AsyncFileSystem::CmpFileTimeExt
{
CmpFileTimeType file_time; // output
FileError error; // output
// methods
void setFileTime(CmpFileTimeType file_time_)
{
file_time=file_time_;
error=FileError_Ok;
}
void setError(FileError error_)
{
file_time=0;
error=error_;
}
};
createFile() creates the empty file with the given file_name. The packet extension Sys::AsyncFileSystem::ErrorExt is used to return the operation result:
struct Sys::AsyncFileSystem::ErrorExt
{
FileError error; // output
// methods
void noError()
{
error=FileError_Ok;
}
void setError(FileError error_)
{
error=error_;
}
};
deleteFile() deletes the file with the given file_name. The packet extension Sys::AsyncFileSystem::ErrorExt is used to return the operation result.
createDir() creates the empty directory with the given dir_name. The packet extension Sys::AsyncFileSystem::ErrorExt is used to return the operation result.
deleteDir() deletes the directory with the given dir_name. If the recursive flag is false, the directory must be empty. Otherwise it is deleted with the all content recursively. The packet extension Sys::AsyncFileSystem::ErrorExt is used to return the operation result.
rename() renames or moves the file of directory. The allow_overwrite flag allows overwriting the existing file. The packet extension Sys::AsyncFileSystem::ErrorExt is used to return the operation result.
remove() deletes ether the existing file or the existing empty directory. The packet extension Sys::AsyncFileSystem::ErrorExt is used to return the operation result.
exec() execute a program on the target device with the given working directory dir, the program path program and the program arguments arg. The packet extension Sys::AsyncFileSystem::ErrorExt is used to return the operation result.
Remaining methods are special: they create temporary "files" to perform the operation. Files are represented by the Sys::AsyncFileState interface. The return object is already opened, so you can perform file operations on it. The packet extension Sys::AsyncFileSystem::FileExt is used to return a result.
struct Sys::AsyncFileSystem::FileExt
{
Sys::AsyncFileState *file_state; // output
FilePosType file_len; // output
FileError error; // output
// methods
void setFileLen(FilePosType file_len_)
{
file_len=file_len_;
error=FileError_Ok;
}
void setError(FileError error_)
{
file_state=0;
file_len=0;
error=error_;
}
};
getFileList() creates a read-only file with the content of the given directory. The file has number of lines, each line starts with a file or directory name, then space, then 'f' for a file or 'd' for a directory. End of line symbol is '\n'.
exec2() creates an empty temporary write-only file. This file should be filled with program arguments. To start a program, the file must be closed with the preserve_file equals true.
The class Sys::AsyncFileSystem is to work with some async file system device.
struct Sys::AsyncFileSystem
{
// public
struct FileTypeExt;
struct ErrorExt;
struct FileExt;
// private data
....
// public
FileError init(StrLen dev_name);
void exit();
void getFileType(Packet<uint8,FileTypeExt> packet,StrLen path);
void getFileUpdateTime(Packet<uint8,CmpFileTimeExt> packet,StrLen path);
void getFileList(Packet<uint8,FileExt> packet,StrLen dir_name);
void createFile(Packet<uint8,ErrorExt> packet,StrLen file_name);
void deleteFile(Packet<uint8,ErrorExt> packet,StrLen file_name);
void createDir(Packet<uint8,ErrorExt> packet,StrLen dir_name);
void deleteDir(Packet<uint8,ErrorExt> packet,StrLen dir_name,bool recursive);
void rename(Packet<uint8,ErrorExt> packet,StrLen old_path,StrLen new_path,bool allow_overwrite);
void remove(Packet<uint8,ErrorExt> packet,StrLen path);
void exec(Packet<uint8,ErrorExt> packet,StrLen dir,StrLen program,StrLen arg);
void exec2(Packet<uint8,FileExt> packet,StrLen dir,StrLen program);
};
init() connects the object with the device by its name.
exit() cleans the object, it must be called after all operations are completed on the connected object.
Other methods are direct calls of Sys::AsyncFileSystemDevice methods.