# minixfs

Minix v2 filesystem implementation

Author | Sebastien Lelong, Copyright © 2011, all rights reserved.
Adapted-by |
Compiler | 2.4o

Description

    Minix v2 implementation
    Partitions aren't supported, so you have to create a filesystem on the whole
    available memory. Typically, instead of "mkfs.minix -v /dev/sdX1", you'll
    have to "mkfs.minix -v /dev/sdX" (and remove sdX1 partition with fdisk)
    Some useful commands:
     - fsck.minix -f -v -s /dev/sdX
          will print Super-Block and some other information about files, dirs, state
     - hexdump -C /dev/sdX
          will dump Minix FS content (only changing lines)
     - hexdump -v -C /dev/sdX
          will do the same, but dump all lines, even if identical
    .
    In order to test your setup, you can untar minix_data.tar.bz2 available at:
    ...
    This archive contains directories and files of different size, used to test
    data zone and helping to understand how Minix filesystem is designed.
       1. prepare your device, no partition (replace /dev/sdX with appropriate device):
             mkfs.minix -v /dev/sdX
             mount /dev/sdX /mnt/tmp
       2. untar test data:
             cd /mnt/tmp && tar xjfv path/to/minix_data.tar.bz2
             cd && umount /mnt/tmp
       3. check content:
             fsck.minix -f -v -s /dev/sdX
          should report something like (1GB SD-card used here):
    .
    Forcing filesystem check on /dev/sdX.
    65535 inodes
    992000 blocks
    Firstdatazone=4227 (4227)
    Zonesize=1024
    Maxsize=2147483647
    Filesystem state=1
    namelen=30
    .
        20 inodes used (0%)
     70858 zones used (7%)
    .
        16 regu
        16 regular files
         2 directories
         0 character device files
         0 block device files
         1 links
         2 symbolic links
         ------
         21 files
    .
    Vocabulary: these are the terms I'm using in this code, may be wrong...
       * storage:  this is the underlying storage layer. Link between MinixFS and storage is done
                   by creating aliases to some spefici proc/funcs. Typically, storage is sd_card.jal
                   library. It could also be hard-disk too.
       * sector:   this is a unit in underlying storage (eg. for SD cards, 512 bytes)
       * block:    this is a unit in minixfs (typically 1024 bytes, that is, 2 * sector's size with SD cards)
       * zone:     same as a block in case of Minix v2
       * inode:    well, that's an inode, a kind of meta description of a file
       * file descriptor: a structure composed with an inode and several information to track how file was
                   opened and where we are within a file (well, again, that's a file descriptor)

Notes

       * I developped this lib and tested it with sd_card storage. It should be possible to use other
       * storages though not tested nor even tried.
       * to developpers: this piece of code is tricky... If you plan to modify this lib, take huge care
                         at variables initialization, there are special values I used, mostly to rollover
                         to 0 when first accessed. It could have been simpler but would have used more
                         variables and thus more resources. There are many counters which, when reaching
                         a specific value, trigger actions (like flushing data, going to next zone, allocate
                         a new zone, etc...). Just don't assume it'll work just because you added a small
                         little line, because everything is quite tied together and you could be victim
                         of an (un)expected butterfly effect :) I myself broke features many times with
                         supposedly minor changes, hurting my brain a lot. Being polite...

Dependencies

- strings

## Summary

### Global variables/contants

- `var word minix_sector_progress = 0`
- `const byte MINIX_ZONE_TRIPLE_INDIRECT = 0b_1000`
- `const word MINIX_SUPER_MAGIC = 0x137F`
- `const word MINIX_SUPER_MAGIC2 = 0x138F`
- `const dword MINIX_MAX_DIRECT_ZONE_SIZE = MINIX_NUM_DIRECT_ZONES * MINIX_BYTES_PER_BLOCK`
- `const byte MINIX_ERR_NONE = 0b_0000_0000`
- `const word MINIX_BOOT_BLOCK_ADDRESS = 0x00`
- `const dword MINIX_NUM_ZONE_BITS_PER_BLOCK = MINIX_BYTES_PER_BLOCK * 8`
- `var byte _minix_last_error = MINIX_ERR_NONE`
- `const word MINIX2_SUPER_MAGIC = 0x2468`
- `const word MINIX_SUPER_BLOCK_ADDRESS = MINIX_BOOT_BLOCK_ADDRESS + MINIX_BYTES_PER_BLOCK`
- `const word MINIX_INODE_ROOT_ID = 1`
- `const byte MINIX_MODE_WRITE = 0b010`
- `const word MINIX_BYTES_PER_INODE = 0x40`
- `const byte MINIX_ERR_NO_SUCH_FILE = 0b_0000_1000`
- `var minix_superblock minix_sb`
- `const byte MINIX_ERR_NOT_DIRECTORY = 0b_0000_0100`
- `const word MINIX_BYTES_PER_BLOCK = 0x400`
- `const word MINIX_MAX_INDIRECT_ZONE_IDX = 0x03FC`
- `const byte MINIX_MAX_FILENANE_LEN = 30`
- `const byte MINIX_NUM_DIRECT_ZONES = 7`
- `const word MINIX2_SUPER_MAGIC2 = 0x2478`
- `const byte MINIX_MODE_APPEND = 0b100`
- `const byte MINIX_ZONE_NONE = 0b_0000`
- `var dword minix_storage_address = 0`
- `const byte MINIX_ZONE_INDIRECT = 0b_0010`
- `const byte MINIX_ZONE_DOUBLE_INDIRECT = 0b_0100`
- `const byte MINIX_ERR_BAD_ADDRESS = 0b_0010_0000`
- `var minix_fd minix_filefd`
- `var dword minix_curzone`
- `var word minix_cwd`
- `const dword MINIX_NUM_INDIRECT_ZONES = 256`
- `const dword MINIX_NUM_DOUBLE_INDIRECT_ZONES = 65536`
- `const dword MINIX_MAX_INDIRECT_ZONE_SIZE = (MINIX_NUM_INDIRECT_ZONES * MINIX_BYTES_PER_BLOCK) + MINIX_MAX_DIRECT_ZONE_SIZE`
- `const word MINIX3_SUPER_MAGIC = 0x4D5A`
- `const byte MINIX_ZONE_DIRECT = 0b_0001`
- `const byte MINIX_MODE_READ = 0b001`
- `const byte MINIX_ERR_END_OF_FILE = 0b_0001_0000`
- `var byte minix_curzonetab[4] at minix_curzone`
- `const byte MINIX_MAX_DIRECT_ZONE_IDX = 6`
- `const word MINIX_MAX_DOUBLE_DIRECT_ZONE_IDX = 0x03FC`
- `const byte MINIX_ERR_BAD_ZONE_LOCATION = 0b_0000_0010`
- `const byte MINIX_ERR_BAD_MAGIC_NUMBER = 0b_0000_0001`

### Procedures

- `minix_read_super_block(bit in check_data_zone)`
- `minix_close()`
- `minix_init(bit in check)`
- `minix_next_zone(bit in create_zone)`
- `minix_open_block_byte(dword in blocknum, word in bytenum)`
- `minix_flush()`
- `minix_storage_write_byte(byte in data)`
- `minix_seek(dword in bytenum)`
- `minix_load_inode(word in inode_num)`
- `minix_cd(byte in dirname[MINIX_MAX_FILENANE_LEN])`
- `minix_storage_flush()`
- `minix_last_error'put(byte in val)`
- `minix_openi(word in inode_num,byte in mode)`
- `minix_cdi(word in inode_num)`
- `minix_write(byte in data)`
- `minix_open_block(dword in num)`
- `minix_open(byte in filename[MINIX_MAX_FILENANE_LEN],byte in mode)`
- `minix_save_inode()`

### Functions

- `minix_zone_alloc() return dword`
- `minix_find_in_cwd(byte in filename[MINIX_MAX_FILENANE_LEN]) return word`
- `minix_last_error'get() return byte`
- `minix_read() return byte`
- `minix_next_entry'get() return minix_dir_entry`
- `minix_storage_read_byte() return byte`

## API details

### Global variables/contants

- `var word minix_sector_progress = 0`

      track progress while accessing underlying storage sector

- `const byte MINIX_ZONE_TRIPLE_INDIRECT = 0b_1000`

  No documentation found

- `const word MINIX_SUPER_MAGIC = 0x137F`

      Magic numbers used to idenfity filesystem version

- `const word MINIX_SUPER_MAGIC2 = 0x138F`

      minix fs, 30 char names

- `const dword MINIX_MAX_DIRECT_ZONE_SIZE = MINIX_NUM_DIRECT_ZONES * MINIX_BYTES_PER_BLOCK`

  No documentation found

- `const byte MINIX_ERR_NONE = 0b_0000_0000`

      Error constants. Following "mkfs" convention, errors are added, so
      minix_last_error can embed several errors

- `const word MINIX_BOOT_BLOCK_ADDRESS = 0x00`

      Super Block is one block after boot block

- `const dword MINIX_NUM_ZONE_BITS_PER_BLOCK = MINIX_BYTES_PER_BLOCK * 8`

  No documentation found

- `var byte _minix_last_error = MINIX_ERR_NONE`

      Auto-resetting variable: errors are added, and when read, reset to 0

- `const word MINIX2_SUPER_MAGIC = 0x2468`

      minix V2 fs

- `const word MINIX_SUPER_BLOCK_ADDRESS = MINIX_BOOT_BLOCK_ADDRESS + MINIX_BYTES_PER_BLOCK`

  No documentation found

- `const word MINIX_INODE_ROOT_ID = 1`

      Inode --

- `const byte MINIX_MODE_WRITE = 0b010`

  No documentation found

- `const word MINIX_BYTES_PER_INODE = 0x40`

      64B per inode

- `const byte MINIX_ERR_NO_SUCH_FILE = 0b_0000_1000`

      try to access invalid/unexisting filename or inode

- `var minix_superblock minix_sb`

      super-block

- `const byte MINIX_ERR_NOT_DIRECTORY = 0b_0000_0100`

      try to act on a directory, but inode isn't a directory

- `const word MINIX_BYTES_PER_BLOCK = 0x400`

      1KB per block

- `const word MINIX_MAX_INDIRECT_ZONE_IDX = 0x03FC`

      0x400 - 4 == one block - one location

- `const byte MINIX_MAX_FILENANE_LEN = 30`

      max filename size according to minix v2

- `const byte MINIX_NUM_DIRECT_ZONES = 7`

  No documentation found

- `const word MINIX2_SUPER_MAGIC2 = 0x2478`

      minix V2 fs, 30 char names

- `const byte MINIX_MODE_APPEND = 0b100`

      write implied

- `const byte MINIX_ZONE_NONE = 0b_0000`

  No documentation found

- `var dword minix_storage_address = 0`

      track underlying storage address

- `const byte MINIX_ZONE_INDIRECT = 0b_0010`

  No documentation found

- `const byte MINIX_ZONE_DOUBLE_INDIRECT = 0b_0100`

  No documentation found

- `const byte MINIX_ERR_BAD_ADDRESS = 0b_0010_0000`

      bad block address

- `var minix_fd minix_filefd`

      file descriptor currently being accessed (file)

- `var dword minix_curzone`

  No documentation found

- `var word minix_cwd`

      current working directory (CWD) inode number

- `const dword MINIX_NUM_INDIRECT_ZONES = 256`

  No documentation found

- `const dword MINIX_NUM_DOUBLE_INDIRECT_ZONES = 65536`

  No documentation found

- `const dword MINIX_MAX_INDIRECT_ZONE_SIZE = (MINIX_NUM_INDIRECT_ZONES * MINIX_BYTES_PER_BLOCK) + MINIX_MAX_DIRECT_ZONE_SIZE`

  No documentation found

- `const word MINIX3_SUPER_MAGIC = 0x4D5A`

      minix V3 fs

- `const byte MINIX_ZONE_DIRECT = 0b_0001`

  No documentation found

- `const byte MINIX_MODE_READ = 0b001`

      File descriptor constants

- `const byte MINIX_ERR_END_OF_FILE = 0b_0001_0000`

      reached EOF

- `var byte minix_curzonetab[4] at minix_curzone`

  No documentation found

- `const byte MINIX_MAX_DIRECT_ZONE_IDX = 6`

  No documentation found

- `const word MINIX_MAX_DOUBLE_DIRECT_ZONE_IDX = 0x03FC`

      0x400 - 4 == one block - one location

- `const byte MINIX_ERR_BAD_ZONE_LOCATION = 0b_0000_0010`

      something is wrong about declared and computed data location

- `const byte MINIX_ERR_BAD_MAGIC_NUMBER = 0b_0000_0001`

      magic number unsupported

### Procedures

- `minix_read_super_block(bit in check_data_zone)`

      Read Super-Block and fill record

- `minix_close()`

  No documentation found

- `minix_init(bit in check)`

  No documentation found

- `minix_next_zone(bit in create_zone)`

      move to next data zone, being direct, indirect ou double
      indirect

- `minix_open_block_byte(dword in blocknum, word in bytenum)`

      move to block number, then to byte number within the block

- `minix_flush()`

  No documentation found

- `minix_storage_write_byte(byte in data)`

      "Raw" read one byte from underlying storage.

- `minix_seek(dword in bytenum)`

      move to byte bytenum within a file
      Notes: assuming file was just opened, no data read
      bytenum must be <= filesize, if greater, expect troubles

- `minix_load_inode(word in inode_num)`

      Load inode data, identified by inode_num, into file descriptor's
      (minix_filefd) inode parameter

- `minix_cd(byte in dirname[MINIX_MAX_FILENANE_LEN])`

  No documentation found

- `minix_storage_flush()`

  No documentation found

- `minix_last_error'put(byte in val)`

  No documentation found

- `minix_openi(word in inode_num,byte in mode)`

  No documentation found

- `minix_cdi(word in inode_num)`

  No documentation found

- `minix_write(byte in data)`

      write a byte to current opened file descriptor

- `minix_open_block(dword in num)`

      move to block number and open read access on underlying storage

- `minix_open(byte in filename[MINIX_MAX_FILENANE_LEN],byte in mode)`

  No documentation found

- `minix_save_inode()`

      Save current file desc's inode (minix_filefd.inode)

### Functions

- `minix_zone_alloc() return dword`

      Walk accross zone bitmap, searching for a free zone number (identified by 0s)
      and return available zone number.
      /!\ zone bitmap and file's content obviously aren't located the same. This means when
      allocating, we're moving in a different place (zone bitmap) than we previously were
      while writing into the file. It's the caller's responsability to move the correct location
      once allocation is done. Yes, that's right: it's dirty, as zone_alloc() won't let the system
      in its previous state. ("why ?" you may ask... because it's simpler like that, and anyway,
      this procedure is somewhat internal, so it shouldn't be a problem in the end).

- `minix_find_in_cwd(byte in filename[MINIX_MAX_FILENANE_LEN]) return word`

      return inode number found for given filename
      can be a file or a dir name) in current directory

- `minix_last_error'get() return byte`

  No documentation found

- `minix_read() return byte`

      Read bytes from file descriptor.
      Walk over memory zones given, returning content
      byte by byte. firt walk over direct zones, then
      swith indirect then double indirect zones. Keep
      track of progress within inode

- `minix_next_entry'get() return minix_dir_entry`

      list current working directory (cwd), returning a
      directory entry each time it's called, until no more
      entry found.

- `minix_storage_read_byte() return byte`

      "Raw" read one byte from underlying storage.

## Related samples

Here are the list of samples which use this library:

18f27j53 | 18f27j53_sd_card_minix_demo.jal
18f27j53 | 18f27j53_sd_card_minix_readi.jal
18f27j53 | 18f27j53_sd_card_minix_read.jal