> ## 10. The Flash File System

> Dynamic C 7.0 introduced a simple file system that can be used with a second flash memory or in SRAM. Dynamic C 7.05 introduced an improved file system with more features:

> - The ability to overwrite parts of a file.
> - The simultaneous use of multiple device types.
> - The ability to partition devices.
> - Efficient support for byte-writable devices.
> - Better performance tuning.
> · High degree of backwards compatibility with its predecessor.

> This file system, known as the filesystem mk II or simply as FS2, uses the same API as the first file system, with some additional functions. Initialization is performed slightly differently, and the data format is not compatible. Z-World recommends that FS2 be used for all new applications. The first file system, which we will refer to as FS1, will be maintained but enhancements will only be implemented for FS2.

> The Dynamic C file system supports a total of 255 files. Unlike FS1, it is not possible to "reserve" a range of file numbers for system use with FS2. Equivalent functionality is available via partitioning of devices.

> The low-level flash memory access functions should not be used in the same area of the flash where the flash file system exists.

> ### 10.1 General Usage

> The recommended use of a flash file system is for infrequently changing data or data rates that have writes on the order of tens of minutes instead of seconds. Rapidly writing data to the flash could result in using up its write cycles too quickly. For example, consider a 256K flash with 64 blocks of 4K each. Using a flash with a maximum recommendation of 10,000 write cycles means a limit of 640,000 writes to the file system. If you are performing one write to the flash per second, in a little over a week you will use up its recommended lifetime.

> Increase the useful lifetime and performance of the flash by buffering data before writing it to the flash. Accumulating 1000 single byte writes into one can extend the life of the flash by an average of 750 times. FS2 does not currently perform any in-memory buffering. If you write a single byte to a file, that byte will cause write activity on the device. This ensures that data is written to non-volatile storage as soon as possible. Buffering may be implemented within the application if possible loss of data is tolerable.

> #### 10.1.1 Maximum File Size

> The maximum file size for an individual file depends on the total file system size and the number of files present. Each file requires at least two sectors: at least one for data and always one for metadata (for information used internally). There also needs to be two free sectors to allow for moving data around. It is not recommended to use the flash file system to store a large number of small files. It is much more efficient to have a few large ones.

> #### 10.1.2 Using SRAM

> The flash file system can be used with battery-backed SRAM. Internally, RAM is treated like a flash device, except that there is no write-cycle limitation, and access is much faster. The file system will work without the battery backup, but would, of course, lose all data when the power went off.

> Currently, the maximum size file system supported in RAM is about 200k. This limitation holds true even on boards with a 512k RAM chip. The limitation involves the placement of BIOS control blocks in the upper part of the lower 256k portion of RAM.

> To obtain more RAM memory, `xalloc()` may be used. If `xalloc()` is called first thing in the program, the same memory addresses will always be returned. This can be used to store non-volatile data is so desired (if the RAM is battery-backed), however, it is not possible to manage this area using the file system.

> When using FS1, since only one device type is allowed at a time, the entire file system would have to be in SRAM. This is recommended for debugging purposes only. Using FS2 increases flexibility, with its capacity to use multiple device types simultaneously. Since RAM is usually a scarce resource, it can be used together with flash memory devices to obtain the best balance of speed, performance and capacity.

> #### 10.1.3 Wear Leveling

> The current code has a rudimentary form of wear leveling. When you write into an existing block it selects a free block with the least number of writes. The file system routines copy the old block into the new block adding in the users new data. This has the effect of evening the wear if there is a reasonable turnover in the flash files.

> #### 10.1.4 Low-level Implementation

> For information on the low-level implementation of the flash file system, refer to the beginning of the library files `FS2.LIB` and `FS_DEV.LIB` if using FS2, or library file `FILESYSTEM.LIB`, if using FS1.

> #### 10.1.5 Multitasking and the File System

> Neither FS1 nor FS2 are re-entrant. If using preemptive multitasking, ensure that only one thread performs calls to the file system, or implement locking around each call.

> ### 10.2 Application Requirements

> The application requirements for FS1 and FS2 are slightly different. This section covers both sets of requirements, including:

> - which library to use
> - which drivers to use
> - defaults and descriptions for configuration macros
> - detailed instructions for using the first flash

> #### 10.2.1 FS1 Requirements

> To use the file system, a macro that determines which low-level driver is loaded must be defined in the application program.

>     #define FS_FLASH   // use 2nd flash for file system
>     #define FS_RAM     // use SRAM (supported for debug purposes)

> The file system library must be compiled with the application.

>     #use "FILESYSTEM.LIB"

> #### 10.2.2 FS1 and Use of the First Flash

> To use FS1 in the first flash, a low-level driver must be used:

>     #define FS_FLASH_SINGLE

> Because this particular low-level driver must share the first flash with the program code, the file system must be carefully placed such that the two do not collide. Also, it should be noted that any time the first flash is written to during runtime, interrupts will be shut off for the duration of the write. This could have serious implications for real-time systems.

> To reserve space in the first flash, such that Dynamic C will not clobber the file system, a minor BIOS modification is necessary. The macro `XMEM_RESERVE_SIZE` in the BIOS is currently set to 0x0000. Increasing this value will reserve that much space between the end of xmem-code that Dynamic C is building, and the SystemID Block at the end of memory. Unfortunately, the file system needs to start on a `FS_BLOCK_SIZE` boundary, which is normally 4096 bytes. Therefore, slightly more space than is needed should be allocated, to allow for the SystemID Block and that the end of xmem space might not lie on a 4096 byte boundary.

> After this space has been allocated, the location of the file system's beginning can be found. The end of where Dynamic C will touch the flash is stored in the macro `END_OF_XMEMORY`, and the file system may start at the next 4096 byte boundary after that point. The following code computes what to pass to `fs_format()`.

>     long fs_start;                       // where to start the file system
>     fs_start = END_OF_XMEMORY;           // start at the end of xmem
>     fs_start = fs_start / FS_BLOCK_SIZE; // divide out the blocksize, to meet
>                                          // requirements for fs_format
>     if((fs_start * FS_BLOCK_SIZE) != END_OF_XMEMORY) {
>        fs_start++;                       // rounding error: move up 1 block so
>                                          // end of xmem is not clobbered
>     }
>     fs_format(fs_start, NUM_BLOCKS, 0);

> After this point, the file system should act normally.

> If the 4096 byte block size is too large, given the limited room in the first flash, that can be overwritten with the macro:

>     #define FS_BLOCK_SIZE 512

> See the sample program, `1stflash.c`, for an example of using the first flash with FS1.

> #### 10.2.3 FS2 Requirements

> The file system library must be compiled with the application:

>     #use "FS2.LIB"

> For the simplest applications, this is all that is necessary for configuration. For more complex applications, there are several other macro definitions that may be used before the inclusion of `FS2.LIB`. These are:

>     #define FS_MAX_DEVICES   3
>     #define FS_MAX_LX        4
>     #define FS_MAX_FILES    10

> These specify certain static array sizes that allow control over the amount of root data space taken by FS2. If you are using only one flash device (and possibly battery-backed RAM), and are not using partitions, then there is no need to set `FS_MAX_DEVICES` or `FS_MAX_LX`.

> For more information on partitioning, please see section 10.4, "Setting up and Partitioning the File System," on page 106.

> #### 10.2.4 FS2 Configuration Macros

> ##### FS_MAX_DEVICES

> This macro defines the maximum physical media. If it is not defined in the program code, `FS_MAX_DEVICES` will default to 1, 2, or 3, depending on the values of `FS2_USE_PROGRAM_FLASH`,`` `XMEM_RESERVE_SIZE` and `FS2_RAM_RESERVE`.

> ##### FS_MAX_LX

> This macro defines the maximum logical extents. You must increase this value by 1 for each new partition your application creates. It this is not defined in the program code it will default to `FS_MAX_DEVICES`.

> For a description of logical extents please see section 10.4.2, "Logical Extents (LX)," on page 107.

> ##### FS_MAX_FILES

> Default: 6. This macro is used to specify the maximum number of files that are allowed to coexist in the entire file system. Most applications will have a fixed number of files defined, so this parameter can be set to that number to avoid wasting root data memory. The default is 6 files. The maximum value for this parameter is 255.

> ##### FS2_RAM_RESERVE

> This BIOS-defined macro determines the amount of space used for FS2 in RAM. If some battery-backed RAM is to be used by FS2, then this macro must be modified to specify the amount of RAM to reserve. The memory is reserved near the top of RAM. Note that this RAM will be reserved whether or not the application actually uses FS2.

> Prior to Dynamic C 7.06 this macro was defined as the number of bytes to reserve and had to be a multiple of 4096. It is now defined as the number of blocks to reserve, with each block being 4096 bytes.

> ##### FS2_USE_PROGRAM_FLASH

> The number of kilobytes reserved in the first flash for use by FS2. The default is zero. The actual amount of flash used by FS2 is determined by the minimum of this macro and `XMEM_RESERVE_SIZE`.

> The first flash may be used in FS1as well. See section 10.2.2 for details.

> ##### XMEM_RESERVE_SIZE

> The number of bytes (which must be a multiple of 4096) reserved in the first flash for use by FS2 and possibly other customer-defined purposes. This is defined in the BIOS as 0x0000. Memory set aside with `XMEM_RESERVE_SIZE` will NOT be available for xmem code.

> #### 10.2.5 FS2 and Use of the First Flash

> To use the first flash in FS2, follow these steps:

> - Define `XMEM_RESERVE_SIZE` (currently set to 0x0000 in the BIOS) to the number of bytes to allocate in the first flash for the file system.

> - Define `FS2_USE_PROGRAM_FLASH` to the number of KB (1024 bytes) to allocate in the first flash for the file system. Do this in the application code before `#use` `"fs2.lib"`.

> - Obtain the LX number of the first flash: Call `fs_get_other_lx()`when there are two flash memories; call `fs_get_flash_lx()` when there is only one.

> - If desired, create additional logical extents by calling the FS2 function `fs_setup()` to further partition the device. This function can also change the logical sector sizes of an extent. Please see the function description for `fs_setup()` in the Dynamic C Function Reference Manual for more information.

> #### 10.2.5.1 Example Code Using First Flash in FS2

> If the target board has two flash memories, the following code will cause the file system to use the first flash:

>     FSLXnum flash1;
>     File f;

>     flash1 = fs_get_other_lx();
>     if (flash1) {
>        fs_set_lx(flash1, flash1);
>        fcreate(&f, 10);
>        . . .
>     }

> To obtain the logical extent number for a one flash board, `fs_get_flash_lx()` must be called instead of `fs_get_other_lx()`.

> ### 10.3 Functions

> For backwards compatibility FS2 uses the same function names as FS1. Some functions have enhanced semantics when using FS2. For example `fwrite()` will allow writing over existing parts of the file rather than just appending.

> #### 10.3.1 FS1 API

> These functions are the file system API for FS1. They are defined in `FILESYSTEM.LIB`. For a complete description of these functions please see the Dynamic C Function Reference Manual.

> Table 10. FS1 API
> Command | Description
> `fs_init (FS1)` | Initialize the internal data structures for the file system.
> `fs_format (FS1)` | Initialize the flash memory and the internal data structures.
> `fs_reserve_blocks (FS1)` | Reserves blocks for privileged files.
> `fsck (FS1)` | Verifies data integrity of files.
> `fcreate (FS1)` | Creates a file and open it for writing.
> `fcreate_unused (FS1)` | Creates a file with an unused file number.
> `fopen_rd (FS1)` | Opens a file for reading.
> `fopen_wr (FS1)` | Opens a file for writing (also opens it for reading.)
> `fshift` | Removes specified number of bytes from file.
> `fwrite (FS1)` | Writes to the end of a file.
> `fread (FS1)` | Reads from the current file pointer.
> `fseek (FS1)` | Moves the read pointer.
> `ftell (FS1)` | Returns the current offset of the file pointer.
> `fclose` | Closes a file.
> `fdelete (FS1)` | Deletes a file.

> #### 10.3.1.1 FS1 API Details

> The functions `fs_init` and `fs_format` are similar, in that they both start the file system. Use `fs_format` to erase all blocks in the file system. This function's third parameter, `wearlevel`, should be `1` for a new flash memory; otherwise it should be `0` to use the current wear leveling.

> Use `fs_init` to preserve blocks that are in use and to do an integrity check of them. In case of loss of power, `fs_init` will delete any blocks that may be partially written and will substitute the last known good block for that file. This means that any changes to the file that occurred between the last write and the power outage would be lost.

> #### 10.3.2 FS2 API

> The API for FS2 is defined in `FS2.LIB`. For more information please see the Dynamic C Function Reference Manual.

> Table 11. FS2 API
> Command | Description
> `fs_setup (FS2)` | Alters the initial default configuration.
> `fs_init (FS2)` | Initialize the internal data structures for the file system.
> `fs_format (FS2)` | Initialize flash and the internal data structures.
> `lx_format` | Formats a specified logical extent (LX).
> `fs_set_lx (FS2)` | Sets the default LX numbers for file creation.
> `fs_get_lx (FS2)` | Returns the current LX number for file creation.
> `fcreate (FS2)` | Creates a file and open it for writing.
> `fcreate_unused (FS2)` | Creates a file with an unused file number.
> `fopen_rd (FS2)` | Opens a file for reading.
> `fopen_wr (FS2)` | Opens a file for writing (and reading).
> `fshift` | Removes specified number of bytes from file.
> `fwrite (FS2)` | Writes to a file starting at "current position."
> `fread (FS2)` | Reads from the current file pointer.
> `fseek (FS2)` | Moves the read/write pointer.
> `ftell (FS2)` | Returns the current offset of the file pointer.
> `fs_sync (FS2)` | Flushes any buffers retained in RAM to the underlying hardware device.
> `fflush (FS2)` | Flushes buffers retained in RAM and associated with the specified file to the underlying hardware device.
> `fs_get_flash_lx (FS2)` | Returns the LX number of the preferred flash device (the 2nd flash if available).
> `fs_get_lx_size (FS2)` | Returns the number of bytes of the specified LX.
> `fs_get_other_lx (FS2)` | Returns LX # of the non-preferred flash (usually the first flash).
> `fs_get_ram_lx (FS2)` | Return the LX number of the RAM file system device.
> `fclose` | Closes a file.
> `fdelete (FS2)` | Deletes a file.

> #### 10.3.2.1 FS2 API Details

> The functions `fs_init` and `fs_format` are used in a slightly different manner than in FS1. `fs_init()` does not use its two parameters (`reserveblocks` and `numblocks`) since it computes appropriate values internally. `fs_format()` should only be called after `fs_init()`, if necessary. This function's first parameter, `reserveblocks`, must be 0; anything else returns an error. This is one of the few cases of incompatibility between FS1 and FS2. The third parameter, `wearlevel`, should be 1 for a new flash memory; otherwise it should be 0 to use the current wear leveling.

> The `fsck()` function is not available and is not needed in FS2; `fs_init()` always completely checks for internal consistency.

> Refer to `\SAMPLES\FILESYSTEM\FS2DEMO1.C` for more details.

> #### 10.3.2.2 FS2 API Error Codes

> When an API function returns an error, it may also return an error code in the global variable `errno`. The error codes are defined in the library file `ERRNO.LIB`.

> ### 10.4 Setting up and Partitioning the File System

> FS2 can be more complex to initialize than FS1. This is because multiple device types can be used in the same application. For example, if the target board contains both battery-backed SRAM and a second flash chip, then both types of storage may be used for their respective advantages. The SRAM might be used for a small application configuration file that changes frequently, and the flash used for a large log file.

> FS2 automatically detects the second flash device (if any) and will also use any SRAM set aside for the file system (if `FS2_RAM_RESERVE` is set).

> #### 10.4.1 Initial Formatting

> The filesystem must be formatted when it is first used. The only exception is when a flash memory device is known to be completely erased, which is the normal condition on receipt from the factory. If the device contains random data, then formatting is required to avoid the possibility of some sectors being permanently locked out of use.

> Formatting is also required if any of the logical extent parameters are changed, such as changing the logical sector size or re-partitioning. This would normally happen only during application development.

> The question for application developers is how to code the application so that it formats the filesystem only the first time it is run. There are several approaches that may be taken:

> - A special program that is loaded and run once in the factory, before the application is loaded. The special program prepares the filesystem and formats it. The application never formats; it expects the filesystem to be in a proper state.

> - The application can perform some sort of consistency check. If it determines an inconsistency, it calls format. The consistency check could include testing for a file that should exist, or by checking some sort of "signature" that would be unlikely to occur by chance.

> - Have the application prompt the end-user, if some form of interaction is possible.

> - A combination of one or more of the above.

> - Rely on a flash device being erased. This would be OK for a production run, but not suitable if battery-backed SRAM was being used for part of the filesystem.

> #### 10.4.2 Logical Extents (LX)

> In FS2, the presence of both "devices" causes an initial default configuration of two logical extents to be set up. An LX is analogous to disk partitions used in other operating systems. It represents a contiguous area of the device set aside for file system operations. An LX contains sectors that are all the same size, and all contiguously addressable within the one device. Thus a flash device with three different sector sizes would necessitate at least three logical extents, and more if the same-sized sectors were not adjacent.

> FS1 does not allow mixing of devices; it supports only one LX as defined in this document.

> Files stored by the file system are comprised of two parts: one part contains the actual application data, and the other is a fixed size area used to contain data controlled by the file system in order to track the file status. This second area, called metadata, is analogous to a "directory entry" of other operating systems. The metadata consumes one sector.

> The data and metadata for a file are usually stored in the same LX, however they may be separated for performance reasons. Since the metadata needs to be updated for each write operation, it is often advantageous to store the metadata in battery-backed SRAM with the bulk of the data on a flash device.

> #### 10.4.2.1 Specifying Logical Extents

> When a file is created, the logical extent(s) to use for the file are defined. This association remains until the file is deleted. The default LX for both data and metadata is the flash device (LX #1) if it exists; otherwise the RAM LX. If both flash and RAM are available, LX #1 is the flash device and LX #2 is the RAM.

> When creating a file, the associated logical extents for the data and the metadata can be changed from the default by calling `fs_set_lx()`. This functions takes two parameters, one to specify the LX for the metadata and the other to specify the LX for the data. Thereafter, all created files are associated with the specified LXs until a new call to `fs_set_lx()` is made. Typically, there will be a call to `fs_set_lx()` before each file is created, in order to ensure that the new file gets created with the desired associations. The file creation function, `fcreate()`, may be used to specify the LX for the metadata by providing a valid LX number in the high byte of the function's second parameter. This will override any LX number set for the metadata in `fs_set_lx()`.

> #### 10.4.2.1.1 Further Partitioning

> FS2 allows the initial default logical extents to be divided further. This must be done before calling `fs_init()`. The function to create sub-partitions is called `fs_setup()`. This function takes an existing LX number, divides that LX according to the given parameters, and returns a newly created LX number. The original partition still exists, but is smaller because of the division. For example, in a system with LX#1 as a flash device of 256K and LX#2 as 4K of RAM, an initial call to `fs_setup()` might be made to partition LX#1 into two equal sized extents of 128K each. LX#1 would then be 128K (the first half of the flash) and LX#3 would be 128K (the other half). LX#2 is untouched.

> Having partitioned once, `fs_setup()` may be called again to perform further subdivision. This may be done on any of the original or new extents. Each call to `fs_setup()` in partitioning mode increases the total number of logical extents. You will need to make sure that `FS_MAX_LX` is defined to a high enough value that the LX array size is not exceeded.

> While developing an application, you might need to adjust partitioning parameters. If any parameter is changed, FS2 will probably not recognize data written using the previous parameters. This problem is common to most operating systems. The "solution" is to save any desired files to outside the file system before changing its organization; then after the change, force a format of the file system.

> Note that in particular, files written by FS1 are not readable by FS2 since the two file systems are incompatible at the device level.

> #### 10.4.3 Logical Sector Size

> `fs_setup()` can also be used to specify non-default logical sector (LS) sizes and other parameters. FS1 uses fixed logical sectors (i.e. "blocks") of 4096 bytes. FS2 allows any LS size between 64 and 8192 bytes, providing the LS size is an exact power of 2. Each LX, including sub-partitions, can have a different LS size. This allows some performance optimization. Small LSs are better for a RAM LX, since it minimizes wasted space without incurring a performance penalty. Larger LSs are better for bulk data such as logs. If the flash physical sector size (i.e. the actual hardware sector size) is large, it is better to use a correspondingly large LS size. This is especially the case for byte-writable devices. Large LSs should also be used for large LXs. This minimizes the amount of time needed to initialize the file system and access large files. As a rule of thumb, there should be no more than 1024 LSs in any LX. The ideal LS size for RAM (which is the default) is 128 bytes. 256 or 512 can also be reasonable values for some applications that have a lot of spare RAM.

> Sector-writable flash devices require: LS size ≥ PS size. Byte-writable devices, however, may use any allowable logical sector size, regardless of the physical sector size.

> Sample program `SAMPLES\FILESYSTEM\FS2DEMO2` illustrates use of `fs_setup()`. This sample also allows you to experiment with various file system settings to obtain the best performance.

> FS2 has been designed to be extensible in order to work with future flash and other non-volatile storage devices. Writing and installing custom low-level device drivers is beyond the scope of this document, however see `FS2.LIB` and `FS_DEV.LIB` for hints.

> ### 10.5 File Identifiers

> There are two ways to identify a particular file in the file system: file numbers and file names.

> #### 10.5.1 File Numbers

> The file number uniquely identifies a file within a logical extent. File numbers must be unique within the entire file system. FS2 accepts file numbers in word format rather than the byte format of FS1:

>     typedef word FileNumber

> The low-order byte specifies the file number and the high-order byte specifies the LX number of the metadata (1 through number of LXs). If the high-order byte is zero, then a suitable "default" LX will be located by the file system. The default LX will default to 1, but will be settable via a `#define`, for file creation. For existing files, a high-order byte of zero will cause the file system to search for the LX that contains the file. This will require no or minimal changes to existing customer code.

> Only the metadata LX may be specified in the file number. This is called a "fully-qualified" file number (FQFN). The LX number always applies to the file metadata. The data can reside on a different LX, however this is always determined by FS2 once the file has been created.

> #### 10.5.2 File Names

> There are several functions in `ZSERVER.LIB` that can be used to associate a descriptive name with a file. The file must exist in the flash file system before using the auxiliary functions listed in the following table. These functions were originally intended for use with an HTTP or FTP server, so some of them take a parameter called `servermask`. To use these functions for file naming purposes only, this parameter should be `SERVER_USER`.

> For a detailed description of these functions please refer to the Dynamic C's TCP/IP User's Manual, or use <`CTRL-H`> in Dynamic C to use the Library Lookup feature.

> Table 12. Flash File System Auxiliary Functions
> Command | Description
> `sspec_addfsfile` | Associate a name with the flash file system file number. The return value is an index into an array of structures associated with the named files.
> `sspec_readfile` | Read a file represented by the return value of `sspec_addfsfile` into a buffer.
> `sspec_getlength` | Get the length (number of bytes) of the file.
> `sspec_getfileloc` | Get the file system file number (1- 255). Cast return value to `FILENUMBER`.
> `sspec_findname` | Find the index into the array of structures associated with named files of the file that has the specified name.
> `sspec_getfiletype` | Get file type. For flash file system files this value will be `SSPEC_FSFILE`.
> `sspec_findnextfile` | Find the next named file in the flash file system, at or following the specified index, and return the index of the file.
> `sspec_remove` | Remove the file name association.
> `sspec_save` | Saves to the flash file system the array of structures that reference the named files in the flash file system.
> `sspec_restore` | Restores the array of structures that reference the named files in the flash file system.

> ### 10.6 Skeleton Program Using FS1

> The following program uses many of the file system commands. It writes several strings into a file, reads the file back and prints the contents to the STDIO window. The macro `RESERVE` should be 0 when the file system is in SRAM. When the file system is in flash memory you can adjust where it starts by defining `RESERVE` to be 0 or a multiple of the block size.

> ###

>     #define FS_FLASH
>     #use "FILESYSTEM.LIB"

>     #define FORMAT

>     #define RESERVE  0L
>     #define BLOCKS  64
>     #define TESTFILE 1

>     main()
>     {
>        File file;
>        static char buffer[256];

>     #ifdef FORMAT
>        fs_format(RESERVE,BLOCKS,1);
>        if(fcreate(&file,TESTFILE)) {
>           printf("error creating TESTFILE\n");
>           return -1;
>        }
>     #else
>        fs_init(RESERVE,BLOCKS);
>        if(fopen_wr(&file,TESTFILE) {
>           printf("error opening TESTFILE\n");
>           return -1;
>        }
>     #endif
>        fwrite(&file,"hello",6);
>        fwrite(&file,"12345",6);
>        fwrite(&file,"67890",6);

>        while(fread(&file,buffer,6)>0) {
>           printf("%s\n",buffer);
>        }
>        fclose(&file);

>     }

> After running this program at least once, comment out "`#define FORMAT`". You will see that it runs in a similar fashion, but now the file is appended using `fopen_wr()` instead of being erased by `fs_format()` and then recreated with `fcreate()`.

> For a more robust program, more error checking should be included.

> ### 10.7 Skeleton Program Using FS2

> The following program uses some of the FS2 API. It writes several strings into a file, reads the file back and prints the contents to the STDIO window.

> ###

>     #use "FS2.LIB"

>     #define TESTFILE 1

>     main()
>     {
>        File file;
>        static char buffer[256];

>        fs_init(0, 0);

>        if (!fcreate(&file, TESTFILE) && fopen_wr(&file,TESTFILE)) {
>           printf("error opening TESTFILE %d\n", errno);
>           return -1;
>        }

>        fseek(&file, 0, SEEK_END);
>        fwrite(&file,"hello",6);
>        fwrite(&file,"12345",6);
>        fwrite(&file,"67890",6);

>        fseek(&file, 0, SEEK_SET);

>        while(fread(&file,buffer,6)>0) {
>           printf("%s\n",buffer);
>        }
>        fclose(&file);

>     }

> For a more robust program, more error checking should be included. See the sample programs `SAMPLES\FILESYSTEM\FS2DEMO?.C` for more complex examples which include error checking, formatting, partitioning and other new features.

> FS2 returns more information in the case of errors than FS1. The library `ERRNO.LIB` contains a list of all possible error codes returnable by the FS2 API. These error codes mostly conform to POSIX standards. If the return value of an FS2 API indicates an error, then the errno variable may be examined to determine a more specific reason for the failure. The possible errno codes returned from each function are documented with the function.

Z-World http://www.zworld.com Voice: (530) 757-3737 FAX: (530) 757-3792 sales@zworld.com