Nitrocid Filesystem
Let's go deeper into the filesystem functionality!
Last updated
Let's go deeper into the filesystem functionality!
Last updated
Generally, Nitrocid KS offers the fully-fledged filesystem functionality that allows you to perform filesystem operations ranging from simple to complex, like copying files to checking their lock state. This is done with the assistance of the kernel drivers, which we covered previously in the below page:
Your mods can access this, too! However, we'll walk you through the Nitrocid filesystem class hierarchy:
Nitrocid.Files
This is the general filesystem namespace containing security-related checks for the validity and openness of the files, like lock checks, which are found in the FilesystemTools
class.
Nitrocid.Files.Attributes
This is the namespace responsible for the attribute management for files.
Nitrocid.Files.Editors
This is the namespace that holds the tools for type-specific text file editing tools
Nitrocid.Files.Extensions
This is the namespace responsible for the extension management for files.
Nitrocid.Files.Folders
This is the namespace that specializes with the listing of folders and querying the current directory.
Nitrocid.Files.Instances
This is the namespace that holds filesystem-related classes.
Nitrocid.Files.LineEndings
This is the namespace responsible for the management of the line endings for text files.
Nitrocid.Files.Operations
This is the namespace which houses common filesystem operations, such as making, copying, opening, or deleting files and folders.
Nitrocid.Files.Paths
This is the namespace that is responsible for the management of the kernel path system and the path lookup system.
We advice you not to use LineEndings
functions on binary files, since they sometimes contain line endings and they may mess with these binary files. Security measures will ensure that these functions throw before any operation is made.
For your mods, access to certain filesystem operations require that you consent to accessing your files. This is to ensure increased privacy.
To learn more about all the available API functions regarding the filesystem, click here.
Every filesystem operation committed within the KS.Files
namespace and its functions get their paths checked with the path neutralizer to make a unified version of the path to point to the file relative to either the current path according to the filesystem routine or to the absolute path provided to the neutralizer. This neutralizer is called Filesystem.NeutralizePath()
.
However, the neutralizer also checks for the validity of the path as a mitigation to the Windows 10 NTFS corruption and forced BSOD bugs by calling the ThrowOnInvalidPath()
function.
If the conditions were met:
Attempting to access a Windows path including $i30
, which is the NTFS volume bitmap, or
Attempting to open the kernelconnect
node on condrv
using a specially crafted path,
The checker will throw a KernelException
with the KernelExcceptionType
of Filesystem
stating that the attempt of accessing these paths is invalid.
Optionally, the functions also make use of the file and folder lock checking mechanisms by invoking one of these functions:
IsFileLocked()
IsFolderLocked()
IsLocked()
WaitForLockRelease()
WaitForLockReleaseIndefinite()
Consult the above link to the API reference for more info about how to use these functions to check the lock on your target file.
FileSystemEntry
contains necessary information about your file or folder, like checking to see if it exists, determining the type of the entry, and so on. These are the information currently available, but you can obtain more information using the BaseEntry
property:
Exists
: Checks to see if the file or directory exists
Type
: The type of the filesystem entry. This is only populated once.
OriginalFilePath
: The original file path that was passed to the constructor
FilePath
: The neutralized file path
FileSize
: The file size. This property's value is -1 if the entry is a directory or non-existent
BaseEntryUnprocessed
: The base entry from the unprocessed file path
BaseEntry
: The base entry from the neutralized file path
You can create a new instance of this class, assuming that you've imported the Nitrocid.Files.Instances
namespace, by simply calling the constructor like below:
You don't need to neutralize the path before making a new instance of this class; it'll neutralize your path and you can access both the original and the neutralized paths.
The Nitrocid filesystem provides you with an option to open the files deterministically without opening the hex editor on binary files using the extension handlers. Currently, only the interactive file manager (IFM) uses this feature to open any file.
Handling extensions consists of a class, called ExtensionHandler
, that contains information about how to open the file ending in a specific extension, and has the following properties:
Extension
File extension that is being handled
MimeType
MIME type of the extension
Implementer
The extension handler implementer name (can also be used as a codename for the handler)
Handler
A function to execute with the full path to the requested file as the first argument
InfoHandler
A function get information from a file and render said information to a string instance
You can register your custom handler using the RegisterHandler()
function found in the ExtensionHandlerTools
class. This way, next time IFM opens up a file with an extension that contains your handler, it will execute your own custom handler.
Additionally, any mod that uses OpenDeterministically()
on a file will trigger your custom handlers.
Make sure that you unregister all your handlers when unloading your mod. RegisterHandler()
throws if it discovers that your handler that handles your specific extension is already added to the list of handlers.
For the list of default handlers, they get saved to the ExtensionHandlers.json
file. These handlers get used everytime a request to GetExtensionHandler(string extension)
function is made.
You can read from a file or write to a file using the Nitrocid API to get its contents or write your own content to a file. The file paths are always neutralized to your current working directory, unless you specify a rooted path (absolute path).
The following writing APIs are available:
WriteContents()
Useful if you have an array of text
WriteContentsText()
Useful if you have a plain text
WriteAllLinesNoBlock()
Useful if you have an array of text and want a non-blocking write
WriteAllTextNoBlock()
Useful if you have a plain text and want a non-blocking write
WriteAllBytes()
Useful for writing binary files
The following reading APIs are available:
ReadContents()
Useful if you have a text file and want to parse it line by line
ReadContentsText()
Useful if you have a text file and want to parse it as a whole string
ReadAllLinesNoBlock()
Useful if you have a text file and want to parse it line by line with a non-blocking read
ReadAllTextNoBlock()
Useful if you have a text file and want to parse it as a whole string with a non-blocking read
ReadAllBytes()
Useful for reading binary files
You can decode and encode files using the below commands:
decodefile <file> [algorithm]
encodefile <file> [algorithm]
Encoded files using the default encoding algorithm are saved to <file>.encoded
, and the decoded files are saved to the original file name without the .encoded
prefix.
When you print file contents to the console or render it as a string for preview, you may need to use one of the FileContentPrinter
functions. However, it depends on your goal:
If you want to print the file content to the console deterministically, use the Display*()
functions.
If you just want to synthesize a string of how it would appear as previewed for different purposes, like previewing a file in an informational box, use the Render*()
functions.
Additionally, the Extensions
part of the filesystem feature contains a mechanism that allows you to manipulate with the MIME metadata.
You can get the MIME type from an extension using the GetMimeType()
function.
The supported MIME types are available here.
Symbolic links are shortcuts to a single file or directory that simplify the path to the target file or folder. They are useful for many purposes.
To make a symbolic link, you can use the MakeSymlink()
function and its Try
counterpart from the Making
class from the Operations
namespace. This function takes two arguments:
The link name specifies a path to the symbolic link. This name must not exist.
The link target specifies a path to an existent file or folder.
The Nitrocid.Files.Paths
namespace contains a group of functions that allow you to use the pre-defined kernel paths and custom paths. The pre-defined kernel paths can be get by either getting a value from its associated property, such as AddonsPath
, or by using the GetKernelPath()
function.
The custom paths can be registered and unregistered by using the functions that are outlined below:
If you want to define your own custom path, you must register the kernel path with a file or folder that you choose. It's not necessarily a file or a folder that exists, since you may create it in your mod. After the registration, you can use the GetKernelPath()
function to give it a name of your registered path type.
The base filesystem driver implements three copying and moving modes:
Copying and moving a source file to a destination
Copying and moving a source directory to a destination
Copying and moving a source file or directory to a destination
When copying or moving a file or directory, the functions first check for the source to check to see if it's a file, a directory, or both, depending on the function used. For example, if you're copying a directory to a destination, you can use either CopyFileOrDir()
or CopyDirectory()
, but not CopyFile()
.
The TryCopy*()
and the TryMove*()
functions return true
if copying or moving is successful, and false if the operation failed. The normal Copy*()
and the Move*()
functions throw an exception if any failure occurs.
The file manager includes two separate TUIs that allow you to select a file or a folder conveniently. We'll explain what do the two selectors do and how they work.
When it comes to file selection, there is a function dedicated to opening the file selector effortlessly, called SelectFile()
, which you can find its two signatures below:
When the selector is open, you can do almost all the things, just like in the normal file management TUI, but with some of the features removed, such as copying and moving to the secondary pane.
To select a file, you can press Enter
to select it. Then, you'll have to exit it manually to save the selected file, thus making SelectedFile
return a selected file.
Like the file selector, but it also allows you to select more than one file to allow your mod to perform various operations on these files, such as bulk copying the selected files to a single target directory.
There is a function that allows you to use this kind of selector, called SelectFiles()
.
To select a file, press Enter
to select it. Once you're done selecting various files, you'll have to exit it manually to save the selected files, thus making SelectedFiles
return a list of selected files.
When the folder selector is open using the SelectFolder()
function, you can select a folder effortlessly by pressing the spacebar on the target directory highlighted.
After that, you can press Esc
to save the selected folder and pass it to the application, which it can access the selected folder value using the SelectedFolder
property.
Like the folder selector, but it also allows you to select more than one folder to allow your mod to perform various operations on these folders, such as bulk copying the selected folders to a single target directory.
There is a function that allows you to use this kind of selector, called SelectFolders()
.
To select a file, press Space
to select it. Once you're done selecting various folders, you'll have to exit it manually to save the selected folders, thus making SelectedFolders
return a list of selected folders.