#lang scribble/doc
@(require
  scribble/manual
  (for-label racket
             (planet "main.rkt" ("murphy" "packed-io.plt" 1 1))
             "../data.rkt"))

@title[#:tag "data"]{Basic Data Structures}

@local-table-of-contents[]

@defmodule[(planet "data.rkt" ("murphy" "9p.plt" 2 0))]{

  Basic data structures that are used by the network level code as well
  as the high level client and server side code.

}

@section{File Information}

@defstruct[qid ([type natural-number/c]
                [version natural-number/c]
                [path natural-number/c])]{

  Information identifying a file in a filesystem uniquely. While
  @racket[type] determines whether the file is a directory and
  contains other type flags, @racket[path] and @racket[version]
  contain an arbitrary combination of numbers unique among all files
  on the file system.
  
  See @hyperlink["http://swtch.com/plan9port/man/man9/stat.html"]{stat(9P)}
  for details about the contents of the structure.

}

@defstruct[stat ([type (or/c natural-number/c #f)]
                 [dev (or/c natural-number/c #f)]
                 [qid (or/c qid? #f)]
                 [mode (or/c natural-number/c #f)]
                 [atime (or/c natural-number/c #f)]
                 [mtime (or/c natural-number/c #f)]
                 [length (or/c natural-number/c #f)]
                 [name (or/c string? #f)]
                 [uid (or/c string? #f)]
                 [gid (or/c string? #f)]
                 [muid (or/c string? #f)])]{

  A directory entry. When reading directories or asking files for their
  stat information, the result normally doesn't contain fields set
  to @racket[#f]. When setting the stat information for a file, any
  field specified as @racket[#f] is not changed. Many fields must
  actually be specified as @racket[#f] in that case, because they are
  considered immutable.
  
  See @hyperlink["http://swtch.com/plan9port/man/man9/stat.html"]{stat(9P)}
  for details about the contents of the structure.

}

@defform[(type-flag id)
         #:contracts ([id (symbols 'file 'dir 'append 'excl 'mount 'auth 'temp)])]{

  Enumeration of file type flags as contained in the @racket[qid-type]
  field or the high bits of the @racket[stat-mode] field. @racketid[file]
  is the neutral value just indicating a normal file, @racketid[dir]
  identifies directories, @racketid[append] files that can oly be
  appended to, @racketid[excl] stands for exclusive access, @racketid[mount]
  indicates mountpoints, @racketid[auth] authentication channels and
  @racketid[temp] temporary files.

}

@defform[(file-type id ...)]{

  Expands to a numeric file type computed from a bitwise inclusive or
  of flag values specified by identifiers as for @racket[type-flag].

}

@defform[(access-flag id)
         #:contracts ([id (symbols 'e 'x 'w 'r)])]{

  Enumeration of file permission flags as contained in the lower bits
  of the @racket[stat-mode] field. @racketid[e] is the neutral value
  and just indicates file existence in permission checks, @racketid[x]
  means execute acces, @racketid[w] write access and @racketid[r] read
  access.

}

@defform*[#:literals (type user group others)
          ((file-mode (type id ...) (user id ...) (group id ...) (others id ...))
           (file-mode (user id ...) (group id ...) (others id ...))
           (file-mode type-bits perm-bits))]{

  Expands to a numeric file mode computed from a bitwise inclusive or
  of bit shifted flag values for the type, specified by identifiers as
  for @racket[type-flag], and for the access permissions, specified by
  identifiers as for @racket[access-flag].
  
  The type clause can be omitted or both type and permissions can be
  given directly as numbers, in which case the macro may still be useful
  because you don't have to remember the correct bit shift counts to
  combine those values.

}


@defproc[(file-mode-type [m natural-number/c]) natural-number/c]{

  Extracts the bits defining the type of a file from a numeric
  file mode.

}

@defproc[(file-mode-user [m natural-number/c]) natural-number/c]{

  Extracts the bits defining the access permissions for a file's owner
  from a numeric file mode.

}

@defproc[(file-mode-group [m natural-number/c]) natural-number/c]{

  Extracts the bits defining the access permissions for members of a
  file's owning group from a numeric file mode.

}

@defproc[(file-mode-others [m natural-number/c]) natural-number/c]{

  Extracts the bits defining the access permissions for other users
  than the file's owner or members of its owning group from a numeric file mode.

}

@section{Operation Modes}

@defform[(open-direction id)
         #:contracts ([id (symbols 'r 'w 'r/w 'x)])]{

  Enumeration of basic access types when opening a file. @racketid[r]
  means read access, @racketid[w] write access, @racket[r/w] both read
  and write access and @racketid[x] means execute access.
  
  Execute access behaves like read access except for the permission
  checks which use execute instead of read permissions.

}

@defform[(open-flag id)
         #:contracts ([id (symbols 'trunc 'rclose)])]{

  Enumeration of additional flags that can be used when opening a file.
  @racketid[trunc] means the file, if opened for writing, should have its
  size reset to zero, @racketid[rclose] means the file should be removed
  once it is closed.

}

@defform[(open-mode dir-id flag-id ...)]{

  Expands to a numeric mode that can be passed to file open calls.
  The mode is computed as a bitwise inclusive or of a direction
  value and open flags that are specified by identifiers as for
  @racket[open-direction] and @racket[open-flag].

}

@defproc[(open-mode-direction [m natural-number/c]) natural-number/c]{

  Extracts the direction value from a numeric file open mode.

}

@defproc[(open-mode-flags [m natural-number/c]) natural-number/c]{

  Extracts the additional open flags from a numeric file open mode.

}

@section[#:tag "data/packing"]{Packings}

@defthing[nstring/p packing?]{

  Packing of a string prefixed with 16 bit size information.

}

@defthing[nbytes/p packing?]{

  Packing of a byte string prefixed with 16 bit size information

}

@defthing[qid/p packing?]{

  Packing of a @racket[qid] file identifier structure.

}

@defthing[stat/p packing?]{

  Packing of a @racket[stat] directory entry structure.

}
