- Removed a bug with attempt to include pure c headers

- Added some more information about the license
 - fennec::file implementation
This commit is contained in:
2025-07-14 05:11:52 -04:00
parent 5e0dc78210
commit 6ae682aff6
26 changed files with 2229 additions and 245 deletions

View File

@@ -6,7 +6,7 @@
1. [Introduction](#introduction)
2. [TODO](#todo)
1. [Security Ramblings](#security-ramblings)
1. [Security Ramblings](#file-security-ramblings)
3. [C++ Language](#c-language-library-lang)
4. [Math Library](#math-library-math)
5. [Memory Library](#memory-library-memory)
@@ -63,6 +63,7 @@ This however can be achieved using events at different stages of those engines t
- 2D Physics (`physics2d`)
- 2D & 3D Audio (`audio`)
### File Security Ramblings:
Windows is starting to piss me off, so I am considering dropping official support for MSVC. MinGW and Cygwin
@@ -78,41 +79,41 @@ The crux of this issue falls at the following specific behaviour:
- Application interface confirms overwrite action
- Application writes to the file after confirmation
A threat actor can introduce a malicious file or symlink to the file that was attempted access between the check and
A threat actor can introduce a malicious file or symlink to the file that was attempted access between the check and
usage of the file. This is called TOCTOU (time of check, time of use).
This issue can be solved using `fopen("<file>", "w+")`, however this specific behaviour is not intuitive to those first
learning how to work with file systems. We can attempt to abstract this away with another wrapper, or simply write
the file structure to handle this behaviour properly. The downside to this method overall is that it will break
common conventions of how humans interpret filesystems and the related control flow logic. What we can do is force the
`'+'` flag to always be present for write operations, and raise an error when desired, if the file is not empty. This
This issue can be solved using `fopen("<file>", "a+")` and `ftell`, however this specific behaviour is not intuitive to
those first learning how to work with file systems. We can attempt to abstract this away with another wrapper, or simply
write the file structure to handle this behaviour properly. The downside to this method overall is that it will break
common conventions of how humans interpret filesystems and the related control flow logic. What we can do is force the
`'+'` flag to always be present for write operations, and raise an error when desired, if the file is not empty. This
unfortunately would have the downside of being unable to open a file as write only.
Using `"wx"` in this instance would not be sufficient since it would require a second call to fopen, which would
Using `"wx"` in this instance would not be sufficient since it would require a second call to fopen, which would
create the conditions for the TOCTOU error described above.
Another issue arises when we are parsing a directory tree. The best we can do is take ownership of the directory that
is opened as the root. However, this requires `dirent.h` which is not implemented in MSVC. A custom implementation of
`dirent.h` may be written for MSVC, however this is one of the few things I am not willing to outsource to another
library. Developing our own implementation would take a non-insignificant amount of time, between writing the library,
debugging it, and testing for vulnerabilities. As stated above, this implementation is native to MinGW and Cygwin,
so we would not have to entirely drop support for Windows. However, MSVC is the most widely used compiler for Windows
Another issue arises when we are parsing a directory tree. The best we can do is take ownership of the directory that
is opened as the root. However, this requires `dirent.h` which is not implemented in MSVC. A custom implementation of
`dirent.h` may be written for MSVC, however this is one of the few things I am not willing to outsource to another
library. Developing our own implementation would take a non-insignificant amount of time, between writing the library,
debugging it, and testing for vulnerabilities. As stated above, this implementation is native to MinGW and Cygwin,
so we would not have to entirely drop support for Windows. However, MSVC is the most widely used compiler for Windows
applications and is native to Visual Studio and VSCode.
What is probably the best solution is to wrap everything in a file interface that does not allow the direct setting of
What is probably the best solution is to wrap everything in a file interface that does not allow the direct setting of
these flags. Then we set our own usage type for the file that informs which flags should be used.
We need to be able to handle the following types of files:
- Assets, such as scenes, audio, textures, metadata, meshes, etc.
- Save files, setting files, etc.
One of the nice things about the assets is that they are guaranteed to be read-only once an application is installed
One of the nice things about the assets is that they are guaranteed to be read-only once an application is installed
on the computer of the end-user. Therefore, this issue only arises with save files and custom file formats.
When the editor is run, all these files should be opened in read/write mode.
Naming conventions should exist for the types of files and how they are read. For example, in release mode,
most assets should be opened once, and then closed immediately. However, this does not make sense for formats
Naming conventions should exist for the types of files and how they are read. For example, in release mode,
most assets should be opened once, and then closed immediately. However, this does not make sense for formats
that are continuous and too large to be kept around in memory, such as video formats.
Perhaps the following conventions:
@@ -120,23 +121,41 @@ Perhaps the following conventions:
- Stream Asset
- Resource
We can turn this into an object-oriented approach by having different formats inherit these base types. We may still
We can turn this into an object-oriented approach by having different formats inherit these base types. We may still
have a base file type that wraps C functionality, but discourage developers from using the interface.
We could also declare the file interface extern so that only internal files know the implementation. However, I would
We could also declare the file interface extern so that only internal files know the implementation. However, I would
not be satisfied by doing this since it would prevent developers from implementing custom file type implementations.
Conserving memory is not really an issue here as long as we are smart about our implementation. Files should only be
open when necessary and be closed when it is no longer necessary to have them open.
Conserving memory is not really an issue here as long as we are smart about our implementation. Files should only be
open when necessary and be closed when it is no longer necessary to have them open. Data should be streamed unless the
all the data in the file is required.
When built in release mode, we also need to pack static assets into some sort of archive that is mountable to reduce
disk space consumption of a program. I am considering encryption for archives, but there likely is not much of a point.
When built in release mode, we also need to pack static assets into some sort of archive that is mountable to reduce
disk space consumption of a program.
I was considering encryption for archives, however it does not make much sense. Assuming someone intends to pirate the
game, there is not much stopping them from running the files. I will add Steam support at some point which would allow
you to use Steam's DRM to prevent the executable from being run. Otherwise, there is no point in attempting to encrypt
game files. Even Unreal PAK files can be cracked in seconds, and even if I managed to write something that cannot be
trivially cracked locally, you can scrape most assets from the GPU and Audio Card.
I have managed to solve the specific case provided at the top of this section, which was done by wrapping C I/O calls
into a file wrapper. This wrapper can handle a few different mode flags and has specific conditions for the flags. See
the documentation for `fennec/fproc/io/file.h` for more info.
One question remains unanswered on this front; should a read/write file open as `r+` or `a+`. `rewind` is slightly faster
than `fseek(SEEK_END)`, however for the case of save files and editor assets, `r+` makes more sense from a usage perspective
Directories remain an issue, with `dirent.h` being the only sensible option at time of writing. The issue with using
`dirent.h` boils back down to security issues on Windows. However, the only option is to write a custom implementation
for MSVC.
## C++ Language Library (`lang`)
Implement header files for standard functions relating to the C++ Language.
So far this is implemented on an as-needed basis. A full implementation should be worked on continuously.