poke-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC] redoxfs.pk: Pickle for RedoxFS file system


From: Mohammad-Reza Nabipoor
Subject: [RFC] redoxfs.pk: Pickle for RedoxFS file system
Date: Fri, 18 Dec 2020 19:19:37 +0330

Hi, Jose.

This pickle `redoxfs.pk` needs your review!
It needs more systematic tests to make sure I didn't miss anything.

The final goal is to provide all facilities to put data in the FS or
get data from it:
  - ls
  - ar a
  - ar x
  - find
  - ...


Regards,
Mohammad-Reza

---

/* redoxfs.pk - RedoxFS file system of Redox OS.  */

/* Copyright (C) 2020 The poke authors */

/* This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/* RedoxFS
 * File-system of RedoxOS (a Unix-like operating system written in Rust)
 *
 * The file-system has a header (type `RedoxFS_Header`). Header has a
 * pointer to root node. Nodes are represented by type `RedoxFS_Node`.
 * Data is stored in `extents` of each node. Extents are represented
 * by type `RedoxFS_Extents`. Each node has 238 extents. If a node needs
 * more extents, it will use the extents of the `next` node.
 * Each node can be a file or directory or symlink.
 * Extents of file nodes are point to the actual data. And extents of
 * directory nodes are point to child nodes.
 *
 * https://gitlab.redox-os.org/redox-os/redoxfs/
 */

/* set_endian(ENDIAN_LITTLE); */

load time;

/* Block size */
unit RedoxFS_BLKSZ = 4096UL * 8;  /* `4096*8` bits */

type RedoxFS_Extent =
  struct
  {
    offset<uint<64>,RedoxFS_BLKSZ> block;
    offset<uint<64>,B> length;

    method empty = int:
      {
        return block == 0#B && length == 0#B;  /* CHKME block ?= 0#B */
      }
    method data = uint<8>[]:
      {
        return uint<8>[length] @ block;
      }
  };

var RedoxFS_MODE_TYPE    = 0xF000UH,
    RedoxFS_MODE_FILE    = 0x8000UH,
    RedoxFS_MODE_DIR     = 0x4000UH,
    RedoxFS_MODE_SYMLINK = 0xA000UH;

var RedoxFS_MODE_PERM  = 0x0FFFUH,
    RedoxFS_MODE_EXEC  = 0o1UH,
    RedoxFS_MODE_WRITE = 0o2UH,
    RedoxFS_MODE_READ  = 0o4UH;

/* A file/folder node */
type RedoxFS_Node =
  struct
  {
    uint<16> mode;
    uint<32> uid;
    uint<32> gid;
    uint<64> ctime;
    uint<32> ctime_nsec;
    uint<64> mtime;
    uint<32> mtime_nsec;
    uint<64> atime;
    uint<32> atime_nsec;
    uint<8>[226] name;
    offset<uint<64>,RedoxFS_BLKSZ> parent;
    offset<uint<64>,RedoxFS_BLKSZ> next;
    RedoxFS_Extent[(#RedoxFS_BLKSZ/#B - 288UL) / (#RedoxFS_Extent/#B)] extents;

    method isdir = int:
      {
        return (mode & RedoxFS_MODE_DIR) == RedoxFS_MODE_DIR;
      }
    method isfile = int:
      {
        return (mode & RedoxFS_MODE_FILE) == RedoxFS_MODE_FILE;
      }
    method issymlink = int:
      {
        return (mode & RedoxFS_MODE_SYMLINK) == RedoxFS_MODE_SYMLINK;
      }
  };

type RedoxFS_Header =
  struct
  {
    uint<8>[8] signature = ['R', 'e', 'd', 'o', 'x', 'F', 'S', 0UB];
    uint<64> version = 4UL;

    /* Disk ID, a 128-bit unique identifier */
    uint<8>[16] uuid;

    offset<uint<64>,B> size;

    offset<uint<64>,RedoxFS_BLKSZ> root;  /* Block of root node */
    offset<uint<64>,RedoxFS_BLKSZ> free;  /* Block of free space node */

    /* Padding */
    /* uint<8>[#RedoxFS_BLKSZ/#B - 56UL]; */
  };


/* Node pretty-printer
 *
 * Prints the contents of a `RedoxFS_Node` in a readable fashion.
 * To increase readability, only non-empty extents are get printed before any
 * other fields. By default, extents are get printed from first one to last
 * one by default, but this can be changed by passing 1 in `reverse` argument.
 */
fun redoxfs_nprint = (RedoxFS_Node n, int reverse = 0) void:
  {
    print ("#<\n  extents = [\n");

    var f = reverse ? n.extents'length : 0UL;  /* first */
    var l = reverse ? 0UL : n.extents'length;  /* last  */

    while (f != l) {
      if (reverse)
        --f;

      var e = n.extents[f];

      if (!e.empty)
        printf ("    .[%u64d]={block=%v, length=%v}\n", f, e.block, e.length);

      if (!reverse)
        ++f;
    }

    var mtype =
      n.issymlink ? "FILE | SYM"
      : n.isfile ? "FILE"
      : n.isdir ? "DIR"
      : "" ;

    printf (
      "  ],\n  mode=%s | %u12o,\n  uid=%u32d,\n  gid=%u32d,\n  ctime=%u64d (",
      mtype, n.mode & RedoxFS_MODE_PERM, n.uid, n.gid, n.ctime);
    ptime (n.ctime);
    printf ("),\n  ctime_nsec=%u64d,\n  mtime=%u64d (", n.ctime_nsec, n.mtime);
    ptime (n.mtime);
    printf ("),\n  mtime_nsec=%u64d,\n  atime=%u64d (", n.mtime_nsec, n.atime);
    ptime (n.atime);
    printf (
      "),\n  atime_nsec=%u64d,\n  name=%s,\n", n.atime_nsec, catos (n.name));
    printf ("  parent=%v,\n  next=%v,\n>\n", n.parent, n.next);
  }

fun redoxfs_root = (RedoxFS_Header hdr = RedoxFS_Header @ 0#B) RedoxFS_Node:
  {
    return RedoxFS_Node @ hdr.root;
  }

/* Visits all the extents of a node (extents + next.extents +
 * next.next.extents + ...).
 */

type RedoxFS_EVisitor = (RedoxFS_Extent) void;
fun redoxfs_extents = (RedoxFS_Node n, RedoxFS_EVisitor v) uint<64>:
  {
    var c = 0;  /* counter */
    var nxt = n.next;

    for (e in n.extents where !e.empty)
      {
        ++c;
        v (e);
      }
    while (nxt != 0#B)
      {
        n = RedoxFS_Node @ nxt;
        nxt = n.next;
        for (e in n.extents where !e.empty)
          {
            ++c;
            v (e);
          }
      }
    return c;
  }

/* File-system walker
 *
 * `redoxfs_walk` traverse the file-system hierarchy and call the vistor
 * callback function for each entiry (file, directory or symlink).
 *
 * First argument of visitor `ftype` is `'f'` for files, `'d'` for
 * directories and `'s'` for symlinks. The next argument is the name of
 * the entity. The third one is path of parent directory of the entity.
 * The last argument is an array of extents corresponds to the entity.
 */

type RedoxFS_Visitor =
  (char /*ftype*/, string /*name*/, string /*path*/, RedoxFS_Extent[]) void;

fun redoxfs_walk = (RedoxFS_Node n, RedoxFS_Visitor v) void:
  {
    fun nothing = (RedoxFS_Extent e) void: {};
    fun filev = (RedoxFS_Node n, string curdir) void:
      {
        /* TODO(mnabipoor) Measure performance of array construction */
        var es_count = redoxfs_extents (n, nothing);
        var es = RedoxFS_Extent[es_count] ();
        var i = 0UL;

        redoxfs_extents (n, lambda (RedoxFS_Extent e) void: { es[i++] = e; });
        v('f', catos (n.name), curdir, es);
      }
    fun visit = (RedoxFS_Node n, string curdir) void:
      {
        if (n.issymlink)
          v('s', catos (n.extents[0].data), curdir, RedoxFS_Extent[] ());
        else if (n.isfile)
          filev (n, curdir);
        else if (n.isdir)
          {
            var name = catos (n.name);
            var path = (curdir == "/" ? "" :  curdir) + "/" + name;
            var es_count = redoxfs_extents (n, nothing);
            var es = RedoxFS_Extent[es_count] ();
            var i = 0UL;
            fun ev = (RedoxFS_Extent e) void:
              {
                es[i++] = e;
                visit (RedoxFS_Node @ e.block, path); 
              };

            redoxfs_extents (n, ev);
            v('d', name, curdir, es);
          }
      }
    var nxt = n.next;

    visit (n, "/");
    while (nxt != 0#B)
      {
        n = RedoxFS_Node @ nxt;
        nxt = n.next;
        visit (n, "/");
      }
  }


reply via email to

[Prev in Thread] Current Thread [Next in Thread]