2.1 Input/Output

Most of the times, standard input, standard output, and standard error go to /dev/cons. This file represents the console for your program.It is the interface to use the device that is known as the console, which corresponds to your terminal.The file interface provided for each process in Plan 9 has a file that provides the list of open file descriptors for the process. For example, to know which file descriptors are open in the shell we are using we can do this.

 term% cat /proc/$pid/fd/usr/glenda
 0 r  M   40 (0000000000000001 0 00)  8192       47 /dev/cons
 1 w  M   40 (0000000000000001 0 00)  8192     3506 /dev/cons
 2 w  M   40 (0000000000000001 0 00)  8192     3506 /dev/cons
 3 r  M    8 (000000000000166b 2 00)  8192      512 /rc/lib/rcmain
 4 r  M   40 (0000000000000001 0 00)  8192       47 /dev/cons

Each time you open a file, the system keeps track of a file offset for that open file, to know the offset in the file where to start working at the next read or write.
The offset for a file descriptor can be changed using the seek system call.

2.2 Write games

A Chan(or Channel) is a data structure, which contains all the information needed to let the kernel reach the file server and perform operations on the file. A Chan is just something used by Plan 9 to speak to a server regarding a file. This may require doing remote procedure calls across the network, but that is up to your kernel, and you can forget. There is one Chan per file in use in the system.

The size of a file corresponds to the highest file offset ever written on it. All the bytes that we did not write were set to zero by Plan 9.
seek(fd, 0, 2); // move to the end
append only permission bit :
; chmod +a /sys/log/diagnostics
; ls -l /sys/log/diagnostics
a-rw-r--r-- M 19 nemo nemo 0 Jul 10 01:11 /sys/log/diagnostics
+a permission bit guarantees that any write will happen at the end of existing data, no matter what the offset is.
Doing a seek in all programs using this file might not suffice. If there are multiple machines writing to this file, each machine would keep its own offset for the file. Therefore, there is some risk of overwriting some data in the file.
The create system call creates one file.
The system call remove removes the named file.
The system call access to check file properties.

2.3 Directory Entry

File metadata is simply what the system needs to know about the file to be able to implement it. File metadata includes the file name, the file size, the time for the last modification to the file, the time for the last access to the file, and other attributes for the file. Thus, file metadata is also known as file attributes.
Plan 9 stores attributes for a file in the directory that contains the file. Thus, the data structure that contains file metadata is known as a directory entry. A directory contains just a sequence of entries, each one providing the attributes for a file contained in it.
To obtain the directory entry for a file, i.e., its attributes, we can use dirstat. This function  uses the actual system call, stat, to read the data, and returns a Dir structure that is more convenient to use in C programs. This structure is stored in dynamic memory allocated with malloc  by dirstat, and the caller is responsible for calling free on it.
Because directories contain directory entries, reading from a directory is very similar to  what we have just done. The function read can be used to read directories as well as files. The  only difference is that the system will read only an integral number of directory entries. If one  more entry does not fit in the buffer you supply to read, it will have to wait until you read again.
The entries are stored in the directory in a portable, machine independent, and not amenable, format. Therefore, instead of using read, it is more convenient to use dirread. This  function calls read to read the data stored in the directory. But before returning to the caller, it  unpacks them into a, more convenient, array of Dir structures.
The function dirwstat is the counterpart of dirstat. It works in a similar way, but  instead of reading the attributes, it updates them. New values for the update are taken from a Dir  structure given as a parameter. However, the function ignores any field set to a null value, to  allow you to change just one attribute, or a few ones. Beware that zero is not a null value for some of the fields, because it would be a perfectly legal value for them. The function nulldir  is to be used to null all of the fields in a given Dir.

2.4 Bio

The bio(2) library in Plan 9 provides buffered input/output. This is an abstraction that,although not provided by the underlying Plan 9, is so common that you really must know how it works. The idea is that your program creates a Bio buffer for reading or writing, called a Biobuf. Your program reads from the Biobuf, by calling a library function, and the library will call read only to refill the buffer each time you exhaust its contents.

#include <u.h>
#include <libc.h>
#include <bio.h>
static void
usage(void)
{
    fprint(2,"usage: %s [-b bufsz] infile outfile/n", argv0);
    exits("usage");
}
void
main(int argc, char* argv[])
{
    char* buf;
    long nr, bufsz = 8*1024;
    Biobuf* bin;
    Biobuf* bout;
    ARGBEGIN{
    case 'b':
        bufsz = atoi(EARGF(usage()));
        break;
    default:
        usage();
    }ARGEND;
    if (argc !=2)
        usage();
    buf = malloc(bufsz);
    if (buf == nil)
        sysfatal("no more memory");
    bin = Bopen(argv[0], OREAD);
    if (bin == nil)
        sysfatal("%s: %s: %r", argv0, argv[0]);
    bout = Bopen(argv[1], OWRITE);
    if (bout == nil)
        sysfatal("%s: %s: %r", argv0, argv[1]);
    for(;;) {
        nr = Bread(bin, buf, bufsz);
        if (nr < 0)
            break;
        Bwrite(bout, buf, nr);
    }
    Bterm(bin);
    Bterm(bout);
    exits(nil);
}