š¾ Archived View for gemini.omarpolo.com āŗ post āŗ taking-about-9p-intro.gmi captured on 2024-05-10 at 11:00:33. Gemini links have been rewritten to link to archived content
ā¬ ļø Previous capture (2023-01-29)
-=-=-=-=-=-=-
Getting to know 9P
Written while listening to āThe Pharaoh Sails to Orionā by Nightwish.
Published: 2021-07-31
Tagged with:
These days Iām hacking on 9P. In case you donāt know, 9P is a protocol for a network file system that was developed as part of the plan9 operating system.
Now, to make it clear, Iāve never ā sigh! ā used 9P nor plan9 before. Iām just starting to explore the 9P protocol, hacking something together (for a secret project), and writing some notes here on my blog.
If you find some errors please be kind and notify me. The contacts are at the end of every entry in the Gemini version of this blog.
The 9P protocol is pretty simple: the client sends requests (called T-messages) and the server replies (with R-messages). Replies can be delayed or received out of order. A transaction of some type is completed when the server replies with the matching R-message (or with an error).
Iām going to use the same syntax used in the plan9 manpages to describe the packets. Fields are written as name[n] where ānameā represents the name of the field and ānā (which is either 1, 2, 4, 8 or 13) represents the number of byte. An exception to this rule are strings and other variable-width fields: they are represented by a two-byte integer counter followed by the actual data. Strings in particular are denoted as name[s] (where āsā is a literal s character.)
Integers are transmitted in little-endian format, and strings are encoded in UTF-8 without the NUL-terminator. The NUL byte is illegal in strings transmitted over 9P and thus excluded by paths, user login names etc.
Both the requests and the replies share a common structure, the header, which looks like this
size[4] type[1] tag[2]
Size, the first field, is a 32 bit field that indicates the length of the message (including āsizeā itself!). Type is a one-byte integer that specifies the type of the requests and tag is an arbitrary client-chosen integer that uniquely represents this transaction. The client cannot issue two or more ongoing transaction with the same tag.
Following the header there is an optional body whose structure depends on the type of message.
Clients can only send T-messages, and the server can only reply with a R-message.
The available messages are:
There are some extension (or ādialectsā should I say) of 9P which adds (and slightly change) these messages, but at least for now Iām trying to stick to 9P2000 āvanillaā.
An important role in 9P is played by āqidās and āfidās. A fid is a 32bit integer chosen by the client that identifies a ācurrent fileā on the server. They are similar, albeit different, to UNIX file descriptors. Qids are the server idea of a file: they are a jumbo object of a whopping 13 bytes: the first one identifies the type (whether is a file, directory, and so on), a four byte integer unique among all files in the hierarchy called āpathā and a four byte āversionā field that should get incremented every time the file is modified.
Fids are often present in T-messages and qids in R-messages.
The first message that a client should issue after it has established a connection to a file server is Tversion to negotiate the version used and the maximum size of the packets. The Tversion signature is
size[4] Tversion tag[2] msize[4] version[s]
(from now on Iāll omit the three header fields when describing the structure of a packet)
The msize is the maximum size of a packet that the client is willing to accept, and the version is a string the identifies the protocol version used. It MUST start with the ā9Pā characters. The client canāt issue further requests until the server replies with a Rversion, which has the same structure. The msize replied by the server has to be smaller or equal to the one proposed by the client.
Then there is an optional authentication using Tauth. Iām not interested in how ānormalā authentication works in 9P in my project (for now at least), but the idea is that the server provides to the client a special āauthentication fileā that an unauthenticated client can read and write to. This is used to implement a custom auth protocol which is external to 9P.
At this point the client can āattachā a file tree using Tattach:
fid[4] afid[4] uname[s] aname[s]
If successful, fid will represent the file tree accessed by aname. āafidā is the authentication fid, which can be -1 (i.e. 0xFFFFFFFF) for the no-authentication case. āunameā is the user name.
If successful, the client has access to a file tree and can start moving around (by means of Twalk) and messing with files (Topen, Tremove, ā¦). This is also all for the introduction: future entries will focus in particular about the other kinds of messages.
-- text: CC0 1.0; code: public domain (unless specified otherwise). No copyright here.