You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
7.7 KiB
309 lines
7.7 KiB
# File system
|
|
## Accessing the file system
|
|
|
|
The user interface to read and write files in `Ada_Drivers_Library` is located
|
|
in the `File_IO` package.
|
|
|
|
At initialization, there is no file system available, so you have to mount one
|
|
before using the operations described below. Please read the section `Mounting
|
|
a file system` to learn how to add a file system.
|
|
|
|
### Opening a file
|
|
|
|
To open a file, use the `Open` function:
|
|
|
|
```ada
|
|
FD : File_Descriptor;
|
|
begin
|
|
if Open (FD, "/host/tmp/file.txt", Read_Only) /= OK then
|
|
-- Error handling...
|
|
end if;
|
|
```
|
|
|
|
You can open the file in `Read_Only`, `Write_Only` or `Read_Write` mode.
|
|
|
|
### Reading from a file
|
|
|
|
Once the file descriptor is open in `Read_Only` or `Read_Write` mode you can
|
|
use the `Read` function to get data from the file:
|
|
|
|
```ada
|
|
|
|
Data : HAL.UInt8_Array (1 .. 10);
|
|
begin
|
|
if Read (FD, Data'Address, Data'Length) /= Data'Length then
|
|
-- Error handling...
|
|
end if;
|
|
```
|
|
|
|
This uses the `'Address` attribute to get the address of the data in memory.
|
|
You also have to specify the size of the data in number of bytes. The return
|
|
value is the number of bytes actually read.
|
|
|
|
A a safer and cleaner alternative is to use the generic function `Generic_Read`
|
|
and instantiate it for the type of data that you want to read:
|
|
|
|
```ada
|
|
type Custom_Type is [...];
|
|
|
|
function Read is new Generic_Read (Custom_Type);
|
|
Data : Custom_Type;
|
|
begin
|
|
if Read (FD, Data) /= OK then
|
|
-- Error handling...
|
|
end if;
|
|
```
|
|
|
|
### Writing to a file
|
|
|
|
Writing operations are very similar to the reading operations:
|
|
|
|
```ada
|
|
|
|
Data : HAL.UInt8_Array (1 .. 10) := (others => 0);
|
|
begin
|
|
if Write (FD, Data'Address, Data'Length) /= Data'Length then
|
|
-- Error handling...
|
|
end if;
|
|
```
|
|
|
|
And the generic version:
|
|
|
|
```ada
|
|
type Custom_Type is [...];
|
|
|
|
function Write is new Generic_Write (Custom_Type);
|
|
Data : Custom_Type;
|
|
begin
|
|
if Write (FD, Data) /= OK then
|
|
-- Error handling...
|
|
end if;
|
|
```
|
|
|
|
### Seek and Offset
|
|
|
|
You can use the `Offset` and `Seek` function to manipulate the file descriptor
|
|
offset.
|
|
|
|
`Offset` will give you the current value of the Offset.
|
|
|
|
```ada
|
|
Current_Offset : File_Size;
|
|
begin
|
|
Current_Offset := Offset (FD);
|
|
```
|
|
|
|
The function `Seek` is used to change the offset:
|
|
|
|
```ada
|
|
Amount : File_Size := 10;
|
|
begin
|
|
if Seek (FD, Forward, Amount) /= OK then
|
|
-- Error handling...
|
|
end if;
|
|
```
|
|
|
|
There are 4 seek modes available:
|
|
- `Forward`: Increase the offset by the given `Amount`
|
|
- `backward`: Decrease the offset by the given `Amount`
|
|
- `From_Start`: Set to offset to `Amount`
|
|
- `From_End`: Set the offset to the size of the file minus `Amount`
|
|
|
|
### Flush
|
|
|
|
Use `Flush` to force all buffered data to be written on the file.
|
|
|
|
### Close file
|
|
|
|
Use `Close` to close the file descriptor and free the associated resources.
|
|
|
|
### Opening a directory
|
|
|
|
To open a directory, use the `Open` function:
|
|
|
|
```ada
|
|
DD : Directory_Descriptor;
|
|
begin
|
|
if Open (DD, "/host/tmp/") /= OK then
|
|
-- Error handling...
|
|
end if;
|
|
```
|
|
|
|
### Traversing a directory
|
|
|
|
Use the `Read` function read a `Directory_Entry`:
|
|
|
|
```ada
|
|
type Directory_Entry (Name_Length : Natural) is record
|
|
Name : String (1 .. Name_Length);
|
|
Subdirectory : Boolean;
|
|
Read_Only : Boolean;
|
|
Hidden : Boolean;
|
|
Symlink : Boolean;
|
|
Size : File_Size;
|
|
end record;
|
|
```
|
|
|
|
Be careful, `Directory_Entry` is a discriminated type which means that once you
|
|
have declared a variable of this type you can only assign a value with the same
|
|
discriminant.
|
|
|
|
For this reason, it's safer to always declare a new variable for each call to
|
|
`Read`. Here is a typical example of how to traverse all the entries of a
|
|
directory:
|
|
|
|
```ada
|
|
loop
|
|
declare
|
|
E : constant Directory_Entry := Read (DD);
|
|
begin
|
|
|
|
exit when E = Invalid_Dir_Entry;
|
|
|
|
-- Use the directory entry here
|
|
|
|
end;
|
|
end loop;
|
|
```
|
|
|
|
Once you went through all the entries of the directory, the `Read` function
|
|
will return `Invalid_Dir_Entry`.
|
|
|
|
You can use the `Reset` function to start reading from the first entry again.
|
|
|
|
### Close directory
|
|
|
|
Use `Close` to close the directory descriptor and free the associated resources.
|
|
|
|
## Mounting a file system
|
|
|
|
To mount a file system you will need a file system driver. Please find below
|
|
detailed instructions on how to instantiate and mount the different file
|
|
systems available in `Ada_Drivers_Library`.
|
|
|
|
```Ada
|
|
if Mount_Volume ("mount_point", A_File_System_Driver) /= OK then
|
|
-- Error handling...
|
|
end
|
|
```
|
|
|
|
You can now access file in the volume, for example `/mount_point/tmp/file.txt`.
|
|
|
|
## Mounting a drive
|
|
|
|
It is also possible to mount a disk drive that has one or more file system.
|
|
Please note that for the moment only FAT file systems are supported.
|
|
|
|
In `Ada_Drivers_Library` disk drive are accessed with a `Block_Driver` interface.
|
|
|
|
```Ada
|
|
if Mount_Drive ("mount_point", A_Block_Driver) /= OK then
|
|
-- Error handling...
|
|
end if;
|
|
```
|
|
|
|
## File system drivers available
|
|
|
|
### File Allocation Table (FAT) drives
|
|
|
|
`Work in progress...`
|
|
|
|
### ARM Semihosting file system
|
|
|
|
The ARM semihosting file system driver uses the [ARM semihosting
|
|
interface](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/Bgbjhiea.html)
|
|
to provide a bridge to the host file system.
|
|
|
|
It is implemented in the package `Semihosting.Filesystem`.
|
|
|
|
#### Limitation
|
|
|
|
Given the semihosting operation available, it is not possible to implement a
|
|
complete file system driver, for instance listing files in a directory. However
|
|
this implementation allows you to open, read and write files on the host
|
|
computer.
|
|
|
|
#### How to mount an ARM semihosting file system
|
|
|
|
To use the ARM semihosting file system you first have to declare it:
|
|
|
|
```ada
|
|
|
|
with Semihosting.Filesystem; use Semihosting.Filesystem;
|
|
|
|
package body My_Package is
|
|
|
|
Semihosting_FS : aliased SHFS;
|
|
|
|
```
|
|
|
|
and finally, mount the file system:
|
|
|
|
```ada
|
|
if Mount_Volume ("host", Semihosting_FS'Access) /= OK then
|
|
-- Error handling
|
|
end if;
|
|
```
|
|
|
|
You can now use the `File_IO` package to access the host file system.
|
|
|
|
For instance, opening `/host/tmp/test.txt` with `File_IO.Open` will actually
|
|
open `/tmp/test.txt` on the host machine.
|
|
|
|
### Native file system
|
|
|
|
The native file system is used on non embedded platform (Windows, Linux, etc.)
|
|
to provide access to the OS file system through the common interface of
|
|
`Ada_Drivers_Library`. This is mostly useful for testing purposes.
|
|
|
|
It is implemented in the package `Filesystem.Native`.
|
|
|
|
#### How to mount a native file system
|
|
|
|
To use the native file system you first have to declare it:
|
|
|
|
```ada
|
|
|
|
with Filesystem.Native; use Filesystem.Native;
|
|
|
|
package body My_Package is
|
|
|
|
Native_FS : aliased Native_FS_Driver;
|
|
|
|
```
|
|
|
|
then use the `Create` function to specify which directory on the host file
|
|
system will be the root of the Native file system driver:
|
|
|
|
```ada
|
|
if Native_FS.Create ("/home/username") /= OK then
|
|
-- Error handling
|
|
end if;
|
|
```
|
|
|
|
and finally, mount the file system:
|
|
|
|
```ada
|
|
if Mount_Volume ("mount_point", FS'Access) /= OK then
|
|
-- Error handling
|
|
end if;
|
|
```
|
|
|
|
You can now use the `File_IO` package to access the native file system.
|
|
|
|
For instance, opening `/mount_point/test.txt` with `File_IO.Open` will actually
|
|
open `/home/username/test.txt` on your machine.
|
|
|
|
### Writing a new driver
|
|
|
|
You may want to write your own file system driver because you use a custom
|
|
format or if you want add support for a format that is not available in
|
|
`Ada_Drivers_Library`.
|
|
|
|
File system drivers have to implement the `HAL.Filesystem.Filesystem_Driver`
|
|
interface.
|
|
|
|
If your file system is located on a disk drive or any other type of mass
|
|
storage device, the driver must use the `HAL.Block_Driver` interface to make
|
|
sure that the code can be re-used on different drives. The FAT driver is an
|
|
example of that.
|
|
|