1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
# 9P2000.txt - Definitions of 9P2000 messages
#
# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-Licence-Identifier: AGPL-3.0-or-later
# The format of each message (excluding the "size[4] msg_type[1]
# tag[2]" header) is written here as a sequence of
# "member_name[member_type]" struct members.
#
# The primitive member types types are the following single-character
# mnemonics:
#
# - 1 = u8
# - 2 = u16le
# - 4 = u32le
# - 8 = u16le
# "9P2000" base protocol
# https://ericvh.github.io/9p-rfc/rfc9p2000.html
# https://github.com/ericvh/9p-rfc/blob/master/9p2000.xml
#
# But due to incompleteness of the draft RFC, the Plan 9 manual
# section-5 and the Plan 9 headers (particularly fcall.h) are a better
# references.
version "9P2000"
# data (u32le `n`, then `n` bytes of data)
d = "len[4] len*(dat[1])"
# string (u16le `n`, then `n` bytes of UTF-8)
s = "len[2] len*(utf8[1])"
# QID Type (see qid below)
bitfield qt 8
7/DIR
6/APPEND
5/EXCL
# QTMOUNT has been around in Plan 9 forever, but is
# undocumented, and is explicitly excluded from the 9P2000
# draft RFC. As I understand it, QTMOUNT indicates that the
# file is mounted by the kernel as a 9P transport; that the
# kernel has a lock on doing I/O on it, so userspace can't do
# I/O on it.
4/_PLAN9_MOUNT
3/AUTH
# Fun historical fact: QTTMP was a relatively late addition to
# Plan 9, in 2003-12.
2/TMP
#1/unused
# "The name QTFILE, defined to be zero, identifies the value
# of the type for a plain file."
FILE=0
# uni"Q"ue "ID"entification - "two files on the same server hierarchy
# are the same if and only if their qids are the same"
#
# - "path" is a unique uint64_t that does most of the work in the
# above statement about files being the same if their QIDs are the
# same; " If a file is deleted and recreated with the same name in
# the same directory, the old and new path components of the qids
# should be different"
#
# - "vers" "is a version number for a file; typically, it is
# incremented every time the file is modified.
#
# - "type" indicates "whether the file is a directory, append-only
# file, etc."; is an instance of the qid_type bitfield.
qid = "type[qt] vers[4] path[8]"
# stat (TODO)
stat = "stat_size[2]"
"kern_type[2]"
"kern_dev[4]"
"file_qid[qid]"
"file_mode[4]"
"file_atime[4]"
"file_mtime[4]"
"file_size[8]"
"file_name[s]"
"file_owner_uid[s]"
"file_owner_gid[s]"
"file_last_modified_uid[s]"
# "O"pen flags (flags to pass to Topen and Tcreate)
bitfield o 8
0/_rwx_0 # low bit of the 2-bit READ/WRITE/RDWR/EXEC enum
1/_rwx_1 # high bit of the 2-bit READ/WRITE/RDWR/EXEC enum
#2/unused
#3/unused
4/TRUNC
#5/unused
6/RCLOSE # remove-on-close
#7/unused
READ = 0
WRITE = 1
RDWR = 2
EXEC = 3
# In the 9P protocol, each message has a type, and message types come
# in pairs (except "Rerror"); "T" and "R"; "T" messages are
# client->server requests, and "R" messages are server->client
# responses (I do not know what the Plan 9 designers intended "T" and
# "R" to stand for). The type of a message is represented by a u8 ID.
100/Tversion = "max_msg_size[4] version[s]"
101/Rversion = "max_msg_size[4] version[s]"
102/Tauth = "afid[4] uname[s] aname[s]"
103/Rauth = "aqid[qid]"
104/Tattach = "fid[4] afid[4] uname[s] aname[s]"
105/Rattach = "qid[qid]"
#106/Terror = "illegal"
107/Rerror = "ename[s]"
108/Tflush = "oldtag[2]"
109/Rflush = ""
110/Twalk = "fid[4] newfid[4] nwname[2] nwname*(wname[s])"
111/Rwalk = "nwqid[2] nwqid*(wqid[qid])"
112/Topen = "fid[4] mode[o]"
113/Ropen = "qid[qid] iounit[4]"
114/Tcreate = "fid[4] name[s] perm[4] mode[o]"
115/Rcreate = "qid[qid] iounit[4]"
116/Tread = "fid[4] offset[8] count[4]"
117/Rread = "data[d]" # for directories data is the sequence "cnt*(entries[stat])"
118/Twrite = "fid[4] offset[8] data[d]"
119/Rwrite = "count[4]"
120/Tclunk = "fid[4]"
121/Rclunk = ""
122/Tremove = "fid[4]"
123/Rremove = ""
124/Tstat = "fid[4]"
125/Rstat = "stat[stat]"
126/Twstat = "fid[4] stat[stat]"
127/Rwstat = ""
|