~vdupras/duskos

cd8c1b3528215e91fa4d3727c096ee0ad2f3d92d — Virgil Dupras a month ago 66f0ce6
ar/tar: new unit

See doc/ar/tar.
3 files changed, 132 insertions(+), 2 deletions(-)

A fs/ar/tar.fs
A fs/doc/ar/tar.txt
M fs/xcomp/bootlo.fs
A fs/ar/tar.fs => fs/ar/tar.fs +46 -0
@@ 0,0 1,46 @@
: parseoctal ( a u -- n )
  0 swap for ( a res ) 8 * over c@ '0' - + dip 1+ | next nip ;

struct[ TarRecord
  $200 const RECORDSZ

  100 sfield' zname
  8   sfield' omode \ o prefix means "octal", ASCII octal.
  8   sfield' ouid
  8   sfield' ogid
  12  sfield' ofilesz
  12  sfield' omtime
  8   sfield' checksum
      sfieldb type
  100 sfield' zlinkname

  : :empty? ( self -- f ) @ not ;
  : :dir? type '5' = ;
  create _buf 100 allot
  : :name ( self -- str )
    zname 0 over 100 [c]? ( zname len )
    2dup 1- + c@ '/' = if 1- then ( zname len )
    dup _buf c!+ swap move _buf ;
  : :filesize ( self -- sz ) ofilesz 11 parseoctal ;
]struct

struct[ Tar
  sfield drv
  sfield sec0
  sfield sec
  SZ &+ buf(
  : :sec! ( sec self -- ) 2dup to sec bi buf( | drv Drive :sec@ ;
  : :new ( sec0 drv -- tar )
    here rot> dup , over , -1 , Drive secsz allot ( tar sec ) over :sec! ;
  : :record ( self -- rec ) buf( ;
  : :rewind dup sec0 swap :sec! ;
  : :next ( self -- rec )
    dup :record dup TarRecord :empty? if abort" end of tar chain" then
    TarRecord :filesize TarRecord RECORDSZ /mod swap bool + 1+ ( self sec+ )
    over sec + over :sec! :record ;
  : :find ( name self -- rec? f ) >r \ V1=self
    V1 :rewind V1 :record begin ( name rec )
      dup TarRecord :empty? not while
      TarRecord :name over s= not while ( name )
      V1 :next repeat drop r> :record 1 else drop rdrop 0 then ;
]struct

A fs/doc/ar/tar.txt => fs/doc/ar/tar.txt +84 -0
@@ 0,0 1,84 @@
# Tape archive (tar) tools

The /ar/tar.fs unit contains tool to manipulate archives of the "tar" format
originating from UNIX. It does so through two structs.

## TarRecord

This wraps a 512 bytes tar header record containing metadata about the
represented element. You are supposed to use it with a pointer to the actual
data. For example, if you've read a tar header sector to "here", then "here
TarRecord :name" will yield the name of the record.

Fields:

zname
omode
ouid
ogid
ofilesz
omtime
checksum
zlinkname
  Pointer to the address corresponding to the record field.

type
  Character corresponding to the record type ('5'=directory, NULL=file)

Methods:

:empty? ( self -- f )
  Whether the record is empty (starts with null characters).

:dir? ( self -- f )
  Whether the record is a directory (type = '5')

:name ( self -- str )
  Name of the file or directory. If the name has a trailing '/', it is removed.
  This name is stored in a static buffer that is overwritten at each :name call.

:filesize ( self -- sz )
  Parsed version of "ofilesz". This is the file size in bytes that follow the
  record.

## Tar

This structure iterates over a Drive, interpreting sectors as tar records. At
creation, it is supplied a Drive struct as well as an "origin" sector. Is is
then possible to iterate over record through :next or to find a record with a
specific name through :find.

Fields:

drv
  Drive we're iterating through

sec0
  Origin sector number

sec
  Sector of the current record

buf(
  Buffer with the contents of the current sector

Methods:

:new ( sec0 drv -- tar )
  Create new Tar with specified Drive and origin sector.

:sec! ( sec self -- )
  Read and set current sector.

:record ( self -- rec )
  TarRecord we're currently pointing at.

:rewind ( self -- )
  Set current sector to origin sector.

:next ( self -- rec )
  Advance current sector to next record and return it.

:find ( name self -- rec? f )
  Rewind, then iterate over record over a record of the specified name is found.
  If found, f=1 and rec is set. Otherwise, f=0 and rec is absent.

M fs/xcomp/bootlo.fs => fs/xcomp/bootlo.fs +2 -2
@@ 377,8 377,8 @@ create _ 0 , EMETA_8B , EMETA_16B ,
struct[ Drive
  sfield secsz
  sfield seccnt
  smethod :sec@
  smethod :sec!
  smethod :sec@ ( sec dst drv -- )
  smethod :sec! ( sec src drv -- )
]struct

struct[ IO