Files CCore/inc/GenFile.h CCore/src/GenFile.cpp
CCore uses an abstract concept of working with a file system. It includes a set of common constants and abstract operations to work with any file system, local or remote. The term file means a true file, i.e. a persistent sequence of octets, stored on some file device and identified by its name, which may include a device specifier, a path specifier and finally a file name. All constant standardize a name, a type, a meaning and a value. You may find these definitions in the txt/cpp/GenFile.txt.cpp also.
/* types */ using FilePosType = uint64 ; using CmpFileTimeType = uint64 ; /* consts */ const ulen MaxPathLen = 512 ;
FilePosType represents a file position and a length, it is 64-bit wide.
CmpFileTimeType represents a file time, it is 64-bit wide. It is an abstract time value, without any known resolution. It can be used to compare file times. Null value is reserved for non-existing files.
MaxPathLen is a path length limit.
enum FileOpenFlags : uint32
{
Open_Read = 0x01, // "Read"
Open_Write = 0x02, // "Write"
Open_Pos = 0x04, // "Pos"
Open_Create = 0x10, // "Create"
Open_Erase = 0x20, // "Erase"
Open_New = 0x40, // "New"
Open_AutoDelete = 0x80, // "AutoDelete"
Open_PosEnd = 0x100, // "PosEnd"
Open_ToRead = Open_Read,
Open_ToWrite = Open_Write|Open_Create|Open_Erase,
Open_ToAppend = Open_Write|Open_Create|Open_PosEnd
};
inline FileOpenFlags operator | (FileOpenFlags a,FileOpenFlags b)
{
return FileOpenFlags( uint32(a)|uint32(b) );
}
class FileOpenFlagsTextDesc
{
FileOpenFlags oflags;
public:
explicit FileOpenFlagsTextDesc(FileOpenFlags oflags_) : oflags(oflags_) {}
template <class P>
void print(P &out) const;
};
inline FileOpenFlagsTextDesc GetTextDesc(FileOpenFlags oflags) { return FileOpenFlagsTextDesc(oflags); }
FileOpenFlags is a set of flags used to control a file open operation. You may use the overloaded operator | to combine a set of flags into a single value.
Open_Read — read operations must be available on opened file.
Open_Write — write operations must be available on opened file.
Open_Pos — position operations must be available on opened file, this includes a file length operation. This flag is used, if a file is opened with the sequential access set of operations.
Open_Create — create a new file, if there is no a file with the given name. If this flag is not set and the file does not exist, the open operation is failed.
Open_Erase — erase the file, if one exists.
Open_New — the file must be a new file. If the file with the given name exists, the operation is failed. If this flags is set, then Open_Create and Open_Erase flags are ignored.
Open_AutoDelete — delete the file during the close operation. The effect of this flag can be cancelled after the file is opened.
Open_PosEnd — the file position is set to the end of the file. This flag is used if a file is opened with the sequential access set of operations. It does not required the Open_Pos flag to be set.
Open_ToRead is a combination Open_Read.
Open_ToWrite is a combination Open_Write|Open_Create|Open_Erase.
Open_ToAppend is a combination Open_Write|Open_Create|Open_PosEnd.
GetTextDesc(FileOpenFlags) creates a temporary object to print a text description of the given flags. The output looks like "Read|Write|Create".
enum FileError : uint32
{
FileError_Ok = 0, // "Success"
FileError_NoDevice = 1, // "No device"
FileError_NoPath = 2, // "No path"
FileError_NoFile = 3, // "No file"
FileError_NoAccess = 4, // "No access"
FileError_FileExist = 5, // "File exist"
FileError_NoMethod = 6, // "No method"
FileError_OpenFault = 7, // "Open fault"
FileError_CloseFault = 8, // "Close fault"
FileError_ReadFault = 9, // "Read fault"
FileError_WriteFault = 10, // "Write fault"
FileError_PosFault = 11, // "Pos fault"
FileError_OpFault = 12, // "Operation fault"
FileError_TransFault = 13, // "Transaction fault"
FileError_Cancelled = 14, // "Operation cancelled"
FileError_SysOverload = 15, // "System overload"
FileError_TooLongPath = 16, // "Too long path"
FileError_DiskFull = 17, // "Disk full"
FileError_WriteProtect = 18, // "Write protect"
FileError_DirIsNotEmpty = 19, // "Dir is not empty"
FileError_BadId = 20, // "Bad file id"
FileError_LenOverflow = 21, // "Length overflow"
FileError_ReadLenMismatch = 22, // "Read length mismatch"
FileError_WriteLenMismatch = 23, // "Write length mismatch"
FileError_BadName = 24, // "Bad name"
FileError_BadPosition = 25, // "Bad file position"
FileError_BadLen = 26, // "Bad length"
FileError_Some = 27 // last , "Some error"
};
const char * GetTextDesc(FileError fe);
FileError represent a list of typical errors happens during file operations.
enum FileType : uint32
{
FileType_none = 0, // "none"
FileType_file = 1, // "file"
FileType_dir = 2 // "dir"
};
const char * GetTextDesc(FileType ft);
FileType is used to designate the file type: is it a file, a directory or there is no such object.
class FileMultiError : NoCopy
{
static const ulen Len = 10 ;
FileError list[Len];
ulen len;
ulen extra;
public:
FileMultiError() : len(0),extra(0) {}
// methods
ulen operator + () const { return len; }
bool operator ! () const { return !len; }
void add(FileError fe);
FileError getFirst() const { return len?list[0]:FileError_Ok; }
void copyTo(FileMultiError &out) const;
// print object
template <class P>
void print(P &out) const;
};
There are situations when several errors can be fired during the one operation, for example, during file closing. FileMultiError can store multiple error codes. It accumulates up to 10 error codes and counts any extra.
operator + and operator ! can be used to test if there are accumulated errors.
add() adds a error code to the object.
getFirst() returns the first error code or FileError_Ok if there is no one.
copyTo() copies the state to another object.
print() prints the content of the object.
There are two file operations sets: the classical, where there is an internal file position and the alternative, where read or write position is provided explicitly. File names are encoded as a byte range. No zero-termination is assumed. The length is given explicitly.
There are few basic types and constants.
/* types */ using FilePosType = uint64 ; using byte = uint8 ; /* consts */ const ulen MaxPathLen = 512 ;
Here is the classical set of operations as an abstract set of functions. The error reporting is omitted.
void open(const byte *file_name,ulen len,FileOpenFlags open_flags); // file_name is not zero-terminated void close(bool preserve_file=false); // if( preserve_file ) ignore(Open_AutoDelete); ulen read(byte *buf,ulen len); // requires Open_Read ulen write(const byte *data,ulen len); // requires Open_Write FilePosType getLen(); // requires Open_Pos FilePosType getPos(); // requires Open_Pos void setPos(FilePosType pos); // requires Open_Pos // if( pos>file_len ) unknown();
To start working with a file it must be opened. The open operation arguments are: the file name (with the file name length), and the open flags. The opened file has the internal file position. This position is set to 0, unless the flag Open_PosEnd is specified. If this flag is set, then the position is set to the file length.
The close operation has the argument: preserve_file. This argument is used with the open flag Open_AutoDelete. If this flag is set then the file is deleted during the close operation. But if the preserve_file is true, it is preserved.
getLen returns the current length of the file. The length can be changed by the write operation.
getPos returns the current file position.
setPos sets the current file position. Setting the file position beyond the end-of-file has an undefined behavior.
read transfers bytes from the file at the current file position to the user buffer and updates the file position. The return value can be less than the given length, if the end-of-file is encountered.
write transfers bytes from the user buffer to the file at the current file position and updates the file position. Write MAY extend the file. The return value should be equal to the given length, unless there is a good reason to implement another behavior.
And the alternative set is:
FilePosType /* file_len */ open(const byte *file_name,ulen len,FileOpenFlags open_flags); // Open_Pos, Open_PosEnd are ignored void close(bool preserve_file=false); // if( preserve_file ) ignore(Open_AutoDelete); void read(FilePosType off,byte *buf,ulen len); // requires Open_Read , off+len<=file_len FilePosType /* file_len */ write(FilePosType off,const byte *data,ulen len); // requires Open_Write , if( off>file_len ) [file_len,off) is unspecified filled
The open operation ignores flags Open_Pos and Open_PosEnd. It returns the file length. There is no the internal file position in this case.
read uses the explicitly given file position. The read range must be in the file range.
write also uses the explicitly given file position. But the write range may be outside the file range. In this case the file is extended. The return length is the new file length. If there is a hole after the end-of-file and before the write position, the hole is filled by unpredicted values.
FileType getFileType(const byte *path,ulen len); CmpFileTimeType getFileUpdateTime(const byte *path,ulen len); void createFile(const byte *file_name,ulen len); void deleteFile(const byte *file_name,ulen len); void createDir(const byte *dir_name,ulen len); void deleteDir(const byte *dir_name,ulen len,bool recursive); // if( !recursive ) dir must be empty void rename(const byte *old_path,ulen old_len,const byte *new_path,ulen new_len,bool allow_overwrite); void remove(const byte *path,ulen len); // if path is dir it must be empty
getFileType() returns the file type.
getFileUpdateTime() returns the last modification time of the file or directory.
createFile() creates the new empty file.
deleteFile() deletes the existing file.
createDir() creates the new empty directory.
deleteDir() deletes the existing directory. If the recursive is false, the directory must be empty. Otherwise it is deleted with the all content recursively.
rename() renames or moves the file of directory. The allow_overwrite flag allows overwriting the existing file.
remove() deletes ether the existing file or the existing empty directory.
To enumerate a directory a some "directory cursor" is required.
byte file_name[MaxPathLen]; ulen len; FileType type; FileError error;
The visible state of the cursor has the following members:
file_name — the name of the current file or directory.
len — the length of the file name.
type — the type of the current file or directory.
error — error code, if any.
void init(const byte *dir_name,ulen len); // set to before-the-first position bool next(); void exit();
There are three cursor operations.
init() initializes the cursor to enumerate the given directory. The cursor is at before-the-first element position. If this operation fails, other operations should not be used.
next() moves to the next element, if such element exists. The return value is true, if the cursor is moved, otherwise, if the cursor is already at the last element, the false is returned.
exit() is used to destroy the cursor.